feat(core): the firewall settings page of routers after Java, measured against Java
The page konfig changes the firewall at run time (into the snapshot, back into the project through projectWithSimulationChanges). KonfigCases feeds Java's plug-in directly (25 cases, de and en); RouterWebRun plays two stories over the network. Ten Java bugs named, not adopted. The web server answers a method not written GET or POST with 501, as Java does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// Feeds FILIUS' firewall settings page (FirewallWebKonfig, the router's web
|
||||
// server's plug-in konfig) with what a browser posts, step after step, and
|
||||
// writes each page and the firewall after it: the reference for the core's
|
||||
// konfig page (packages/core/src/runtime/apps/firewallSettings.ts). Each case
|
||||
// starts from a new router; its firewall holds no rules ("empty"), three
|
||||
// ("three"), one only a file can bring ("portZero": port 0, ICMP), or the
|
||||
// one rule a case adds ("sourceRule", "destinationRule":
|
||||
// the page Java would answer, had it taken the rule). The cases file is
|
||||
// ASCII, with Java-style unicode escapes (backslash, u, four hex digits) for
|
||||
// anything else:
|
||||
//
|
||||
// case <name> <start>
|
||||
// GET the page without data (Java: holeHtmlSeite(null))
|
||||
// POST <data> the page with the data a form posts ("POST" alone: empty)
|
||||
//
|
||||
// Usage: java -cp filius.jar:lib/*:classes KonfigCases <de|en> <cases txt> <output json>
|
||||
|
||||
import filius.hardware.knoten.Vermittlungsrechner;
|
||||
import filius.rahmenprogramm.Information;
|
||||
import filius.software.firewall.Firewall;
|
||||
import filius.software.firewall.FirewallRule;
|
||||
import filius.software.system.VermittlungsrechnerBetriebssystem;
|
||||
import filius.software.www.WebServerPlugIn;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class KonfigCases {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Before any class reads the message bundle (I18n.messages is read once).
|
||||
Information.getInformation().setLocale(args[0].equals("en") ? new Locale("en", "GB") : Locale.GERMANY);
|
||||
List<Object> cases = new ArrayList<>();
|
||||
Map<String, Object> current = null;
|
||||
List<Object> steps = null;
|
||||
WebServerPlugIn page = null;
|
||||
Firewall firewall = null;
|
||||
for (String line : Files.readAllLines(Path.of(args[1]), StandardCharsets.US_ASCII)) {
|
||||
if (line.isEmpty() || line.startsWith("#")) continue;
|
||||
if (line.startsWith("case ")) {
|
||||
String[] words = line.split(" ");
|
||||
current = new LinkedHashMap<>();
|
||||
steps = new ArrayList<>();
|
||||
current.put("name", words[1]);
|
||||
current.put("start", words[2]);
|
||||
current.put("steps", steps);
|
||||
cases.add(current);
|
||||
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) new Vermittlungsrechner().getSystemSoftware();
|
||||
firewall = os.holeFirewall();
|
||||
page = os.holeWebServer().holePlugin("konfig");
|
||||
if (words[2].equals("three")) {
|
||||
firewall.setActivated(true);
|
||||
firewall.addRule(new FirewallRule("", "", "", "", 80, FirewallRule.TCP, FirewallRule.ACCEPT));
|
||||
firewall.addRule(new FirewallRule("999.999.999.999", "", "20.0.0.0", "255.0.0.0", FirewallRule.ALL_PORTS, FirewallRule.UDP, FirewallRule.DROP));
|
||||
firewall.addRule(new FirewallRule("10.0.0.0", "255.0.0.0", "", "", FirewallRule.ALL_PORTS, FirewallRule.ALL_PROTOCOLS, FirewallRule.DROP));
|
||||
} else if (words[2].equals("portZero")) {
|
||||
firewall.addRule(new FirewallRule("", "", "", "", 0, FirewallRule.ICMP, FirewallRule.ACCEPT));
|
||||
} else if (words[2].equals("sourceRule")) {
|
||||
firewall.addRule(new FirewallRule("10.0.0.0", "255.255.255.0", "", "", 80, FirewallRule.TCP, FirewallRule.DROP));
|
||||
} else if (words[2].equals("destinationRule")) {
|
||||
firewall.addRule(new FirewallRule("", "", "20.0.0.0", "255.0.0.0", FirewallRule.ALL_PORTS, FirewallRule.UDP, FirewallRule.ACCEPT));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String post = line.equals("GET") ? null : line.equals("POST") ? "" : IpCheckCases.unescape(line.substring("POST ".length()));
|
||||
Map<String, Object> step = new LinkedHashMap<>();
|
||||
step.put("post", post);
|
||||
try {
|
||||
step.put("page", page.holeHtmlSeite(post));
|
||||
} catch (RuntimeException error) {
|
||||
step.put("page", "!" + error.getClass().getSimpleName());
|
||||
}
|
||||
step.put("firewall", state(firewall));
|
||||
steps.add(step);
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(args[2])) {
|
||||
out.write((FlsOracle.Json.write(cases, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
System.out.println("konfig cases (" + args[0] + "): " + cases.size());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
static Map<String, Object> state(Firewall firewall) {
|
||||
Map<String, Object> state = new LinkedHashMap<>();
|
||||
state.put("isActive", firewall.isActivated());
|
||||
state.put("dropIcmp", firewall.getDropICMP());
|
||||
state.put("filterSynSegmentsOnly", firewall.getFilterSYNSegmentsOnly());
|
||||
state.put("defaultPolicy", firewall.getDefaultPolicy() == FirewallRule.ACCEPT ? "accept" : "drop");
|
||||
List<Object> rules = new ArrayList<>();
|
||||
for (FirewallRule rule : firewall.getRuleset()) {
|
||||
String protocol = rule.protocol == FirewallRule.TCP ? "tcp" : rule.protocol == FirewallRule.UDP ? "udp" : rule.protocol == FirewallRule.ICMP ? "icmp" : rule.protocol == FirewallRule.ALL_PROTOCOLS ? "all" : String.valueOf(rule.protocol);
|
||||
rules.add(Arrays.asList(rule.srcIP, rule.srcMask, rule.destIP, rule.destMask, rule.port, protocol, rule.action == FirewallRule.ACCEPT ? "accept" : "drop"));
|
||||
}
|
||||
state.put("rules", rules);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@
|
||||
// routerLog a ping to 20.0.0.2 (dropped), the index, then
|
||||
// 10.0.0.1/log
|
||||
// routerKonfig 10.0.0.1/konfig
|
||||
// konfigIcmp a ping to 20.0.0.2 (dropped), the settings saved
|
||||
// without "drop ICMP" (the form as Java's browser window
|
||||
// posts it), the ping again
|
||||
// konfigBlock a rule added (TCP 80: drop), moved up above the rule
|
||||
// that accepts the browser, then the index again
|
||||
// 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)
|
||||
@@ -61,6 +66,22 @@ public class RouterWebRun {
|
||||
browser.holeWebseite(new URL("http", parts[0], path.isEmpty() ? "/" : path));
|
||||
}
|
||||
|
||||
/** What the browser window posts when a button of the settings form is pressed (Swing: every field, the button). */
|
||||
static void post(String typed, String data) throws Exception {
|
||||
event("browser", "call holeWebseite " + typed + " " + data);
|
||||
String[] parts = typed.split("/", 2);
|
||||
browser.holeWebseite(new URL("http", parts[0], "/" + parts[1]), data);
|
||||
}
|
||||
|
||||
static void ping(InternetKnotenBetriebssystem host) {
|
||||
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();
|
||||
}
|
||||
|
||||
static String id(int suffix) {
|
||||
return String.format("00000000-0000-0000-0000-%012d", suffix);
|
||||
}
|
||||
@@ -124,12 +145,7 @@ public class RouterWebRun {
|
||||
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();
|
||||
ping(host);
|
||||
sleepUntil(3500);
|
||||
open("10.0.0.1");
|
||||
sleepUntil(7000);
|
||||
@@ -139,6 +155,20 @@ public class RouterWebRun {
|
||||
case "routerKonfig":
|
||||
open("10.0.0.1/konfig");
|
||||
break;
|
||||
case "konfigIcmp":
|
||||
ping(host);
|
||||
sleepUntil(3500);
|
||||
post("10.0.0.1/konfig", "firewallActivate=1&onlySYN=1&btnSave=speichern&defaultPolicy=accept&srcIP=&srcMask=&destIP=&destMask=&protocol=*&port=&action=drop");
|
||||
sleepUntil(7000);
|
||||
ping(host);
|
||||
break;
|
||||
case "konfigBlock":
|
||||
post("10.0.0.1/konfig", "firewallActivate=1&dropICMP=1&onlySYN=1&defaultPolicy=accept&srcIP=&srcMask=&destIP=&destMask=&protocol=TCP&port=80&action=drop&addrule=hinzuf%C3%BCgen");
|
||||
sleepUntil(4000);
|
||||
post("10.0.0.1/konfig", "firewallActivate=1&dropICMP=1&onlySYN=1&defaultPolicy=accept&radioRule=2&moveup=rauf&srcIP=&srcMask=&destIP=&destMask=&protocol=*&port=&action=drop");
|
||||
sleepUntil(8000);
|
||||
open("10.0.0.1");
|
||||
break;
|
||||
case "gatewayIndex":
|
||||
open("192.168.0.1");
|
||||
sleepUntil(4000);
|
||||
|
||||
Reference in New Issue
Block a user