feat(core): DNS after Java, measured with Java FILIUS

DNS follows Java's DNSServer and Resolver, not Swift's typed format:
Java's text messages (dns.ts), a server on port 53 answering from its
records (no question in the answer, RCODE 0, a referral with NS and A in
the answer section), an iterative resolver that waits five round trips per
query and remembers only the servers it was referred to. Recursion throws
NotPortedError until the next step. The snapshot carries the DNS servers
switched on. receiveUdp returns as soon as a datagram is there, as Java's
empfangen does.

dnsJava.test.ts compares DnsRun's five lookups; four match frame by frame,
the missing server waits for Java's ARP (named as not yet like Java).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 16:53:32 +00:00
co-authored by Claude Opus 5.5
parent 24ebcea67f
commit 8869c865b1
8 changed files with 588 additions and 4 deletions
+21
View File
@@ -15,6 +15,7 @@ import {
type ManualRoute,
type NodeKind,
type TopologySnapshot,
type DnsRecordType,
} from '../src/index.js';
export interface Scenario {
@@ -50,6 +51,8 @@ export interface Scenario {
{ active?: boolean; lower?: string; upper?: string; gateway?: string; dns?: string; own?: boolean; staticAssignments?: [string, string][] }
>;
dhcpClients?: string[];
/** Records as `name TYPE target` (Java's hinzuRecord: TTL 3600). */
dnsServers?: Record<string, { records: string[]; recursive?: boolean }>;
steps: {
op: string;
from?: string;
@@ -164,6 +167,24 @@ export function snapshotOf(scenario: Scenario): TopologySnapshot {
config.retention === undefined ? switchConfiguration(config.ssid) : switchConfiguration(config.ssid, config.retention),
]),
),
dnsServerConfigurationsByNodeId: new Map(
Object.entries(scenario.dnsServers ?? {}).map(([node, config]) => [
node,
{
recursiveResolutionEnabled: config.recursive ?? false,
records: config.records.map((line) => {
const [name = '', type = 'A', target = ''] = line.split(' ');
const nameServerOrMail = type === 'NS' || type === 'MX';
return {
name: name.replace(/\.$/, '').toLowerCase() || '.',
type: type as DnsRecordType,
ttlSeconds: 3600,
target: nameServerOrMail && !target.endsWith('.') ? `${target}.` : target,
};
}),
},
]),
),
firewallConfigurationsByNodeId: firewalls,
});
}