rgbdns is a memory-safe Rust reimplementation of djbdns. The current runnable
slice provides djbdns-compatible tinydns text and CDB data, authoritative UDP
and TCP DNS, a DNSSEC-validating iterative cache, tinydns-get,
tinydns-data, axfrdns, axfr-get, rbldns, walldns, and dnsq, with
strict bounded packet parsing, IPv4/IPv6, wildcards, negative answers, and safe
OS-generated query IDs.
cargo test
IP=127.0.0.1 PORT=5353 cargo run --release --bin tinydns
IP=127.0.0.1 PORT=5354 cargo run --release --bin dnscache
IP=127.0.0.1 PORT=5355 cargo run --release --bin axfrdns
cargo run --release --bin axfr-get -- example 127.0.0.1:5355 data.new data.tmptinydns-data atomically compiles data to the original djbdns data.cdb
layout, and tinydns reads data.cdb by default. The loader bounds the database
and validates every key, value, name, and RDATA field rather than relying on
unchecked native-memory parsing. Set DATA=data to serve the text form
directly. See docs/compatibility.md for scope and
research.
dnscache performs iteration from config/root.hints, validates DNSSEC using
the bundled root trust anchor, randomizes UDP query IDs, ports, and letter case,
and only serves loopback clients by default. Set ALLOW_NETS to a comma-
separated CIDR list to authorize additional clients.
axfrdns is TCP-only and likewise permits loopback clients by default. Its
ALLOW_NETS setting accepts comma-separated IPv4 or IPv6 CIDRs.
Authoritative DNSSEC is entirely opt-in. With no dnssec policy file, rgbdns
uses the original djbdns-compatible data → tinydns-data → data.cdb path
and preserves its existing query, referral, ANAME, ACME, and service behavior.
When enabled, small utilities compose an offline signed snapshot: rgbsec-keygen
creates a protected ECDSA P-256 key, aname-materialize converts ANAME answers
to ordinary A/AAAA records, rgbsec-sign adds DNSKEY/NSEC/RRSIG records,
rgbsec-data compiles atomically, rgbsec-ds prints the parent DS, and
rgbsec-check verifies every signature and its remaining lifetime. tinydns
and all secondaries remain keyless; standard AXFR carries the finished DNSSEC
records. A K policy line signs a zone and a U line explicitly preserves an
unsigned zone, so one CDB can safely serve both. See
docs/DNSSEC.md.
Production configuration and application code are intentionally maintained outside this public implementation repository:
alexy/cronshowns the private consolidatedrgbdns.data,rgbdns.zones, BuddyNS policy, and deployment workflow fora.ns.cron.shandb.ns.cron.sh.querygraph/wishfullyowns the private Wishfully Vercel control plane and CLI. It submits reviewed DNS-state pull requests toalexy/cronsh.
No production zone data, deployment credential, or Wishfully application secret belongs in this repository.
The recursive client commands read DNSCACHEIP (a comma-separated list of IP
or IP:port endpoints) when set, otherwise they use /etc/resolv.conf.
rgbdns supports private ANAME directives for CNAME-like apex hosting without placing an invalid CNAME on the wire:
.example.com:192.0.2.53:ns1.example.com
Aexample.com:customer.blog-host.example:300
The A line resolves the target and synthesizes authoritative A and AAAA
answers owned by example.com; 300 seconds is the TTL cap. It may coexist
with the apex SOA, NS, MX, and TXT records, but not with A, AAAA, or CNAME at
the same owner. ANAME resolution uses DNSCACHEIP or /etc/resolv.conf.
ANAME directives survive AXFR between rgbdns peers through an explicitly
negotiated private extension. axfr-get requests it automatically; ordinary
AXFR clients receive only standard DNS records and no private metadata.
The standards-track proposal in
ietf/draft-khrabrov-dnsop-aname-axfr-00.xml
defines a portable ANAME RR, native AXFR/IXFR behavior, capability signaling,
DNSSEC and failure handling, and migration from rgbdns's experimental
encoding. Render it with make -C ietf; see ietf/README.md
for review and submission guidance.
The *-conf commands generate djbdns-style service directories. They reference
rgbdns's own setuidgid and multilog binaries by absolute path, so
daemontools is not a runtime dependency. multilog t ./main writes TAI64N
timestamps to main/current; optional s<size> and n<count> arguments set
the rotation threshold and retained-file count. Daemons continue to write
diagnostics to stderr, allowing the same binaries to work under daemontools,
systemd, containers, or another supervisor.
tinydns also writes one original-compatible request record to stderr by
default. The raw record deliberately has no timestamp, so systemd-journald or
multilog t can timestamp and rotate the same stream. Set QUERY_LOG=0, or
pass rgbdns-setup --query-log 0, only when per-request logging is
intentionally disabled.
rgbdns-log-report aggregates that stream by authoritative zone, including
subdomain queries, and reports total queries plus distinct client/resolver IP
addresses in descending-total order. Packages include an opt-in daily systemd
timer that reads the preceding local day from journald and delivers the report
through a sendmail-compatible mail transport. DNS query counts are not HTTP
pageviews or unique people.
The repository includes native Debian and openSUSE RPM packaging, hardened systemd services, and
an idempotent rgbdns-setup command for primary and secondary authoritative
servers. See docs/DEBIAN.md for package builds, account and
directory layout, tinydns data-file setup, firewalls, AXFR allow-lists, timed
secondary refresh, verification, upgrades, and troubleshooting. It includes a
complete example based on the cron.sh deployment topology. Live zone state is
kept in the private alexy/cronsh repository.
Primaries watch rgbdns.data, and secondaries watch a canonical
one-zone-per-line /var/lib/rgbdns/incoming/rgbdns.zones in managed state.
Publish either file through a .new name followed by a remote rename. rgbdns
validates and compiles primary data before activation, and validates secondary
lists before starting AXFR refresh.
rgbdns 0.4.0 accepts TCP RFC 2136 UPDATE messages authenticated with
HMAC-SHA256 TSIG for narrowly scoped ACME DNS-01 TXT records. Updates are
disabled by default. A key can modify only _acme-challenge owners in its
configured primary zone; accepted values are durable, immediately visible to
queries, assigned a monotonic SOA serial, and included in standard AXFR.
Create a 32-byte secret and configure a policy:
openssl rand -base64 32
sudoedit /etc/rgbdns/acme-update.confcertbot-chiefscientist. hmac-sha256. BASE64_SECRET chiefscientist.org. _acme-challenge. 60
Enable it while configuring the primary:
sudo rgbdns-setup primary --data rgbdns.data \
--acme-update-config /etc/rgbdns/acme-update.confCertbot's RFC 2136 credentials use the same server, key name, secret, and
HMAC-SHA256 algorithm. rgbdns-acme present and cleanup provide a local
manual-hook interface; cleanup removes only its specified value so overlapping
wildcard and ordinary validations remain safe. See RGBDNS_LETS.md
for the protocol, state, policy, security, and test design.
For the complete production-shaped fieldnotes.es example using
a.ns.cron.sh, b.ns.cron.sh, BuddyNS, primary data pickup, and secondary
zone-list pickup, follow
docs/RGBDNS_SETUP.md.
For the current openSUSE Leap 16.0 x86_64 AWS Marketplace AMI, see
docs/OPENSUSE.md. It covers launch, RPM build and install,
firewalld, the complete cron.sh primary, integrated AXFR, BuddyNS delegation,
systemd persistence, upgrades, removal, and troubleshooting.
On Debian or Ubuntu, build the package with:
sudo apt install build-essential cargo debhelper rustc
packaging/build-deb.sh
sudo apt install ../rgbdns_0.6.5_$(dpkg --print-architecture).debOn openSUSE Leap 16.0, build the RPM with:
sudo zypper --non-interactive install \
git cargo rust python3 rpm-build systemd-rpm-macros
packaging/build-rpm.sh
sudo zypper --non-interactive --no-gpg-checks install \
dist/rpmbuild/RPMS/x86_64/rgbdns-0.6.5-1.x86_64.rpmDNS from First Principles develops the protocol from
names and packets through authority, recursion, DNSSEC, transfers, operations,
and security, then maps each concept to rgbdns. It also compares systemd,
runit, s6/s6-rc, OpenRC, and container-native replacements for
svc/supervise.
The committed Obsidian reader vault adds a codebase-exploration part, collocates the full text/code surface, and bundles a reader plugin for chapter navigation and prose-to-code fragment jumps. See the vault guide to rebuild and validate it.
Build the FirstPair package with Pandoc and Typst:
docs/book/build.sh
docs/book/validate.shdocs/conformance.md maps implemented DNS requirements
to RFC-numbered, adversarial, property, live-network, and independent ldns
tests. docs/performance.md documents the stable-Rust
core benchmark:
cargo test --test rfc_conformance
cargo test --test wire_security
cargo bench --bench dns_core