From e80be3bbdfdfc1601ec75bd6cbe8aeb73b882678 Mon Sep 17 00:00:00 2001 From: Julian Kiedaisch Date: Wed, 30 Sep 2026 09:54:04 +0000 Subject: [PATCH] feat(core): UDP sockets in the simulation core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit engine.ts ports the UDP part of Swift's "UDP sockets and Router RIP": a socket bound to a given port or to a free one drawn from 49152–65534 with Java's random numbers on Swift's seed; sending, also as a limited broadcast on every interface (or the bound one) with TTL 1; delivery into the queue of every socket on the destination port, which then answers to the last sender; receiving, with a timeout that advances the virtual clock; closing. Stopping forgets sockets and queues. RIP stays not ported; Swift's DHCP handling of a datagram has nothing to do until DHCP is in the snapshot. The oracle gets the steps bindUdp, sendUdp, receiveUdp and closeSocket on both sides and reports the sockets. Two new scenarios — a LAN, and two networks through a router with a UDP firewall rule and a broadcast that does not cross it — match the Swift engine trace for trace, the random ports included. Swift's four UDP engine tests are ported, with a test for stopping. 11 mutation probes were all caught (one only after the stop test was added). Co-Authored-By: Claude Opus 5.5 --- CHANGES.md | 4 +- packages/core/src/runtime/engine.ts | 261 +- packages/core/test/engine.test.ts | 113 +- packages/core/test/oracle.test.ts | 58 + .../scenarios/firewall-and-loss.swift.json | 3 + .../scenarios/routed-two-networks.swift.json | 3 + .../router-chain-manual-routes.swift.json | 3 + .../switch-ageing-boundary.swift.json | 3 + .../core/test/scenarios/switch-lan.swift.json | 3 + .../core/test/scenarios/udp-lan.scenario.json | 209 ++ .../core/test/scenarios/udp-lan.swift.json | 2676 +++++++++++++++++ .../test/scenarios/udp-routed.scenario.json | 171 ++ .../core/test/scenarios/udp-routed.swift.json | 2321 ++++++++++++++ tools/swift-oracle/README.md | 6 + tools/swift-oracle/Sources/Oracle/main.swift | 34 + 15 files changed, 5862 insertions(+), 6 deletions(-) create mode 100644 packages/core/test/scenarios/udp-lan.scenario.json create mode 100644 packages/core/test/scenarios/udp-lan.swift.json create mode 100644 packages/core/test/scenarios/udp-routed.scenario.json create mode 100644 packages/core/test/scenarios/udp-routed.swift.json diff --git a/CHANGES.md b/CHANGES.md index 6921258..f489661 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,7 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand | `src/model/link.ts`, `src/model/graph.ts` | `Model/TopologyLink.swift`, `Model/TopologyGraph.swift` | übertragen, bisher nur die Daten (Abfragen folgen mit dem Editor) | | `src/model/documentation.ts` | `Model/TopologyDocumentation.swift` | übertragen; FNV-Kennung mit BigInt, gegen die IDs aus dem Swift-Import geprüft | | `src/runtime/config.ts` | `State/TopologyEditorState.swift` (Laufzeit-Konfigurationen, WLAN eines Rechners, DHCP, Portweiterleitung, Remote Link ohne LAN-Transport, Programme und ihre Konfiguration, Firewall, DNS-Einträge aus `State/TopologyDNSResolver.swift`, E-Mail-Konten und -Nachrichten aus `State/TopologyEmail.swift`); dazu Echo-Server- und Client-Konfiguration, die Swift nicht speichert | übertragen; Java-Beschriftungen der Oberfläche weggelassen | -| `src/runtime/engine.ts` | `State/TopologyNetworkRuntimeEngine.swift` Z. ~313–3585, ~4753–4850 | übertragen: Warteschlange, Uhr, Ethernet, Switch, ARP, IPv4, ICMP, Routing, Firewall. Klasse statt Werttyp. Noch nicht übertragen (wirft `NotPortedError`): Gateway-NAT, UDP, TCP, DHCP, DNS, RIP, Remote Link, WLAN | +| `src/runtime/engine.ts` | `State/TopologyNetworkRuntimeEngine.swift` Z. ~313–3585, ~4472–5187 (UDP), ~4753–4850 | übertragen: Warteschlange, Uhr, Ethernet, Switch, ARP, IPv4, ICMP, Routing, Firewall, UDP-Sockets (binden, freie Ports nach Javas Zufall, senden samt Broadcast, zustellen, empfangen mit Wartezeit, schließen). Klasse statt Werttyp. Noch nicht übertragen (wirft `NotPortedError`): Gateway-NAT, TCP, DHCP, DNS, RIP, Remote Link, WLAN | | `src/runtime/ipv4.ts` | Engine `parseIPv4`/`sameSubnet` | übertragen | | `src/runtime/packets.ts` | Engine, Paketmodelle | übertragen; `Data` → `Uint8Array` | | `src/runtime/random.ts` | Engine, `TopologyJavaCompatibleRandom` | übertragen; BigInt für die 48-Bit-Arithmetik | @@ -27,7 +27,7 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand | `test/virtualFileSystem.test.ts`, `test/vfs.*.json` | `TopologyProjectPersistenceTests.swift`, `TopologyEditorReducerTests.swift` (drei Dateisystem-Tests, als Fälle) | übertragen und erweitert: 11 Fälle, Ergebnis aus dem Swift-Kern | | `test/strings.test.ts`, `test/strings.*.json` | — | neu: Fälle und ganze Zeichenmengen, Ergebnis aus dem Swift-Kern | | `test/engine.test.ts` | `TopologyNetworkRuntimeEngineTests.swift` (21 von 72 Tests) | übertragen; `nextInt`-Referenzwerte an OpenJDK 21 gemessen | -| `test/oracle.test.ts`, `test/scenarios/` | — | neu: 5 Szenarien, Ergebnis mit dem Swift-Kern abgeglichen (`tools/swift-oracle`) | +| `test/oracle.test.ts`, `test/scenarios/` | — | neu: 7 Szenarien (davon 2 UDP), Ergebnis mit dem Swift-Kern abgeglichen (`tools/swift-oracle`); Schritte `bindUdp`, `sendUdp`, `receiveUdp`, `closeSocket` | | `test/routeTable.test.ts` | `TopologyJavaRouteTableTests.swift` (8 von 12 Tests) | übertragen; Geometrie- und Reducer-Tests folgen mit Editor und Dokument | ## packages/fls diff --git a/packages/core/src/runtime/engine.ts b/packages/core/src/runtime/engine.ts index e283f52..31f70a3 100644 --- a/packages/core/src/runtime/engine.ts +++ b/packages/core/src/runtime/engine.ts @@ -14,8 +14,12 @@ // Calls that block in Java (resolving an address, waiting for an echo reply) // advance the virtual clock inside the call, exactly as the Swift port does. // +// "UDP sockets and Router RIP" (lines ~4472–5187, the +// UDP sockets; RIP not yet) +// // Not ported yet — each place throws NotPortedError instead of guessing: -// gateway NAT, UDP and TCP delivery, RIP routing, remote links. +// gateway NAT, TCP delivery, RIP routing, remote links. DHCP is not in the +// snapshot yet, so Swift's DHCP handling of a datagram has nothing to do. import { compareIds, type Id } from '../ids.js'; import { isPcClassEndpoint, stableGeneratedMacAddress } from '../model/node.js'; @@ -47,6 +51,7 @@ import { type IcmpMessage, type IcmpMessageKind, type IPv4Packet, + type UdpDatagram, } from './packets.js'; import { JavaCompatibleRandom } from './random.js'; import { routeTableRows, type RouteRow } from './routeTable.js'; @@ -225,6 +230,38 @@ export interface FirewallDecision { export type RuntimePhase = 'stopped' | 'running'; +export type SocketProtocol = 'udp' | 'tcp'; + +/** Swift's TopologyRuntimeSocketRecord (UDP so far). */ +export interface SocketRecord { + readonly id: Id; + readonly nodeId: Id; + readonly protocol: SocketProtocol; + readonly localIPAddress: string | undefined; + /** 0…65535 */ + readonly localPort: number; + remoteIPAddress: string | undefined; + remotePort: number | undefined; +} + +/** A datagram waiting in a UDP socket's queue. */ +export interface UdpReceivedDatagram { + readonly senderIPAddress: string; + readonly receiverIPAddress: string; + readonly datagram: UdpDatagram; + readonly receivedAtMilliseconds: number; +} + +export const UDP_EPHEMERAL_PORT_LOWER_BOUND = 49_152; +export const UDP_EPHEMERAL_PORT_UPPER_BOUND_EXCLUSIVE = 65_535; +export const RIP_DESTINATION_PORT = 520; +export const RIP_SOURCE_PORT = 521; + +/** Swift's deterministicSocketID: the sequence number as the UUID's last twelve hex digits. */ +export function deterministicSocketId(sequence: number): Id { + return `00000000-0000-0000-0000-${sequence.toString(16).toUpperCase().padStart(12, '0')}`; +} + export interface RuntimeState { phase: RuntimePhase; currentTimeMilliseconds: number; @@ -242,6 +279,9 @@ export interface RuntimeState { deliveredIPv4PacketsByNodeId: Map; icmpObservationsByNodeId: Map; firewallDecisions: FirewallDecision[]; + socketsById: Map; + udpReceiveQueuesBySocketId: Map; + nextSocketSequenceNumber: number; nextEventSequenceNumber: number; nextFrameIdentity: number; nextPacketIdentity: number; @@ -266,6 +306,9 @@ function initialState(seed: bigint): RuntimeState { deliveredIPv4PacketsByNodeId: new Map(), icmpObservationsByNodeId: new Map(), firewallDecisions: [], + socketsById: new Map(), + udpReceiveQueuesBySocketId: new Map(), + nextSocketSequenceNumber: 1, nextEventSequenceNumber: 0, nextFrameIdentity: 1, nextPacketIdentity: 1, @@ -398,6 +441,8 @@ export class NetworkRuntimeEngine { state.switchSeenFrameIdentitiesByNodeId.clear(); state.deliveredIPv4PacketsByNodeId.clear(); state.icmpObservationsByNodeId.clear(); + state.socketsById.clear(); + state.udpReceiveQueuesBySocketId.clear(); state.firewallDecisions = []; return [this.output({ type: 'stopped' })]; } @@ -603,6 +648,209 @@ export class NetworkRuntimeEngine { return true; } + // ── UDP sockets ────────────────────────────────────────────────────────── + + /** + * A UDP socket on `nodeId`: on `localPort`, else on a free port drawn at + * random from the ephemeral range; undefined while stopped, when the port + * is taken or the node has no interface with `localIPAddress`. + */ + bindUdpSocket( + nodeId: Id, + options: { localPort?: number; localIPAddress?: string; remoteIPAddress?: string; remotePort?: number } = {}, + ): Id | undefined { + const state = this.stateValue; + if (state.phase !== 'running') return undefined; + let reservedPort: number; + if (options.localPort !== undefined) { + if (this.isUdpPortReserved(nodeId, options.localPort)) return undefined; + reservedPort = options.localPort; + } else { + const port = this.reserveFreeUdpPort(nodeId); + if (port === undefined) return undefined; + reservedPort = port; + } + if ( + options.localIPAddress !== undefined && + !this.networkInterfaces(nodeId).some((networkInterface) => networkInterface.ipAddress === options.localIPAddress) + ) { + return undefined; + } + const id = deterministicSocketId(state.nextSocketSequenceNumber); + state.nextSocketSequenceNumber += 1; + state.socketsById.set(id, { + id, + nodeId, + protocol: 'udp', + localIPAddress: options.localIPAddress, + localPort: reservedPort, + remoteIPAddress: options.remoteIPAddress, + remotePort: options.remotePort, + }); + state.udpReceiveQueuesBySocketId.set(id, []); + return id; + } + + private isUdpPortReserved(nodeId: Id, port: number): boolean { + // Swift also counts a gateway's NAT mappings; gateways do not run here yet. + for (const socket of this.stateValue.socketsById.values()) { + if (socket.nodeId === nodeId && socket.protocol === 'udp' && socket.localPort === port) return true; + } + return false; + } + + private reserveFreeUdpPort(nodeId: Id): number | undefined { + const span = UDP_EPHEMERAL_PORT_UPPER_BOUND_EXCLUSIVE - UDP_EPHEMERAL_PORT_LOWER_BOUND; + for (let attempt = 0; attempt < span; attempt++) { + const port = UDP_EPHEMERAL_PORT_LOWER_BOUND + this.udpPortRandom.nextInt(span); + if (!this.isUdpPortReserved(nodeId, port)) return port; + } + return undefined; + } + + closeSocket(socketId: Id): void { + if (this.stateValue.socketsById.get(socketId)?.protocol === 'tcp') throw new NotPortedError('TCP sockets'); + this.stateValue.socketsById.delete(socketId); + this.stateValue.udpReceiveQueuesBySocketId.delete(socketId); + } + + /** Forgets a socket without closing it (Swift's discardSocket; TCP children once TCP is ported). */ + discardSocket(socketId: Id): void { + this.stateValue.socketsById.delete(socketId); + this.stateValue.udpReceiveQueuesBySocketId.delete(socketId); + } + + /** + * The oldest datagram in the socket's queue; with a timeout, the clock + * advances up to it when the queue is empty, as a blocking receive in Java. + */ + receiveUdp(socketId: Id, timeoutMilliseconds = 0): UdpReceivedDatagram | undefined { + const next = () => this.stateValue.udpReceiveQueuesBySocketId.get(socketId)?.shift(); + const datagram = next(); + if (datagram !== undefined) return datagram; + if (timeoutMilliseconds <= 0 || this.stateValue.phase !== 'running') return undefined; + const deadline = this.stateValue.currentTimeMilliseconds + timeoutMilliseconds; + if (!Number.isSafeInteger(deadline)) return undefined; + this.advance(deadline); + return next(); + } + + /** Sends from a UDP socket to its remote end, or to the given one. */ + sendUdp( + socketId: Id, + payload: Uint8Array, + destination: { ipAddress?: string; port?: number } = {}, + ): IPv4DeliveryResult | undefined { + const socket = this.stateValue.socketsById.get(socketId); + if (socket === undefined || socket.protocol !== 'udp') return undefined; + const destinationIPAddress = destination.ipAddress ?? socket.remoteIPAddress; + const destinationPort = destination.port ?? socket.remotePort; + if (destinationIPAddress === undefined || destinationPort === undefined) return undefined; + const interfaces = this.networkInterfaces(socket.nodeId); + if (interfaces.length === 0) return undefined; + const boundInterface = + socket.localIPAddress === undefined + ? undefined + : interfaces.find((networkInterface) => networkInterface.ipAddress === socket.localIPAddress); + const packetIdentity = this.allocatePacketIdentity(); + const datagram: UdpDatagram = { sourcePort: socket.localPort, destinationPort, payload }; + const traceSent = (networkInterface: NetworkInterface, identity: number) => + this.recordTrace({ + packetIdentity: identity, + nodeId: socket.nodeId, + interfaceId: networkInterface.portId, + direction: 'outbound', + layer: 'transport', + operation: 'sent', + afterHeaders: udpHeaders(datagram), + }); + + if (destinationIPAddress === LIMITED_BROADCAST_IP_ADDRESS) { + for (const networkInterface of boundInterface === undefined ? interfaces : [boundInterface]) { + const packet: IPv4Packet = { + identity: packetIdentity, + senderIPAddress: networkInterface.ipAddress, + receiverIPAddress: destinationIPAddress, + timeToLive: 1, + protocol: 'udp', + payload: { kind: 'udp', datagram }, + }; + traceSent(networkInterface, packet.identity); + this.sendLimitedBroadcastPacket(socket.nodeId, networkInterface, packet); + } + return { type: 'delivered', packetIdentity, nodeId: socket.nodeId }; + } + + let networkInterface: NetworkInterface; + if (boundInterface !== undefined) { + networkInterface = boundInterface; + } else { + const route = this.routeForPacket(socket.nodeId, destinationIPAddress); + networkInterface = route.type === 'egress' ? route.interface : interfaces[0]!; + } + const packet: IPv4Packet = { + identity: packetIdentity, + senderIPAddress: networkInterface.ipAddress, + receiverIPAddress: destinationIPAddress, + timeToLive: 64, + protocol: 'udp', + payload: { kind: 'udp', datagram }, + }; + traceSent(networkInterface, packet.identity); + return this.sendIPv4Packet(socket.nodeId, packet, networkInterface.portId); + } + + private sendLimitedBroadcastPacket(fromNodeId: Id, networkInterface: NetworkInterface, packet: IPv4Packet): void { + const broadcastPacket: IPv4Packet = { + ...packet, + senderIPAddress: networkInterface.ipAddress, + receiverIPAddress: LIMITED_BROADCAST_IP_ADDRESS, + timeToLive: 1, + }; + const frame: EthernetFrame = { + identity: this.allocateFrameIdentity(), + sourceMacAddress: networkInterface.macAddress, + destinationMacAddress: ETHERNET_BROADCAST_MAC_ADDRESS, + payload: { kind: 'ipv4', packet: broadcastPacket }, + }; + this.recordIPv4Send(broadcastPacket, frame, fromNodeId, networkInterface.portId, 'sent'); + this.sendEthernetFrame(fromNodeId, networkInterface.portId, frame); + } + + /** Into the queue of every UDP socket on the destination port, which then answers to the sender. */ + private deliverUdp(packet: IPv4Packet, datagram: UdpDatagram, nodeId: Id, networkInterface: NetworkInterface): void { + if ( + datagram.destinationPort === RIP_DESTINATION_PORT && + datagram.sourcePort === RIP_SOURCE_PORT && + this.isRipEnabledRouter(nodeId) + ) { + throw new NotPortedError('RIP advertisements'); + } + const state = this.stateValue; + const matching = [...state.socketsById.values()] + .filter((socket) => socket.nodeId === nodeId && socket.protocol === 'udp' && socket.localPort === datagram.destinationPort) + .sort((lhs, rhs) => compareIds(lhs.id, rhs.id)); + for (const socket of matching) { + getOrCreate(state.udpReceiveQueuesBySocketId, socket.id, () => []).push({ + senderIPAddress: packet.senderIPAddress, + receiverIPAddress: packet.receiverIPAddress, + datagram, + receivedAtMilliseconds: state.currentTimeMilliseconds, + }); + state.socketsById.set(socket.id, { ...socket, remoteIPAddress: packet.senderIPAddress, remotePort: datagram.sourcePort }); + } + this.recordTrace({ + packetIdentity: packet.identity, + nodeId, + interfaceId: networkInterface.portId, + direction: 'local', + layer: 'transport', + operation: matching.length === 0 ? 'dropped' : 'accepted', + beforeHeaders: udpHeaders(datagram), + detail: matching.length === 0 ? 'UDP destination port unbound' : 'UDP queued', + }); + } + // ── Later slices hook in here ──────────────────────────────────────────── private initializeRipState(): void { @@ -1527,7 +1775,8 @@ export class NetworkRuntimeEngine { interfaceId: networkInterface.portId, packet, }); - throw new NotPortedError('UDP delivery'); + this.deliverUdp(packet, payload.datagram, nodeId, networkInterface); + return; case 'tcp': getOrCreate(this.stateValue.deliveredIPv4PacketsByNodeId, nodeId, () => []).push({ nodeId, @@ -1930,6 +2179,14 @@ export function ipv4Headers(packet: IPv4Packet): HeaderField[] { ]; } +export function udpHeaders(datagram: UdpDatagram): HeaderField[] { + return [ + { name: 'sourcePort', value: String(datagram.sourcePort) }, + { name: 'destinationPort', value: String(datagram.destinationPort) }, + { name: 'payloadLength', value: String(datagram.payload.length) }, + ]; +} + export function icmpHeaders(message: IcmpMessage): HeaderField[] { return [ { name: 'kind', value: message.kind }, diff --git a/packages/core/test/engine.test.ts b/packages/core/test/engine.test.ts index e60489a..0d36202 100644 --- a/packages/core/test/engine.test.ts +++ b/packages/core/test/engine.test.ts @@ -1,8 +1,9 @@ // Ported from filius-ipad ios/FiliusPadTests/TopologyNetworkRuntimeEngineTests.swift: // the event queue, the virtual clock, Java-compatible randomness, restart, // Ethernet/switch/ARP/IPv4/ICMP, routing errors, the firewall, packet loss -// and trace retention. The remaining Swift tests (UDP, TCP, DHCP, DNS, RIP, -// NAT, remote link, packet viewer) follow with their protocol slices. +// and trace retention, UDP sockets. The remaining Swift tests (TCP, DHCP, +// DNS, RIP, NAT, remote link, packet viewer) follow with their protocol +// slices. import { describe, expect, it } from 'vitest'; import { @@ -191,6 +192,114 @@ describe('event queue and virtual clock', () => { expect(engine.allocateFrameIdentity()).toBe(1); expect(engine.allocatePacketIdentity()).toBe(1); }); + + it('forgets UDP sockets on stop, binds none while stopped, and numbers them from one again', () => { + const nodeId = uuid(0x13); + const portId = uuid(0x14); + const input = { nodes: [pc(nodeId, portId)], links: [], deviceConfigurations: new Map([[nodeId, device('10.2.0.1')]]) }; + const engine = startedEngine(input); + expect(engine.bindUdpSocket(nodeId, { localPort: 7 })).toBe(uuid(1)); + expect(engine.bindUdpSocket(nodeId)).toBe(uuid(2)); + + engine.handle({ type: 'stop' }); + expect(engine.state.socketsById.size).toBe(0); + expect(engine.state.udpReceiveQueuesBySocketId.size).toBe(0); + expect(engine.bindUdpSocket(nodeId, { localPort: 7 })).toBeUndefined(); + + engine.handle({ type: 'start', snapshot: topologySnapshot(input), seed: 14, initialTimeMilliseconds: 0 }); + expect(engine.bindUdpSocket(nodeId, { localPort: 7 })).toBe(uuid(1)); + }); +}); + +describe('UDP sockets', () => { + const text = (payload: Uint8Array | undefined) => new TextDecoder().decode(payload ?? new Uint8Array()); + + it('binds, delivers and releases a port', () => { + const [sourceNodeId, sourcePortId, targetNodeId, targetPortId] = [0x15b1, 0x15b2, 0x15b3, 0x15b4].map(uuid) as [string, string, string, string]; + const engine = startedEngine({ + nodes: [pc(sourceNodeId, sourcePortId), pc(targetNodeId, targetPortId)], + links: [link(sourceNodeId, sourcePortId, targetNodeId, targetPortId)], + deviceConfigurations: new Map([ + [sourceNodeId, device('192.168.5.10')], + [targetNodeId, device('192.168.5.20')], + ]), + }); + const automatic = engine.bindUdpSocket(targetNodeId); + const automaticPort = automatic === undefined ? undefined : engine.state.socketsById.get(automatic)?.localPort; + expect(automaticPort).toBeGreaterThanOrEqual(49_152); + expect(automaticPort).toBeLessThan(65_535); + + const receiver = engine.bindUdpSocket(targetNodeId, { localPort: 9000 }); + const sender = engine.bindUdpSocket(sourceNodeId, { localPort: 8000, remoteIPAddress: '192.168.5.20', remotePort: 9000 }); + expect(receiver).toBeDefined(); + expect(sender).toBeDefined(); + expect(engine.bindUdpSocket(targetNodeId, { localPort: 9000 })).toBeUndefined(); + + engine.sendUdp(sender!, new TextEncoder().encode('hello')); + const received = engine.receiveUdp(receiver!); + expect(text(received?.datagram.payload)).toBe('hello'); + expect(received?.senderIPAddress).toBe('192.168.5.10'); + + engine.closeSocket(receiver!); + expect(engine.bindUdpSocket(targetNodeId, { localPort: 9000 })).toBeDefined(); + }); + + it('draws ephemeral ports without disturbing the seeded RIP jitter', () => { + const nodeId = uuid(0x15f1); + const input = { nodes: [pc(nodeId, uuid(0x15f2))], links: [], deviceConfigurations: new Map([[nodeId, device('192.168.10.10')]]) }; + const socketEngine = startedEngine(input); + const ripOnlyEngine = startedEngine(input); + + expect(socketEngine.bindUdpSocket(nodeId)).toBeDefined(); + expect(socketEngine.nextRipJitterMilliseconds()).toBe(ripOnlyEngine.nextRipJitterMilliseconds()); + }); + + it('broadcasts on every interface, and the receiver replies to its last peer', () => { + const [routerId, routerPortA, routerPortB, pcAId, pcAPort, pcBId, pcBPort] = [0x15e1, 0x15e2, 0x15e3, 0x15e4, 0x15e5, 0x15e6, 0x15e7].map( + uuid, + ) as [string, string, string, string, string, string, string]; + const engine = startedEngine( + { + nodes: [ + { id: routerId, kind: 'router', ports: [portSnapshot(routerPortA, 'rt1'), portSnapshot(routerPortB, 'rt2')] }, + pc(pcAId, pcAPort), + pc(pcBId, pcBPort), + ], + links: [link(routerId, routerPortA, pcAId, pcAPort), link(routerId, routerPortB, pcBId, pcBPort)], + deviceConfigurations: new Map([ + [pcAId, device('10.0.0.2')], + [pcBId, device('20.0.0.2')], + ]), + interfaceConfigurations: new Map([ + [interfaceKey(routerId, routerPortA), { ipAddress: '10.0.0.1', subnetMask: '255.255.255.0' }], + [interfaceKey(routerId, routerPortB), { ipAddress: '20.0.0.1', subnetMask: '255.255.255.0' }], + ]), + }, + 15, + ); + const sender = engine.bindUdpSocket(routerId, { localPort: 8000 })!; + const receiverA = engine.bindUdpSocket(pcAId, { localPort: 9000 })!; + const receiverB = engine.bindUdpSocket(pcBId, { localPort: 9000 })!; + + engine.sendUdp(sender, new TextEncoder().encode('broadcast'), { ipAddress: '255.255.255.255', port: 9000 }); + + expect(engine.receiveUdp(receiverA)?.senderIPAddress).toBe('10.0.0.1'); + expect(engine.receiveUdp(receiverB)?.senderIPAddress).toBe('20.0.0.1'); + expect(engine.state.socketsById.get(receiverA)?.remoteIPAddress).toBe('10.0.0.1'); + expect(engine.state.socketsById.get(receiverA)?.remotePort).toBe(8000); + + engine.sendUdp(receiverA, new TextEncoder().encode('reply')); + expect(text(engine.receiveUdp(sender)?.datagram.payload)).toBe('reply'); + }); + + it('advances the virtual clock for a receive timeout and returns nothing', () => { + const nodeId = uuid(0x15d1); + const engine = startedEngine({ nodes: [pc(nodeId, uuid(0x15d2))], links: [], deviceConfigurations: new Map([[nodeId, device('10.1.0.1')]]) }); + const socketId = engine.bindUdpSocket(nodeId, { localPort: 9999 })!; + + expect(engine.receiveUdp(socketId, 250)).toBeUndefined(); + expect(engine.state.currentTimeMilliseconds).toBe(250); + }); }); describe('Java-compatible randomness', () => { diff --git a/packages/core/test/oracle.test.ts b/packages/core/test/oracle.test.ts index 0b704b5..16b1f41 100644 --- a/packages/core/test/oracle.test.ts +++ b/packages/core/test/oracle.test.ts @@ -67,6 +67,14 @@ interface Scenario { to?: number; enabled?: boolean; percent?: number; + // UDP: a socket is named by the id bindUdp returned. + port?: number; + localIp?: string; + remoteIp?: string; + remotePort?: number; + socket?: string; + payload?: string; + timeout?: number; }[]; } @@ -239,6 +247,44 @@ function run(scenario: Scenario): Record { engine.setSimulationSpeed(step.percent!); results.push(engine.simulationSpeed.percent); break; + case 'bindUdp': + results.push( + engine.bindUdpSocket(step.node!, { + ...(step.port === undefined ? {} : { localPort: step.port }), + ...(step.localIp === undefined ? {} : { localIPAddress: step.localIp }), + ...(step.remoteIp === undefined ? {} : { remoteIPAddress: step.remoteIp }), + ...(step.remotePort === undefined ? {} : { remotePort: step.remotePort }), + }) ?? null, + ); + break; + case 'sendUdp': { + const result = engine.sendUdp(step.socket!, new TextEncoder().encode(step.payload ?? ''), { + ...(step.target === undefined ? {} : { ipAddress: step.target }), + ...(step.port === undefined ? {} : { port: step.port }), + }); + results.push(result === undefined ? null : deliveryJson(result)); + break; + } + case 'receiveUdp': { + const item = engine.receiveUdp(step.socket!, step.timeout ?? 0); + results.push( + item === undefined + ? null + : { + sender: item.senderIPAddress, + receiver: item.receiverIPAddress, + sourcePort: item.datagram.sourcePort, + destinationPort: item.datagram.destinationPort, + payload: new TextDecoder().decode(item.datagram.payload), + at: item.receivedAtMilliseconds, + }, + ); + break; + } + case 'closeSocket': + engine.closeSocket(step.socket!); + results.push(!engine.state.socketsById.has(step.socket!)); + break; default: throw new Error(`unknown step ${step.op}`); } @@ -259,6 +305,18 @@ function run(scenario: Scenario): Record { Object.fromEntries([...table].map(([mac, port]) => [mac, upper(port)])), ), icmpObservations: mapOf(state.icmpObservationsByNodeId, (items) => items.map(observationJson)), + sockets: [...state.socketsById.values()] + .sort((lhs, rhs) => (upper(lhs.id) < upper(rhs.id) ? -1 : 1)) + .map((socket) => ({ + id: upper(socket.id), + node: upper(socket.nodeId), + protocol: socket.protocol, + localIp: socket.localIPAddress ?? null, + localPort: socket.localPort, + remoteIp: socket.remoteIPAddress ?? null, + remotePort: socket.remotePort ?? null, + queued: state.udpReceiveQueuesBySocketId.get(socket.id)?.length ?? 0, + })), firewallDecisions: state.firewallDecisions.map((decision) => ({ packet: decision.packetIdentity, node: upper(decision.nodeId), diff --git a/packages/core/test/scenarios/firewall-and-loss.swift.json b/packages/core/test/scenarios/firewall-and-loss.swift.json index 1b23777..6516721 100644 --- a/packages/core/test/scenarios/firewall-and-loss.swift.json +++ b/packages/core/test/scenarios/firewall-and-loss.swift.json @@ -80,6 +80,9 @@ "packet" : 7, "type" : "delivered" } + ], + "sockets" : [ + ], "switchTables" : { "00000000-0000-0000-0000-000000000405" : { diff --git a/packages/core/test/scenarios/routed-two-networks.swift.json b/packages/core/test/scenarios/routed-two-networks.swift.json index 7c796a3..b44ab9f 100644 --- a/packages/core/test/scenarios/routed-two-networks.swift.json +++ b/packages/core/test/scenarios/routed-two-networks.swift.json @@ -151,6 +151,9 @@ "type" : "delivered" }, "02:00:00:00:02:22" + ], + "sockets" : [ + ], "switchTables" : { diff --git a/packages/core/test/scenarios/router-chain-manual-routes.swift.json b/packages/core/test/scenarios/router-chain-manual-routes.swift.json index 4d10ad4..c13905f 100644 --- a/packages/core/test/scenarios/router-chain-manual-routes.swift.json +++ b/packages/core/test/scenarios/router-chain-manual-routes.swift.json @@ -204,6 +204,9 @@ "packet" : 13, "type" : "delivered" } + ], + "sockets" : [ + ], "switchTables" : { diff --git a/packages/core/test/scenarios/switch-ageing-boundary.swift.json b/packages/core/test/scenarios/switch-ageing-boundary.swift.json index 1a478dc..24a3ec2 100644 --- a/packages/core/test/scenarios/switch-ageing-boundary.swift.json +++ b/packages/core/test/scenarios/switch-ageing-boundary.swift.json @@ -795,6 +795,9 @@ "packet" : 3, "type" : "delivered" } + ], + "sockets" : [ + ], "switchTables" : { "00000000-0000-0000-0000-000000000503" : { diff --git a/packages/core/test/scenarios/switch-lan.swift.json b/packages/core/test/scenarios/switch-lan.swift.json index c50d680..3b2defe 100644 --- a/packages/core/test/scenarios/switch-lan.swift.json +++ b/packages/core/test/scenarios/switch-lan.swift.json @@ -99,6 +99,9 @@ "packet" : 12, "type" : "delivered" } + ], + "sockets" : [ + ], "switchTables" : { "00000000-0000-0000-0000-000000000104" : { diff --git a/packages/core/test/scenarios/udp-lan.scenario.json b/packages/core/test/scenarios/udp-lan.scenario.json new file mode 100644 index 0000000..d8bc3d5 --- /dev/null +++ b/packages/core/test/scenarios/udp-lan.scenario.json @@ -0,0 +1,209 @@ +{ + "seed": 21, + "nodes": [ + { + "id": "00000000-0000-0000-0000-000000000101", + "kind": "pc", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000111", + "label": "eth0" + } + ] + }, + { + "id": "00000000-0000-0000-0000-000000000102", + "kind": "pc", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000112", + "label": "eth0" + } + ] + }, + { + "id": "00000000-0000-0000-0000-000000000103", + "kind": "pc", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000113", + "label": "eth0" + } + ] + }, + { + "id": "00000000-0000-0000-0000-000000000104", + "kind": "networkSwitch", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000121", + "label": "sw1" + }, + { + "id": "00000000-0000-0000-0000-000000000122", + "label": "sw2" + }, + { + "id": "00000000-0000-0000-0000-000000000123", + "label": "sw3" + }, + { + "id": "00000000-0000-0000-0000-000000000124", + "label": "sw4" + } + ] + } + ], + "links": [ + { + "id": "00000000-0000-0000-0000-00000000F001", + "sourceNode": "00000000-0000-0000-0000-000000000101", + "sourcePort": "00000000-0000-0000-0000-000000000111", + "targetNode": "00000000-0000-0000-0000-000000000104", + "targetPort": "00000000-0000-0000-0000-000000000121" + }, + { + "id": "00000000-0000-0000-0000-00000000F002", + "sourceNode": "00000000-0000-0000-0000-000000000102", + "sourcePort": "00000000-0000-0000-0000-000000000112", + "targetNode": "00000000-0000-0000-0000-000000000104", + "targetPort": "00000000-0000-0000-0000-000000000122" + }, + { + "id": "00000000-0000-0000-0000-00000000F003", + "sourceNode": "00000000-0000-0000-0000-000000000103", + "sourcePort": "00000000-0000-0000-0000-000000000113", + "targetNode": "00000000-0000-0000-0000-000000000104", + "targetPort": "00000000-0000-0000-0000-000000000123" + } + ], + "devices": { + "00000000-0000-0000-0000-000000000101": { + "ip": "192.168.0.10", + "mask": "255.255.255.0" + }, + "00000000-0000-0000-0000-000000000102": { + "ip": "192.168.0.20", + "mask": "255.255.255.0" + }, + "00000000-0000-0000-0000-000000000103": { + "ip": "192.168.0.30", + "mask": "255.255.255.0" + } + }, + "switches": { + "00000000-0000-0000-0000-000000000104": { + "ssid": "lab", + "retention": 5000 + } + }, + "steps": [ + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000101", + "port": 5000 + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000102" + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000101", + "port": 5000 + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000101", + "localIp": "10.9.9.9" + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000103", + "port": 7000, + "localIp": "192.168.0.30" + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000002", + "target": "192.168.0.10", + "port": 5000, + "payload": "hallo" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000001" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "timeout": 200 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "payload": "antwort" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000002", + "timeout": 200 + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000002" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000002", + "timeout": 500 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000002", + "target": "192.168.0.30", + "port": 6000, + "payload": "niemand" + }, + { + "op": "advance", + "to": 2000 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "target": "255.255.255.255", + "port": 5000, + "payload": "an alle" + }, + { + "op": "advance", + "to": 3000 + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000001" + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "payload": "ohne Ziel" + }, + { + "op": "closeSocket", + "socket": "00000000-0000-0000-0000-000000000001" + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "target": "192.168.0.20", + "port": 5000, + "payload": "geschlossen" + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000101", + "port": 5000 + } + ] +} diff --git a/packages/core/test/scenarios/udp-lan.swift.json b/packages/core/test/scenarios/udp-lan.swift.json new file mode 100644 index 0000000..03c7b43 --- /dev/null +++ b/packages/core/test/scenarios/udp-lan.swift.json @@ -0,0 +1,2676 @@ +{ + "arp" : { + "00000000-0000-0000-0000-000000000101" : { + "192.168.0.20" : "02:00:00:00:01:12" + }, + "00000000-0000-0000-0000-000000000102" : { + "192.168.0.10" : "02:00:00:00:01:11", + "192.168.0.30" : "02:00:00:00:01:13" + }, + "00000000-0000-0000-0000-000000000103" : { + "192.168.0.20" : "02:00:00:00:01:12" + } + }, + "firewallDecisions" : [ + + ], + "icmpObservations" : { + + }, + "pendingEvents" : 0, + "results" : [ + "00000000-0000-0000-0000-000000000001", + "00000000-0000-0000-0000-000000000002", + null, + null, + "00000000-0000-0000-0000-000000000003", + { + "node" : "00000000-0000-0000-0000-000000000102", + "packet" : 1, + "type" : "delivered" + }, + { + "at" : 330, + "destinationPort" : 5000, + "payload" : "hallo", + "receiver" : "192.168.0.10", + "sender" : "192.168.0.20", + "sourcePort" : 51180 + }, + null, + { + "node" : "00000000-0000-0000-0000-000000000101", + "packet" : 2, + "type" : "delivered" + }, + { + "at" : 640, + "destinationPort" : 51180, + "payload" : "antwort", + "receiver" : "192.168.0.20", + "sender" : "192.168.0.10", + "sourcePort" : 5000 + }, + null, + null, + { + "node" : "00000000-0000-0000-0000-000000000102", + "packet" : 3, + "type" : "delivered" + }, + 2000, + { + "node" : "00000000-0000-0000-0000-000000000103", + "packet" : 4, + "type" : "delivered" + }, + 3000, + { + "at" : 2110, + "destinationPort" : 5000, + "payload" : "an alle", + "receiver" : "255.255.255.255", + "sender" : "192.168.0.30", + "sourcePort" : 7000 + }, + null, + true, + null, + "00000000-0000-0000-0000-000000000004" + ], + "sockets" : [ + { + "id" : "00000000-0000-0000-0000-000000000002", + "localIp" : null, + "localPort" : 51180, + "node" : "00000000-0000-0000-0000-000000000102", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : "192.168.0.10", + "remotePort" : 5000 + }, + { + "id" : "00000000-0000-0000-0000-000000000003", + "localIp" : "192.168.0.30", + "localPort" : 7000, + "node" : "00000000-0000-0000-0000-000000000103", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : null, + "remotePort" : null + }, + { + "id" : "00000000-0000-0000-0000-000000000004", + "localIp" : null, + "localPort" : 5000, + "node" : "00000000-0000-0000-0000-000000000101", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : null, + "remotePort" : null + } + ], + "switchTables" : { + "00000000-0000-0000-0000-000000000104" : { + "02:00:00:00:01:11" : "00000000-0000-0000-0000-000000000121", + "02:00:00:00:01:12" : "00000000-0000-0000-0000-000000000122", + "02:00:00:00:01:13" : "00000000-0000-0000-0000-000000000123" + } + }, + "time" : 3000, + "traces" : [ + { + "after" : [ + [ + "sourcePort", + "51180" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "5" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 1, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 1, + "time" : 0 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "ARP request for 192.168.0.10", + "direction" : "outbound", + "frame" : 1, + "id" : 2, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "created", + "time" : 0 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 1, + "id" : 3, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "time" : 0 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 4, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "time" : 55 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 1, + "id" : 5, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 1, + "id" : 6, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 1, + "id" : 7, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 1, + "id" : 8, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 1, + "id" : 9, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 55 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 10, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 11, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:01:12" + ], + [ + "senderIP", + "192.168.0.20" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "192.168.0.10" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 12, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "accepted", + "time" : 110 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "detail" : "ARP reply for 192.168.0.10", + "direction" : "outbound", + "frame" : 2, + "id" : 13, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "created", + "time" : 110 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 2, + "id" : 14, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "sent", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 15, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 16, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:01:12" + ], + [ + "senderIP", + "192.168.0.20" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "192.168.0.10" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 17, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "accepted", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 18, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 2, + "id" : 19, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "detail" : "switch learned unicast forwarding", + "direction" : "outbound", + "frame" : 2, + "id" : 20, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 2, + "id" : 21, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 22, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 23, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "reply" + ], + [ + "senderMAC", + "02:00:00:00:01:11" + ], + [ + "senderIP", + "192.168.0.10" + ], + [ + "targetMAC", + "02:00:00:00:01:12" + ], + [ + "targetIP", + "192.168.0.20" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 24, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "accepted", + "time" : 220 + }, + { + "after" : [ + [ + "senderIP", + "192.168.0.20" + ], + [ + "receiverIP", + "192.168.0.10" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 25, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 1, + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 26, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "created", + "packet" : 1, + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 27, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 1, + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 28, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 3, + "id" : 29, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "before" : [ + + ], + "detail" : "switch learned unicast forwarding", + "direction" : "outbound", + "frame" : 3, + "id" : 30, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 31, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 32, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:11" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 33, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "192.168.0.20" + ], + [ + "receiverIP", + "192.168.0.10" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 34, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "51180" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "5" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 35, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "accepted", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + [ + "sourcePort", + "5000" + ], + [ + "destinationPort", + "51180" + ], + [ + "payloadLength", + "7" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 36, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "sent", + "packet" : 2, + "time" : 530 + }, + { + "after" : [ + [ + "senderIP", + "192.168.0.10" + ], + [ + "receiverIP", + "192.168.0.20" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 4, + "id" : 37, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "sent", + "packet" : 2, + "time" : 530 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 4, + "id" : 38, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "created", + "packet" : 2, + "time" : 530 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 4, + "id" : 39, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "sent", + "packet" : 2, + "time" : 530 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 40, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "packet" : 2, + "time" : 585 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 4, + "id" : 41, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "packet" : 2, + "time" : 585 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "detail" : "switch learned unicast forwarding", + "direction" : "outbound", + "frame" : 4, + "id" : 42, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "packet" : 2, + "time" : 585 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 4, + "id" : 43, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "packet" : 2, + "time" : 585 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 44, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 2, + "time" : 640 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:11" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 45, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 2, + "time" : 640 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "192.168.0.10" + ], + [ + "receiverIP", + "192.168.0.20" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 46, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 2, + "time" : 640 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "5000" + ], + [ + "destinationPort", + "51180" + ], + [ + "payloadLength", + "7" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 47, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "accepted", + "packet" : 2, + "time" : 640 + }, + { + "after" : [ + [ + "sourcePort", + "51180" + ], + [ + "destinationPort", + "6000" + ], + [ + "payloadLength", + "7" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 48, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 3, + "time" : 1140 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "ARP request for 192.168.0.30", + "direction" : "outbound", + "frame" : 5, + "id" : 49, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "created", + "time" : 1140 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 5, + "id" : 50, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "time" : 1140 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 51, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "time" : 1195 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 5, + "id" : 52, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "time" : 1195 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 5, + "id" : 53, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 1195 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 5, + "id" : 54, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 1195 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 5, + "id" : 55, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 1195 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 5, + "id" : 56, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 1195 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 57, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 58, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:01:12" + ], + [ + "senderIP", + "192.168.0.20" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "192.168.0.30" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 59, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "accepted", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 60, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 61, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:01:12" + ], + [ + "senderIP", + "192.168.0.20" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "192.168.0.30" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 62, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "accepted", + "time" : 1250 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "detail" : "ARP reply for 192.168.0.30", + "direction" : "outbound", + "frame" : 6, + "id" : 63, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "created", + "time" : 1250 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 6, + "id" : 64, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "sent", + "time" : 1250 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 65, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "time" : 1305 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 6, + "id" : 66, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "time" : 1305 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "detail" : "switch learned unicast forwarding", + "direction" : "outbound", + "frame" : 6, + "id" : 67, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "time" : 1305 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 6, + "id" : 68, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "time" : 1305 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 69, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "time" : 1360 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "02:00:00:00:01:12" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 70, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "time" : 1360 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "reply" + ], + [ + "senderMAC", + "02:00:00:00:01:13" + ], + [ + "senderIP", + "192.168.0.30" + ], + [ + "targetMAC", + "02:00:00:00:01:12" + ], + [ + "targetIP", + "192.168.0.20" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 71, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "accepted", + "time" : 1360 + }, + { + "after" : [ + [ + "senderIP", + "192.168.0.20" + ], + [ + "receiverIP", + "192.168.0.30" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 7, + "id" : 72, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 3, + "time" : 1360 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 7, + "id" : 73, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "created", + "packet" : 3, + "time" : 1360 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 7, + "id" : 74, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "sent", + "packet" : 3, + "time" : 1360 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 75, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "packet" : 3, + "time" : 1415 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 7, + "id" : 76, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "packet" : 3, + "time" : 1415 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "before" : [ + + ], + "detail" : "switch learned unicast forwarding", + "direction" : "outbound", + "frame" : 7, + "id" : 77, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "packet" : 3, + "time" : 1415 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 7, + "id" : 78, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "packet" : 3, + "time" : 1415 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 79, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "packet" : 3, + "time" : 1470 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:12" + ], + [ + "destinationMAC", + "02:00:00:00:01:13" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 80, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "packet" : 3, + "time" : 1470 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "192.168.0.20" + ], + [ + "receiverIP", + "192.168.0.30" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 81, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "received", + "packet" : 3, + "time" : 1470 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "51180" + ], + [ + "destinationPort", + "6000" + ], + [ + "payloadLength", + "7" + ] + ], + "detail" : "UDP destination port unbound", + "direction" : "local", + "id" : 82, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "dropped", + "packet" : 3, + "time" : 1470 + }, + { + "after" : [ + [ + "sourcePort", + "7000" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "7" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 83, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "sent", + "packet" : 4, + "time" : 2000 + }, + { + "after" : [ + [ + "senderIP", + "192.168.0.30" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 84, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "sent", + "packet" : 4, + "time" : 2000 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 85, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "created", + "packet" : 4, + "time" : 2000 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 86, + "interface" : "00000000-0000-0000-0000-000000000113", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000103", + "operation" : "sent", + "packet" : 4, + "time" : 2000 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 87, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "received", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "detail" : "switch learned source MAC", + "direction" : "inbound", + "frame" : 8, + "id" : 88, + "interface" : "00000000-0000-0000-0000-000000000123", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "accepted", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 8, + "id" : 89, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 90, + "interface" : "00000000-0000-0000-0000-000000000121", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "switch broadcast flooding", + "direction" : "outbound", + "frame" : 8, + "id" : 91, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "forwarded", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 92, + "interface" : "00000000-0000-0000-0000-000000000122", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000104", + "operation" : "sent", + "packet" : 4, + "time" : 2055 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 93, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 94, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "192.168.0.30" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 95, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "7000" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "7" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 96, + "interface" : "00000000-0000-0000-0000-000000000111", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000101", + "operation" : "accepted", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 97, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:01:13" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 98, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "192.168.0.30" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 99, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "received", + "packet" : 4, + "time" : 2110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "7000" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "7" + ] + ], + "detail" : "UDP destination port unbound", + "direction" : "local", + "id" : 100, + "interface" : "00000000-0000-0000-0000-000000000112", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000102", + "operation" : "dropped", + "packet" : 4, + "time" : 2110 + } + ] +} diff --git a/packages/core/test/scenarios/udp-routed.scenario.json b/packages/core/test/scenarios/udp-routed.scenario.json new file mode 100644 index 0000000..8d5a1d0 --- /dev/null +++ b/packages/core/test/scenarios/udp-routed.scenario.json @@ -0,0 +1,171 @@ +{ + "seed": 22, + "nodes": [ + { + "id": "00000000-0000-0000-0000-000000000201", + "kind": "pc", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000211", + "label": "eth0" + } + ] + }, + { + "id": "00000000-0000-0000-0000-000000000202", + "kind": "router", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000221", + "label": "rt1" + }, + { + "id": "00000000-0000-0000-0000-000000000222", + "label": "rt2" + } + ] + }, + { + "id": "00000000-0000-0000-0000-000000000203", + "kind": "pc", + "ports": [ + { + "id": "00000000-0000-0000-0000-000000000213", + "label": "eth0" + } + ] + } + ], + "links": [ + { + "id": "00000000-0000-0000-0000-00000000F004", + "sourceNode": "00000000-0000-0000-0000-000000000201", + "sourcePort": "00000000-0000-0000-0000-000000000211", + "targetNode": "00000000-0000-0000-0000-000000000202", + "targetPort": "00000000-0000-0000-0000-000000000221" + }, + { + "id": "00000000-0000-0000-0000-00000000F005", + "sourceNode": "00000000-0000-0000-0000-000000000202", + "sourcePort": "00000000-0000-0000-0000-000000000222", + "targetNode": "00000000-0000-0000-0000-000000000203", + "targetPort": "00000000-0000-0000-0000-000000000213" + } + ], + "devices": { + "00000000-0000-0000-0000-000000000201": { + "ip": "10.0.0.2", + "mask": "255.255.255.0", + "gateway": "10.0.0.1" + }, + "00000000-0000-0000-0000-000000000202": { + "ip": "10.0.0.1", + "mask": "255.255.255.0" + }, + "00000000-0000-0000-0000-000000000203": { + "ip": "20.0.0.2", + "mask": "255.255.255.0", + "gateway": "20.0.0.1" + } + }, + "interfaces": [ + { + "node": "00000000-0000-0000-0000-000000000202", + "port": "00000000-0000-0000-0000-000000000221", + "ip": "10.0.0.1", + "mask": "255.255.255.0" + }, + { + "node": "00000000-0000-0000-0000-000000000202", + "port": "00000000-0000-0000-0000-000000000222", + "ip": "20.0.0.1", + "mask": "255.255.255.0" + } + ], + "steps": [ + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000203", + "port": 5000 + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000203", + "port": 5001 + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000201" + }, + { + "op": "bindUdp", + "node": "00000000-0000-0000-0000-000000000202", + "port": 5000 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "target": "20.0.0.2", + "port": 5000, + "payload": "durch den Router" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "timeout": 500 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "target": "20.0.0.2", + "port": 5001, + "payload": "verboten" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000002", + "timeout": 500 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "target": "255.255.255.255", + "port": 5000, + "payload": "Broadcast" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000004", + "timeout": 500 + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "timeout": 500 + }, + { + "op": "sendUdp", + "socket": "00000000-0000-0000-0000-000000000001", + "payload": "zurueck" + }, + { + "op": "receiveUdp", + "socket": "00000000-0000-0000-0000-000000000003", + "timeout": 500 + } + ], + "firewalls": { + "00000000-0000-0000-0000-000000000202": { + "active": true, + "defaultPolicy": "accept", + "filterUdp": true, + "rules": [ + { + "protocol": "udp", + "port": 5001, + "action": "drop" + } + ] + } + } +} diff --git a/packages/core/test/scenarios/udp-routed.swift.json b/packages/core/test/scenarios/udp-routed.swift.json new file mode 100644 index 0000000..370c37f --- /dev/null +++ b/packages/core/test/scenarios/udp-routed.swift.json @@ -0,0 +1,2321 @@ +{ + "arp" : { + "00000000-0000-0000-0000-000000000201" : { + "10.0.0.1" : "02:00:00:00:02:21" + }, + "00000000-0000-0000-0000-000000000202" : { + "10.0.0.2" : "02:00:00:00:02:11", + "20.0.0.2" : "02:00:00:00:02:13" + }, + "00000000-0000-0000-0000-000000000203" : { + "20.0.0.1" : "02:00:00:00:02:22" + } + }, + "firewallDecisions" : [ + { + "accepted" : true, + "node" : "00000000-0000-0000-0000-000000000202", + "packet" : 1 + }, + { + "accepted" : false, + "node" : "00000000-0000-0000-0000-000000000202", + "packet" : 2, + "rule" : 0 + }, + { + "accepted" : true, + "node" : "00000000-0000-0000-0000-000000000202", + "packet" : 3 + }, + { + "accepted" : true, + "node" : "00000000-0000-0000-0000-000000000202", + "packet" : 4 + } + ], + "icmpObservations" : { + + }, + "pendingEvents" : 0, + "results" : [ + "00000000-0000-0000-0000-000000000001", + "00000000-0000-0000-0000-000000000002", + "00000000-0000-0000-0000-000000000003", + "00000000-0000-0000-0000-000000000004", + { + "node" : "00000000-0000-0000-0000-000000000201", + "packet" : 1, + "type" : "delivered" + }, + { + "at" : 330, + "destinationPort" : 5000, + "payload" : "durch den Router", + "receiver" : "20.0.0.2", + "sender" : "10.0.0.2", + "sourcePort" : 54899 + }, + { + "node" : "00000000-0000-0000-0000-000000000201", + "packet" : 2, + "type" : "delivered" + }, + null, + { + "node" : "00000000-0000-0000-0000-000000000201", + "packet" : 3, + "type" : "delivered" + }, + { + "at" : 940, + "destinationPort" : 5000, + "payload" : "Broadcast", + "receiver" : "255.255.255.255", + "sender" : "10.0.0.2", + "sourcePort" : 54899 + }, + null, + { + "node" : "00000000-0000-0000-0000-000000000203", + "packet" : 4, + "type" : "delivered" + }, + { + "at" : 1550, + "destinationPort" : 54899, + "payload" : "zurueck", + "receiver" : "10.0.0.2", + "sender" : "20.0.0.2", + "sourcePort" : 5000 + } + ], + "sockets" : [ + { + "id" : "00000000-0000-0000-0000-000000000001", + "localIp" : null, + "localPort" : 5000, + "node" : "00000000-0000-0000-0000-000000000203", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : "10.0.0.2", + "remotePort" : 54899 + }, + { + "id" : "00000000-0000-0000-0000-000000000002", + "localIp" : null, + "localPort" : 5001, + "node" : "00000000-0000-0000-0000-000000000203", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : null, + "remotePort" : null + }, + { + "id" : "00000000-0000-0000-0000-000000000003", + "localIp" : null, + "localPort" : 54899, + "node" : "00000000-0000-0000-0000-000000000201", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : "20.0.0.2", + "remotePort" : 5000 + }, + { + "id" : "00000000-0000-0000-0000-000000000004", + "localIp" : null, + "localPort" : 5000, + "node" : "00000000-0000-0000-0000-000000000202", + "protocol" : "udp", + "queued" : 0, + "remoteIp" : "10.0.0.2", + "remotePort" : 54899 + } + ], + "switchTables" : { + + }, + "time" : 1550, + "traces" : [ + { + "after" : [ + [ + "sourcePort", + "54899" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "16" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 1, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 1, + "time" : 0 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "ARP request for 10.0.0.1", + "direction" : "outbound", + "frame" : 1, + "id" : 2, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "created", + "time" : 0 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 1, + "id" : 3, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "time" : 0 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 4, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 55 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 5, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 55 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:02:11" + ], + [ + "senderIP", + "10.0.0.2" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "10.0.0.1" + ] + ], + "direction" : "inbound", + "frame" : 1, + "id" : 6, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "before" : [ + + ], + "detail" : "ARP reply for 10.0.0.1", + "direction" : "outbound", + "frame" : 2, + "id" : 7, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "time" : 55 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 2, + "id" : 8, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "sent", + "time" : 55 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 9, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 10, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "received", + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "reply" + ], + [ + "senderMAC", + "02:00:00:00:02:21" + ], + [ + "senderIP", + "10.0.0.1" + ], + [ + "targetMAC", + "02:00:00:00:02:11" + ], + [ + "targetIP", + "10.0.0.2" + ] + ], + "direction" : "inbound", + "frame" : 2, + "id" : 11, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "accepted", + "time" : 110 + }, + { + "after" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 12, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 1, + "time" : 110 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 13, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "created", + "packet" : 1, + "time" : 110 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 3, + "id" : 14, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 1, + "time" : 110 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 15, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 16, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 3, + "id" : 17, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "firewall default policy", + "direction" : "inbound", + "frame" : 3, + "id" : 18, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "TTL decremented", + "direction" : "outbound", + "frame" : 3, + "id" : 19, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "forwarded", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "ARP request for 20.0.0.2", + "direction" : "outbound", + "frame" : 4, + "id" : 20, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 4, + "id" : 21, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "sent", + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "detail" : "ARP request for 20.0.0.2", + "direction" : "outbound", + "frame" : 5, + "id" : 22, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "time" : 165 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 5, + "id" : 23, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "sent", + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "waiting for ARP resolution of 20.0.0.2", + "direction" : "outbound", + "id" : 24, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "packet" : 1, + "time" : 165 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 25, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 26, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:02:22" + ], + [ + "senderIP", + "20.0.0.1" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "20.0.0.2" + ] + ], + "direction" : "inbound", + "frame" : 4, + "id" : 27, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "accepted", + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "detail" : "ARP reply for 20.0.0.2", + "direction" : "outbound", + "frame" : 6, + "id" : 28, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "created", + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 6, + "id" : 29, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "sent", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 30, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 31, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "request" + ], + [ + "senderMAC", + "02:00:00:00:02:22" + ], + [ + "senderIP", + "20.0.0.1" + ], + [ + "targetMAC", + "00:00:00:00:00:00" + ], + [ + "targetIP", + "20.0.0.2" + ] + ], + "direction" : "inbound", + "frame" : 5, + "id" : 32, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "accepted", + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "detail" : "ARP reply for 20.0.0.2", + "direction" : "outbound", + "frame" : 7, + "id" : 33, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "created", + "time" : 220 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 7, + "id" : 34, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "sent", + "time" : 220 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 35, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 36, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 275 + }, + { + "after" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 37, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "forwarded", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "02:00:00:00:02:13" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 38, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "02:00:00:00:02:13" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 8, + "id" : 39, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "sent", + "packet" : 1, + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "reply" + ], + [ + "senderMAC", + "02:00:00:00:02:13" + ], + [ + "senderIP", + "20.0.0.2" + ], + [ + "targetMAC", + "02:00:00:00:02:22" + ], + [ + "targetIP", + "20.0.0.1" + ] + ], + "direction" : "inbound", + "frame" : 6, + "id" : 40, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 41, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 42, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "operation", + "reply" + ], + [ + "senderMAC", + "02:00:00:00:02:13" + ], + [ + "senderIP", + "20.0.0.2" + ], + [ + "targetMAC", + "02:00:00:00:02:22" + ], + [ + "targetIP", + "20.0.0.1" + ] + ], + "direction" : "inbound", + "frame" : 7, + "id" : 43, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "time" : 275 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "02:00:00:00:02:13" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 44, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:22" + ], + [ + "destinationMAC", + "02:00:00:00:02:13" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 45, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 8, + "id" : 46, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "received", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "54899" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "16" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 47, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "accepted", + "packet" : 1, + "time" : 330 + }, + { + "after" : [ + [ + "sourcePort", + "54899" + ], + [ + "destinationPort", + "5001" + ], + [ + "payloadLength", + "8" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 48, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 2, + "time" : 330 + }, + { + "after" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 9, + "id" : 49, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 2, + "time" : 330 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 9, + "id" : 50, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "created", + "packet" : 2, + "time" : 330 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 9, + "id" : 51, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 2, + "time" : 330 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "direction" : "inbound", + "frame" : 9, + "id" : 52, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 2, + "time" : 385 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "02:00:00:00:02:21" + ] + ], + "direction" : "inbound", + "frame" : 9, + "id" : 53, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 2, + "time" : 385 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 9, + "id" : 54, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 2, + "time" : 385 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "20.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "UDP matched rule #1", + "direction" : "inbound", + "frame" : 9, + "id" : 55, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "dropped", + "packet" : 2, + "time" : 385 + }, + { + "after" : [ + [ + "sourcePort", + "54899" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "9" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 56, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 3, + "time" : 885 + }, + { + "after" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 10, + "id" : 57, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 3, + "time" : 885 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 10, + "id" : 58, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "created", + "packet" : 3, + "time" : 885 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 10, + "id" : 59, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "sent", + "packet" : 3, + "time" : 885 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 10, + "id" : 60, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 3, + "time" : 940 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:11" + ], + [ + "destinationMAC", + "FF:FF:FF:FF:FF:FF" + ] + ], + "direction" : "inbound", + "frame" : 10, + "id" : 61, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 3, + "time" : 940 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 10, + "id" : 62, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 3, + "time" : 940 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "10.0.0.2" + ], + [ + "receiverIP", + "255.255.255.255" + ], + [ + "ttl", + "1" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "firewall default policy", + "direction" : "inbound", + "frame" : 10, + "id" : 63, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "packet" : 3, + "time" : 940 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "54899" + ], + [ + "destinationPort", + "5000" + ], + [ + "payloadLength", + "9" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 64, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "packet" : 3, + "time" : 940 + }, + { + "after" : [ + [ + "sourcePort", + "5000" + ], + [ + "destinationPort", + "54899" + ], + [ + "payloadLength", + "7" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "id" : 65, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "sent", + "packet" : 4, + "time" : 1440 + }, + { + "after" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 11, + "id" : 66, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "sent", + "packet" : 4, + "time" : 1440 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 11, + "id" : 67, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "created", + "packet" : 4, + "time" : 1440 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 11, + "id" : 68, + "interface" : "00000000-0000-0000-0000-000000000213", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000203", + "operation" : "sent", + "packet" : 4, + "time" : 1440 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 11, + "id" : 69, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:13" + ], + [ + "destinationMAC", + "02:00:00:00:02:22" + ] + ], + "direction" : "inbound", + "frame" : 11, + "id" : 70, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 11, + "id" : 71, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "received", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "firewall default policy", + "direction" : "inbound", + "frame" : 11, + "id" : 72, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "accepted", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "64" + ], + [ + "protocol", + "17" + ] + ], + "detail" : "TTL decremented", + "direction" : "outbound", + "frame" : 11, + "id" : 73, + "interface" : "00000000-0000-0000-0000-000000000222", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "forwarded", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 12, + "id" : 74, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "forwarded", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 12, + "id" : 75, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "created", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "before" : [ + + ], + "direction" : "outbound", + "frame" : 12, + "id" : 76, + "interface" : "00000000-0000-0000-0000-000000000221", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000202", + "operation" : "sent", + "packet" : 4, + "time" : 1495 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "direction" : "inbound", + "frame" : 12, + "id" : 77, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "physical", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "received", + "packet" : 4, + "time" : 1550 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourceMAC", + "02:00:00:00:02:21" + ], + [ + "destinationMAC", + "02:00:00:00:02:11" + ] + ], + "direction" : "inbound", + "frame" : 12, + "id" : 78, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "dataLink", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "received", + "packet" : 4, + "time" : 1550 + }, + { + "after" : [ + + ], + "before" : [ + [ + "senderIP", + "20.0.0.2" + ], + [ + "receiverIP", + "10.0.0.2" + ], + [ + "ttl", + "63" + ], + [ + "protocol", + "17" + ] + ], + "direction" : "inbound", + "frame" : 12, + "id" : 79, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "network", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "received", + "packet" : 4, + "time" : 1550 + }, + { + "after" : [ + + ], + "before" : [ + [ + "sourcePort", + "5000" + ], + [ + "destinationPort", + "54899" + ], + [ + "payloadLength", + "7" + ] + ], + "detail" : "UDP queued", + "direction" : "local", + "id" : 80, + "interface" : "00000000-0000-0000-0000-000000000211", + "layer" : "transport", + "node" : "00000000-0000-0000-0000-000000000201", + "operation" : "accepted", + "packet" : 4, + "time" : 1550 + } + ] +} diff --git a/tools/swift-oracle/README.md b/tools/swift-oracle/README.md index 40823b6..f62c014 100644 --- a/tools/swift-oracle/README.md +++ b/tools/swift-oracle/README.md @@ -17,6 +17,12 @@ npm test # vergleicht mit den geschriebenen *.swift.json die Tests ohne Docker und ohne Swift laufen. * Vergleich: `packages/core/test/oracle.test.ts`. Er meldet das **erste** abweichende Spurereignis mit Nummer. +* Schritte: `ping`, `traceroute`, `resolveMac`, `advance`, `packetLoss`, + `sat`, `speed`; UDP (seit F2): `bindUdp` (Knoten, optional Port, lokale + Adresse, Gegenstelle; Ergebnis die Socket-ID), `sendUdp` (Socket, Text, + optional Ziel und Port), `receiveUdp` (Socket, optional Wartezeit), + `closeSocket`. Das Ergebnis enthält die Sockets mit der Länge ihrer + Warteschlange. ## Korpus diff --git a/tools/swift-oracle/Sources/Oracle/main.swift b/tools/swift-oracle/Sources/Oracle/main.swift index 38a4458..1094df6 100644 --- a/tools/swift-oracle/Sources/Oracle/main.swift +++ b/tools/swift-oracle/Sources/Oracle/main.swift @@ -36,6 +36,9 @@ struct ScenarioStep: Decodable { let from: String?; let node: String?; let target: String? let ttl: UInt8?; let identifier: UInt16?; let sequence: UInt16?; let maxTtl: UInt8? let to: UInt64?; let enabled: Bool?; let percent: Int? + // UDP: a socket is named by the id bindUdp returned. + let port: UInt16?; let localIp: String?; let remoteIp: String?; let remotePort: UInt16? + let socket: String?; let payload: String?; let timeout: UInt64? } struct Scenario: Decodable { let seed: UInt64 @@ -222,6 +225,29 @@ func run(_ scenario: Scenario) -> JSON { case "speed": engine.setSimulationSpeed(percent: step.percent!) results.append(engine.simulationSpeed.percent) + case "bindUdp": + results.append(engine.bindUDPSocket( + nodeID: uuid(step.node!), localPort: step.port, localIPAddress: step.localIp, + remoteIPAddress: step.remoteIp, remotePort: step.remotePort + )?.uuidString ?? NSNull()) + case "sendUdp": + results.append(engine.sendUDP( + socketID: uuid(step.socket!), payload: Data((step.payload ?? "").utf8), + destinationIPAddress: step.target, destinationPort: step.port + ).map(delivery) ?? NSNull()) + case "receiveUdp": + let received = step.timeout.map { engine.receiveUDP(socketID: uuid(step.socket!), timeoutMilliseconds: $0) } + ?? engine.receiveUDP(socketID: uuid(step.socket!)) + results.append(received.map { item -> JSON in + [ + "sender": item.senderIPAddress, "receiver": item.receiverIPAddress, + "sourcePort": item.datagram.sourcePort, "destinationPort": item.datagram.destinationPort, + "payload": String(decoding: item.datagram.payload, as: UTF8.self), "at": item.receivedAtMilliseconds, + ] + } ?? NSNull()) + case "closeSocket": + engine.closeSocket(socketID: uuid(step.socket!)) + results.append(engine.state.socketsByID[uuid(step.socket!)] == nil) default: fatalError("unknown step \(step.op)") } @@ -248,6 +274,14 @@ func run(_ scenario: Scenario) -> JSON { "arp": arp, "switchTables": switchTables, "icmpObservations": observations, + "sockets": state.socketsByID.values.sorted { $0.id.uuidString < $1.id.uuidString }.map { socket -> JSON in + [ + "id": socket.id.uuidString, "node": socket.nodeID.uuidString, "protocol": socket.protocolKind.rawValue, + "localIp": socket.localIPAddress ?? NSNull(), "localPort": socket.localPort, + "remoteIp": socket.remoteIPAddress ?? NSNull(), "remotePort": socket.remotePort.map { $0 as Any } ?? NSNull(), + "queued": state.udpReceiveQueuesBySocketID[socket.id]?.count ?? 0, + ] + }, "firewallDecisions": state.firewallDecisions.map { decision -> JSON in var json: JSON = [ "packet": decision.packetIdentity, "node": decision.nodeID.uuidString, "accepted": decision.accepted,