// Runs rip-chain's network in Java FILIUS (ScenarioNetwork) and records what // RIP really does: every frame each card saw, every change of each router's // RIP table, and the calls of the story. // // RipRun // // PC 10.0.1.2 - R1 (10.0.1.1, 10.0.12.1) - R2 (10.0.12.2, 10.0.23.2) - // R3 (10.0.23.3, 10.0.3.1) - PC 10.0.3.2, each router with RIP. Java draws a // router's pauses from a new Random; this tool gives each the seed the core // gives it (ripSeed: the scenario's seed, 0x52495000 and the FNV-1a hash of // the router's id). The stories: // converge the tables fill; at 45 s 10.0.1.2 pings 10.0.3.2 // expire at 10 s R3 falls silent (its next beacon never comes); its // network expires at R2, which tells R1; at 125 s the ping again import filius.hardware.knoten.Knoten; import filius.software.rip.RIPBeacon; import filius.software.rip.RIPRoute; import filius.software.rip.RIPTable; import filius.software.system.VermittlungsrechnerBetriebssystem; import filius.software.vermittlungsschicht.IcmpPaket; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; public class RipRun { static final String PC_A = "00000000-0000-0000-0000-000000000401"; static final String R3 = "00000000-0000-0000-0000-000000000404"; static ScenarioNetwork network; static final List events = new ArrayList<>(); static final List tables = new ArrayList<>(); static final Map lastTables = new LinkedHashMap<>(); static synchronized void event(String what) { events.add(new Object[] { System.currentTimeMillis() - network.start, what }); } /** The table as one line: `network/mask gateway interface hops; …`, in its order. */ static String tableText(RIPTable table) { StringBuilder text = new StringBuilder(); synchronized (table) { for (RIPRoute route : table.routes) { if (text.length() > 0) text.append("; "); text.append(route.getNetAddress()).append('/').append(route.getNetMask()).append(' ').append(route.getGateway()) .append(' ').append(route.getInterfaceIpAddress()).append(' ').append(route.hops); } } return text.toString(); } static synchronized void pollTables() { for (Map.Entry entry : network.nodes.entrySet()) { if (!(entry.getValue().getSystemSoftware() instanceof VermittlungsrechnerBetriebssystem)) continue; RIPTable table = ((VermittlungsrechnerBetriebssystem) entry.getValue().getSystemSoftware()).getRIPTable(); if (table == null) continue; String text = tableText(table); if (!text.equals(lastTables.get(entry.getKey()))) { lastTables.put(entry.getKey(), text); tables.add(new Object[] { System.currentTimeMillis() - network.start, entry.getKey(), text }); } } } /** The core's ripSeed. */ static long ripSeed(long seed, String nodeId) { int hash = 0x811c9dc5; for (int index = 0; index < nodeId.length(); index++) { hash = (hash ^ nodeId.charAt(index)) * 0x01000193; } return seed ^ 0x52495000L ^ (hash & 0xffffffffL); } static String icmp(IcmpPaket packet) { return packet == null ? "null" : "ICMP " + packet.getIcmpType() + "/" + packet.getIcmpCode() + " from " + packet.getSender(); } static void ping(String target) { event("sendProbe " + target + " called"); IcmpPaket answer = network.system(PC_A).holeICMP().sendProbe(target, 64, 1, 1); event("sendProbe " + target + " returned " + icmp(answer)); } static void sleepUntil(long milliseconds) throws InterruptedException { long rest = network.start + milliseconds - System.currentTimeMillis(); if (rest > 0) Thread.sleep(rest); } public static void main(String[] args) throws Exception { network = ScenarioNetwork.read(args[0]); String story = args[1]; long end = Long.parseLong(args[2]); long seed = ScenarioNetwork.seed(args[0]); network.start(); Field beaconField = VermittlungsrechnerBetriebssystem.class.getDeclaredField("ripbeacon"); beaconField.setAccessible(true); Field randomField = RIPBeacon.class.getDeclaredField("rand"); randomField.setAccessible(true); for (Map.Entry entry : network.nodes.entrySet()) { if (!(entry.getValue().getSystemSoftware() instanceof VermittlungsrechnerBetriebssystem)) continue; VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) entry.getValue().getSystemSoftware(); if (!os.isRipEnabled()) continue; randomField.set(beaconField.get(os), new Random(ripSeed(seed, entry.getKey()))); } event("seeded"); Thread poller = new Thread(() -> { while (true) { pollTables(); try { Thread.sleep(2); } catch (InterruptedException e) { return; } } }); poller.setDaemon(true); poller.start(); switch (story) { case "converge": sleepUntil(45_000); ping("10.0.3.2"); break; case "expire": sleepUntil(10_000); ((VermittlungsrechnerBetriebssystem) network.system(R3)).getRIPTable().setNextBeacon(Long.MAX_VALUE); event("R3 silent"); sleepUntil(125_000); ping("10.0.3.2"); break; default: throw new IllegalArgumentException("unknown story " + story); } sleepUntil(end); pollTables(); ScenarioNetwork.Json out = new ScenarioNetwork.Json(); out.open('{'); network.writeFrames(out); synchronized (RipRun.class) { out.key("events").open('['); for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).close(']'); out.close(']'); out.key("tables").open('['); for (Object[] each : tables) out.open('[').number((Long) each[0]).string((String) each[1]).string((String) each[2]).close(']'); out.close(']'); } out.close('}'); network.stop(); ScenarioNetwork.write(args[3], out); System.exit(0); } }