feat(fls): write the system software of a .fls, loaded by Java as the original

topologyWriter.ts now sets the system software each device's constructor
makes, through its setters: a switch's SSID and learning time, a host's
SSID, RIP, manual routes, DHCP client and server with static assignments,
static NAT, the modem, and a router's or home router's firewall. The
firewall is reached as XMLEncoder reaches it, through the web server's
`konfig` plug-in: the constructor hangs the same object there and among
the applications, where its key differs (Firewall on a router, NatGateway
on a home router). A switch's SSID the file lacked stays unwritten, so Java
rolls one as it did. Files and applications are later layers.

javaBeansWriter.ts: a call can carry statements on its result (a map's
value changed through get(key)), checked by Java's XMLDecoder in a new
case; a short() helper for Java's short values.

Checked by Java against Java: every corpus file, read and written again,
loads with the same system software (without files and applications) as
the original. The synthetic topology adds what the corpus lacks: a router
firewall switched on with rules of every protocol (one with a null
address), every flag away from its default, a modem with its own port and
target, and a PC's SSID, routes and DHCP server. 16 mutation probes, each
rewritten and loaded by Java, were all caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 08:18:52 +00:00
co-authored by Claude Opus 5.5
parent 314f696515
commit facad5843e
8 changed files with 749 additions and 227 deletions
+3 -3
View File
@@ -48,9 +48,9 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand
| `test/javaIp.test.ts`, `test/ip-check.*` | — | neu: `IP.ipCheck`-Fälle, Ergebnis aus Java |
| `src/javaEmail.ts` | Java `EmailServer` (Konten-Bean, `kontenLaden`/`stringZuListeBenutzerkonten`), `EmailAnwendung` (Ordner, Adressbuch, `laden`), `EmailKonto`, `Email`, `AddressEntry`, `EmailUtils` | neu nach Java: E-Mail-Beans über ihre Setter, `/mailserver/konten.txt` und `/konten.txt` im Format von Javas Lesern, ohne ihre Fehler (leere Felder zählen, eine kurze Zeile fällt allein weg, Nachrichten mit leerem Text oder Betreff bleiben, `;` im Betreff bleibt, CRLF, beim Client die letzte vollständige Zeile); Empfänger älterer Dateien als Zeichenketten; gegen Java auf dem Korpus und an 43 Fällen geprüft (13 benannte Java-Fehler) |
| `src/javaBeansWriter.ts` | — | neu: Schreiber für das `XMLDecoder`-Format, Gegenstück zu `javabeans.ts`; ausdrücklich typisierte Eingabe, geteilte Objekte über `id`/`idref`, was XML nicht fassen kann (und CR) als `<char code>`; von Java selbst geprüft (`BeansDump`) |
| `test/javaBeansWriter.test.ts`, `test/beans/` | — | neu: 9 Dateien des Schreibers, von Javas `XMLDecoder` gelesen und beschrieben; Erwartungen von Hand |
| `src/topologyWriter.ts` | Java `SzenarioVerwaltung.netzwerkSpeichern`, Konstruktoren von `NetzwerkInterface`, `Port`, `GUIKabelItem` | neu nach Java: `konfiguration.xml` aus Javas Sicht — Geräte, Schnittstellen (vom Konstruktor angelegte über Getter, weitere per `add`), Ports über Getter-Verweise, Kabel samt Zeichen-Enden (`kabelpanel`), Doku-Elemente; Kopf „Filius version: 2.14.0 (mdg-filius)“ |
| `test/topologyWriter.test.ts`, `test/written.java.json` | — | neu: alle 23 Korpus-Dateien gelesen und neu geschrieben, von Java geladen — Topologie wie beim Original (Java gegen Java); dazu eine künstliche Topologie mit dem, was der Korpus nicht hat |
| `test/javaBeansWriter.test.ts`, `test/beans/` | — | neu: 11 Dateien des Schreibers, von Javas `XMLDecoder` gelesen und beschrieben; Erwartungen von Hand |
| `src/topologyWriter.ts` | Java `SzenarioVerwaltung.netzwerkSpeichern`, Konstruktoren von `NetzwerkInterface`, `Port`, `GUIKabelItem` und der Systemsoftware | neu nach Java: `konfiguration.xml` aus Javas Sicht — Geräte, Schnittstellen (vom Konstruktor angelegte über Getter, weitere per `add`), Ports über Getter-Verweise, Kabel samt Zeichen-Enden (`kabelpanel`), Doku-Elemente; Systemsoftware über ihre Setter: SSID, Lernzeit, RIP, manuelle Routen, DHCP-Client und -Server, statische NAT, Modem, Router-Firewall (über das `konfig`-Plug-in des Webservers, wie XMLEncoder sie erreicht); Kopf „Filius version: 2.14.0 (mdg-filius)“ |
| `test/topologyWriter.test.ts`, `test/written.java.json` | — | neu: alle 23 Korpus-Dateien gelesen und neu geschrieben, von Java geladen — Topologie und Systemsoftware (ohne Dateien und Programme) wie beim Original (Java gegen Java); dazu eine künstliche Topologie mit dem, was der Korpus nicht hat (u. a. eingeschaltete Router-Firewall mit Regeln jedes Protokolls, alle Firewall-Schalter abseits der Vorgabe, Modem mit eigenem Port und Ziel) |
| `src/importEmail.ts` | `Persistence/TopologyProjectStore.swift` (`registerJavaEmailConfigurations`, `assignedJavaEmailMessages`) | übertragen, Eingabe ist Javas Sicht: Server-Konten aus `/mailserver/konten.txt`, ohne Datei aus der Bean-Liste (Java verlöre sie); Client-Konto aus `/konten.txt`, ohne Datei aus der älteren `kontoListe` (Filius 2.14 liest sie nicht mehr); Konten und Nachrichten bleiben, wo Swift verwirft, was seine Prüfung nicht besteht; Vor- und Nachname getrennt; Empfangszeit nur aus der Datei (Swift nummeriert); gegen Swifts Modell geprüft |
| `test/importEmail.test.ts`, `test/email-*.swift.json` | `State/TopologyEmail.swift` (`decodeJavaServer`, `decodeJavaClient`) als Vergleich | neu: dieselben 43 Kontodateien mit Swifts Leser; wie Swift bis auf benannte Fälle, in denen Swift prüft und die ganze Datei verwirft, wo Java liest |
| `src/javaFileSystem.ts`, `src/javaString.ts` | Java `Dateisystem.holeDatei`, `String.trim`/`split`/`equalsIgnoreCase` | neu nach Java; die Groß-/Kleinschreibung gegenüber ASCII am JDK über die ganze BMP gemessen |
+10 -4
View File
@@ -59,14 +59,15 @@ export type BeanStatement =
| { readonly set: string; readonly value: BeanValue }
/** target.getP(), then the statements on its result; `as` names the result */
| { readonly get: string; readonly statements: readonly BeanStatement[]; readonly as?: BeanReference }
/** target.m(args) */
| { readonly call: string; readonly args: readonly BeanValue[] }
/** target.m(args), then the statements on its result */
| { readonly call: string; readonly args: readonly BeanValue[]; readonly statements?: readonly BeanStatement[] }
/** target.set(index, value) on a list */
| { readonly setIndex: number; readonly value: BeanValue }
/** target.get(index), then the statements on its result; `as` names the result */
| { readonly getIndex: number; readonly statements: readonly BeanStatement[]; readonly as?: BeanReference };
export const int = (value: number): BeanPrimitive => ({ kind: 'int', value });
export const short = (value: number): BeanPrimitive => ({ kind: 'short', value });
export const long = (value: number | bigint): BeanPrimitive => ({ kind: 'long', value });
export const double = (value: number): BeanPrimitive => ({ kind: 'double', value });
export const float = (value: number): BeanPrimitive => ({ kind: 'float', value });
@@ -194,12 +195,14 @@ class Writer {
} else if ('get' in statement) {
this.getter(`property="${escapeAttribute(statement.get)}"`, statement.statements, statement.as, depth, lines);
} else if ('call' in statement) {
if (statement.args.length === 0) {
const inner = statement.statements ?? [];
if (statement.args.length === 0 && inner.length === 0) {
lines.push(`${indent}<void method="${escapeAttribute(statement.call)}"/>`);
return;
}
nested(`<void method="${escapeAttribute(statement.call)}"`, () => {
for (const arg of statement.args) this.value(arg, depth + 1, lines);
for (const each of inner) this.statement(each, depth + 1, lines);
});
} else if ('setIndex' in statement) {
nested(`<void index="${statement.setIndex}"`, () => this.value(statement.value, depth + 1, lines));
@@ -252,7 +255,10 @@ function sharedObjects(roots: readonly BeanValue[]): Set<BeanObject | BeanArray>
const shared = new Set<BeanObject | BeanArray>();
const visitStatement = (statement: BeanStatement): void => {
if ('set' in statement || 'setIndex' in statement) visit(statement.value);
else if ('call' in statement) statement.args.forEach(visit);
else if ('call' in statement) {
statement.args.forEach(visit);
(statement.statements ?? []).forEach(visitStatement);
}
else statement.statements.forEach(visitStatement);
};
const visit = (value: BeanValue): void => {
+116 -3
View File
@@ -1,5 +1,6 @@
// Writes `projekt/konfiguration.xml` from Java's view of a project — the
// counterpart of topology.ts. The four values Java's netzwerkLaden reads: the
// counterpart of topology.ts and, for the system software, of
// systemSoftware.ts. The four values Java's netzwerkLaden reads: the
// version line, the list of GUIKnotenItem, of GUIKabelItem and of
// GUIDocuItem. What a node's constructor makes (its interfaces, a switch's
// ports) is reached through getters and changed there, as XMLEncoder does;
@@ -7,28 +8,42 @@
// objects of the nodes, so the same cable joins the same ports when Java
// loads the file.
//
// The system software is the one the node's constructor makes; its settings
// are set through getters. A router's or home router's firewall is reached
// the way XMLEncoder reaches it: through the web server's `konfig` plug-in,
// which holds the same object (its key among the installed applications
// differs: Firewall on a router, NatGateway on a home router). Files and
// applications are later layers.
//
// Checked by Java: every corpus file, read and written again, loads in Java
// FILIUS to the same topology (topologyWriter.test.ts, tools/java-oracle).
// FILIUS to the same topology and system software (topologyWriter.test.ts,
// tools/java-oracle).
import {
encodeJavaBeans,
int,
long,
object,
reference,
type BeanObject,
type BeanReference,
type BeanStatement,
type BeanValue,
short,
} from './javaBeansWriter.js';
import type { FlsFirewall, FlsSystemSoftware } from './systemSoftware.js';
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNode, FlsNodeClass } from './topology.js';
/** The version line of the files this writer makes: the format of FILIUS 2.14. */
export const WRITTEN_VERSION_LINE = 'Filius version: 2.14.0 (mdg-filius)';
/** The system software's settings; its files and applications are later layers. */
export type SystemToWrite = Omit<FlsSystemSoftware, 'fileSystem' | 'applications'>;
export type NodeToWrite = Pick<
FlsNode,
'javaClass' | 'name' | 'x' | 'y' | 'useIpAsName' | 'useMacAsName' | 'interfaces' | 'portCount'
>;
> & { readonly system: SystemToWrite };
export interface TopologyToWrite {
readonly nodes: readonly NodeToWrite[];
@@ -124,9 +139,107 @@ function device(node: NodeToWrite, ports: BeanValue[]): BeanObject {
),
);
}
statements.push({ get: 'systemSoftware', statements: systemStatements(node.system, node.javaClass) });
return object(`filius.hardware.knoten.${node.javaClass}`, statements);
}
const WEB_SERVER_CLASS = 'filius.software.www.WebServer';
/**
* The settings the file has, each set on the constructor's system software.
* A switch's SSID the file lacked stays unwritten, so Java rolls one as it did.
*/
function systemStatements(system: SystemToWrite, javaClass: FlsNodeClass): BeanStatement[] {
const statements: BeanStatement[] = [];
if (system.firewall !== undefined) {
statements.push({
get: 'installierteAnwendungen',
statements: [
{
call: 'get',
args: [WEB_SERVER_CLASS],
statements: [
{ get: 'plugins', statements: [{ call: 'get', args: ['konfig'], statements: [{ get: 'firewall', statements: firewallStatements(system.firewall) }] }] },
],
},
],
});
}
if (system.dhcpServer !== undefined) {
const server = system.dhcpServer;
statements.push({
get: 'DHCPServer',
statements: [
{ set: 'aktiv', value: server.isActive },
{ set: 'untergrenze', value: server.lowerBound },
{ set: 'obergrenze', value: server.upperBound },
{ set: 'gatewayip', value: server.gateway },
{ set: 'dnsserverip', value: server.dnsServer },
{ set: 'ownSettings', value: server.useOwnSettings },
{
set: 'staticAssignedAddresses',
value: object(
'java.util.ArrayList',
server.staticAssignedAddresses.map(({ mac, ip }) => ({ call: 'add', args: [`${mac} ${ip}`] })),
),
},
],
});
}
if (system.dhcpClient !== undefined) statements.push({ set: 'DHCPKonfiguration', value: system.dhcpClient });
if (system.manualRoutes !== undefined) {
statements.push({ get: 'weiterleitungstabelle', statements: [{ set: 'manuelleTabelle', value: rows(system.manualRoutes) }] });
}
if (system.ripEnabled !== undefined) statements.push({ set: 'ripEnabled', value: system.ripEnabled });
if (system.retentionTime !== undefined) statements.push({ set: 'retentionTime', value: long(system.retentionTime) });
if (system.staticNAT !== undefined) statements.push({ set: 'staticNAT', value: rows(system.staticNAT) });
if (system.modem !== undefined) {
statements.push(
{ set: 'mode', value: int(system.modem.mode) },
{ set: 'port', value: int(system.modem.port) },
{ set: 'ipAdresse', value: system.modem.ipAddress },
);
}
// SwitchFirmware.setSSID, Betriebssystem.setSsid.
if (system.ssid !== undefined) statements.push({ set: javaClass === 'Switch' ? 'SSID' : 'ssid', value: system.ssid });
return statements;
}
/** A LinkedList of String arrays: routes, static NAT. */
function rows(table: readonly (readonly (string | null)[])[]): BeanObject {
return listOf(table.map((row) => ({ kind: 'array', componentClass: 'java.lang.String', items: [...row] })));
}
function firewallStatements(firewall: FlsFirewall): BeanStatement[] {
return [
{ set: 'activated', value: firewall.activated },
{ set: 'defaultPolicy', value: short(firewall.defaultPolicy) },
{ set: 'dropICMP', value: firewall.dropICMP },
{ set: 'filterSYNSegmentsOnly', value: firewall.filterSYNSegmentsOnly },
{ set: 'filterUdp', value: firewall.filterUdp },
{
set: 'ruleset',
value: object(
'java.util.Vector',
firewall.rules.map((rule) => ({
call: 'add',
args: [
object('filius.software.firewall.FirewallRule', [], [
rule.srcIP,
rule.srcMask,
rule.destIP,
rule.destMask,
int(rule.port),
short(rule.protocol),
short(rule.action),
]),
],
})),
),
},
];
}
/**
* A list the constructor filled with `constructed` elements: those are
* changed through `get(index)`, more are added. With fewer, the list is set
+29 -1
View File
@@ -316,7 +316,7 @@
"string": "10.0.0.1"
},
"mac": {
"string": "8E:A8:7E:96:38:62"
"string": "EE:8A:4E:46:17:34"
},
"port": {
"id": 2,
@@ -337,6 +337,34 @@
],
"errors": []
},
"results.xml": {
"values": [
{
"id": 0,
"class": "java.util.HashMap",
"entries": [
[
{
"string": "key"
},
{
"id": 1,
"class": "java.util.ArrayList",
"items": [
{
"string": "first"
},
{
"string": "second"
}
]
}
]
]
}
],
"errors": []
},
"shared.xml": {
"values": [
{
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="17" class="java.beans.XMLDecoder">
<object class="java.util.HashMap">
<void method="put">
<string>key</string>
<object class="java.util.ArrayList">
<void method="add">
<string>first</string>
</void>
</object>
</void>
<void method="get">
<string>key</string>
<void method="add">
<string>second</string>
</void>
</void>
</object>
</java>
+12
View File
@@ -82,6 +82,18 @@ const CASES: Record<string, { values: BeanValue[]; expected: unknown[] }> = {
{ class: 'java.util.HashMap', entries: [[text('key'), { int: 8 }]] },
],
},
// A method's result changed by the statements inside its call: a map's
// value reached through get(key), as XMLEncoder reaches what a
// constructor put into a map.
results: {
values: [
object('java.util.HashMap', [
{ call: 'put', args: ['key', list('java.util.ArrayList', ['first'])] },
{ call: 'get', args: ['key'], statements: [{ call: 'add', args: ['second'] }] },
]),
],
expected: [{ class: 'java.util.HashMap', entries: [[text('key'), items('java.util.ArrayList', [text('first'), text('second')])]] }],
},
shared: {
values: [list('java.util.LinkedList', [inner, other, inner, other]), file, file],
expected: [
+144 -9
View File
@@ -1,8 +1,9 @@
// Every corpus file, read and written again: Java FILIUS loads the written
// file (tools/java-oracle, written.java.json) to the same topology as the
// original (corpus.java.json) — devices, names, positions, interfaces,
// cables and documentation. Java against Java: no mapping of this package
// stands between the two.
// system software (without files and applications), cables and
// documentation. Java against Java: no mapping of this package stands
// between the two.
//
// UPDATE_WRITTEN=1 writes the files to test/written/ (not checked in); the
// Java oracle then loads them and records each file's SHA-256, which must
@@ -28,13 +29,30 @@ function flsFiles(directory: string): string[] {
});
}
type JavaNode = { class: string; name: string | null; bounds: number[]; useIpAsName: boolean; useMacAsName: boolean; ports: unknown };
type JavaNode = {
class: string;
name: string | null;
bounds: number[];
useIpAsName: boolean;
useMacAsName: boolean;
ports: unknown;
system: Record<string, unknown>;
};
type JavaFile = { success: boolean; nodes: JavaNode[]; cables: unknown[]; documentation: unknown[]; sha256?: string };
const original = JSON.parse(readFileSync(join(corpusRoot, 'corpus.java.json'), 'utf8')) as Record<string, JavaFile>;
const written = JSON.parse(readFileSync(join(here, 'written.java.json'), 'utf8')) as Record<string, JavaFile>;
/** The topology of Java's view: the label's position, not its size, which Java works out itself. */
/** The system software without its files and applications, which are later layers. */
function systemOf(system: Record<string, unknown>) {
const { fileSystem: _files, applications: _applications, ...settings } = system;
return settings;
}
/**
* The topology of Java's view: the label's position, not its size, which
* Java works out itself.
*/
function topologyOf(view: JavaFile) {
return {
success: view.success,
@@ -45,6 +63,7 @@ function topologyOf(view: JavaFile) {
useIpAsName: node.useIpAsName,
useMacAsName: node.useMacAsName,
ports: node.ports,
system: systemOf(node.system),
})),
cables: view.cables,
documentation: view.documentation,
@@ -70,7 +89,13 @@ describe('the topology written again, as Java loads it', () => {
}
});
/** What the corpus does not have: a name set to null, useMACAsName, fewer ports than the constructor makes, more interfaces. */
/**
* What the corpus does not have: a name set to null, useMACAsName, fewer
* ports than the constructor makes, more interfaces; a PC's SSID, routes and
* DHCP server with static assignments; a router's firewall switched on, with
* every flag away from its default and rules of every protocol, one with a
* null address; a modem's own port and address.
*/
const SYNTHETIC: TopologyToWrite = {
nodes: [
{
@@ -82,8 +107,32 @@ const SYNTHETIC: TopologyToWrite = {
useMacAsName: true,
interfaces: [{ ip: '10.0.0.1', mask: '255.0.0.0', mac: 'AA:BB:CC:DD:EE:01', gateway: null, dns: '10.0.0.53' }],
portCount: 1,
system: {
ssid: 'Lab',
manualRoutes: [['10.1.0.0', '255.255.0.0', '10.0.0.254', '10.0.0.1']],
dhcpClient: true,
dhcpServer: {
isActive: true,
lowerBound: '10.0.0.100',
upperBound: '10.0.0.199',
gateway: '10.0.0.254',
dnsServer: '10.0.0.53',
useOwnSettings: true,
staticAssignedAddresses: [{ mac: 'AA:BB:CC:DD:EE:77', ip: '10.0.0.77' }],
},
},
},
{
javaClass: 'Switch',
name: 'S',
x: 100,
y: 20,
useIpAsName: false,
useMacAsName: false,
interfaces: [],
portCount: 3,
system: { ssid: 'S-net', retentionTime: 1234 },
},
{ javaClass: 'Switch', name: 'S', x: 100, y: 20, useIpAsName: false, useMacAsName: false, interfaces: [], portCount: 3 },
{
javaClass: 'Vermittlungsrechner',
name: 'R',
@@ -99,8 +148,34 @@ const SYNTHETIC: TopologyToWrite = {
dns: '',
})),
portCount: 3,
system: {
ripEnabled: true,
firewall: {
activated: true,
defaultPolicy: 1,
dropICMP: true,
filterSYNSegmentsOnly: false,
filterUdp: false,
rules: [
{ srcIP: '10.0.1.0', srcMask: '255.255.255.0', destIP: '', destMask: '', port: -1, protocol: -1, action: 1 },
{ srcIP: '', srcMask: '', destIP: '10.0.2.5', destMask: '255.255.255.255', port: 80, protocol: 6, action: 0 },
{ srcIP: null, srcMask: '', destIP: '', destMask: '', port: 53, protocol: 17, action: 1 },
{ srcIP: '', srcMask: '', destIP: '', destMask: '', port: -1, protocol: 1, action: 0 },
],
},
},
},
{
javaClass: 'Modem',
name: 'M',
x: 300,
y: 20,
useIpAsName: false,
useMacAsName: false,
interfaces: [],
portCount: 1,
system: { modem: { mode: 1, port: 4242, ipAddress: '192.168.1.5' } },
},
{ javaClass: 'Modem', name: 'M', x: 300, y: 20, useIpAsName: false, useMacAsName: false, interfaces: [], portCount: 1 },
],
links: [
{ ends: [{ node: 0, port: 0 }, { node: 1, port: 2 }], wireless: false, panel: [0, 1] },
@@ -109,6 +184,17 @@ const SYNTHETIC: TopologyToWrite = {
documentation: [{ type: 1, text: null, x: 5, y: 6, width: 70, height: 80, color: null, font: null }],
};
/** The DHCP server as every IP stack's constructor leaves it. */
const JAVA_DHCP_DEFAULTS = {
aktiv: false,
untergrenze: '0.0.0.0',
obergrenze: '0.0.0.0',
gatewayip: '0.0.0.0',
dnsserverip: '0.0.0.0',
ownSettings: false,
staticAssignedAddresses: [],
};
describe('a topology beyond the corpus, as Java loads it', () => {
it('keeps what the corpus never sets', () => {
const name = 'synthetic/synthetic.fls';
@@ -132,8 +218,30 @@ describe('a topology beyond the corpus, as Java loads it', () => {
useIpAsName: false,
useMacAsName: true,
ports: [{ ip: '10.0.0.1', mask: '255.0.0.0', mac: 'AA:BB:CC:DD:EE:01', gateway: null, dns: '10.0.0.53' }],
system: {
ssid: 'Lab',
manualRoutes: [['10.1.0.0', '255.255.0.0', '10.0.0.254', '10.0.0.1']],
dhcpClient: true,
dhcpServer: {
aktiv: true,
untergrenze: '10.0.0.100',
obergrenze: '10.0.0.199',
gatewayip: '10.0.0.254',
dnsserverip: '10.0.0.53',
ownSettings: true,
staticAssignedAddresses: ['AA:BB:CC:DD:EE:77 10.0.0.77'],
},
},
},
{
class: 'Switch',
name: 'S',
position: [100, 20],
useIpAsName: undefined,
useMacAsName: undefined,
ports: [{}, {}, {}],
system: { ssid: 'S-net', retentionTime: 1234 },
},
{ class: 'Switch', name: 'S', position: [100, 20], useIpAsName: undefined, useMacAsName: undefined, ports: [{}, {}, {}] },
{
class: 'Vermittlungsrechner',
name: 'R',
@@ -141,8 +249,35 @@ describe('a topology beyond the corpus, as Java loads it', () => {
useIpAsName: undefined,
useMacAsName: undefined,
ports: ['1', '2', '3'].map(plainInterface),
system: {
ripEnabled: true,
manualRoutes: [],
dhcpClient: false,
dhcpServer: JAVA_DHCP_DEFAULTS,
firewall: {
activated: true,
defaultPolicy: 1,
dropICMP: true,
filterSYNSegmentsOnly: false,
filterUdp: false,
rules: [
['10.0.1.0', '255.255.255.0', '', '', -1, -1, 1],
['', '', '10.0.2.5', '255.255.255.255', 80, 6, 0],
[null, '', '', '', 53, 17, 1],
['', '', '', '', -1, 1, 0],
],
},
},
},
{
class: 'Modem',
name: 'M',
position: [300, 20],
useIpAsName: undefined,
useMacAsName: undefined,
ports: [{}],
system: { modem: { mode: 1, port: 4242, ipAdresse: '192.168.1.5' } },
},
{ class: 'Modem', name: 'M', position: [300, 20], useIpAsName: undefined, useMacAsName: undefined, ports: [{}] },
],
cables: [
{ ends: [[0, 0], [1, 2]], wireless: false, panel: [0, 1] },
File diff suppressed because it is too large Load Diff