feat(core): the pages of routers and home routers after Java, measured against Java
Routers and home routers start a web server on port 80 with Java's index, log and routes pages in the project's language (routerPages.ts); the firewall keeps a log per node that outlives a new start; RIP routes carry the telling router's public address. TCP counts sequence numbers and segments in Java's characters, not bytes. RouterWebRun records six stories, with firewalls now built by ScenarioNetwork. Not taken from Java: its router server sometimes never listening (a race in setAktiv), and </titel>. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
// Runs a story with the web pages of FILIUS' routers and home routers: each
|
||||
// starts a web server on port 80 with its own index page and the plug-ins
|
||||
// log (the firewall's log), konfig (the firewall's settings) and, on a
|
||||
// router, routes (VermittlungWeb: forwarding or RIP table). A host's web
|
||||
// browser asks for them; recorded are every frame each card saw, the
|
||||
// router's web server's window lines and everything the browser told its
|
||||
// window.
|
||||
//
|
||||
// RouterWebRun <scenario.json> <story> <milliseconds> <out.json>
|
||||
//
|
||||
// router-web (router 10.0.0.1/20.0.0.1 with a firewall: drops ICMP,
|
||||
// accepts TCP to port 80 from 10.0.0.0/24; browser on 10.0.0.2):
|
||||
// routerIndex 10.0.0.1
|
||||
// routerRoutes 10.0.0.1/routes (the forwarding table)
|
||||
// routerLog a ping to 20.0.0.2 (dropped), the index, then
|
||||
// 10.0.0.1/log
|
||||
// routerKonfig 10.0.0.1/konfig
|
||||
// nat-home (home router 42.0.0.10/192.168.0.1):
|
||||
// gatewayIndex from the LAN PC 192.168.0.10: 192.168.0.1, then
|
||||
// 192.168.0.1/routes (no such page on a home router)
|
||||
// gatewayFromWan from the WAN host 42.0.0.20: 42.0.0.10
|
||||
// rip-chain (three RIP routers, each seeded as RipRun seeds it):
|
||||
// ripRoutes from 10.0.1.2, after 40 s: 10.0.1.1/routes
|
||||
|
||||
import filius.hardware.knoten.Knoten;
|
||||
import filius.rahmenprogramm.EingabenUeberpruefung;
|
||||
import filius.software.rip.RIPBeacon;
|
||||
import filius.software.system.InternetKnotenBetriebssystem;
|
||||
import filius.software.system.VermittlungsrechnerBetriebssystem;
|
||||
import filius.software.www.HTTPNachricht;
|
||||
import filius.software.www.WebBrowser;
|
||||
import filius.software.www.WebServer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class RouterWebRun {
|
||||
static ScenarioNetwork network;
|
||||
static WebBrowser browser;
|
||||
static final List<Object[]> events = new ArrayList<>();
|
||||
|
||||
static synchronized void event(String who, String what) {
|
||||
events.add(new Object[] { System.currentTimeMillis() - network.start, who, what });
|
||||
}
|
||||
|
||||
static void sleepUntil(long milliseconds) throws InterruptedException {
|
||||
long rest = network.start + milliseconds - System.currentTimeMillis();
|
||||
if (rest > 0) Thread.sleep(rest);
|
||||
}
|
||||
|
||||
static void open(String typed) throws Exception {
|
||||
event("browser", "call holeWebseite " + typed);
|
||||
String[] parts = typed.split("/");
|
||||
String path = "";
|
||||
for (int i = 1; i < parts.length; i++) path = path + "/" + parts[i];
|
||||
if (!EingabenUeberpruefung.isGueltig(parts[0], EingabenUeberpruefung.musterIpAdresse)) throw new IllegalArgumentException(typed);
|
||||
browser.holeWebseite(new URL("http", parts[0], path.isEmpty() ? "/" : path));
|
||||
}
|
||||
|
||||
static String id(int suffix) {
|
||||
return String.format("00000000-0000-0000-0000-%012d", suffix);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
network = ScenarioNetwork.read(args[0]);
|
||||
String story = args[1];
|
||||
long end = Long.parseLong(args[2]);
|
||||
String browserNode;
|
||||
String routerNode;
|
||||
switch (story) {
|
||||
case "gatewayIndex":
|
||||
browserNode = id(501);
|
||||
routerNode = id(502);
|
||||
break;
|
||||
case "gatewayFromWan":
|
||||
browserNode = id(504);
|
||||
routerNode = id(502);
|
||||
break;
|
||||
case "ripRoutes":
|
||||
browserNode = id(401);
|
||||
routerNode = id(402);
|
||||
break;
|
||||
default:
|
||||
browserNode = id(301);
|
||||
routerNode = id(302);
|
||||
}
|
||||
InternetKnotenBetriebssystem host = network.system(browserNode);
|
||||
host.installApp("filius.software.www.WebBrowser", false);
|
||||
browser = (WebBrowser) host.holeSoftware("filius.software.www.WebBrowser");
|
||||
WebServer server = (WebServer) network.system(routerNode).holeSoftware("filius.software.www.WebServer");
|
||||
server.hinzuBeobachter((observable, data) -> event("server", String.valueOf(data)));
|
||||
browser.hinzuBeobachter((observable, data) -> {
|
||||
if (data instanceof HTTPNachricht) {
|
||||
HTTPNachricht page = (HTTPNachricht) data;
|
||||
event("browser", "page " + page.getStatusCode() + " " + page.getContentType() + "\n" + page.getDaten());
|
||||
} else {
|
||||
event("browser", data == null ? "update" : String.valueOf(data));
|
||||
}
|
||||
});
|
||||
network.start();
|
||||
if (story.equals("ripRoutes")) {
|
||||
long seed = ScenarioNetwork.seed(args[0]);
|
||||
Field beaconField = VermittlungsrechnerBetriebssystem.class.getDeclaredField("ripbeacon");
|
||||
beaconField.setAccessible(true);
|
||||
Field randomField = RIPBeacon.class.getDeclaredField("rand");
|
||||
randomField.setAccessible(true);
|
||||
for (Map.Entry<String, Knoten> entry : network.nodes.entrySet()) {
|
||||
if (!(entry.getValue().getSystemSoftware() instanceof VermittlungsrechnerBetriebssystem)) continue;
|
||||
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) entry.getValue().getSystemSoftware();
|
||||
if (os.isRipEnabled()) randomField.set(beaconField.get(os), new Random(RipRun.ripSeed(seed, entry.getKey())));
|
||||
}
|
||||
}
|
||||
sleepUntil(500);
|
||||
|
||||
switch (story) {
|
||||
case "routerIndex":
|
||||
open("10.0.0.1");
|
||||
break;
|
||||
case "routerRoutes":
|
||||
open("10.0.0.1/routes");
|
||||
break;
|
||||
case "routerLog": {
|
||||
Thread ping = new Thread(() -> {
|
||||
event("ping", "call sendProbe 20.0.0.2");
|
||||
Object answer = host.holeICMP().sendProbe("20.0.0.2", 64, 1, 1);
|
||||
event("ping", "returned " + (answer == null ? "null" : "answer"));
|
||||
});
|
||||
ping.start();
|
||||
sleepUntil(3500);
|
||||
open("10.0.0.1");
|
||||
sleepUntil(7000);
|
||||
open("10.0.0.1/log");
|
||||
break;
|
||||
}
|
||||
case "routerKonfig":
|
||||
open("10.0.0.1/konfig");
|
||||
break;
|
||||
case "gatewayIndex":
|
||||
open("192.168.0.1");
|
||||
sleepUntil(4000);
|
||||
open("192.168.0.1/routes");
|
||||
break;
|
||||
case "gatewayFromWan":
|
||||
open("42.0.0.10");
|
||||
break;
|
||||
case "ripRoutes":
|
||||
sleepUntil(40000);
|
||||
open("10.0.1.1/routes");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown story " + story);
|
||||
}
|
||||
sleepUntil(end);
|
||||
|
||||
ScenarioNetwork.Json out = new ScenarioNetwork.Json();
|
||||
out.open('{');
|
||||
network.writeFrames(out);
|
||||
synchronized (RouterWebRun.class) {
|
||||
out.key("events").open('[');
|
||||
for (Object[] each : events) 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);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import filius.hardware.knoten.Vermittlungsrechner;
|
||||
import filius.rahmenprogramm.nachrichten.Lauscher;
|
||||
import filius.software.dhcp.DHCPServer;
|
||||
import filius.software.dns.DNSServer;
|
||||
import filius.software.firewall.Firewall;
|
||||
import filius.software.firewall.FirewallRule;
|
||||
import filius.software.netzzugangsschicht.EthernetFrame;
|
||||
import filius.software.system.Betriebssystem;
|
||||
import filius.software.system.GatewayFirmware;
|
||||
@@ -233,6 +235,29 @@ public class ScenarioNetwork {
|
||||
for (Object each : list(scenario.getOrDefault("rip", new ArrayList<>()))) {
|
||||
((VermittlungsrechnerBetriebssystem) system(nodes.get((String) each))).setRipEnabled(true);
|
||||
}
|
||||
// Firewalls: the core's defaults (inactive, drop, ICMP through, SYN only, UDP filtered) and its rules.
|
||||
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("firewalls", new HashMap<>())).entrySet()) {
|
||||
Map<String, Object> config = map(entry.getValue());
|
||||
InternetKnotenBetriebssystem os = system(nodes.get(entry.getKey()));
|
||||
Firewall firewall = os instanceof VermittlungsrechnerBetriebssystem ? ((VermittlungsrechnerBetriebssystem) os).holeFirewall()
|
||||
: os instanceof GatewayFirmware ? ((GatewayFirmware) os).holeFirewall()
|
||||
: (Firewall) os.holeSoftware("filius.software.firewall.Firewall");
|
||||
firewall.setActivated(Boolean.TRUE.equals(config.get("active")));
|
||||
firewall.setDefaultPolicy("accept".equals(config.get("defaultPolicy")) ? FirewallRule.ACCEPT : FirewallRule.DROP);
|
||||
firewall.setDropICMP(Boolean.TRUE.equals(config.get("dropIcmp")));
|
||||
firewall.setFilterSYNSegmentsOnly(!Boolean.FALSE.equals(config.get("synOnly")));
|
||||
firewall.setFilterUdp(!Boolean.FALSE.equals(config.get("filterUdp")));
|
||||
for (Object each : list(config.getOrDefault("rules", new ArrayList<>()))) {
|
||||
Map<String, Object> rule = map(each);
|
||||
String protocol = (String) rule.getOrDefault("protocol", "tcp");
|
||||
short number = protocol.equals("all") ? FirewallRule.ALL_PROTOCOLS
|
||||
: protocol.equals("icmp") ? FirewallRule.ICMP : protocol.equals("udp") ? FirewallRule.UDP : FirewallRule.TCP;
|
||||
firewall.addRule(new FirewallRule((String) rule.getOrDefault("source", ""), (String) rule.getOrDefault("sourceMask", ""),
|
||||
(String) rule.getOrDefault("destination", ""), (String) rule.getOrDefault("destinationMask", ""),
|
||||
rule.containsKey("port") ? ((Number) rule.get("port")).intValue() : FirewallRule.ALL_PORTS, number,
|
||||
"accept".equals(rule.get("action")) ? FirewallRule.ACCEPT : FirewallRule.DROP));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user