feat(fls): DNS records from /dns/hosts, as Java's server answers them

Java's DNS server reads its records from the text file /dns/hosts on every
query. dnsHosts.ts ports that reading (DNSServer.leseRecordListe,
ResourceRecord, Dateisystem.holeDatei) and keeps in the model the records
Java answers: type exactly A, MX or NS, and a name Java accepted. The file
stays in the file system as it is.

Both oracles read 76 hand-picked hosts files (dns-hosts.cases.txt): the
Java oracle through DNSServer.holeResourceRecords (DnsHostsCases), the
Swift oracle through TopologyDNSHostsFileCodec (--dns-hosts). The Java view
matches Java on every case; the model matches Swift except for 33 named
cases in twelve reasons: Java splits at single spaces and LF only, has no
comments or "IN", turns a TTL that is no int into 3600, keeps duplicates,
and empties names with a leading digit. The Swift dump now carries each
server's records; the corpus comparison covers them on 16 files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 06:38:01 +00:00
co-authored by Claude Opus 5.5
parent 1cc0dfd899
commit c80d212c90
17 changed files with 2518 additions and 11 deletions
+76
View File
@@ -0,0 +1,76 @@
www.filius.de. A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4
WWW.Filius.DE A 3600 1.2.3.4\u000A
www.filius.de a 3600 1.2.3.4\u000A
filius.de mx 3600 mail.filius.de\u000A
www.filius.de A 3600 1.2.3.4\u000A
www.filius.de\u0009A\u00093600\u00091.2.3.4\u000A
www.filius.de A 3600 1.2.3.4 \u000A
www.filius.de A 3600 1.2.3.4 # comment\u000A
# www.filius.de A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4#x\u000A
www.filius.de A IN 3600 1.2.3.4\u000A
www.filius.de 3600 IN A 1.2.3.4\u000A
www.filius.de A x 1.2.3.4\u000A
www.filius.de A -5 1.2.3.4\u000A
www.filius.de A 0 1.2.3.4\u000A
www.filius.de A +5 1.2.3.4\u000A
www.filius.de A 4294967295 1.2.3.4\u000A
www.filius.de A 99999999999 1.2.3.4\u000A
www.filius.de A 3600 010.0.0.1\u000A
www.filius.de A 3600 1.2.3\u000A
www.filius.de A 3600 256.0.0.1\u000A
www.filius.de A 3600 1.2.3.4.\u000A
www.filius.de A 3600 1.2.3.4 extra\u000A
www.filius.de A 3600\u000A
1und1.de A 3600 1.2.3.4\u000A
a_b.de A 3600 1.2.3.4\u000A
-a.de A 3600 1.2.3.4\u000A
a-.de A 3600 1.2.3.4\u000A
www..de A 3600 1.2.3.4\u000A
www.filius.de.. A 3600 1.2.3.4\u000A
www.1und1.de A 3600 1.2.3.4\u000A
www.a\u005Cb.de A 3600 1.2.3.4\u000A
m\u00FCller.de A 3600 1.2.3.4\u000A
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\u000A
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\u000A
localhost A 3600 127.0.0.1\u000A
. NS 3600 dns-root.\u000A
de NS 3600 dns.de\u000A
de. NS 3600 .\u000A
filius.de MX 3600 mail.filius.de\u000A
filius.de MX 3600 10 mail.filius.de\u000A
filius.de MX 3600 1.2.3.4\u000A
filius.de CNAME 3600 www.filius.de\u000A
filius.de TXT 3600 hello\u000A
www.filius.de A 3600 1.2.3.4\u000Awww.filius.de A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u000Awww.filius.de A 7200 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u000AWWW.filius.de. A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u000Awww.filius.de A 3600 1.2.3.5\u000A
www.filius.de A 3600 1.2.3.4\u000D\u000Amail.filius.de A 3600 1.2.3.5\u000D\u000A
www.filius.de A 3600 1.2.3.4\u000Dmail.filius.de A 3600 1.2.3.5\u000D
www.filius.de A 3600 1.2.3.4\u2028mail.filius.de A 3600 1.2.3.5\u000A
www.filius.de\u00A0A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u0085\u000A
\u000A\u000Awww.filius.de A 3600 1.2.3.4\u000A\u000A
filius.de. MX 3600 smtp.filius.de.\u000Adns-root. A 3600 141.99.5.13\u000A. NS 3600 dns-root.\u000A
www.filius.de A \u0661\u0660 1.2.3.4\u000A
www.filius.de A 2147483647 1.2.3.4\u000A
www.filius.de A -2147483648 1.2.3.4\u000A
www.filius.de A 2147483648 1.2.3.4\u000A
www.filius.de \u0009 A 3600 1.2.3.4\u000A
www.filius.de A \u0009 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4 \u0009\u000A
www.filius.de A 3600 1.2.3.4\u000A
www.filius.de A 3600 1.2.3.4\u000A
www.filius.de A 3600 0.0.0.0\u000A
www.filius.de A 3600 00000000000000000001.2.3.4\u000A
filius.de NS 3600 dns..de\u000A
filius.de NS 3600 dns.filius.de..\u000A
filius.de. MX 3600 Mail.Filius.DE.\u000A
www.filius.de A 3600 .1.2.3\u000A
www.filius.de A 3600 1.2.3.4\u0001\u000A
www.filius.de A 3600 1.2.3.4\u00A0\u000A
\u001Fwww.filius.de A 3600 1.2.3.4\u000A
+754
View File
@@ -0,0 +1,754 @@
[
[
"www.filius.de. A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"WWW.Filius.DE A 3600 1.2.3.4\\u000A",
[
[
"WWW.Filius.DE.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de a 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"a",
3600,
"1.2.3.4"
]
]
],
[
"filius.de mx 3600 mail.filius.de\\u000A",
[
[
"filius.de.",
"mx",
3600,
"mail.filius.de"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de\\u0009A\\u00093600\\u00091.2.3.4\\u000A",
[]
],
[
" www.filius.de A 3600 1.2.3.4 \\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4 # comment\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"# www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"",
"www.filius.de",
3600,
"3600"
]
]
],
[
"www.filius.de A 3600 1.2.3.4#x\\u000A",
[]
],
[
"www.filius.de A IN 3600 1.2.3.4\\u000A",
[]
],
[
"www.filius.de 3600 IN A 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"3600",
3600,
"A"
]
]
],
[
"www.filius.de A x 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A -5 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
-5,
"1.2.3.4"
]
]
],
[
"www.filius.de A 0 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
0,
"1.2.3.4"
]
]
],
[
"www.filius.de A +5 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
5,
"1.2.3.4"
]
]
],
[
"www.filius.de A 4294967295 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 99999999999 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 010.0.0.1\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"010.0.0.1"
]
]
],
[
"www.filius.de A 3600 1.2.3\\u000A",
[]
],
[
"www.filius.de A 3600 256.0.0.1\\u000A",
[]
],
[
"www.filius.de A 3600 1.2.3.4.\\u000A",
[]
],
[
"www.filius.de A 3600 1.2.3.4 extra\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600\\u000A",
[]
],
[
"1und1.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"a_b.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"-a.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"a-.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www..de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de.. A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.1und1.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.a\\u005Cb.de A 3600 1.2.3.4\\u000A",
[
[
"www.a\\b.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"m\\u00FCller.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\\u000A",
[
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\\u000A",
[
[
"",
"A",
3600,
"1.2.3.4"
]
]
],
[
"localhost A 3600 127.0.0.1\\u000A",
[
[
"localhost.",
"A",
3600,
"127.0.0.1"
]
]
],
[
". NS 3600 dns-root.\\u000A",
[
[
".",
"NS",
3600,
"dns-root."
]
]
],
[
"de NS 3600 dns.de\\u000A",
[
[
"de.",
"NS",
3600,
"dns.de."
]
]
],
[
"de. NS 3600 .\\u000A",
[
[
"de.",
"NS",
3600,
"."
]
]
],
[
"filius.de MX 3600 mail.filius.de\\u000A",
[
[
"filius.de.",
"MX",
3600,
"mail.filius.de."
]
]
],
[
"filius.de MX 3600 10 mail.filius.de\\u000A",
[]
],
[
"filius.de MX 3600 1.2.3.4\\u000A",
[]
],
[
"filius.de CNAME 3600 www.filius.de\\u000A",
[
[
"filius.de.",
"CNAME",
3600,
"www.filius.de"
]
]
],
[
"filius.de TXT 3600 hello\\u000A",
[
[
"filius.de.",
"TXT",
3600,
"hello"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
],
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 7200 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
],
[
"www.filius.de.",
"A",
7200,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000AWWW.filius.de. A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
],
[
"WWW.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 3600 1.2.3.5\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
],
[
"www.filius.de.",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000D\\u000Amail.filius.de A 3600 1.2.3.5\\u000D\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
],
[
"mail.filius.de.",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Dmail.filius.de A 3600 1.2.3.5\\u000D",
[]
],
[
"www.filius.de A 3600 1.2.3.4\\u2028mail.filius.de A 3600 1.2.3.5\\u000A",
[]
],
[
"www.filius.de\\u00A0A 3600 1.2.3.4\\u000A",
[]
],
[
"www.filius.de A 3600 1.2.3.4\\u0085\\u000A",
[]
],
[
"",
[]
],
[
"\\u000A\\u000Awww.filius.de A 3600 1.2.3.4\\u000A\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"filius.de. MX 3600 smtp.filius.de.\\u000Adns-root. A 3600 141.99.5.13\\u000A. NS 3600 dns-root.\\u000A",
[
[
"filius.de.",
"MX",
3600,
"smtp.filius.de."
],
[
"dns-root.",
"A",
3600,
"141.99.5.13"
],
[
".",
"NS",
3600,
"dns-root."
]
]
],
[
"www.filius.de A \\u0661\\u0660 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
10,
"1.2.3.4"
]
]
],
[
"www.filius.de A 2147483647 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
2147483647,
"1.2.3.4"
]
]
],
[
"www.filius.de A -2147483648 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
-2147483648,
"1.2.3.4"
]
]
],
[
"www.filius.de A 2147483648 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de \\u0009 A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"",
3600,
"3600"
]
]
],
[
"www.filius.de A \\u0009 3600 1.2.3.4\\u000A",
[]
],
[
"www.filius.de A 3600 1.2.3.4 \\u0009\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 0.0.0.0\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"0.0.0.0"
]
]
],
[
"www.filius.de A 3600 00000000000000000001.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"00000000000000000001.2.3.4"
]
]
],
[
"filius.de NS 3600 dns..de\\u000A",
[]
],
[
"filius.de NS 3600 dns.filius.de..\\u000A",
[]
],
[
"filius.de. MX 3600 Mail.Filius.DE.\\u000A",
[
[
"filius.de.",
"MX",
3600,
"Mail.Filius.DE."
]
]
],
[
"www.filius.de A 3600 .1.2.3\\u000A",
[
[
"www.filius.de.",
"A",
3600,
".1.2.3"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u0001\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u00A0\\u000A",
[]
],
[
"\\u001Fwww.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de.",
"A",
3600,
"1.2.3.4"
]
]
]
]
+749
View File
@@ -0,0 +1,749 @@
[
[
"www.filius.de. A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"WWW.Filius.DE A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de a 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"filius.de mx 3600 mail.filius.de\\u000A",
[
[
"filius.de",
"MX",
3600,
"mail.filius.de."
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de\\u0009A\\u00093600\\u00091.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
" www.filius.de A 3600 1.2.3.4 \\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4 # comment\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"# www.filius.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4#x\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A IN 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de 3600 IN A 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A x 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A -5 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A 0 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
0,
"1.2.3.4"
]
]
],
[
"www.filius.de A +5 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
5,
"1.2.3.4"
]
]
],
[
"www.filius.de A 4294967295 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
4294967295,
"1.2.3.4"
]
]
],
[
"www.filius.de A 99999999999 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A 3600 010.0.0.1\\u000A",
[
[
"www.filius.de",
"A",
3600,
"10.0.0.1"
]
]
],
[
"www.filius.de A 3600 1.2.3\\u000A",
[
]
],
[
"www.filius.de A 3600 256.0.0.1\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4.\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4 extra\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600\\u000A",
[
]
],
[
"1und1.de A 3600 1.2.3.4\\u000A",
[
[
"1und1.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"a_b.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"-a.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"a-.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"www..de A 3600 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de.. A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.1und1.de A 3600 1.2.3.4\\u000A",
[
[
"www.1und1.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.a\\u005Cb.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"m\\u00FCller.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\\u000A",
[
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.de A 3600 1.2.3.4\\u000A",
[
]
],
[
"localhost A 3600 127.0.0.1\\u000A",
[
[
"localhost",
"A",
3600,
"127.0.0.1"
]
]
],
[
". NS 3600 dns-root.\\u000A",
[
[
".",
"NS",
3600,
"dns-root."
]
]
],
[
"de NS 3600 dns.de\\u000A",
[
[
"de",
"NS",
3600,
"dns.de."
]
]
],
[
"de. NS 3600 .\\u000A",
[
]
],
[
"filius.de MX 3600 mail.filius.de\\u000A",
[
[
"filius.de",
"MX",
3600,
"mail.filius.de."
]
]
],
[
"filius.de MX 3600 10 mail.filius.de\\u000A",
[
[
"filius.de",
"MX",
3600,
"10."
]
]
],
[
"filius.de MX 3600 1.2.3.4\\u000A",
[
[
"filius.de",
"MX",
3600,
"1.2.3.4."
]
]
],
[
"filius.de CNAME 3600 www.filius.de\\u000A",
[
]
],
[
"filius.de TXT 3600 hello\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 7200 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000AWWW.filius.de. A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Awww.filius.de A 3600 1.2.3.5\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
],
[
"www.filius.de",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000D\\u000Amail.filius.de A 3600 1.2.3.5\\u000D\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
],
[
"mail.filius.de",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000Dmail.filius.de A 3600 1.2.3.5\\u000D",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
],
[
"mail.filius.de",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u2028mail.filius.de A 3600 1.2.3.5\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
],
[
"mail.filius.de",
"A",
3600,
"1.2.3.5"
]
]
],
[
"www.filius.de\\u00A0A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u0085\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"",
[
]
],
[
"\\u000A\\u000Awww.filius.de A 3600 1.2.3.4\\u000A\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"filius.de. MX 3600 smtp.filius.de.\\u000Adns-root. A 3600 141.99.5.13\\u000A. NS 3600 dns-root.\\u000A",
[
[
"filius.de",
"MX",
3600,
"smtp.filius.de."
],
[
"dns-root",
"A",
3600,
"141.99.5.13"
],
[
".",
"NS",
3600,
"dns-root."
]
]
],
[
"www.filius.de A \\u0661\\u0660 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A 2147483647 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
2147483647,
"1.2.3.4"
]
]
],
[
"www.filius.de A -2147483648 1.2.3.4\\u000A",
[
]
],
[
"www.filius.de A 2147483648 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
2147483648,
"1.2.3.4"
]
]
],
[
"www.filius.de \\u0009 A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A \\u0009 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4 \\u0009\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 1.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"www.filius.de A 3600 0.0.0.0\\u000A",
[
[
"www.filius.de",
"A",
3600,
"0.0.0.0"
]
]
],
[
"www.filius.de A 3600 00000000000000000001.2.3.4\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"filius.de NS 3600 dns..de\\u000A",
[
]
],
[
"filius.de NS 3600 dns.filius.de..\\u000A",
[
[
"filius.de",
"NS",
3600,
"dns.filius.de."
]
]
],
[
"filius.de. MX 3600 Mail.Filius.DE.\\u000A",
[
[
"filius.de",
"MX",
3600,
"mail.filius.de."
]
]
],
[
"www.filius.de A 3600 .1.2.3\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4\\u0001\\u000A",
[
]
],
[
"www.filius.de A 3600 1.2.3.4\\u00A0\\u000A",
[
[
"www.filius.de",
"A",
3600,
"1.2.3.4"
]
]
],
[
"\\u001Fwww.filius.de A 3600 1.2.3.4\\u000A",
[
]
]
]
+209
View File
@@ -0,0 +1,209 @@
// Java's reading of /dns/hosts (DNSServer.leseRecordListe): every case in
// dns-hosts.cases.txt was run through Java (dns-hosts.java.json) and through
// Swift's hosts-file codec (dns-hosts.swift.json, tools/swift-oracle). The
// Java view must match Java exactly; the records the model keeps must match
// Swift except where Java answers differently — each case named below.
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import type { FlsFileTree } from '../src/index.js';
import { dnsRecordsOf, javaHostsFileContent, readJavaDnsHosts } from '../src/dnsHosts.js';
const here = dirname(fileURLToPath(import.meta.url));
type Row = [string, string, number, string];
const javaMeasured = JSON.parse(readFileSync(join(here, 'dns-hosts.java.json'), 'utf8')) as [string, Row[]][];
const swiftMeasured = JSON.parse(readFileSync(join(here, 'dns-hosts.swift.json'), 'utf8')) as [string, Row[]][];
/** The cases file's escapes: a backslash, `u` and four hex digits for one UTF-16 unit. */
function unescape(line: string): string {
return line.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)));
}
function modelRows(line: string, warnings: string[] = []): Row[] {
return dnsRecordsOf(readJavaDnsHosts(unescape(line)), (message) => warnings.push(message)).map((record) => [
record.name,
record.type,
record.ttlSeconds,
record.target,
]);
}
/** Lines Swift reads as records that Java never answers. */
const SWIFT_READS_JAVA_NEVER_ANSWERS: { reason: string; lines: string[] }[] = [
{
reason: 'a type in lower case is another type in Java, which never answers',
lines: [
String.raw`www.filius.de a 3600 1.2.3.4\u000A`,
String.raw`filius.de mx 3600 mail.filius.de\u000A`,
],
},
{
reason: 'Java splits fields at single spaces only: a tab or NBSP is part of a field',
lines: [
String.raw`www.filius.de\u0009A\u00093600\u00091.2.3.4\u000A`,
String.raw`www.filius.de\u00A0A 3600 1.2.3.4\u000A`,
String.raw`www.filius.de A 3600 1.2.3.4\u00A0\u000A`,
String.raw`www.filius.de \u0009 A 3600 1.2.3.4\u000A`,
String.raw`www.filius.de A \u0009 3600 1.2.3.4\u000A`,
],
},
{
reason: 'Java splits lines at LF only: CR, LS and NEL stay in the line',
lines: [
String.raw`www.filius.de A 3600 1.2.3.4\u000Dmail.filius.de A 3600 1.2.3.5\u000D`,
String.raw`www.filius.de A 3600 1.2.3.4\u2028mail.filius.de A 3600 1.2.3.5\u000A`,
String.raw`www.filius.de A 3600 1.2.3.4\u0085\u000A`,
],
},
{
reason: 'Java has no comments, no "IN" and no zone-file order',
lines: [
String.raw`www.filius.de A 3600 1.2.3.4#x\u000A`,
String.raw`www.filius.de A IN 3600 1.2.3.4\u000A`,
String.raw`www.filius.de 3600 IN A 1.2.3.4\u000A`,
],
},
{
reason: 'a label that starts with a digit, or two final dots, make the name empty in Java',
lines: [
String.raw`1und1.de A 3600 1.2.3.4\u000A`,
String.raw`www.1und1.de A 3600 1.2.3.4\u000A`,
String.raw`www.filius.de.. A 3600 1.2.3.4\u000A`,
],
},
{
reason: 'an MX or NS target must be a name Java accepts: no preference, no address, one final dot',
lines: [
String.raw`filius.de MX 3600 10 mail.filius.de\u000A`,
String.raw`filius.de MX 3600 1.2.3.4\u000A`,
String.raw`filius.de NS 3600 dns.filius.de..\u000A`,
],
},
];
/** Lines Java answers that Swift drops or reads otherwise. */
const JAVA_ANSWERS_SWIFT_DROPS: { reason: string; lines: string[] }[] = [
{
reason: 'a TTL that is no Java int is 3600',
lines: [
String.raw`www.filius.de A x 1.2.3.4\u000A`,
String.raw`www.filius.de A 4294967295 1.2.3.4\u000A`,
String.raw`www.filius.de A 99999999999 1.2.3.4\u000A`,
String.raw`www.filius.de A 2147483648 1.2.3.4\u000A`,
],
},
{
reason: 'a TTL is Java\'s Integer.parseInt: negative, and in any script\'s digits',
lines: [
String.raw`www.filius.de A -5 1.2.3.4\u000A`,
String.raw`www.filius.de A -2147483648 1.2.3.4\u000A`,
String.raw`www.filius.de A \u0661\u0660 1.2.3.4\u000A`,
],
},
{
reason: 'labels after the first may hold a backslash (Java\'s domain pattern)',
lines: [
String.raw`www.a\u005Cb.de A 3600 1.2.3.4\u000A`,
],
},
{
reason: 'Java trims control characters off a line (String.trim)',
lines: [
String.raw`www.filius.de A 3600 1.2.3.4\u0001\u000A`,
String.raw`\u001Fwww.filius.de A 3600 1.2.3.4\u000A`,
],
},
{
reason: 'an NS record may name the root',
lines: [
String.raw`de. NS 3600 .\u000A`,
],
},
{
reason: 'duplicates stay, as in Java\'s list',
lines: [
String.raw`www.filius.de A 3600 1.2.3.4\u000Awww.filius.de A 3600 1.2.3.4\u000A`,
String.raw`www.filius.de A 3600 1.2.3.4\u000Awww.filius.de A 7200 1.2.3.4\u000A`,
String.raw`www.filius.de A 3600 1.2.3.4\u000AWWW.filius.de. A 3600 1.2.3.4\u000A`,
],
},
];
const departures = new Map(
[...SWIFT_READS_JAVA_NEVER_ANSWERS, ...JAVA_ANSWERS_SWIFT_DROPS].flatMap(({ reason, lines }) =>
lines.map((line) => [line, reason] as const),
),
);
describe('readJavaDnsHosts against Java', () => {
it('covers every line of the cases file, in both oracles', () => {
const lines = readFileSync(join(here, 'dns-hosts.cases.txt'), 'ascii').split('\n').slice(0, -1);
expect(javaMeasured.map(([line]) => line)).toEqual(lines);
expect(swiftMeasured.map(([line]) => line)).toEqual(lines);
});
for (const [line, expected] of javaMeasured) {
it(JSON.stringify(line), () => {
const records = readJavaDnsHosts(unescape(line));
expect(records.map((record) => [record.domainName, record.type, record.ttl, record.rdata])).toEqual(expected);
});
}
});
describe('the records the model keeps, against Swift', () => {
it('names only cases of the cases file as departures', () => {
const lines = new Set(swiftMeasured.map(([line]) => line));
expect([...departures.keys()].filter((line) => !lines.has(line))).toEqual([]);
});
for (const [line, swift] of swiftMeasured) {
const reason = departures.get(line);
it(reason === undefined ? JSON.stringify(line) : `${JSON.stringify(line)} (departs: ${reason})`, () => {
if (reason === undefined) expect(modelRows(line)).toEqual(swift);
else expect(modelRows(line)).not.toEqual(swift);
});
}
});
describe('the records Java answers', () => {
it('leave out records Java never answers: an empty name, or a type other than A, MX, NS', () => {
expect(modelRows(String.raw`1und1.de A 3600 1.2.3.4\u000Afilius.de CNAME 3600 www.filius.de\u000Afilius.de a 3600 1.2.3.4`)).toEqual([]);
});
it('take names in lower case without the final dot, A targets as FILIUS normalises addresses', () => {
expect(modelRows(String.raw`WWW.Filius.DE. A 60 010.000.0.1\u000Afilius.de MX 3600 Mail.Filius.DE\u000A. NS 3600 dns-root`)).toEqual([
['www.filius.de', 'A', 60, '10.0.0.1'],
['filius.de', 'MX', 3600, 'mail.filius.de.'],
['.', 'NS', 3600, 'dns-root.'],
]);
});
it('warn about an A record Java answers with an address FILIUS cannot use', () => {
const warnings: string[] = [];
expect(modelRows(String.raw`www.filius.de A 3600 .1.2.3`, warnings)).toEqual([]);
expect(warnings).toEqual(["DNS record 'www.filius.de A .1.2.3' has no usable IPv4 address, left out (it stays in /dns/hosts)"]);
});
});
describe('javaHostsFileContent', () => {
const file = (name: string, content: string | null): FlsFileTree => ({ kind: 'file', name, type: 'text', content, children: [] });
const directory = (name: string, ...children: FlsFileTree[]): FlsFileTree => ({ kind: 'directory', name, children });
it('finds /dns/hosts ignoring case, as Java does', () => {
expect(javaHostsFileContent(directory('root', directory('DNS', file('Hosts', 'x'))))).toBe('x');
expect(javaHostsFileContent(directory('root', directory('dns', file('ho\u017Fts', 'long s'))))).toBe('long s');
});
it('takes the first match in preorder, and nothing when that is a directory', () => {
expect(javaHostsFileContent(directory('root', directory('dns', file('hosts', 'first')), directory('DNS', file('hosts', 'second'))))).toBe('first');
expect(javaHostsFileContent(directory('root', directory('dns', directory('hosts'), file('HOSTS', 'later'))))).toBeUndefined();
});
it('is undefined without the file, and empty for a file without content', () => {
expect(javaHostsFileContent(undefined)).toBeUndefined();
expect(javaHostsFileContent(directory('root', file('hosts', 'x')))).toBeUndefined();
expect(javaHostsFileContent(directory('root', directory('dns', file('hosts', null))))).toBe('');
});
});
+31 -3
View File
@@ -145,6 +145,7 @@ function systemOf(project: ImportedProject, nodeId: Id) {
result.dnsServer = {
recursiveResolutionEnabled: dns.recursiveResolutionEnabled,
forwardingServerIPAddress: dns.forwardingServerIPAddress ?? null,
records: dns.records.map((record) => [record.name, record.type, record.ttlSeconds, record.target]),
};
}
const remoteLink = project.remoteLinkConfigurations.get(nodeId);
@@ -787,12 +788,39 @@ describe('importProject rules', () => {
expect(project.simpleClientConfigurations.get(notebook!)).toEqual({ targetAddress: '10.0.0.9', targetPort: 7 });
expect(project.firewallConfigurationsByNodeId.get(notebook!)).toMatchObject({ isActive: true, defaultPolicy: 'accept' });
expect([forwarding, self, iterative].map((id) => project.dnsServerConfigurations.get(id!))).toEqual([
{ recursiveResolutionEnabled: true, forwardingServerIPAddress: '8.8.8.8' },
{ recursiveResolutionEnabled: true },
{ recursiveResolutionEnabled: false },
{ recursiveResolutionEnabled: true, forwardingServerIPAddress: '8.8.8.8', records: [] },
{ recursiveResolutionEnabled: true, records: [] },
{ recursiveResolutionEnabled: false, records: [] },
]);
});
it("takes a DNS server's records from its /dns/hosts, and names the node in a warning", () => {
const hosts = 'www.filius.de A 3600 141.99.2.10\nfilius.de MX 3600 mail.filius.de\nbroken.de A 3600 .1.2.3\n';
const server = flsNode('Rechner', {
name: 'DNS',
interfaces: [nic('10.0.0.1')],
system: {
applications: [{ key: 'dns', javaClass: 'filius.software.dns.DNSServer', source: flsNode('Rechner').source, isActive: true }],
fileSystem: {
kind: 'directory',
name: 'root',
children: [
{ kind: 'directory', name: 'dns', children: [{ kind: 'file', name: 'hosts', type: 'text', content: hosts, children: [] }] },
],
},
},
});
const project = importProject(topology({ nodes: [server] }), counter());
const [id] = project.graph.nodes.map((node) => node.id);
expect(project.dnsServerConfigurations.get(id!)?.records).toEqual([
{ name: 'www.filius.de', type: 'A', ttlSeconds: 3600, target: '141.99.2.10' },
{ name: 'filius.de', type: 'MX', ttlSeconds: 3600, target: 'mail.filius.de.' },
]);
expect(project.virtualFileSystems.get(id!)?.textFile('/dns/hosts')).toBe(hosts);
expect(project.warnings).toEqual(["node 'DNS': DNS record 'broken.de A .1.2.3' has no usable IPv4 address, left out (it stays in /dns/hosts)"]);
});
it('leaves out a cable to itself and one to a port that already has a cable', () => {
const project = importProject(
topology({