Rust · BSD-3-Clause · ~5 MB Image

IPv6-Reverse-DNS. Ohne Zonendateien.

PanoptiDNS ist ein kleiner autoritativer DNS-Server, der PTR-Einträge und die passenden AAAA-Einträge pro Anfrage berechnet — für jede Adresse Ihrer Präfixe, in beide Richtungen. Ein gehärteter Ersatz für AllKnowingDNS, der dieselbe Konfigurationsdatei liest.

18 446 744 073 709 551 616

Adressen in einem einzigen /64. Keine Zonendatei kann sie aufzählen — aber die Zuordnung zwischen Adresse und Hostname ist eine reine Funktion, also berechnet PanoptiDNS sie einfach bei jeder Anfrage. SLAAC-Clients, Privacy-Adressen und ganze Kundenpräfixe bekommen konsistentes Reverse- und Forward-DNS ohne jede Provisionierung.

Klein, streng und im Betrieb langweilig

Ein statisches Binary, eine Konfigurationsdatei, keine Datenbank, keine Zonentransfers.

⇄

Beide Richtungen

PTR für die Adresse, AAAA für den erzeugten Namen — immer konsistent, weil beides aus derselben Funktion der 128-Bit-Adresse entsteht.

≡

AllKnowingDNS-Konfiguration, unverändert

Liest das Format von AllKnowingDNS v1.7 wie es ist; dessen Akzeptanztests sind Teil der Testsuite. Vorlagen mit %DIGITS% und %DIGITS-DASHED%.

✓

Konfigurationsprüfung mit Zeilennummern

--check-config meldet alle Fehler auf einmal, im rustc-Stil mit Markierung. SIGHUP lädt neu; eine fehlerhafte Datei lässt die laufende Konfiguration stehen.

⛨

Durch keine Anfrage abzuschießen

Anfragenamen werden in ein u128 geparst oder abgelehnt — nie als Text weiterverwendet. Panics im Anfragepfad sind per Lint verboten und werden als SERVFAIL abgefangen.

⏱

Response Rate Limiting

Standardmäßig aktiv, mit getrennten Budgets für Antworten und negative Antworten, Aggregation pro Präfix und slip wie bei BIND.

↗

Gehärteter Upstream

with upstream-Abfragen laufen asynchron mit festem Timeout, hinter einem Circuit Breaker und mit strikter Allowlist für weitergereichte Einträge.

§

Sauberes DNS-Verhalten

SOA und NS am Zonen-Apex, SOA in negativen Antworten (RFC 2308), EDNS(0), TCP und BADVERS für unbekannte EDNS-Versionen.

▣

Winziger, abgeschotteter Container

~5-MB-Distroless-Image für amd64/arm64, uid 65532, schreibgeschütztes Dateisystem, alle Capabilities entzogen. systemd-Unit mit DynamicUser liegt bei.

Abbildung ausprobieren

Geben Sie eine beliebige Adresse ein. Das läuft im Browser nach derselben Regel wie im Server: Der Host-Anteil wird zu den Hex-Ziffern im Namen.

PTR-Anfrage
PTR-Antwort
AAAA des Namens

Hervorgehoben ist der Host-Anteil — 16 Hex-Ziffern bei einem /64. Gespeichert wird nichts; der Server rechnet bei jeder Anfrage genau so.

Der Fehler, mit dem alles anfing

Warum eine Neuimplementierung statt eines Patches.

AllKnowingDNS v1.7 (Perl, seit 2013 nicht mehr gepflegt) ließ sich mit einem einzigen UDP-Paket beenden. Es baute Einträge, indem es den vom Angreifer kontrollierten Anfragenamen in einen Text im Master-File-Format einsetzte — und dort werden ; und " nicht maskiert. Ein rohes ; in einem Label brachte den Parser zum Absturz, niemand fing die Exception, der Prozess endete.

In PanoptiDNS ist diese Fehlerklasse gar nicht darstellbar: Namen sind nie Text, eine Zone ist ein ganzzahliges Präfix mit Maske, und der Anfragepfad kann nicht abbrechen. Fünf weitere Mängel des Originals — darunter eine bis zu 20 s blockierende Upstream-Abfrage — haben je einen eigenen Regressionstest.

Sicherheitsrichtlinie · Umstieg von AllKnowingDNS (englisch)

# Anfragename des Angreifers → Master-File-Text
Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata")

# ein Paket, ohne Login, beliebig wiederholbar
$ dig PTR 'a;b.0.c.c.c.e.0.0.1.8.b.d.0.1.0.0.2.ip6.arpa'
→ AllKnowingDNS: Prozess beendet
→ PanoptiDNS:    NXDOMAIN, läuft weiter

Loslegen

Konfiguration schreiben, Container starten, Zonen delegieren. Multi-Arch-Images auf GHCR und Docker Hub; im Produktivbetrieb eine feste Version wie 0.2.0 pinnen.

1 · Konfigurieren und starten

primary     ns1.example.net.
hostmaster  hostmaster.example.net.
ns          ns1.example.net.

network 2001:db8:100e:ccc0::/64
    resolves to ipv6-%DIGITS%.nutzer.example.net

Als panoptidns.conf neben der Compose-Datei speichern, dann prüfen und starten:

docker compose run --rm panoptidns --check-config
docker compose up -d

2 · Delegieren

; reverse
0.c.c.c.e.0.0.1.8.b.d.0.1.0.0.2.ip6.arpa. IN NS ipv6-rdns.example.net.

; forward
nutzer.example.net. IN NS ipv6-rdns.example.net.

Images:

ghcr.io/cygnusnetworks/panoptidns:stable
cygnusnetworks/panoptidns:stable
Rust · hickory-dns statisch (musl) · distroless amd64 / arm64 105 Tests · Property-Tests systemd-Unit BSD-3-Clause

AllKnowingDNS noch heute ersetzen

Dieselbe Konfigurationsdatei, dieselben Antworten — ohne den Fern-Ausschalter.