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

IPv6 reverse DNS. No zone files.

PanoptiDNS is a small authoritative DNS server that computes PTR records and matching AAAA records per query — for every address in your prefixes, in both directions. A drop-in, hardened replacement for AllKnowingDNS that reads the same configuration file.

18 446 744 073 709 551 616

addresses in a single /64. No zone file can enumerate them — but the mapping between an address and a hostname is a pure function, so PanoptiDNS simply computes it for each query. SLAAC clients, privacy addresses and whole customer prefixes get consistent reverse and forward DNS without any provisioning.

Small, strict, and boring in production

One static binary, one configuration file, no database, no zone transfers.

⇄

Both directions

PTR for the address, AAAA for the generated name — always consistent, because both come from the same function of the 128-bit address.

≡

AllKnowingDNS config, unchanged

Reads the AllKnowingDNS v1.7 format as is; its acceptance vectors are part of the test suite. %DIGITS% and %DIGITS-DASHED% templates.

✓

Config check with line numbers

--check-config reports every problem at once, rustc-style with a caret. SIGHUP reloads; a broken file keeps the running config.

⛨

Cannot be aborted by a query

Query names are parsed into a u128 or rejected — never used as text. Panics on the request path are denied by lint and caught as SERVFAIL.

⏱

Response rate limiting

On by default, with separate budgets for answers and negative responses, per-prefix aggregation and BIND-style slip.

↗

Hardened upstream

with upstream lookups are asynchronous, deadline-bound, behind a circuit breaker, and relayed only through a strict record allowlist.

§

Proper DNS citizen

Apex SOA and NS, SOA in negative answers (RFC 2308), EDNS(0), TCP, and BADVERS for unknown EDNS versions.

▣

Tiny, locked-down container

~5 MB distroless image for amd64/arm64, uid 65532, read-only root, all capabilities dropped. systemd unit with DynamicUser included.

Try the mapping

Type any address. This runs in your browser with the same rule the server applies: the host part becomes the hex digits in the name.

PTR query
PTR answer
AAAA of that name

The highlighted nibbles are the host part — 16 hex digits for a /64. Nothing is stored anywhere; the server does exactly this arithmetic per query.

The bug that started it

Why a rewrite instead of a patch.

AllKnowingDNS v1.7 (Perl, unmaintained since 2013) could be terminated by a single UDP packet. It built records by interpolating the attacker-controlled query name into a DNS master-file presentation string — and ; and " are not escaped there. One raw ; in a label made the parser die, nothing caught the exception, and the process exited.

PanoptiDNS makes that class of bug unrepresentable: names are never presentation text, a zone is an integer prefix and mask, and the request path cannot abort. Five further defects of the original — a 20 s blocking upstream lookup among them — each have a named regression test.

Security policy · Migrating from AllKnowingDNS

# attacker-controlled $qname → master-file text
Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata")

# one packet, no auth, endlessly repeatable
$ dig PTR 'a;b.0.c.c.c.e.0.0.1.8.b.d.0.1.0.0.2.ip6.arpa'
→ AllKnowingDNS: process exits
→ PanoptiDNS:    NXDOMAIN, keeps serving

Get started

Write a config, start the container, delegate the zones. Multi-arch images on GHCR and Docker Hub; pin an exact version like 0.2.0 in production.

1 · Configure and run

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

Save as panoptidns.conf next to the compose file, then validate and start:

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

2 · Delegate

; 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 static musl · distroless amd64 / arm64 105 tests · property tests systemd unit BSD-3-Clause

Replace AllKnowingDNS today

Same config file, same answers — without the remote kill switch.