feat(editor): F4.5d the firewall in the device sheet

Measured first: SheetRun drives FILIUS' firewall dialog down to its table
editor (Swing's own end of an edit). Java's table writes a cell into the
rule before it checks it, so that the firewall holds "abc", a mask of
255.0.255.0 or port 0 while the table shows the old value, and reads a
port that is no number as all ports. Here nothing the check refuses
reaches the rule.

- doc: the three switches, the default action, rules (new as Java's,
  cells by Java's checks: masks of ones then zeros, the directly connected
  marker as a source only, an empty port for all ports; protocol, action,
  moved up or down, removed)
- editor: the firewall as a page of the router's and home router's sheet,
  with Java's explanations; the general tab named so (Java: "network
  interfaces")

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 12:27:10 +00:00
co-authored by Claude Opus 5.5
parent c8edb87210
commit 4e062bb347
15 changed files with 1399 additions and 12 deletions
+89 -1
View File
@@ -27,13 +27,17 @@
// a host's (gateway and DNS with its own settings on) or a home router's;
// then what the dialog shows without own settings, the static assignments
// ("dhcp") and a home router's port forwarding as its dialog keeps it
// (JPortForwardingDialog, "forwarding").
// (JPortForwardingDialog, "forwarding"). Last, a router's firewall dialog
// (JFirewallDialog, "firewall"): a new rule, a cell of a rule edited in its
// table as the table takes it (GatewayFirewallConfigTable.closeEditor), the
// rules moved and removed with the dialog's buttons.
//
// Usage: java -cp filius.jar:lib/*:classes SheetRun <cases txt> <output json>
import filius.gui.GUIContainer;
import filius.gui.JMainFrame;
import filius.gui.netzwerksicht.JDHCPKonfiguration;
import filius.gui.netzwerksicht.JFirewallDialog;
import filius.gui.netzwerksicht.JKonfiguration;
import filius.gui.netzwerksicht.JPortForwardingDialog;
import filius.gui.netzwerksicht.JWeiterleitungsTabelle;
@@ -52,6 +56,8 @@ import filius.software.system.ModemFirmware;
import filius.software.system.SwitchFirmware;
import filius.software.system.VermittlungsrechnerBetriebssystem;
import filius.software.dhcp.DHCPAddressAssignment;
import filius.software.firewall.Firewall;
import filius.software.firewall.FirewallRule;
import filius.software.dhcp.DHCPServer;
import filius.software.vermittlungsschicht.Weiterleitungstabelle;
@@ -384,6 +390,87 @@ public class SheetRun {
return flows;
}
static Map<String, Object> rule(FirewallRule rule) {
Map<String, Object> fields = new LinkedHashMap<>();
fields.put("srcIP", rule.srcIP);
fields.put("srcMask", rule.srcMask);
fields.put("destIP", rule.destIP);
fields.put("destMask", rule.destMask);
fields.put("port", rule.port);
fields.put("protocol", (int) rule.protocol);
fields.put("action", (int) rule.action);
return fields;
}
static Firewall routerFirewall() {
Vermittlungsrechner router = new Vermittlungsrechner();
router.setzeAnzahlAnschluesse(2);
return ((VermittlungsrechnerBetriebssystem) router.getSystemSoftware()).holeFirewall();
}
/** A cell of the dialog's only rule, typed into the table's editor and taken as the table takes it ("#i": the i-th choice of a list). */
static Map<String, Object> firewallCell(int column, String text) throws Exception {
Firewall firewall = routerFirewall();
firewall.addRule();
JFirewallDialog dialog = new JFirewallDialog(firewall, JMainFrame.getJMainFrame());
JTable table = (JTable) get(dialog, "ruleTable");
table.editCellAt(0, column);
java.awt.Component editor = table.getEditorComponent();
if (editor instanceof JTextField) ((JTextField) editor).setText(text);
else if (text.startsWith("#")) ((javax.swing.JComboBox<?>) editor).setSelectedIndex(Integer.parseInt(text.substring(1)));
else ((javax.swing.JComboBox<?>) editor).setSelectedItem(text);
// As Swing ends an edit: the editor stops, the table hears it (editingStopped → closeEditor).
table.getCellEditor().stopCellEditing();
Map<String, Object> result = new LinkedHashMap<>();
result.put("column", column);
result.put("input", text);
FirewallRule rule = firewall.getRuleset().get(0);
result.put("rule", rule(rule));
result.put("valid", rule.validateExistingAttributes());
List<Object> shown = new ArrayList<>();
for (int i = 1; i < 8; i++) shown.add(table.getValueAt(0, i));
result.put("shown", shown);
dialog.dispose();
return result;
}
static Map<String, Object> firewallFlows() throws Exception {
Map<String, Object> flows = new LinkedHashMap<>();
{
Firewall firewall = routerFirewall();
JFirewallDialog dialog = new JFirewallDialog(firewall, JMainFrame.getJMainFrame());
firewall.addRule();
dialog.updateRuleTable();
flows.put("newRule", rule(firewall.getRuleset().get(0)));
flows.put("newRuleShown", dialog.ruleAsVector(1, firewall.getRuleset().get(0)));
flows.put("newFirewall", Arrays.asList(firewall.isActivated(), (int) firewall.getDefaultPolicy(), firewall.getDropICMP(), firewall.getFilterSYNSegmentsOnly()));
dialog.dispose();
}
String[][] cells = { { "1", "10.0.0.0" }, { "1", "abc" }, { "1", ".0.0.1" }, { "1", "999.999.999.999" }, { "1", "010.0.0.0" }, { "1", " " }, { "2", "255.255.0.0" }, { "2", "255.0.255.0" },
{ "2", "0.0.0.0" }, { "2", "255.255.255.255" }, { "2", "0255.255.0.0" }, { "3", "192.168.0.1" }, { "3", "999.999.999.999" }, { "4", "255.255.255.0" }, { "6", "80" }, { "6", "abc" },
{ "6", "0" }, { "6", "080" }, { "6", "" }, { "6", "65536" }, { "5", "UDP" }, { "5", "*" }, { "7", "#0" } };
List<Object> edits = new ArrayList<>();
for (String[] cell : cells) edits.add(firewallCell(Integer.parseInt(cell[0]), cell[1]));
flows.put("cells", edits);
// Moving with the ids the dialog passes (1 for the first row), and removing.
Firewall firewall = routerFirewall();
for (String source : new String[] { "1.1.1.1", "2.2.2.2", "3.3.3.3" }) firewall.addRule(new FirewallRule(source, "", "", "", FirewallRule.ALL_PORTS, FirewallRule.TCP, FirewallRule.DROP));
List<Object> moves = new ArrayList<>();
Object[][] steps = { { "up", 1 }, { "up", 3 }, { "down", 3 }, { "down", 1 }, { "delete", 2 } };
for (Object[] step : steps) {
int id = (Integer) step[1];
Object answer = null;
if (step[0].equals("up")) answer = firewall.moveUp(id);
else if (step[0].equals("down")) answer = firewall.moveDown(id);
else firewall.deleteRule(id - 1);
List<Object> order = new ArrayList<>();
for (FirewallRule each : firewall.getRuleset()) order.add(each.srcIP);
moves.add(Arrays.asList(step[0], id, answer, order));
}
flows.put("moves", moves);
return flows;
}
public static void main(String[] args) throws Exception {
// FILIUS' window keeps the JVM alive: end it on any failure too.
try {
@@ -508,6 +595,7 @@ public class SheetRun {
output.put("tables", tables);
output.put("dhcp", dhcpFlows());
output.put("forwarding", forwardingFlows());
output.put("firewall", firewallFlows());
output.put("edits", edits);
try (FileOutputStream out = new FileOutputStream(args[1])) {
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));