SheetRun now clicks through Java's JConnectionsDialog with a router, a computer and a switch cabled in the GUIContainer: a click marks a card, the same click unmarks it, another card swaps the cables or moves the one; "+" adds 192.168.0.10/24 up to eight cards, "-" removes the last card with its cable down to none, and a router without a card keeps no gateway. The document adds, removes and swaps a router's cards (the same cables, the same devices), Java's click logic is one function for the test and the page, and the sheet names the address at a cable's far end. The page "Verbindungen verwalten" shows Java's RJ45 buttons in Java's colours with each card's far end below. Not adopted: the last card stays. A card tab or a mark whose card is undone away falls back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
743 lines
40 KiB
Java
743 lines
40 KiB
Java
// Types into FILIUS' own settings panels (JHostKonfiguration,
|
|
// JSwitchKonfiguration, JModemKonfiguration, JVermittlungsrechnerKonfiguration,
|
|
// JGatewayConfiguration) and lets them take the text as
|
|
// they do when a field loses the focus (aenderungenAnnehmen), then writes,
|
|
// for each case, whether the panel marked the text red while typing, what the
|
|
// device holds afterwards and what the field shows then (updateAttribute):
|
|
// the reference for the editor's device sheet (packages/doc/test/sheet.test.ts).
|
|
// Each case starts from a new device ("start": the field's value then). The cases file is ASCII, with
|
|
// Java-style unicode escapes (backslash, u, four hex digits) for anything
|
|
// else, one case a line:
|
|
//
|
|
// <host|switch|modem|router|homeRouter> <field> <text> the text may be empty
|
|
//
|
|
// Fields: host name, ip, mask, gateway, dns; switch name, ssid, retention;
|
|
// modem name, port; router name, ip, mask (its first interface), gateway;
|
|
// homeRouter name, gateway, wanIp, wanMask, lanIp, lanMask. A field without
|
|
// a check method of its own is marked as its key listener marks it (the
|
|
// pattern). After the cases, a few flows ("flows"): a host's name while it
|
|
// shows its address or MAC address, DHCP switched on while the device's own
|
|
// DHCP server runs; then a router's forwarding table as Java shows it
|
|
// (Weiterleitungstabelle.holeTabelle, "tables") and its rows edited in the
|
|
// panel's table (JWeiterleitungsTabelle, "edits"). The DHCP dialog
|
|
// (JDHCPKonfiguration) takes its fields with its button (speichern):
|
|
//
|
|
// <dhcpHost|dhcpHome> <lower|upper|gateway|dns> <text>
|
|
//
|
|
// 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"). 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. Then a router's
|
|
// connections dialog (JConnectionsDialog, "connections"): its cards and what
|
|
// their cables join, cables swapped with two clicks, cards added up to the
|
|
// last and removed down to none, and the router's panel and gateway with one
|
|
// card and with none.
|
|
//
|
|
// Usage: java -cp filius.jar:lib/*:classes SheetRun <cases txt> <output json>
|
|
|
|
import filius.gui.GUIContainer;
|
|
import filius.gui.JMainFrame;
|
|
import filius.gui.netzwerksicht.GUIDesignSidebar;
|
|
import filius.gui.netzwerksicht.GUIKabelItem;
|
|
import filius.gui.netzwerksicht.GUIKnotenItem;
|
|
import filius.gui.netzwerksicht.JConnectionsDialog;
|
|
import filius.gui.netzwerksicht.JDHCPKonfiguration;
|
|
import filius.gui.netzwerksicht.JSidebarButton;
|
|
import filius.gui.netzwerksicht.JFirewallDialog;
|
|
import filius.gui.netzwerksicht.JKonfiguration;
|
|
import filius.gui.netzwerksicht.JPortForwardingDialog;
|
|
import filius.gui.netzwerksicht.JWeiterleitungsTabelle;
|
|
import filius.hardware.Kabel;
|
|
import filius.hardware.NetzwerkInterface;
|
|
import filius.hardware.Port;
|
|
import filius.hardware.knoten.Knoten;
|
|
import filius.hardware.knoten.Gateway;
|
|
import filius.hardware.knoten.Host;
|
|
import filius.hardware.knoten.Modem;
|
|
import filius.hardware.knoten.Rechner;
|
|
import filius.hardware.knoten.Switch;
|
|
import filius.hardware.knoten.Vermittlungsrechner;
|
|
import filius.rahmenprogramm.EingabenUeberpruefung;
|
|
import filius.software.system.Betriebssystem;
|
|
import filius.software.system.GatewayFirmware;
|
|
import filius.software.system.InternetKnotenBetriebssystem;
|
|
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;
|
|
|
|
import java.io.FileOutputStream;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Method;
|
|
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.Map;
|
|
import java.util.regex.Pattern;
|
|
import javax.swing.ImageIcon;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JCheckBox;
|
|
import javax.swing.JLabel;
|
|
import java.awt.Color;
|
|
import javax.swing.JTable;
|
|
import javax.swing.table.DefaultTableModel;
|
|
import java.util.LinkedList;
|
|
import javax.swing.JTextField;
|
|
|
|
public class SheetRun {
|
|
/** A private field of a panel; "name#i" is the i-th of an array. */
|
|
static Object get(Object panel, String name) throws Exception {
|
|
String[] parts = name.split("#");
|
|
Field field = panel.getClass().getDeclaredField(parts[0]);
|
|
field.setAccessible(true);
|
|
Object value = field.get(panel);
|
|
return parts.length == 1 ? value : ((Object[]) value)[Integer.parseInt(parts[1])];
|
|
}
|
|
|
|
static void call(Object panel, String name) throws Exception {
|
|
Method method = panel.getClass().getDeclaredMethod(name);
|
|
method.setAccessible(true);
|
|
method.invoke(panel);
|
|
}
|
|
|
|
/** The panel's field, its check (the method its key listener calls) or else the pattern its key listener checks, per device and field. */
|
|
static final Map<String, String[]> FIELDS = new LinkedHashMap<>();
|
|
static {
|
|
FIELDS.put("host name", new String[] { "name", null, null });
|
|
FIELDS.put("host ip", new String[] { "ipAdresse", "checkIpAddress", null });
|
|
FIELDS.put("host mask", new String[] { "netzmaske", "checkNetmask", null });
|
|
FIELDS.put("host gateway", new String[] { "gateway", "checkGatewayAddress", null });
|
|
FIELDS.put("host dns", new String[] { "dns", "checkDnsAddress", null });
|
|
FIELDS.put("switch name", new String[] { "name", null, null });
|
|
FIELDS.put("switch ssid", new String[] { "ssid", "checkSSID", null });
|
|
FIELDS.put("switch retention", new String[] { "retentionTime", "checkRetentionTime", null });
|
|
FIELDS.put("modem name", new String[] { "name", null, null });
|
|
FIELDS.put("modem port", new String[] { "tfPort", null, null });
|
|
FIELDS.put("router name", new String[] { "name", null, null });
|
|
FIELDS.put("router ip", new String[] { "ipAdressen#0", null, "ip" });
|
|
FIELDS.put("router mask", new String[] { "netzmasken#0", null, "mask" });
|
|
FIELDS.put("router gateway", new String[] { "gateway", null, "ip" });
|
|
FIELDS.put("homeRouter name", new String[] { "name", null, null });
|
|
FIELDS.put("homeRouter gateway", new String[] { "gatewayName", null, "ip" });
|
|
FIELDS.put("homeRouter wanIp", new String[] { "ipAddressWANPort", null, "ip" });
|
|
FIELDS.put("homeRouter wanMask", new String[] { "netmaskWANPort", null, "mask" });
|
|
FIELDS.put("homeRouter lanIp", new String[] { "ipAddressLANPort", null, "ip" });
|
|
FIELDS.put("homeRouter lanMask", new String[] { "netmaskLANPort", null, "mask" });
|
|
}
|
|
|
|
static Pattern pattern(String name) {
|
|
return name.equals("ip") ? EingabenUeberpruefung.musterIpAdresse : EingabenUeberpruefung.musterSubNetz;
|
|
}
|
|
|
|
static String stored(Object device, String key) {
|
|
if (device instanceof Host) {
|
|
Host host = (Host) device;
|
|
Betriebssystem os = (Betriebssystem) host.getSystemSoftware();
|
|
switch (key) {
|
|
case "host name": return host.getName();
|
|
case "host ip": return os.primaryIPAdresse();
|
|
case "host mask": return os.primarySubnetMask();
|
|
case "host gateway": return os.getStandardGateway();
|
|
case "host dns": return os.getDNSServer();
|
|
}
|
|
} else if (device instanceof Switch) {
|
|
Switch sw = (Switch) device;
|
|
SwitchFirmware firmware = (SwitchFirmware) sw.getSystemSoftware();
|
|
switch (key) {
|
|
case "switch name": return sw.getName();
|
|
case "switch ssid": return firmware.getSSID();
|
|
case "switch retention": return Long.toString(firmware.getRetentionTime());
|
|
}
|
|
} else if (device instanceof Vermittlungsrechner) {
|
|
Vermittlungsrechner router = (Vermittlungsrechner) device;
|
|
NetzwerkInterface first = router.getNetzwerkInterfaces().get(0);
|
|
switch (key) {
|
|
case "router name": return router.getName();
|
|
case "router ip": return first.getIp();
|
|
case "router mask": return first.getSubnetzMaske();
|
|
case "router gateway": return ((InternetKnotenBetriebssystem) router.getSystemSoftware()).getStandardGateway();
|
|
}
|
|
} else if (device instanceof Gateway) {
|
|
Gateway home = (Gateway) device;
|
|
switch (key) {
|
|
case "homeRouter name": return home.getName();
|
|
case "homeRouter gateway": return ((InternetKnotenBetriebssystem) home.getSystemSoftware()).getStandardGateway();
|
|
case "homeRouter wanIp": return home.holeWANInterface().getIp();
|
|
case "homeRouter wanMask": return home.holeWANInterface().getSubnetzMaske();
|
|
case "homeRouter lanIp": return home.holeLANInterface().getIp();
|
|
case "homeRouter lanMask": return home.holeLANInterface().getSubnetzMaske();
|
|
}
|
|
} else if (device instanceof Modem) {
|
|
Modem modem = (Modem) device;
|
|
switch (key) {
|
|
case "modem name": return modem.getName();
|
|
case "modem port": return Integer.toString(((ModemFirmware) modem.getSystemSoftware()).getPort());
|
|
}
|
|
}
|
|
throw new IllegalArgumentException(key);
|
|
}
|
|
|
|
/** A new device; a host with a gateway and a DNS server, a switch with a known SSID, so that what a case leaves alone shows. */
|
|
static Object device(String kind) {
|
|
switch (kind) {
|
|
case "host": {
|
|
Rechner host = new Rechner();
|
|
Betriebssystem os = (Betriebssystem) host.getSystemSoftware();
|
|
os.setStandardGateway("192.168.0.254");
|
|
os.setDNSServer("192.168.0.253");
|
|
return host;
|
|
}
|
|
case "switch": {
|
|
Switch sw = new Switch();
|
|
((SwitchFirmware) sw.getSystemSoftware()).setSSID("Start");
|
|
return sw;
|
|
}
|
|
case "modem": return new Modem();
|
|
case "router": {
|
|
Vermittlungsrechner router = new Vermittlungsrechner();
|
|
router.setzeAnzahlAnschluesse(2);
|
|
((InternetKnotenBetriebssystem) router.getSystemSoftware()).setStandardGateway("192.168.0.254");
|
|
return router;
|
|
}
|
|
case "homeRouter": {
|
|
Gateway home = new Gateway();
|
|
((InternetKnotenBetriebssystem) home.getSystemSoftware()).setStandardGateway("192.168.0.254");
|
|
return home;
|
|
}
|
|
}
|
|
throw new IllegalArgumentException(kind);
|
|
}
|
|
|
|
/** A router's forwarding table (Weiterleitungstabelle.holeTabelle) with its manual flags. */
|
|
static List<Object> table(String[] interfaces, String gateway, String[][] manual) {
|
|
Vermittlungsrechner router = new Vermittlungsrechner();
|
|
router.setzeAnzahlAnschluesse(interfaces.length / 2);
|
|
for (int i = 0; i < interfaces.length / 2; i++) {
|
|
router.getNetzwerkInterfaces().get(i).setIp(interfaces[2 * i]);
|
|
router.getNetzwerkInterfaces().get(i).setSubnetzMaske(interfaces[2 * i + 1]);
|
|
}
|
|
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) router.getSystemSoftware();
|
|
os.setStandardGateway(gateway);
|
|
Weiterleitungstabelle table = os.getWeiterleitungstabelle();
|
|
for (String[] row : manual) table.addManuellenEintrag(row[0], row[1], row[2], row[3]);
|
|
List<Object> rows = new ArrayList<>();
|
|
List<String[]> entries = table.holeTabelle();
|
|
List<Boolean> flags = table.holeManuelleEintraegeFlags();
|
|
for (int i = 0; i < entries.size(); i++) {
|
|
Map<String, Object> row = new LinkedHashMap<>();
|
|
row.put("cells", Arrays.asList(entries.get(i)));
|
|
row.put("manual", flags.get(i));
|
|
rows.add(row);
|
|
}
|
|
return rows;
|
|
}
|
|
|
|
/**
|
|
* Steps in the panel's table of a router with one manual row, only the
|
|
* manual rows shown: {"<column>", text} sets a cell of the first row,
|
|
* {"N<column>", text} of the last row, {"new"} adds a row, {"remove"}
|
|
* removes the first; each step taken as the table takes it. The manual
|
|
* rows afterwards (and the rows shown, when asked).
|
|
*/
|
|
static Map<String, Object> edit(String[][] steps, boolean shown) throws Exception {
|
|
Vermittlungsrechner router = new Vermittlungsrechner();
|
|
router.setzeAnzahlAnschluesse(2);
|
|
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) router.getSystemSoftware();
|
|
os.getWeiterleitungstabelle().addManuellenEintrag("172.16.0.0", "255.255.0.0", "192.168.0.2", "192.168.0.10");
|
|
JKonfiguration panel = JKonfiguration.getInstance(router);
|
|
JWeiterleitungsTabelle table = (JWeiterleitungsTabelle) get(panel, "weiterleitungstabelle");
|
|
table.setzeAlleEintraegeAnzeigen(false);
|
|
table.updateAttribute();
|
|
for (String[] step : steps) {
|
|
if (step[0].equals("new")) {
|
|
table.neuerEintrag();
|
|
} else if (step[0].equals("remove")) {
|
|
table.setRowSelectionInterval(0, 0);
|
|
table.markiertenEintragLoeschen();
|
|
} else {
|
|
boolean last = step[0].startsWith("N");
|
|
int column = Integer.parseInt(last ? step[0].substring(1) : step[0]);
|
|
table.setValueAt(step[1], last ? table.getRowCount() - 1 : 0, column);
|
|
table.aenderungenAnnehmen();
|
|
}
|
|
}
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
List<Object> rows = new ArrayList<>();
|
|
for (String[] row : os.getWeiterleitungstabelle().getManuelleTabelle()) rows.add(Arrays.asList(row));
|
|
result.put("manual", rows);
|
|
if (shown) result.put("rowsShown", table.getRowCount());
|
|
return result;
|
|
}
|
|
|
|
/** A device whose DHCP server the dialog edits: a host 192.168.0.10/24 with gateway and DNS, or a home router; the server with known settings. */
|
|
static InternetKnotenBetriebssystem dhcpDevice(String kind) {
|
|
InternetKnotenBetriebssystem os;
|
|
if (kind.equals("dhcpHost")) {
|
|
Rechner host = new Rechner();
|
|
os = (InternetKnotenBetriebssystem) host.getSystemSoftware();
|
|
os.setStandardGateway("192.168.0.254");
|
|
os.setDNSServer("192.168.0.253");
|
|
} else {
|
|
os = (InternetKnotenBetriebssystem) new Gateway().getSystemSoftware();
|
|
}
|
|
DHCPServer server = os.getDHCPServer();
|
|
server.setUntergrenze("192.168.0.100");
|
|
server.setObergrenze("192.168.0.200");
|
|
server.setGatewayip("10.0.0.1");
|
|
server.setDnsserverip("10.0.0.2");
|
|
return os;
|
|
}
|
|
|
|
static JDHCPKonfiguration dhcpDialog(InternetKnotenBetriebssystem os) {
|
|
return new JDHCPKonfiguration(JMainFrame.getJMainFrame(), "DHCP", os);
|
|
}
|
|
|
|
static String dhcpValue(DHCPServer server, String field) {
|
|
switch (field) {
|
|
case "lower": return server.getUntergrenze();
|
|
case "upper": return server.getObergrenze();
|
|
case "gateway": return server.getGatewayip();
|
|
case "dns": return server.getDnsserverip();
|
|
}
|
|
throw new IllegalArgumentException(field);
|
|
}
|
|
|
|
/** A field of the DHCP dialog typed and taken with its button. */
|
|
static Map<String, Object> dhcpCase(String kind, String field, String text) throws Exception {
|
|
InternetKnotenBetriebssystem os = dhcpDevice(kind);
|
|
DHCPServer server = os.getDHCPServer();
|
|
String start = dhcpValue(server, field);
|
|
JDHCPKonfiguration dialog = dhcpDialog(os);
|
|
if (kind.equals("dhcpHost")) ((JCheckBox) get(dialog, "cbUseInternal")).setSelected(true);
|
|
String name = field.equals("lower") ? "tfUntergrenze" : field.equals("upper") ? "tfObergrenze" : field.equals("gateway") ? "tfGateway" : "tfDNSServer";
|
|
JTextField input = (JTextField) get(dialog, name);
|
|
input.setText(text);
|
|
boolean marked = !dialog.ueberpruefen(EingabenUeberpruefung.musterIpAdresse, input);
|
|
call(dialog, "speichern");
|
|
dialog.dispose();
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
result.put("device", kind);
|
|
result.put("field", field);
|
|
result.put("input", text);
|
|
result.put("start", start);
|
|
result.put("marked", marked);
|
|
result.put("stored", dhcpValue(server, field));
|
|
result.put("shown", dhcpValue(server, field));
|
|
return result;
|
|
}
|
|
|
|
/** What the DHCP dialog shows without own settings, and its static assignments taken with its button. */
|
|
static Map<String, Object> dhcpFlows() throws Exception {
|
|
Map<String, Object> flows = new LinkedHashMap<>();
|
|
for (String kind : new String[] { "dhcpHost", "dhcpHome" }) {
|
|
InternetKnotenBetriebssystem os = dhcpDevice(kind);
|
|
JDHCPKonfiguration dialog = dhcpDialog(os);
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
for (String name : new String[] { "tfUntergrenze", "tfObergrenze", "tfNetzmaske", "tfGateway", "tfDNSServer" }) {
|
|
JTextField input = (JTextField) get(dialog, name);
|
|
shown.put(name, Arrays.asList(input.getText(), input.isEditable()));
|
|
}
|
|
dialog.dispose();
|
|
flows.put(kind + "Shown", shown);
|
|
}
|
|
{
|
|
Rechner host = new Rechner();
|
|
InternetKnotenBetriebssystem os = (InternetKnotenBetriebssystem) host.getSystemSoftware();
|
|
JDHCPKonfiguration dialog = dhcpDialog(os);
|
|
flows.put("hostWithoutGatewayShown", Arrays.asList(((JTextField) get(dialog, "tfGateway")).getText(), ((JTextField) get(dialog, "tfDNSServer")).getText()));
|
|
dialog.dispose();
|
|
}
|
|
// Static assignments: rows of the dialog's table, taken with its button.
|
|
String[][] rows = { { "aa:bb:cc:dd:ee:01", "192.168.0.50" }, { "AA:BB:CC:DD:EE:01", "192.168.0.51" }, { "AA:BB:CC:DD:EE:_F", "192.168.0.52" }, { "AA:BB:CC:DD:EE:02", "192.168.0.256" },
|
|
{ "AA:BB:CC:DD:EE:03", "010.0.0.1" }, { "AABBCCDDEE04", "192.168.0.54" } };
|
|
InternetKnotenBetriebssystem os = dhcpDevice("dhcpHost");
|
|
JDHCPKonfiguration dialog = dhcpDialog(os);
|
|
DefaultTableModel model = (DefaultTableModel) ((JTable) get(dialog, "staticAddressTable")).getModel();
|
|
for (String[] row : rows) model.addRow(new Object[] { row[0], row[1] });
|
|
call(dialog, "speichern");
|
|
dialog.dispose();
|
|
List<Object> kept = new ArrayList<>();
|
|
for (DHCPAddressAssignment entry : os.getDHCPServer().holeStaticAssignedAddresses()) kept.add(Arrays.asList(entry.getMAC(), entry.getIp()));
|
|
flows.put("staticAssignments", kept);
|
|
// The add button's own check, per row: MAC and address patterns.
|
|
List<Object> addable = new ArrayList<>();
|
|
for (String[] row : rows) addable.add(EingabenUeberpruefung.isGueltig(row[0], EingabenUeberpruefung.musterMacAddress) && EingabenUeberpruefung.isGueltig(row[1], EingabenUeberpruefung.musterIpAdresse));
|
|
flows.put("addable", addable);
|
|
return flows;
|
|
}
|
|
|
|
/** A home router's port forwarding rows as its dialog keeps them, and which of them its firmware would forward (musterProtocol, musterPort, musterIpAdresse). */
|
|
static Map<String, Object> forwardingFlows() throws Exception {
|
|
Gateway home = new Gateway();
|
|
GatewayFirmware firmware = (GatewayFirmware) home.getSystemSoftware();
|
|
JPortForwardingDialog dialog = new JPortForwardingDialog(firmware.getStaticNAT(), JMainFrame.getJMainFrame());
|
|
dialog.createStaticTable();
|
|
String[][] rows = { { "TCP", "80", "192.168.0.20", "8080" }, { "UDP", "0", "192.168.0.21", "53" }, { "TCP", "abc", "192.168.0.22", "80" }, { "tcp", "443", "192.168.0.300", "443" },
|
|
{ "17", "5353", "192.168.0.23", "05353" } };
|
|
for (String[] row : rows) {
|
|
dialog.neuerEintrag();
|
|
JTable table = (JTable) get(dialog, "staticTable");
|
|
int last = table.getRowCount() - 1;
|
|
for (int column = 0; column < 4; column++) table.setValueAt(row[column], last, column);
|
|
}
|
|
dialog.aenderungenAnnehmen();
|
|
dialog.dispose();
|
|
Map<String, Object> flows = new LinkedHashMap<>();
|
|
List<Object> kept = new ArrayList<>();
|
|
List<Object> valid = new ArrayList<>();
|
|
for (String[] row : firmware.getStaticNAT()) {
|
|
kept.add(Arrays.asList(row));
|
|
valid.add(EingabenUeberpruefung.isGueltig(row[0], EingabenUeberpruefung.musterProtocol) && EingabenUeberpruefung.isGueltig(row[1], EingabenUeberpruefung.musterPort)
|
|
&& EingabenUeberpruefung.isGueltig(row[2], EingabenUeberpruefung.musterIpAdresse) && EingabenUeberpruefung.isGueltig(row[3], EingabenUeberpruefung.musterPort));
|
|
}
|
|
flows.put("rows", kept);
|
|
flows.put("valid", valid);
|
|
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;
|
|
}
|
|
|
|
/** A device on the design surface, as GUIContainer keeps it (NewDeviceRun.add). */
|
|
static GUIKnotenItem item(Knoten device, String icon) {
|
|
JSidebarButton label = new JSidebarButton(new ImageIcon(SheetRun.class.getResource("/" + icon + ".png")), device.holeHardwareTyp());
|
|
label.initTextAndUpdateLocation(device.holeAnzeigeName());
|
|
GUIKnotenItem item = new GUIKnotenItem();
|
|
item.setKnoten(device);
|
|
item.setImageLabel(label);
|
|
GUIContainer.getGUIContainer().getKnotenItems().add(item);
|
|
return item;
|
|
}
|
|
|
|
/** A cable as GUIEvents.createConnection plugs it, from the first device's port to the second's. */
|
|
static void cable(GUIKnotenItem one, Port first, GUIKnotenItem two, Port second) {
|
|
GUIKabelItem item = new GUIKabelItem();
|
|
item.getKabelpanel().setZiel1(one);
|
|
item.getKabelpanel().setZiel2(two);
|
|
item.setDasKabel(new Kabel(first, second));
|
|
GUIContainer.getGUIContainer().getCableItems().add(item);
|
|
}
|
|
|
|
/** What the dialog shows and what the router's cards are joined to. */
|
|
static Map<String, Object> connectionsState(JConnectionsDialog dialog, Vermittlungsrechner router) throws Exception {
|
|
Map<String, Object> state = new LinkedHashMap<>();
|
|
List<Object> local = new ArrayList<>();
|
|
List<Object> remote = new ArrayList<>();
|
|
List<Object> colours = new ArrayList<>();
|
|
for (int i = 0; i < 8; i++) {
|
|
local.add(((JLabel) get(dialog, "lblLocal#" + i)).getText());
|
|
remote.add(((JLabel) get(dialog, "lblRemote#" + i)).getText());
|
|
JButton button = (JButton) get(dialog, "btnLocal#" + i);
|
|
Color colour = button.getBackground();
|
|
colours.add(!button.isEnabled() ? "off" : colour.equals(Color.YELLOW) ? "marked" : colour.equals(Color.GREEN) ? "plugged" : colour.equals(Color.RED) ? "free" : "other");
|
|
}
|
|
state.put("local", local);
|
|
state.put("remote", remote);
|
|
state.put("buttons", colours);
|
|
state.put("add", ((JButton) get(dialog, "btnAddInterface")).isEnabled());
|
|
state.put("remove", ((JButton) get(dialog, "btnRemoveInterface")).isEnabled());
|
|
// Each card: its address, mask, and the device its cable joins ("" for none).
|
|
List<Object> cards = new ArrayList<>();
|
|
for (NetzwerkInterface nic : router.getNetzwerkInterfaces()) {
|
|
String joined = "";
|
|
if (nic.getPort().getVerbindung() != null) {
|
|
for (Port port : nic.getPort().getVerbindung().getAnschluesse()) {
|
|
if (port != nic.getPort()) {
|
|
for (GUIKnotenItem each : GUIContainer.getGUIContainer().getKnotenItems()) {
|
|
Knoten node = each.getKnoten();
|
|
boolean owns = node instanceof Switch ? ((Switch) node).getAnschluesse().contains(port)
|
|
: node instanceof filius.hardware.knoten.InternetKnoten && ((filius.hardware.knoten.InternetKnoten) node).getNetzwerkInterfaces().stream().anyMatch(other -> other.getPort() == port);
|
|
if (owns) joined = node.holeAnzeigeName();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cards.add(Arrays.asList(nic.getIp(), nic.getSubnetzMaske(), joined));
|
|
}
|
|
state.put("cards", cards);
|
|
state.put("cables", GUIContainer.getGUIContainer().getCableItems().size());
|
|
return state;
|
|
}
|
|
|
|
static Map<String, Object> connectionsFlows() throws Exception {
|
|
GUIContainer.getGUIContainer().getKnotenItems().clear();
|
|
GUIContainer.getGUIContainer().getCableItems().clear();
|
|
Vermittlungsrechner router = new Vermittlungsrechner();
|
|
router.setzeAnzahlAnschluesse(3);
|
|
router.setName("R");
|
|
String[] addresses = { "10.0.0.1", "10.1.0.1", "10.2.0.1" };
|
|
for (int i = 0; i < 3; i++) router.getNetzwerkInterfaces().get(i).setIp(addresses[i]);
|
|
Rechner host = new Rechner();
|
|
host.setName("A");
|
|
host.getNetzwerkInterfaces().get(0).setIp("10.0.0.2");
|
|
Switch sw = new Switch();
|
|
sw.setName("S");
|
|
GUIKnotenItem routerItem = item(router, GUIDesignSidebar.VERMITTLUNGSRECHNER);
|
|
GUIKnotenItem hostItem = item(host, GUIDesignSidebar.RECHNER);
|
|
GUIKnotenItem switchItem = item(sw, GUIDesignSidebar.SWITCH);
|
|
// The host plugs into the router (the host first), the router into the switch.
|
|
cable(hostItem, host.getNetzwerkInterfaces().get(0).getPort(), routerItem, router.getNetzwerkInterfaces().get(0).getPort());
|
|
cable(routerItem, router.getNetzwerkInterfaces().get(1).getPort(), switchItem, sw.holeFreienPort());
|
|
JConnectionsDialog dialog = new JConnectionsDialog(JMainFrame.getJMainFrame(), router);
|
|
List<Object> steps = new ArrayList<>();
|
|
// A click on a card's button ("c<i>"), "+" and "-".
|
|
String[] clicks = { "start", "c0", "c0", "c0", "c2", "c2", "c1", "c1", "c1", "c0", "+", "c2", "c3", "-", "-", "+", "c0", "c2", "c0", "c1", "+", "+", "+", "+", "+", "+", "-", "-", "-", "-", "-", "-", "-", "-" };
|
|
for (String click : clicks) {
|
|
if (click.startsWith("c")) ((JButton) get(dialog, "btnLocal#" + click.substring(1))).doClick();
|
|
else if (click.equals("+")) ((JButton) get(dialog, "btnAddInterface")).doClick();
|
|
else if (click.equals("-")) ((JButton) get(dialog, "btnRemoveInterface")).doClick();
|
|
Map<String, Object> step = new LinkedHashMap<>();
|
|
step.put("click", click);
|
|
step.putAll(connectionsState(dialog, router));
|
|
// The router's panel with this many cards: does it still draw?
|
|
if (router.getNetzwerkInterfaces().size() <= 1) {
|
|
String error = null;
|
|
try {
|
|
JKonfiguration panel = JKonfiguration.getInstance(router);
|
|
panel.updateAttribute();
|
|
} catch (RuntimeException thrown) {
|
|
error = thrown.getClass().getSimpleName();
|
|
}
|
|
step.put("panelError", error);
|
|
// Java keeps the gateway in the cards: does a router without one keep it?
|
|
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) router.getSystemSoftware();
|
|
os.setStandardGateway("10.0.0.254");
|
|
step.put("gateway", os.getStandardGateway());
|
|
os.setStandardGateway("");
|
|
}
|
|
steps.add(step);
|
|
}
|
|
// New cards: their MAC addresses differ from each other and from the first cards'.
|
|
List<String> macs = new ArrayList<>();
|
|
for (NetzwerkInterface nic : router.getNetzwerkInterfaces()) macs.add(nic.getMac());
|
|
Map<String, Object> flows = new LinkedHashMap<>();
|
|
flows.put("steps", steps);
|
|
flows.put("hostPortFree", host.getNetzwerkInterfaces().get(0).getPort().getVerbindung() == null);
|
|
flows.put("switchPortsFree", sw.getAnschluesse().stream().allMatch(port -> port.getVerbindung() == null));
|
|
dialog.dispose();
|
|
return flows;
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// FILIUS' window keeps the JVM alive: end it on any failure too.
|
|
try {
|
|
run(args);
|
|
} catch (Throwable error) {
|
|
error.printStackTrace();
|
|
System.exit(1);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
static void run(String[] args) throws Exception {
|
|
GUIContainer.getGUIContainer();
|
|
List<Object> cases = new ArrayList<>();
|
|
for (String line : Files.readAllLines(Path.of(args[0]), StandardCharsets.US_ASCII)) {
|
|
if (line.isEmpty() || line.startsWith("#")) continue;
|
|
String[] words = line.split(" ", 3);
|
|
String key = words[0] + " " + words[1];
|
|
String text = words.length < 3 ? "" : IpCheckCases.unescape(words[2]);
|
|
if (words[0].startsWith("dhcp")) {
|
|
cases.add(dhcpCase(words[0], words[1], text));
|
|
continue;
|
|
}
|
|
String[] names = FIELDS.get(key);
|
|
if (names == null) throw new IllegalArgumentException(line);
|
|
Object device = device(words[0]);
|
|
String start = stored(device, key);
|
|
JKonfiguration panel = JKonfiguration.getInstance((filius.hardware.Hardware) device);
|
|
JTextField field = (JTextField) get(panel, names[0]);
|
|
field.setText(text);
|
|
boolean marked = false;
|
|
if (names[1] != null) {
|
|
call(panel, names[1]);
|
|
marked = field.getForeground().equals(EingabenUeberpruefung.farbeFalsch);
|
|
} else if (names[2] != null) {
|
|
marked = !panel.ueberpruefen(pattern(names[2]), field);
|
|
}
|
|
// A panel that throws is part of the measurement ("error").
|
|
String error = null;
|
|
try {
|
|
call(panel, "aenderungenAnnehmen");
|
|
panel.updateAttribute();
|
|
} catch (java.lang.reflect.InvocationTargetException thrown) {
|
|
error = thrown.getCause().getClass().getSimpleName();
|
|
} catch (RuntimeException thrown) {
|
|
error = thrown.getClass().getSimpleName();
|
|
}
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
result.put("device", words[0]);
|
|
result.put("field", words[1]);
|
|
result.put("input", text);
|
|
result.put("start", start);
|
|
result.put("marked", marked);
|
|
result.put("stored", stored(device, key));
|
|
result.put("shown", field.getText());
|
|
if (error != null) result.put("error", error);
|
|
cases.add(result);
|
|
}
|
|
|
|
Map<String, Object> flows = new LinkedHashMap<>();
|
|
// The MAC address as name, then another field taken: what becomes of the name?
|
|
for (String box : new String[] { "useMacAsName", "useIpAsName" }) {
|
|
Rechner host = new Rechner();
|
|
host.setName("PC-A");
|
|
JKonfiguration panel = JKonfiguration.getInstance(host);
|
|
((JCheckBox) get(panel, box)).setSelected(true);
|
|
call(panel, "aendereAnzeigeName");
|
|
((JTextField) get(panel, "gateway")).setText("192.168.0.1");
|
|
call(panel, "aenderungenAnnehmen");
|
|
((JCheckBox) get(panel, box)).setSelected(false);
|
|
call(panel, "aendereAnzeigeName");
|
|
flows.put(box + "ThenOff", host.getName());
|
|
}
|
|
// DHCP for the configuration while the host's own DHCP server is on.
|
|
{
|
|
Rechner host = new Rechner();
|
|
Betriebssystem os = (Betriebssystem) host.getSystemSoftware();
|
|
os.getDHCPServer().setAktiv(true);
|
|
JKonfiguration panel = JKonfiguration.getInstance(host);
|
|
((JCheckBox) get(panel, "dhcp")).setSelected(true);
|
|
call(panel, "aenderungenAnnehmen");
|
|
flows.put("dhcpClientStopsServer", !os.getDHCPServer().isAktiv());
|
|
flows.put("dhcpClient", os.isDHCPKonfiguration());
|
|
}
|
|
// The same on a home router (its WAN card).
|
|
{
|
|
Gateway home = new Gateway();
|
|
GatewayFirmware firmware = (GatewayFirmware) home.getSystemSoftware();
|
|
firmware.getDHCPServer().setAktiv(true);
|
|
JKonfiguration panel = JKonfiguration.getInstance(home);
|
|
((JCheckBox) get(panel, "dhcp")).setSelected(true);
|
|
call(panel, "aenderungenAnnehmen");
|
|
flows.put("homeRouterDhcpClientStopsServer", !firmware.getDHCPServer().isAktiv());
|
|
flows.put("homeRouterDhcpClient", firmware.isDHCPKonfiguration());
|
|
}
|
|
|
|
// Forwarding tables: two interfaces, a gateway, manual rows.
|
|
Map<String, Object> tables = new LinkedHashMap<>();
|
|
String[][] manual = { { "172.16.0.0", "255.255.0.0", "192.168.1.2", "192.168.1.1" }, { "010.020.0.0", "255.255.0.0", "10.0.0.2", "10.0.0.1" } };
|
|
tables.put("gatewayInSecondNetwork", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "192.168.1.254", manual));
|
|
tables.put("gatewayInNoNetwork", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "172.30.0.1", manual));
|
|
tables.put("gatewayInBothNetworks", table(new String[] { "10.0.0.1", "255.0.0.0", "10.1.0.1", "255.255.0.0" }, "10.1.0.254", new String[0][]));
|
|
tables.put("noGateway", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "", manual));
|
|
tables.put("threeInterfaces", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0", "172.16.5.1", "255.255.0.0" }, "10.0.0.254", new String[0][]));
|
|
|
|
// The panel's table: a manual row edited, a new row, a row removed (only the manual rows shown).
|
|
Map<String, Object> edits = new LinkedHashMap<>();
|
|
edits.put("invalidCell", edit(new String[][] { { 0 + "", "abc" } }, false));
|
|
edits.put("emptyCell", edit(new String[][] { { 0 + "", "" } }, false));
|
|
edits.put("leadingZeros", edit(new String[][] { { 0 + "", "010.0.0.0" } }, false));
|
|
edits.put("dottedTwice", edit(new String[][] { { 0 + "", "10..0.0" } }, false));
|
|
edits.put("maskCell", edit(new String[][] { { 1 + "", "255.0.255.0" } }, false));
|
|
edits.put("newRowThreeCells", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" } }, false));
|
|
edits.put("newRowFourCells", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" }, { "N3", "10.0.0.1" } }, false));
|
|
edits.put("newRowInvalidCell", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" }, { "N3", "10..0.0.1" } }, false));
|
|
edits.put("newRowTwice", edit(new String[][] { { "new" }, { "new" } }, true));
|
|
edits.put("removeRow", edit(new String[][] { { "remove" } }, false));
|
|
|
|
Map<String, Object> output = new LinkedHashMap<>();
|
|
output.put("cases", cases);
|
|
output.put("flows", flows);
|
|
output.put("tables", tables);
|
|
output.put("dhcp", dhcpFlows());
|
|
output.put("forwarding", forwardingFlows());
|
|
output.put("firewall", firewallFlows());
|
|
output.put("connections", connectionsFlows());
|
|
output.put("edits", edits);
|
|
try (FileOutputStream out = new FileOutputStream(args[1])) {
|
|
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
System.out.println("sheet cases: " + cases.size());
|
|
}
|
|
}
|