feat(core): home router NAT after Java, measured with Java FILIUS

The core translates before the IP thread, as Java's NAT threads sit
between card and Ethernet: out, the WAN address and the entry's port (ICMP
keeps its identifier); in, by remote end, port and protocol, else by the
port forwarding, which then makes a dynamic entry; a ping at the WAN
address is answered by the router, packets from outside for the LAN are
dropped, both sides pass the router's firewall, TTL 1 going out gets time
exceeded. Dynamic entries expire at Java's check each second, 300 s times
the delay factor old (55 minutes at 90 %), refreshed only by what comes in.
The home router forwards as a router does.

Measured and not taken: when a LAN endpoint sends to a second remote end,
Java gives it the entry's WAN port but no entry, and the answer stays at
the router; the core adds an entry for each new remote end on that port.

The oracle now records every card of a node (the second card of routers
was missing); the ARP and RIP runs are recorded anew and still match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 20:06:04 +00:00
co-authored by Claude Opus 5.5
parent 5505e8e8af
commit 7a77bc1b43
23 changed files with 2915 additions and 748 deletions
+8
View File
@@ -51,6 +51,8 @@ export interface Scenario {
{ active?: boolean; lower?: string; upper?: string; gateway?: string; dns?: string; own?: boolean; staticAssignments?: [string, string][] }
>;
dhcpClients?: string[];
/** Home routers' port forwarding: rows of protocol, public port, LAN address, LAN port. */
portForwarding?: Record<string, [string, string, string, string][]>;
/** Routers with RIP switched on. */
rip?: string[];
/** Records as `name TYPE target` (Java's hinzuRecord: TTL 3600). */
@@ -164,6 +166,12 @@ export function snapshotOf(scenario: Scenario): TopologySnapshot {
),
dhcpClientConfigurationsByNodeId: new Map((scenario.dhcpClients ?? []).map((node) => [node, { isEnabled: true }])),
ripEnabledByNodeId: new Map((scenario.rip ?? []).map((node) => [node, true])),
portForwardingRowsByNodeId: new Map(
Object.entries(scenario.portForwarding ?? {}).map(([node, rows]) => [
node,
rows.map(([protocolValue, publicPortValue, lanIPAddress, lanPortValue]) => ({ protocolValue, publicPortValue, lanIPAddress, lanPortValue })),
]),
),
switchConfigurationsByNodeId: new Map(
Object.entries(scenario.switches ?? {}).map(([node, config]) => [
node,