feat(core): UDP sockets in the simulation core
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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', () => {
|
||||
|
||||
@@ -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<string, unknown> {
|
||||
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<string, unknown> {
|
||||
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),
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
"packet" : 7,
|
||||
"type" : "delivered"
|
||||
}
|
||||
],
|
||||
"sockets" : [
|
||||
|
||||
],
|
||||
"switchTables" : {
|
||||
"00000000-0000-0000-0000-000000000405" : {
|
||||
|
||||
@@ -151,6 +151,9 @@
|
||||
"type" : "delivered"
|
||||
},
|
||||
"02:00:00:00:02:22"
|
||||
],
|
||||
"sockets" : [
|
||||
|
||||
],
|
||||
"switchTables" : {
|
||||
|
||||
|
||||
@@ -204,6 +204,9 @@
|
||||
"packet" : 13,
|
||||
"type" : "delivered"
|
||||
}
|
||||
],
|
||||
"sockets" : [
|
||||
|
||||
],
|
||||
"switchTables" : {
|
||||
|
||||
|
||||
@@ -795,6 +795,9 @@
|
||||
"packet" : 3,
|
||||
"type" : "delivered"
|
||||
}
|
||||
],
|
||||
"sockets" : [
|
||||
|
||||
],
|
||||
"switchTables" : {
|
||||
"00000000-0000-0000-0000-000000000503" : {
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
"packet" : 12,
|
||||
"type" : "delivered"
|
||||
}
|
||||
],
|
||||
"sockets" : [
|
||||
|
||||
],
|
||||
"switchTables" : {
|
||||
"00000000-0000-0000-0000-000000000104" : {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user