// Runs a story of sends to addresses ARP cannot resolve on arp-routed's // network in Java FILIUS (ScenarioNetwork) and records every frame each card // saw and when each call started and ended. // // ArpRun // // 10.0.0.2 sits behind a switch on the router's 10.0.0.1; 20.0.0.2 on the // router's 20.0.0.1. No card has 10.0.0.9 or 20.0.0.9. The stories: // pingLan 10.0.0.2 pings 10.0.0.9 (ICMP.sendProbe, as the ping command) // pingRouted 10.0.0.2 pings 20.0.0.9: the router's ARP fails // udpTwice 10.0.0.2 sends two UDP datagrams to 10.0.0.9 at once // udpBehind 10.0.0.2 sends a UDP datagram to 10.0.0.9, then one to 20.0.0.2 // routedUdpBehind 10.0.0.2 sends a UDP datagram to 20.0.0.9, then one // to 20.0.0.2: the router forwards both // routedPingBesideUdp a ping to 20.0.0.2 (the router learns it), a UDP // datagram to 20.0.0.9, 100 ms later (the UDP thread // sends first) a ping to 20.0.0.2 again: only // one thread waits for ARP at a time. Two would meet // ARP's notify, which wakes one waiter, not the one // whose answer came (a Java bug the core does not take) // routedPingBehindPing an echo request to 20.0.0.9 (sent, not waited for), // then a ping to 20.0.0.2 import filius.software.transportschicht.UDPSocket; import filius.software.vermittlungsschicht.ICMP; import filius.software.vermittlungsschicht.IcmpPaket; import java.util.ArrayList; import java.util.List; public class ArpRun { static final String HOST = "00000000-0000-0000-0000-000000000301"; static ScenarioNetwork network; static final List events = new ArrayList<>(); interface Call { String run() throws Exception; } static synchronized void event(String what) { events.add(new Object[] { System.currentTimeMillis() - network.start, what }); } static void call(String label, Call call) { event(label + " called"); try { event(label + " returned " + call.run()); } catch (Exception e) { event(label + " failed " + e.getClass().getSimpleName()); } } static String icmp(IcmpPaket packet) { return packet == null ? "null" : "ICMP " + packet.getIcmpType() + "/" + packet.getIcmpCode() + " from " + packet.getSender(); } static void send(String target, String payload) throws Exception { UDPSocket socket = new UDPSocket(network.system(HOST), target, 9); socket.verbinden(); socket.senden(payload); } public static void main(String[] args) throws Exception { network = ScenarioNetwork.read(args[0]); String story = args[1]; long end = Long.parseLong(args[2]); network.start(); Thread.sleep(500); switch (story) { case "pingLan": call("sendProbe 10.0.0.9", () -> icmp(network.system(HOST).holeICMP().sendProbe("10.0.0.9", 64, 1, 1))); break; case "pingRouted": call("sendProbe 20.0.0.9", () -> icmp(network.system(HOST).holeICMP().sendProbe("20.0.0.9", 64, 1, 1))); break; case "udpTwice": call("senden eins", () -> { send("10.0.0.9", "eins"); return ""; }); call("senden zwei", () -> { send("10.0.0.9", "zwei"); return ""; }); break; case "udpBehind": call("senden verloren", () -> { send("10.0.0.9", "verloren"); return ""; }); call("senden dahinter", () -> { send("20.0.0.2", "dahinter"); return ""; }); break; case "routedUdpBehind": call("senden verloren", () -> { send("20.0.0.9", "verloren"); return ""; }); call("senden dahinter", () -> { send("20.0.0.2", "dahinter"); return ""; }); break; case "routedPingBesideUdp": call("sendProbe 20.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("20.0.0.2", 64, 1, 1))); call("senden verloren", () -> { send("20.0.0.9", "verloren"); return ""; }); Thread.sleep(100); call("sendProbe 20.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("20.0.0.2", 64, 1, 2))); break; case "routedPingBehindPing": call("sendeICMP 20.0.0.9", () -> { network.system(HOST).holeICMP().sendeICMP(ICMP.TYPE_ECHO_REQUEST, ICMP.CODE_ECHO, 2, 2, null, "20.0.0.9"); return ""; }); call("sendProbe 20.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("20.0.0.2", 64, 1, 1))); break; default: throw new IllegalArgumentException("unknown story " + story); } long rest = network.start + end - System.currentTimeMillis(); if (rest > 0) Thread.sleep(rest); ScenarioNetwork.Json out = new ScenarioNetwork.Json(); out.open('{'); network.writeFrames(out); synchronized (ArpRun.class) { out.key("events").open('['); for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).close(']'); out.close(']'); } out.close('}'); network.stop(); ScenarioNetwork.write(args[3], out); System.exit(0); } }