From fd445e88896c15aaf6dc3277e8214719a35c1b85 Mon Sep 17 00:00:00 2001 From: Julian Kiedaisch Date: Wed, 30 Sep 2026 10:33:58 +0000 Subject: [PATCH] test(java-oracle): DhcpRun records DHCP as Java FILIUS runs it Builds a core scenario's network in Java FILIUS, starts it as the action mode does and writes every frame each card saw (the Lauscher) and the addresses at the end. References for the four DHCP scenarios: one DISCOVER/REQUEST per attempt, an ARP check that waits one RTT, DECLINE on a conflict, link-local 169.254.1.x after the fifth failure. Co-Authored-By: Claude Opus 5.5 --- .../test/scenarios/dhcp-conflict.java.json | 489 ++++++++++++++++++ .../core/test/scenarios/dhcp-lan.java.json | 331 ++++++++++++ .../test/scenarios/dhcp-no-server.java.json | 243 +++++++++ .../test/scenarios/dhcp-two-servers.java.json | 219 ++++++++ tools/java-oracle/README.md | 33 ++ tools/java-oracle/run.sh | 15 +- tools/java-oracle/src/DhcpRun.java | 396 ++++++++++++++ 7 files changed, 1725 insertions(+), 1 deletion(-) create mode 100644 packages/core/test/scenarios/dhcp-conflict.java.json create mode 100644 packages/core/test/scenarios/dhcp-lan.java.json create mode 100644 packages/core/test/scenarios/dhcp-no-server.java.json create mode 100644 packages/core/test/scenarios/dhcp-two-servers.java.json create mode 100644 tools/java-oracle/src/DhcpRun.java diff --git a/packages/core/test/scenarios/dhcp-conflict.java.json b/packages/core/test/scenarios/dhcp-conflict.java.json new file mode 100644 index 0000000..dc8b33e --- /dev/null +++ b/packages/core/test/scenarios/dhcp-conflict.java.json @@ -0,0 +1,489 @@ +{ + "frames": { + "00000000-0000-0000-0000-000000000101": [ + { + "time": 459, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 464, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 688, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 801, + "source": "02:00:00:00:01:13", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "192.168.0.100", + "targetIp": "255.255.255.255" + }, + { + "time": 912, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 968, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3663, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 6413, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 9164, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11914, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11915, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 12138, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 12194, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14889, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.191" + }, + { + "time": 17640, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.191", + "targetIp": "255.255.255.255" + } + ], + "00000000-0000-0000-0000-000000000102": [ + { + "time": 338, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 576, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 577, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 801, + "source": "02:00:00:00:01:13", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "192.168.0.100", + "targetIp": "255.255.255.255" + }, + { + "time": 801, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 857, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3552, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 6302, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 9052, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11802, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 12026, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 12027, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 12082, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14778, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.191" + }, + { + "time": 17528, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.191", + "targetIp": "255.255.255.255" + } + ], + "00000000-0000-0000-0000-000000000103": [ + { + "time": 459, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 576, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 688, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 690, + "source": "02:00:00:00:01:13", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "192.168.0.100", + "targetIp": "255.255.255.255" + }, + { + "time": 912, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 968, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3663, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 6413, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 9164, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11914, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 12026, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=0.0.0.0\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 12138, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDECLINE\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 12194, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14889, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.191" + }, + { + "time": 17640, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.191", + "targetIp": "255.255.255.255" + } + ] + }, + "devices": { + "00000000-0000-0000-0000-000000000101": [ + "192.168.0.10", + "255.255.255.0", + "", + "" + ], + "00000000-0000-0000-0000-000000000102": [ + "169.254.1.191", + "255.255.0.0", + "", + "" + ], + "00000000-0000-0000-0000-000000000103": [ + "192.168.0.100", + "255.255.255.0", + "", + "" + ] + } +} diff --git a/packages/core/test/scenarios/dhcp-lan.java.json b/packages/core/test/scenarios/dhcp-lan.java.json new file mode 100644 index 0000000..780a9df --- /dev/null +++ b/packages/core/test/scenarios/dhcp-lan.java.json @@ -0,0 +1,331 @@ +{ + "frames": { + "00000000-0000-0000-0000-000000000101": [ + { + "time": 460, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 464, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 516, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:13" + }, + { + "time": 520, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 688, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 743, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.150" + }, + { + "time": 3438, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3438, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + }, + { + "time": 3493, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:13\nrequested=192.168.0.150\nserverident=192.168.0.10" + }, + { + "time": 3494, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nserverident=192.168.0.10" + } + ], + "00000000-0000-0000-0000-000000000102": [ + { + "time": 337, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 460, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:13" + }, + { + "time": 575, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 576, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 631, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 743, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.150" + }, + { + "time": 3327, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3493, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:13\nrequested=192.168.0.150\nserverident=192.168.0.10" + }, + { + "time": 3549, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + }, + { + "time": 3605, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nserverident=192.168.0.10" + } + ], + "00000000-0000-0000-0000-000000000103": [ + { + "time": 460, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 575, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 631, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=192.168.0.53\nserverident=192.168.0.10" + }, + { + "time": 631, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.150" + }, + { + "time": 688, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 3382, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:13\nrequested=192.168.0.150\nserverident=192.168.0.10" + }, + { + "time": 3438, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3549, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + }, + { + "time": 3605, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.150\nchaddr=02:00:00:00:01:13\nserverident=192.168.0.10" + } + ] + }, + "devices": { + "00000000-0000-0000-0000-000000000101": [ + "192.168.0.10", + "255.255.255.0", + "", + "" + ], + "00000000-0000-0000-0000-000000000102": [ + "192.168.0.100", + "255.255.255.0", + "192.168.0.1", + "192.168.0.53" + ], + "00000000-0000-0000-0000-000000000103": [ + "192.168.0.150", + "255.255.255.0", + "192.168.0.1", + "192.168.0.53" + ] + } +} diff --git a/packages/core/test/scenarios/dhcp-no-server.java.json b/packages/core/test/scenarios/dhcp-no-server.java.json new file mode 100644 index 0000000..6c82241 --- /dev/null +++ b/packages/core/test/scenarios/dhcp-no-server.java.json @@ -0,0 +1,243 @@ +{ + "frames": { + "00000000-0000-0000-0000-000000000101": [ + { + "time": 466, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3199, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 5949, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 8699, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11450, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14201, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.72" + }, + { + "time": 16951, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.72", + "targetIp": "255.255.255.255" + } + ], + "00000000-0000-0000-0000-000000000102": [ + { + "time": 342, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3087, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 5838, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 8588, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11338, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14089, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.72" + }, + { + "time": 16840, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.72", + "targetIp": "255.255.255.255" + } + ], + "00000000-0000-0000-0000-000000000103": [ + { + "time": 466, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 3199, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 5949, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 8699, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 11450, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 14201, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "169.254.1.72" + }, + { + "time": 16951, + "source": "02:00:00:00:01:12", + "destination": "ff:ff:ff:ff:ff:ff", + "arp": 2, + "senderIp": "169.254.1.72", + "targetIp": "255.255.255.255" + } + ] + }, + "devices": { + "00000000-0000-0000-0000-000000000101": [ + "192.168.0.10", + "255.255.255.0", + "", + "" + ], + "00000000-0000-0000-0000-000000000102": [ + "169.254.1.72", + "255.255.0.0", + "", + "" + ], + "00000000-0000-0000-0000-000000000103": [ + "192.168.0.30", + "255.255.255.0", + "", + "" + ] + } +} diff --git a/packages/core/test/scenarios/dhcp-two-servers.java.json b/packages/core/test/scenarios/dhcp-two-servers.java.json new file mode 100644 index 0000000..51055e7 --- /dev/null +++ b/packages/core/test/scenarios/dhcp-two-servers.java.json @@ -0,0 +1,219 @@ +{ + "frames": { + "00000000-0000-0000-0000-000000000101": [ + { + "time": 455, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 460, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.254\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 572, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.30", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.200\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=8.8.8.8\nserverident=192.168.0.30" + }, + { + "time": 684, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 3435, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3435, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + } + ], + "00000000-0000-0000-0000-000000000102": [ + { + "time": 333, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 572, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.254\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 572, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 627, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.30", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.200\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=8.8.8.8\nserverident=192.168.0.30" + }, + { + "time": 3323, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3547, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + } + ], + "00000000-0000-0000-0000-000000000103": [ + { + "time": 455, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPDISCOVER\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12" + }, + { + "time": 460, + "source": "02:00:00:00:01:13", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.30", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.200\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.1\nsubnetmask=255.255.255.0\ndnsserver=8.8.8.8\nserverident=192.168.0.30" + }, + { + "time": 572, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPOFFER\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nrouter=192.168.0.254\nsubnetmask=255.255.255.0\ndnsserver=0.0.0.0\nserverident=192.168.0.10" + }, + { + "time": 684, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "arp": 1, + "senderIp": "0.0.0.0", + "targetIp": "192.168.0.100" + }, + { + "time": 3435, + "source": "02:00:00:00:01:12", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "0.0.0.0", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 68, + "destinationPort": 67, + "payload": "DHCPREQUEST\nyiaddr=0.0.0.0\nchaddr=02:00:00:00:01:12\nrequested=192.168.0.100\nserverident=192.168.0.10" + }, + { + "time": 3547, + "source": "02:00:00:00:01:11", + "destination": "FF:FF:FF:FF:FF:FF", + "sourceIp": "192.168.0.10", + "destinationIp": "255.255.255.255", + "protocol": 17, + "sourcePort": 67, + "destinationPort": 68, + "payload": "DHCPACK\nyiaddr=192.168.0.100\nchaddr=02:00:00:00:01:12\nserverident=192.168.0.10" + } + ] + }, + "devices": { + "00000000-0000-0000-0000-000000000101": [ + "192.168.0.10", + "255.255.255.0", + "192.168.0.254", + "" + ], + "00000000-0000-0000-0000-000000000102": [ + "192.168.0.100", + "255.255.255.0", + "192.168.0.254", + "0.0.0.0" + ], + "00000000-0000-0000-0000-000000000103": [ + "192.168.0.30", + "255.255.255.0", + "", + "" + ] + } +} diff --git a/tools/java-oracle/README.md b/tools/java-oracle/README.md index da8e387..92c55c4 100644 --- a/tools/java-oracle/README.md +++ b/tools/java-oracle/README.md @@ -139,3 +139,36 @@ mit weniger als fünf Feldern lässt Java die ganze Datei verwerfen überspringt Java, statt sie zu zählen; eine Nachricht mit leerem Text geht verloren, weil `split` leere Felder am Ende abschneidet. Beim Client gewinnt die letzte Zeile, auch eine kaputte, die das Konto leert. + +## DHCP zur Laufzeit + +`DhcpRun` baut das Netz eines Kern-Szenarios (`packages/core/test/scenarios/*.scenario.json`: +Knoten, Kabel, Geräte, DHCP-Server und -Clients; die Schritte bleiben +unbeachtet) in Java-Filius nach und startet es wie der Aktionsmodus +(`starten()` jeder Systemsoftware). Nach der angegebenen Echtzeit schreibt es +nach `.java.json`, was jede Netzwerkkarte gesehen hat (Filius' eigener +Mitschnitt, der `Lauscher`: Zeit, MACs, ARP-Operation und -Adressen, +IP/UDP-Adressen und -Ports samt DHCP-Text), und die Adressen jedes Rechners +am Ende. Die MAC eines Ports ist dieselbe wie im Kern (`mac`, sonst +`stableGeneratedMacAddress`). + +* Switches und DHCP-Server starten zuerst: Javas Client wartet auf jeden + aktiven Server, findet sie aber über die Knotenliste der Oberfläche, die das + Werkzeug nicht hat. +* `GUIContainer.getGUIContainer()` wird vor dem Start einmal aufgerufen. Im + echten Filius steht das Fenster schon; ohne das legen zwei Clients den + Singleton gleichzeitig an (nicht synchronisiert), und einer von ihnen + sendet nie etwas (gemessen am Szenario `dhcp-lan`). +* Die Zeiten schwanken von Lauf zu Lauf um einige zehn Millisekunden (echte + Threads), die Link-Local-Adresse würfelt Java mit `Math.random`. Die + Reihenfolge der Nachrichten eines Clients und ihr Inhalt schwanken nicht. + +Gemessen (30.09.2026), was Swift anders macht: Je Versuch sendet Java genau +ein DISCOVER bzw. REQUEST und wartet dann bis zu einer RTT (2,5 s) auf die +Antwort; eine unpassende Antwort (etwa das Angebot des zweiten Servers) liest +es und verwirft sie. Vor dem REQUEST prüft es die angebotene Adresse per ARP +und wartet dabei eine RTT; antwortet ein anderer Rechner, lehnt es mit +DHCPDECLINE ab. Javas Server übergeht das DECLINE und hält die Adresse +weiter als Angebot fest (4 RTT). Nach dem fünften Fehlversuch (Zeitablauf) +nimmt der Client eine Link-Local-Adresse `169.254.1.x/16`: ARP-Probe, eine +RTT warten, dann ein ARP-Reply an alle. diff --git a/tools/java-oracle/run.sh b/tools/java-oracle/run.sh index 874e663..57b6e23 100755 --- a/tools/java-oracle/run.sh +++ b/tools/java-oracle/run.sh @@ -21,7 +21,7 @@ if [ ! -f "$upstream/target/filius.jar" ]; then fi classpath="$upstream/target/filius.jar:$upstream/target/lib/*" mkdir -p "$here/.build" -javac -encoding UTF-8 -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" "$here/src/GetterDefaults.java" "$here/src/IpCheckCases.java" "$here/src/DnsHostsCases.java" "$here/src/EmailFileCases.java" "$here/src/BeansDump.java" "$here/src/Base64Cases.java" +javac -encoding UTF-8 -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" "$here/src/GetterDefaults.java" "$here/src/IpCheckCases.java" "$here/src/DnsHostsCases.java" "$here/src/EmailFileCases.java" "$here/src/BeansDump.java" "$here/src/Base64Cases.java" "$here/src/DhcpRun.java" # FILIUS writes its settings below $HOME; keep them out of the real one. mkdir -p "$here/.build/home" # Removed first: a crashed run must not leave the previous result standing. @@ -106,3 +106,16 @@ for written in "$root/packages/fls/test/written" "$root/packages/fls/test/export test -s "$written.java.json" fi done + +# DHCP as Java FILIUS runs it: a core scenario's network, started as the +# action mode starts it, for the given real-time milliseconds; every frame +# each card saw and the addresses at the end (packages/core/test/dhcpJava.test.ts). +# One run after another: a busy machine stretches the times. +for run in dhcp-lan:8000 dhcp-two-servers:8000 dhcp-conflict:25000 dhcp-no-server:25000; do + name="${run%%:*}" + output="$root/packages/core/test/scenarios/$name.java.json" + rm -f "$output" + HOME="$here/.build/home" xvfb-run -a java -cp "$classpath:$here/.build" DhcpRun \ + "$root/packages/core/test/scenarios/$name.scenario.json" "${run##*:}" "$output" 2>&1 | grep -v 'logback\|^$' || true + test -s "$output" +done diff --git a/tools/java-oracle/src/DhcpRun.java b/tools/java-oracle/src/DhcpRun.java new file mode 100644 index 0000000..df756f6 --- /dev/null +++ b/tools/java-oracle/src/DhcpRun.java @@ -0,0 +1,396 @@ +// Runs a core scenario's network in Java FILIUS and records what DHCP really +// does: every frame each network card saw (FILIUS' own packet log, the +// Lauscher) and each host's address configuration at the end. +// +// DhcpRun +// +// The network is built from the scenario (nodes, links, devices, +// dhcpServers, dhcpClients; steps are ignored) the way the core reads it: a +// port's MAC is its `mac`, else the core's stableGeneratedMacAddress. The +// simulation then runs as the action mode starts it (every system software's +// starten()), in real time, for the given milliseconds. Threads make the +// times vary from run to run; the order of one client's messages does not. + +import filius.gui.GUIContainer; +import filius.hardware.Kabel; +import filius.hardware.NetzwerkInterface; +import filius.hardware.Port; +import filius.hardware.knoten.InternetKnoten; +import filius.hardware.knoten.Knoten; +import filius.hardware.knoten.LokalerKnoten; +import filius.hardware.knoten.Notebook; +import filius.hardware.knoten.Rechner; +import filius.hardware.knoten.Switch; +import filius.rahmenprogramm.nachrichten.Lauscher; +import filius.software.dhcp.DHCPServer; +import filius.software.netzzugangsschicht.EthernetFrame; +import filius.software.system.InternetKnotenBetriebssystem; +import filius.software.transportschicht.Segment; +import filius.software.vermittlungsschicht.ArpPaket; +import filius.software.vermittlungsschicht.IcmpPaket; +import filius.software.vermittlungsschicht.IpPaket; + +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public class DhcpRun { + + public static void main(String[] args) throws Exception { + @SuppressWarnings("unchecked") + Map scenario = (Map) new JsonReader( + new String(Files.readAllBytes(Paths.get(args[0])), StandardCharsets.UTF_8)).value(); + long duration = Long.parseLong(args[1]); + + Map nodes = new LinkedHashMap<>(); + Map ports = new HashMap<>(); + Map macByNode = new LinkedHashMap<>(); + for (Object each : list(scenario.get("nodes"))) { + Map node = map(each); + String id = (String) node.get("id"); + String kind = (String) node.get("kind"); + List nodePorts = list(node.get("ports")); + Knoten knoten; + switch (kind) { + case "pc": + knoten = new Rechner(); + break; + case "notebook": + knoten = new Notebook(); + break; + case "networkSwitch": + knoten = new Switch(); + break; + default: + throw new IllegalArgumentException("node kind " + kind + " is not built by this tool"); + } + knoten.setName(id); + if (knoten instanceof InternetKnoten) { + if (nodePorts.size() != 1) throw new IllegalArgumentException("a host has one port here"); + Map port = map(nodePorts.get(0)); + NetzwerkInterface nic = ((InternetKnoten) knoten).getNetzwerkInterfaces().get(0); + String mac = port.containsKey("mac") ? (String) port.get("mac") : stableMac((String) port.get("id")); + nic.setMac(mac); + ports.put((String) port.get("id"), nic.getPort()); + macByNode.put(id, mac); + } else { + LinkedList switchPorts = ((LokalerKnoten) knoten).getAnschluesse(); + for (int index = 0; index < nodePorts.size(); index++) { + ports.put((String) map(nodePorts.get(index)).get("id"), switchPorts.get(index)); + } + } + nodes.put(id, knoten); + } + for (Map.Entry entry : map(scenario.getOrDefault("devices", new HashMap<>())).entrySet()) { + Map device = map(entry.getValue()); + NetzwerkInterface nic = ((InternetKnoten) nodes.get(entry.getKey())).getNetzwerkInterfaces().get(0); + nic.setIp((String) device.get("ip")); + nic.setSubnetzMaske((String) device.get("mask")); + nic.setGateway((String) device.getOrDefault("gateway", "")); + nic.setDns((String) device.getOrDefault("dns", "")); + } + for (Object each : list(scenario.get("links"))) { + Map link = map(each); + Kabel cable = new Kabel(); + cable.setAnschluesse(new Port[] { ports.get(link.get("sourcePort")), ports.get(link.get("targetPort")) }); + } + List servers = new ArrayList<>(); + for (Map.Entry entry : map(scenario.getOrDefault("dhcpServers", new HashMap<>())).entrySet()) { + Map config = map(entry.getValue()); + DHCPServer server = system(nodes.get(entry.getKey())).getDHCPServer(); + server.setUntergrenze((String) config.getOrDefault("lower", "0.0.0.0")); + server.setObergrenze((String) config.getOrDefault("upper", "0.0.0.0")); + server.setGatewayip((String) config.getOrDefault("gateway", "0.0.0.0")); + server.setDnsserverip((String) config.getOrDefault("dns", "0.0.0.0")); + server.setOwnSettings(Boolean.TRUE.equals(config.get("own"))); + for (Object assignment : list(config.getOrDefault("staticAssignments", new ArrayList<>()))) { + server.addStaticAssignment((String) list(assignment).get(0), (String) list(assignment).get(1)); + } + server.setAktiv(Boolean.TRUE.equals(config.get("active"))); + servers.add(entry.getKey()); + } + for (Object each : list(scenario.getOrDefault("dhcpClients", new ArrayList<>()))) { + system(nodes.get((String) each)).setDHCPKonfiguration(true); + } + + // Switches and DHCP servers first: FILIUS' client waits for every active + // server to have started (waitUntilDhcpServerStarted, through the GUI's + // node list, which this tool has not got). + // FILIUS' window exists before a simulation starts; created lazily and + // unsynchronized, the first clients to ask for it would race. + GUIContainer.getGUIContainer(); + long start = System.currentTimeMillis(); + for (Map.Entry entry : nodes.entrySet()) { + if (entry.getValue() instanceof Switch || servers.contains(entry.getKey())) entry.getValue().getSystemSoftware().starten(); + } + Thread.sleep(200); + for (Map.Entry entry : nodes.entrySet()) { + if (!(entry.getValue() instanceof Switch || servers.contains(entry.getKey()))) entry.getValue().getSystemSoftware().starten(); + } + Thread.sleep(duration); + + Field field = Lauscher.class.getDeclaredField("datenEinheiten"); + field.setAccessible(true); + @SuppressWarnings("unchecked") + Map> log = (Map>) field.get(Lauscher.getLauscher()); + + Json out = new Json(); + out.open('{'); + out.key("frames").open('{'); + for (Map.Entry entry : macByNode.entrySet()) { + out.key(entry.getKey()).open('['); + LinkedList frames = log.get(entry.getValue()); + if (frames != null) { + synchronized (frames) { + for (Object[] stamped : frames) frame(out, ((Long) stamped[0]) - start, (EthernetFrame) stamped[1]); + } + } + out.close(']'); + } + out.close('}'); + out.key("devices").open('{'); + for (Map.Entry entry : nodes.entrySet()) { + if (!(entry.getValue() instanceof InternetKnoten)) continue; + NetzwerkInterface nic = ((InternetKnoten) entry.getValue()).getNetzwerkInterfaces().get(0); + out.key(entry.getKey()).open('[').string(nic.getIp()).string(nic.getSubnetzMaske()).string(nic.getGateway()) + .string(nic.getDns()).close(']'); + } + out.close('}'); + out.close('}'); + + for (Knoten knoten : nodes.values()) { + try { + knoten.getSystemSoftware().beenden(); + } catch (Exception e) {} + } + try (Writer writer = new OutputStreamWriter(new FileOutputStream(args[2]), StandardCharsets.UTF_8)) { + writer.write(out.toString()); + writer.write('\n'); + } + System.exit(0); + } + + private static void frame(Json out, long time, EthernetFrame frame) { + out.open('{').key("time").number(time).key("source").string(frame.getQuellMacAdresse()).key("destination") + .string(frame.getZielMacAdresse()); + Object data = frame.getDaten(); + if (data instanceof ArpPaket) { + ArpPaket arp = (ArpPaket) data; + out.key("arp").number(arp.getOperation()).key("senderIp").string(arp.getSenderIP()).key("targetIp") + .string(arp.getTargetIP()); + } else if (data instanceof IcmpPaket) { + out.key("icmp").number(((IcmpPaket) data).getIcmpType()); + } else if (data instanceof IpPaket) { + IpPaket ip = (IpPaket) data; + Segment segment = ip.getSegment(); + out.key("sourceIp").string(ip.getSender()).key("destinationIp").string(ip.getEmpfaenger()).key("protocol") + .number(ip.getProtocol()).key("sourcePort").number(segment.getQuellPort()).key("destinationPort") + .number(segment.getZielPort()).key("payload").string(segment.getDaten()); + } + out.close('}'); + } + + private static InternetKnotenBetriebssystem system(Knoten knoten) { + return (InternetKnotenBetriebssystem) knoten.getSystemSoftware(); + } + + /** The core's stableGeneratedMacAddress (packages/core/src/model/node.ts). */ + static String stableMac(String portId) { + String compact = portId.toUpperCase().replace("-", ""); + String suffix = compact.substring(compact.length() - 10); + StringBuilder mac = new StringBuilder("02"); + for (int offset = 0; offset < suffix.length(); offset += 2) mac.append(':').append(suffix, offset, offset + 2); + return mac.toString(); + } + + @SuppressWarnings("unchecked") + private static Map map(Object value) { + return (Map) value; + } + + @SuppressWarnings("unchecked") + private static List list(Object value) { + return (List) value; + } + + /** Just enough JSON for a scenario: objects, arrays, strings, numbers, booleans, null. */ + static final class JsonReader { + private final String text; + private int position; + + JsonReader(String text) { + this.text = text; + } + + Object value() { + skip(); + char c = text.charAt(position); + if (c == '{') { + Map result = new TreeMap<>(); + position++; + skip(); + if (text.charAt(position) == '}') { + position++; + return result; + } + for (;;) { + skip(); + String key = (String) value(); + skip(); + expect(':'); + result.put(key, value()); + skip(); + if (text.charAt(position++) == '}') return result; + } + } + if (c == '[') { + List result = new ArrayList<>(); + position++; + skip(); + if (text.charAt(position) == ']') { + position++; + return result; + } + for (;;) { + result.add(value()); + skip(); + if (text.charAt(position++) == ']') return result; + } + } + if (c == '"') { + StringBuilder result = new StringBuilder(); + position++; + for (char each = text.charAt(position++); each != '"'; each = text.charAt(position++)) { + if (each == '\\') { + char escaped = text.charAt(position++); + switch (escaped) { + case 'n': + result.append('\n'); + break; + case 't': + result.append('\t'); + break; + case 'u': + result.append((char) Integer.parseInt(text.substring(position, position + 4), 16)); + position += 4; + break; + default: + result.append(escaped); + } + } else { + result.append(each); + } + } + return result.toString(); + } + if (text.startsWith("true", position)) { + position += 4; + return Boolean.TRUE; + } + if (text.startsWith("false", position)) { + position += 5; + return Boolean.FALSE; + } + if (text.startsWith("null", position)) { + position += 4; + return null; + } + int begin = position; + while (position < text.length() && "+-.eE0123456789".indexOf(text.charAt(position)) >= 0) position++; + return Double.parseDouble(text.substring(begin, position)); + } + + private void skip() { + while (position < text.length() && Character.isWhitespace(text.charAt(position))) position++; + } + + private void expect(char c) { + if (text.charAt(position++) != c) throw new IllegalArgumentException("expected " + c + " at " + (position - 1)); + } + } + + /** A JSON writer with commas and indentation. */ + static final class Json { + private final StringBuilder text = new StringBuilder(); + private final LinkedList first = new LinkedList<>(); + private boolean afterKey; + + private void separate() { + if (afterKey) { + afterKey = false; + return; + } + if (first.isEmpty()) return; + if (!first.peek()) text.append(','); + first.pop(); + first.push(false); + text.append('\n'); + for (int i = 0; i < first.size(); i++) text.append(" "); + } + + Json open(char bracket) { + separate(); + text.append(bracket); + first.push(true); + return this; + } + + Json close(char bracket) { + boolean empty = first.pop(); + if (!empty) { + text.append('\n'); + for (int i = 0; i < first.size(); i++) text.append(" "); + } + text.append(bracket); + return this; + } + + Json key(String key) { + separate(); + quote(key); + text.append(": "); + afterKey = true; + return this; + } + + Json string(String value) { + separate(); + if (value == null) text.append("null"); + else quote(value); + return this; + } + + Json number(long value) { + separate(); + text.append(value); + return this; + } + + private void quote(String value) { + text.append('"'); + for (char c : value.toCharArray()) { + if (c == '"' || c == '\\') text.append('\\').append(c); + else if (c == '\n') text.append("\\n"); + else if (c < 0x20) text.append(String.format("\\u%04x", (int) c)); + else text.append(c); + } + text.append('"'); + } + + @Override + public String toString() { + return text.toString(); + } + } +}