TinyDNS tinydns.org

How DNS resolves a name, and how the servers that do it are run.

Five servers, and what each was built to be good at

tinydns, and the file it answers from

The authoritative server D. J. Bernstein built refuses to recurse, refuses to query anything, and answers every question from a single prebuilt file — and that narrow scope is the entire design.

A terminal showing a compact data file, warm desk lamp beside the screen
Which server is installed matters less than the decision made before it was installed: answer for a zone, or resolve on somebody else’s behalf.Photograph

A resolver and an authoritative server are two different problems

DNS software has a long history of treating recursion and authoritative service as one job. BIND, the implementation that ran most of the internet through the 1990s, handled both in a single process. That pairing is convenient for operators who want one configuration file and one daemon to restart, but it means a bug in the recursive stack can compromise authoritative data, and a malformed authoritative response can be fed directly into the resolver's cache. The attack surface of either function includes the code of the other, whether or not the operator wanted both enabled.

Bernstein's response to this, in the djbdns suite released in 2001, was a hard split: tinydns handles authoritative service only, and dnscache handles recursion only. Neither speaks to the other at runtime, and neither can be made to perform the other's role. Why the two jobs were split apart is its own story, but the consequence for tinydns is that its entire codebase is shaped by what it is allowed to refuse — no recursive queries, no outbound resolution, no caching layer to maintain.

An adult engineer at an open rack door in an exchange-point facility, hand on a labelled cable
Cable labels are the only place a delegation is written down in the physical world. Where they disagree with the zone, the zone wins and nobody finds out for months.Photograph

The constant database and what it means for correctness

The most distinctive part of tinydns is not its scope restriction but its data model. Where BIND and its successors read zone files from disk and parse them into memory at startup (or on reload), tinydns answers from a CDB — a constant database. CDB is a file format Bernstein designed for fast, read-only lookup: a single hash-table file built once and then never modified in place. Adding or changing a record means rebuilding the entire file from the source data and replacing it atomically.

That atomic replacement is the point. A BIND zone reload reprocesses text files and updates live internal state; during that window, the server may be partially updated, or may reject a malformed record mid-file and leave the rest of the zone unloaded. The tinydns CDB swap is an atomic file rename ↗: the kernel either serves the old file or the new one — there is no intermediate state visible to a querying client.

CDB's lookup is also branch-minimal. Because the file is constant, there are no locks, no write paths, and no in-memory data structure to corrupt under concurrent load. A query arrives, the code computes a hash, seeks into the file, and returns an answer. The simplicity is not incidental — it is how tinydns achieves correctness guarantees that are difficult to obtain in a general-purpose server with a mutable runtime state. The CDB format specification ↗ is public and short enough to read in an afternoon.

What the data file contains, and what that rules out

tinydns source records are kept in a flat text file — typically called data — with a compact, line-oriented syntax. One line per record, a leading character encodes the type, and the fields follow colon-separated. The tinydns-data tool compiles this source file into the CDB. Because the compilation step is explicit and external to the server, a syntactically invalid record fails at build time, not at serve time. The running server cannot encounter a malformed record.

This also means tinydns has no notion of a live zone transfer in the conventional sense. Secondaries receive data by running their own tinydns-data compilation against a source that was replicated separately — by rsync, by a custom pipeline, by axfr-get (a companion tool) feeding a received AXFR back into the djbdns toolchain. The server itself never pulls from a primary; that pull happens in a separate process which then rebuilds the CDB and swaps it in. Dynamic update (RFC 2136) is not supported; the data file is not a writable structure at runtime.

SOA serial management follows from this: because the CDB is rebuilt entirely each time, serial numbers must be set correctly in the source data before each build. A serial that does not increment means secondaries will not see the new data — the same failure mode that plagues any implementation, but in djbdns it is particularly visible because the build step is deliberate and auditable. If no serial is given in the data file, tinydns-data derives it from the data file's modification time; an operator who wants control can set the serial explicitly.

NSD was built on an explicit authoritative-only philosophy — no recursion, no caching — and its architecture owes something to the same reasoning Bernstein put into print twenty years earlier.

What remains in use, and what it was built to demonstrate

djbdns entered public domain in 2007 ↗, and tinydns remains in production use in environments that prize its simplicity and its small, auditable codebase. Forks and packaging — including dbndns and the version maintained by various BSD ports trees — have extended it with IPv6 support and minor fixes, but the core data model is unchanged. The CDB answer file is still the center of the design.

tinydns does not implement DNSSEC signing; that was not part of the original design, and no widely adopted fork has added it in a way that matches the elegance of the rest of the architecture. Operators who need DNSSEC at the authoritative layer typically use NLnet Labs' NSD, ISC's BIND 9, or CZ.NIC's Knot DNS, all of which support online or offline signing workflows. What tinydns offers instead is a model of what an authoritative server strictly needs to do: read a prebuilt file, match a question to a record type, return an answer. Everything outside that scope is a separate process with a separate codebase.

That separation is still being rediscovered. NSD was built on an explicit authoritative-only philosophy — no recursion, no caching — and its architecture owes something to the same reasoning Bernstein put into print twenty years earlier. The lesson tinydns embodies is not that every authoritative server must use a constant database; it is that the authoritative function is narrow enough to be fully specified, and that narrowness makes verification possible. A server that cannot recurse cannot be tricked into doing so, and a file that cannot be written at runtime cannot be corrupted by a query.

A patch panel with numbered ports and neatly combed fibre looms
Numbered ports are a name’s last hop. Everything above them is a chain of referrals that exists only as records in other people’s zones.Photograph
A hand-annotated zone file printout on a desk beside a keyboard
The serial at the top of the file is the one line a secondary reads before deciding whether to pull anything at all.Photograph

What tinydns offers instead is a model of what an authoritative server strictly needs to do: read a prebuilt file, match a question to a record type, return an answer.

Read next, in this section