netdiag-app/tools/pruefe-dns.mjs
Eduard Wisch 2f7b1c91a4 DNS-Pruefung: eigener UDP-Client fragt jeden Server namentlich
Neu: Dns.kt (eigener DNS-Client auf UDP/53, Aufbau wie Snmp.kt) und das
Werkzeug "DNS-Pruefung". Unterschied zur Internet-Kette: dort antwortet, wen
das System fuer richtig haelt, und der Systemcache liegt dazwischen. Hier geht
je ein Paket an je einen Server aus der Netzkonfiguration - nur so laesst sich
sagen, WELCHER Server hakt, und genau das ist beim Kunden die
Reparaturanweisung ("die Fritzbox antwortet, der zweite DHCP-Eintrag zeigt
ins Leere").

Vier Ausgaenge, bewusst nicht zu "geht/geht nicht" verkuerzt:
ok, unbekannt (NXDOMAIN - ein FUNKTIONIERENDER Server!), ohneAdresse
(SERVFAIL/REFUSED - Stoerung), keineAntwort (Ausfall).

Beim Emulator-Test einen Fehlalarm gefunden und behoben: die erste Fassung
meldete "DNS-Server antworten unterschiedlich", sobald zwei Resolver
verschiedene IPs lieferten. Gegen www.google.de gemessen taten sie das sofort
(10.0.2.3 -> 192.178.24.195, 9.9.9.9 -> 192.178.183.94) - bei jedem CDN normal.
Die Warnung waere bei praktisch jeder Messung gekommen und haette im
Kundendokument eine gelbe Ampel ohne Befund erzeugt. Gewertet wird jetzt nur
noch der Sortenunterschied privat gegen oeffentlich - so sieht Split-Horizon
oder ein Fremd-DNS aus. Beide Antworten stehen ohnehin einzeln im Protokoll.

tools/pruefe-dns.mjs: 10 Bewertungsfaelle plus 10 Adressbereiche fuer
istPrivat() (172.16-31 macht eine naive Zeichenkettenpruefung falsch).

Im Emulator gemessen: 10.0.2.3 und 9.9.9.9 beide befragt und beantwortet;
der Cache-Effekt ist sichtbar (16 ms lokal, 500 ms zu Quad9).

Ausserdem: inputmode fuer die Eingabefelder im ToolDialog ('decimal' bei
Adress-/Netzfeldern, damit die Tastatur einen Punkt hat - mit 'numeric' laesst
sich keine IP eingeben), Autokorrektur und Grossschreibung aus (sonst wird aus
"fritz.box" beim Tippen "Fritz.Box").

Der Debug-Selbsttest uebernimmt jetzt die Vorgabewerte des Werkzeugs - vorher
mass er mit leeren Parametern etwas anderes als der Techniker vor Ort (die
DNS-Pruefung fragte "1 von 1 Servern", weil der Vergleichsserver fehlte).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 23:24:32 +02:00

68 lines
3.2 KiB
JavaScript

/**
* Prueft die Bewertung der DNS-Pruefung gegen konstruierte Antworten.
*
* Der Browser-Mock liefert auch hier nur den Gutfall. Entscheidend ist, dass
* "Server antwortet, kennt den Namen nicht" (NXDOMAIN) NICHT wie ein Ausfall
* behandelt wird - das ist ein funktionierender Server.
*
* Start: node tools/pruefe-dns.mjs
*/
const { bewerteDns, istPrivat } = await import('../src/lib/tools/netzwerk/dns-bewertung.ts');
const ok = (server, ips = ['142.250.185.67']) =>
({ server, name: 'www.google.de', status: 'ok', ips, latenzMs: 12 });
const stumm = (server) =>
({ server, name: 'www.google.de', status: 'keineAntwort', ips: [], meldung: 'Keine Antwort innerhalb von 2000 ms' });
const nxdomain = (server) =>
({ server, name: 'intern.firma.local', status: 'unbekannt', ips: [], latenzMs: 4 });
const servfail = (server) =>
({ server, name: 'www.google.de', status: 'ohneAdresse', ips: [], latenzMs: 9, meldung: 'Serverfehler (SERVFAIL)' });
const faelle = [
{ name: 'Alle Server antworten gleich -> GRUEN',
a: [ok('192.168.1.1'), ok('9.9.9.9')], soll: 0 },
{ name: 'Kein Server antwortet -> ROT',
a: [stumm('192.168.1.1'), stumm('192.168.1.2')], soll: 2 },
{ name: 'Erster Server stumm, Vergleichsserver geht -> GELB (faellt sonst nicht auf)',
a: [stumm('192.168.1.2'), ok('9.9.9.9')], soll: 1 },
{ name: 'SERVFAIL ueberall -> ROT',
a: [servfail('192.168.1.1')], soll: 2 },
{ name: 'NXDOMAIN ueberall -> GELB, KEIN Ausfall (Server arbeiten)',
a: [nxdomain('192.168.1.1'), nxdomain('9.9.9.9')], soll: 1 },
{ name: 'Privat vs. oeffentlich -> GELB (Split-Horizon oder Fremd-DNS)',
a: [ok('192.168.1.1', ['10.0.0.5']), ok('9.9.9.9', ['142.250.185.67'])], soll: 1 },
{ name: 'Zwei verschiedene OEFFENTLICHE Adressen -> GRUEN (CDN, kein Befund)',
a: [ok('10.0.2.3', ['192.178.24.195']), ok('9.9.9.9', ['192.178.183.94'])], soll: 0 },
{ name: 'Zwei verschiedene PRIVATE Adressen -> GRUEN (zwei interne Server, beide intern)',
a: [ok('192.168.1.1', ['192.168.1.50']), ok('192.168.1.2', ['192.168.1.51'])], soll: 0 },
{ name: 'Gar kein DNS-Server bekannt -> NICHT MESSBAR',
a: [], soll: 3 },
{ name: 'Ein Server ok, einer SERVFAIL -> GELB',
a: [ok('192.168.1.1'), servfail('192.168.1.2')], soll: 1 },
];
let fehler = 0;
for (const f of faelle) {
const r = bewerteDns(f.a);
const okk = r.status === f.soll;
if (!okk) fehler++;
console.log(`${okk ? 'OK ' : 'FEHL'} ${f.name}`);
console.log(` status=${r.status} (soll ${f.soll}) ${r.label}`);
}
// Adressbereiche einzeln nachrechnen - 172.16-31 ist der Bereich, den eine
// naive Zeichenkettenpruefung falsch macht.
const privatFaelle = [
['10.0.0.5', true], ['192.168.1.1', true], ['172.16.0.1', true],
['172.31.255.254', true], ['169.254.1.1', true],
['172.15.0.1', false], ['172.32.0.1', false], ['8.8.8.8', false],
['142.250.185.67', false], ['193.168.1.1', false],
];
for (const [ip, soll] of privatFaelle) {
const ist = istPrivat(ip);
const okk = ist === soll;
if (!okk) fehler++;
console.log(`${okk ? 'OK ' : 'FEHL'} istPrivat("${ip}") = ${ist} (soll ${soll})`);
}
console.log(fehler === 0 ? 'ALLE FAELLE KORREKT' : `${fehler} FEHLER`);
process.exit(fehler === 0 ? 0 : 1);