// Runs a story of FILIUS' command line (Terminal) on terminal-net in Java // FILIUS and records what really happens: every frame each card saw, Java's // tables of them, and everything each host's command line told its window // (each text and each Boolean "busy" mark), with the time. // // TerminalRun // // terminal-net: the client 192.168.0.20 (gateway .1, DNS server .10), the // DNS server .10 (no gateway, no DNS server), .30, .31 (the echo server on // 55555 in netstat, as on the DNS server), the router .1 / 10.0.0.1, and 10.0.0.2 behind it // (DNS server 192.168.0.53, which is not there). The DNS server knows // www.filius.de, filius.de (A and MX), mail.filius.de, multi.filius.de (two // A), fern.filius.de (10.0.0.2), weg.filius.de (.99, no one) and post.filius.de // (MX only). A line is typed as the window hands it over // (Terminal.terminalEingabeAuswerten, the // first word the command, the others its parameters, then three empty ones): // the program's thread runs it, one after the other; "^C" is the window's // Ctrl+C (setInterrupt). Each story's lines with their times are in the // output (acts), for the core's test to type them at the same times. // pingLan ping .31, arp typed while it runs // pingRouted ping fern.filius.de (behind the router), arp on both ends, ping the router's far address // pingNobody ping .99, which no one has, then by name (weg.filius.de) // pingUnreachable ping 10.0.0.99 (no one behind the router), 172.16.0.1 (no route at the router) // pingBroadcast ping .255, ping -b .255, arp, ping (-b) 255.255.255.255, also without a route; // ping -b .255 from behind the router // pingSelf ping its own address, localhost, 127.0.0.1 // pingErrors usage, unknown names, no route, no DNS server, a first word other than -b // interrupt ping .31, Ctrl+C after 1.8 s; again, then arp typed at once; again, then an unknown command // dns host and nslookup on known and unknown names, localhost, usage, a name with MX only // dnsTimeout host, nslookup and ping by name where the DNS server is not there // arp arp after a ping and a lookup, -a, -d, unknown options, no address, the broadcast row removed // netstat netstat on the client connected to the echo server, on the echo server, on the DNS server; // the connection closed, on both again // traceLan traceroute .31 (one hop) // traceRouted traceroute fern.filius.de (two hops), the router's far address // traceUnreachable traceroute 10.0.0.99 (no one behind the router) // traceNoRoute traceroute 172.16.0.1 (no route at the router) // traceNobody traceroute .99 (no one in the LAN) // traceSelf traceroute its own address, localhost // traceErrors usage, an unknown name, no DNS server // traceInterrupt traceroute 10.0.0.99, Ctrl+C after 3.5 s // tcpdump tcpdump on .31 and on the DNS server while the client pings .31, looks up a name // and connects to .31's echo server; arp typed on .31 meanwhile; Ctrl+C on both import filius.software.clientserver.ClientBaustein; import filius.software.clientserver.ServerBaustein; import filius.software.lokal.Terminal; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; public class TerminalRun { static final String CLIENT = "00000000-0000-0000-0000-000000000401"; static final String DNS = "00000000-0000-0000-0000-000000000402"; static final String WEB = "00000000-0000-0000-0000-000000000403"; static final String ECHO = "00000000-0000-0000-0000-000000000404"; static final String FAR = "00000000-0000-0000-0000-000000000406"; static final String TERMINAL_CLASS = "filius.software.lokal.Terminal"; static ScenarioNetwork network; static final List events = new ArrayList<>(); static synchronized void event(String host, String kind, String text) { events.add(new Object[] { System.currentTimeMillis() - network.start, host, kind, text }); } static void sleepUntil(long milliseconds) throws InterruptedException { long rest = network.start + milliseconds - System.currentTimeMillis(); if (rest > 0) Thread.sleep(rest); } /** The story's lines: time, host, line. */ static List acts(String story) { List acts = new ArrayList<>(); switch (story) { case "pingLan": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 1500L, CLIENT, "arp" }); break; case "pingRouted": acts.add(new Object[] { 500L, CLIENT, "ping fern.filius.de" }); acts.add(new Object[] { 6500L, CLIENT, "arp" }); acts.add(new Object[] { 6700L, FAR, "arp" }); acts.add(new Object[] { 7000L, CLIENT, "ping 10.0.0.1" }); break; case "pingNobody": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.99" }); acts.add(new Object[] { 23500L, CLIENT, "ping weg.filius.de" }); break; case "pingUnreachable": acts.add(new Object[] { 500L, CLIENT, "ping 10.0.0.99" }); acts.add(new Object[] { 40000L, CLIENT, "ping 172.16.0.1" }); break; case "pingBroadcast": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.255" }); acts.add(new Object[] { 1000L, CLIENT, "ping -b 192.168.0.255" }); acts.add(new Object[] { 7000L, CLIENT, "arp" }); acts.add(new Object[] { 7200L, CLIENT, "ping 255.255.255.255" }); acts.add(new Object[] { 7400L, CLIENT, "ping -b 255.255.255.255" }); acts.add(new Object[] { 12500L, DNS, "ping 255.255.255.255" }); acts.add(new Object[] { 13000L, FAR, "ping -b 192.168.0.255" }); break; case "pingSelf": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.20" }); acts.add(new Object[] { 6000L, CLIENT, "ping localhost" }); acts.add(new Object[] { 11500L, CLIENT, "ping 127.0.0.1" }); break; case "pingErrors": acts.add(new Object[] { 500L, CLIENT, "ping" }); acts.add(new Object[] { 700L, CLIENT, "ping a b c" }); acts.add(new Object[] { 900L, CLIENT, "ping gibtsnicht.filius.de" }); acts.add(new Object[] { 2500L, CLIENT, "ping 1.2.3" }); acts.add(new Object[] { 4000L, DNS, "ping 10.0.0.2" }); acts.add(new Object[] { 4200L, DNS, "ping www.filius.de" }); acts.add(new Object[] { 8000L, CLIENT, "ping -x 192.168.0.31" }); break; case "interrupt": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 2300L, CLIENT, "^C" }); acts.add(new Object[] { 5000L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 5800L, CLIENT, "^C" }); acts.add(new Object[] { 5900L, CLIENT, "arp" }); acts.add(new Object[] { 10000L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 10800L, CLIENT, "^C" }); acts.add(new Object[] { 10900L, CLIENT, "gibtsnicht" }); break; case "dns": acts.add(new Object[] { 500L, CLIENT, "host www.filius.de" }); acts.add(new Object[] { 2000L, CLIENT, "host filius.de" }); acts.add(new Object[] { 3500L, CLIENT, "host multi.filius.de" }); acts.add(new Object[] { 5000L, CLIENT, "host gibtsnicht.filius.de" }); acts.add(new Object[] { 6500L, CLIENT, "nslookup www.filius.de" }); acts.add(new Object[] { 8000L, CLIENT, "nslookup multi.filius.de" }); acts.add(new Object[] { 9500L, CLIENT, "nslookup localhost" }); acts.add(new Object[] { 9700L, CLIENT, "nslookup gibtsnicht.filius.de" }); acts.add(new Object[] { 11500L, CLIENT, "host" }); acts.add(new Object[] { 11600L, CLIENT, "nslookup" }); acts.add(new Object[] { 11700L, CLIENT, "host localhost" }); acts.add(new Object[] { 11900L, CLIENT, "nslookup filius.de" }); acts.add(new Object[] { 12100L, CLIENT, "host post.filius.de" }); break; case "dnsTimeout": acts.add(new Object[] { 500L, FAR, "host www.filius.de" }); acts.add(new Object[] { 30000L, FAR, "nslookup www.filius.de" }); acts.add(new Object[] { 60000L, FAR, "ping www.filius.de" }); break; case "arp": acts.add(new Object[] { 500L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 5500L, CLIENT, "host www.filius.de" }); acts.add(new Object[] { 7000L, CLIENT, "arp" }); acts.add(new Object[] { 7200L, CLIENT, "arp -a 192.168.0.31" }); acts.add(new Object[] { 7400L, CLIENT, "arp -a 192.168.0.99" }); acts.add(new Object[] { 7600L, CLIENT, "arp -d 192.168.0.31" }); acts.add(new Object[] { 7800L, CLIENT, "arp" }); acts.add(new Object[] { 8000L, CLIENT, "arp -x 1.2.3.4" }); acts.add(new Object[] { 8200L, CLIENT, "arp foo" }); acts.add(new Object[] { 8250L, CLIENT, "arp -a foo" }); acts.add(new Object[] { 8300L, CLIENT, "arp -d foo" }); acts.add(new Object[] { 8400L, CLIENT, "arp -d" }); acts.add(new Object[] { 8600L, CLIENT, "arp" }); acts.add(new Object[] { 8800L, CLIENT, "arp -d 255.255.255.255" }); acts.add(new Object[] { 9000L, CLIENT, "arp" }); acts.add(new Object[] { 9200L, CLIENT, "arp -d" }); break; case "netstat": acts.add(new Object[] { 2500L, CLIENT, "netstat" }); acts.add(new Object[] { 2700L, ECHO, "netstat" }); acts.add(new Object[] { 2900L, CLIENT, "host www.filius.de" }); acts.add(new Object[] { 4500L, DNS, "netstat" }); acts.add(new Object[] { 4700L, WEB, "netstat" }); acts.add(new Object[] { 4900L, CLIENT, "netstat x" }); acts.add(new Object[] { 5000L, CLIENT, "disconnect" }); acts.add(new Object[] { 8000L, CLIENT, "netstat" }); acts.add(new Object[] { 8200L, ECHO, "netstat" }); break; case "traceLan": acts.add(new Object[] { 500L, CLIENT, "traceroute 192.168.0.31" }); break; case "traceRouted": acts.add(new Object[] { 500L, CLIENT, "traceroute fern.filius.de" }); acts.add(new Object[] { 3000L, CLIENT, "traceroute 10.0.0.1" }); break; case "traceUnreachable": acts.add(new Object[] { 500L, CLIENT, "traceroute 10.0.0.99" }); break; case "traceNoRoute": acts.add(new Object[] { 500L, CLIENT, "traceroute 172.16.0.1" }); break; case "traceNobody": acts.add(new Object[] { 500L, CLIENT, "traceroute 192.168.0.99" }); break; case "traceSelf": acts.add(new Object[] { 500L, CLIENT, "traceroute 192.168.0.20" }); acts.add(new Object[] { 1500L, CLIENT, "traceroute localhost" }); break; case "traceErrors": acts.add(new Object[] { 500L, CLIENT, "traceroute" }); acts.add(new Object[] { 700L, CLIENT, "traceroute a b" }); acts.add(new Object[] { 900L, CLIENT, "traceroute gibtsnicht.filius.de" }); acts.add(new Object[] { 3000L, FAR, "traceroute www.filius.de" }); break; case "traceInterrupt": acts.add(new Object[] { 500L, CLIENT, "traceroute 10.0.0.99" }); acts.add(new Object[] { 4000L, CLIENT, "^C" }); break; case "tcpdump": acts.add(new Object[] { 500L, ECHO, "tcpdump" }); acts.add(new Object[] { 600L, DNS, "tcpdump" }); acts.add(new Object[] { 1000L, CLIENT, "ping 192.168.0.31" }); acts.add(new Object[] { 3000L, ECHO, "arp" }); acts.add(new Object[] { 5500L, CLIENT, "host www.filius.de" }); acts.add(new Object[] { 6500L, CLIENT, "connect" }); acts.add(new Object[] { 8000L, ECHO, "^C" }); acts.add(new Object[] { 8100L, DNS, "^C" }); break; default: throw new IllegalArgumentException("unknown story " + story); } return acts; } /** GUIApplicationTerminalWindow on Enter (or Ctrl+C): the line handed to the program. */ static void type(Terminal terminal, String host, String line) { event(host, "call", line); if (line.equals("^C")) { terminal.setInterrupt(true); return; } StringTokenizer tokens = new StringTokenizer(line, " "); String command = tokens.nextToken(); String[] parameters = new String[3 + tokens.countTokens()]; Arrays.fill(parameters, ""); for (int index = 0; tokens.hasMoreTokens(); index++) parameters[index] = tokens.nextToken(); terminal.terminalEingabeAuswerten(command, parameters); } public static void main(String[] args) throws Exception { network = ScenarioNetwork.read(args[0]); String story = args[1]; long end = Long.parseLong(args[2]); List acts = acts(story); Map terminals = new LinkedHashMap<>(); for (String host : new String[] { CLIENT, DNS, WEB, ECHO, FAR }) { network.system(host).installApp(TERMINAL_CLASS, false); Terminal terminal = (Terminal) network.system(host).holeSoftware(TERMINAL_CLASS); terminal.hinzuBeobachter((observable, data) -> { if (data instanceof Boolean) event(host, "busy", data.toString()); else if (data != null) event(host, "text", data.toString()); }); terminals.put(host, terminal); } ClientBaustein client = null; if (story.equals("netstat") || story.equals("tcpdump")) { for (String host : new String[] { ECHO, DNS }) { network.system(host).installApp("filius.software.clientserver.ServerBaustein", false); ServerBaustein server = (ServerBaustein) network.system(host).holeSoftware("filius.software.clientserver.ServerBaustein"); server.setPort(55555); server.setAktiv(true); } network.system(CLIENT).installApp("filius.software.clientserver.ClientBaustein", false); client = (ClientBaustein) network.system(CLIENT).holeSoftware("filius.software.clientserver.ClientBaustein"); } network.start(); if (story.equals("netstat")) { sleepUntil(500); event(CLIENT, "call", "connect 192.168.0.31:55555"); client.setZielIPAdresse("192.168.0.31"); client.setZielPort(55555); client.verbinden(); } for (Object[] act : acts) { sleepUntil((Long) act[0]); if (act[2].equals("connect")) { // The echo client's window: connect to the echo server (ClientBaustein.verbinden). event(CLIENT, "call", "connect 192.168.0.31:55555"); client.setZielIPAdresse("192.168.0.31"); client.setZielPort(55555); client.verbinden(); continue; } if (act[2].equals("disconnect")) { // The echo client's window: its connection closed (ClientBaustein.trennen). event(CLIENT, "call", "disconnect"); client.trennen(); continue; } type(terminals.get((String) act[1]), (String) act[1], (String) act[2]); } sleepUntil(end); ScenarioNetwork.Json out = new ScenarioNetwork.Json(); out.open('{'); network.writeFrames(out); out.key("acts").open('['); for (Object[] act : acts) out.open('[').number((Long) act[0]).string((String) act[1]).string((String) act[2]).close(']'); out.close(']'); synchronized (TerminalRun.class) { out.key("events").open('['); for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).string((String) each[2]).string((String) each[3]).close(']'); out.close(']'); } out.close('}'); network.stop(); ScenarioNetwork.write(args[3], out); System.exit(0); } }