Dan's bundle of DNS utils and servers is called DNScache, but that only begins
to describe it. DNScache consists of the following components, each of which
operate independently or in conjunction with each other to provide a complete
suite of DNS services that is capable of replacing BIND in most installations.
- dnscache - A client resolver daemon, it listens for UDP and TCP queries, recurses on behalf of clients, and caches answers based on simple rules that are designed to thwart cache poisoning attacks.
- tinydns - An authoritative DNS server, it listens for UDP queries, and
answers with zone data read directly from a fast hash database, and is immune
from cache poisoning because it doesn't have one.
- axfrdns - The zone transfer server, it reads data from the tinydns
database to satisfy zone transfer requests in order to provide interoperability
with BIND. It also answers client queries over TCP from the tinydns database.
- axfr-get - The zone transfer client, again for BIND interoperability.
- walldns - A specialized in-addr.arpa DNS server, it provides consistent forward and reverse resolution for your netblock without revealing any hostnames and
requires no zone data.
- pickdns - A load-balancing DNS server that can answer with different records
depending on the client source address.
- rbldns - A specialized DNS server suitable for serving lists of IP addresses, RBL-style.
All servers run chrooted, as a non-privileged userid. They are managed by
another package called daemontools,
which supervises the daemons, and allows the admin to send signals to managed
processes. Daemontools also manages the logs for the
programs it supervises. To support DNS over TCP or zone transfers, you'll also
need to get ucspi-tcp.
This review will focus on dnscache and tinydns, the tools most likely to be useful to most installations.
The caching client resolver component implements a number of design features that make it practically immune to attack. For one, its responses are given
with a TTL of zero, to make it difficult for hostile clients to discover when
the TTL expires for a particular record, which in turn makes it difficult to
mount some poisoning attacks that can affect BIND.
Because of this, dnscache is only suitable for listing in a client's
resolv.conf or equivalent. It should never be listed as
authoritative for a domain for this reason, and also because it never sets the
authoritative flag in its responses. This also means that it cannot
daisy-chain to another dnscache, as is often done with BIND in split-DNS
configurations. But no matter, dnscache has other features that make it
firewall-friendly. It reads a configuration file at startup which is the
equivalent of the BIND cache or hints file, and uses those servers as the
roots. Unlike BIND, it believes the sysadmin when he tells it who the roots
are. BIND queries the servers listed in its hints file, and uses their answers
to discover the roots. DNScache can also be told to ignore the roots for
particular domains, and query the designated servers directly. This allows it
to service queries for public domains and private domains without a messy
Its credibility rules are the heart of its poison avoidance strategy.
DNScache will not return or cache a response while recursing to resolve a
domain name unless it got the answer from the roots, the authorities for the
second-level domain, or the authority for the domain itself. It rigorously
refuses to believe any answer that does not descend from a chain of
delegations that can be traced to the roots (or from an admin override).
glue is discarded. Dr. Bernstein would like to see domain policies changed
so that all servers listed in the roots belong to the zone they are
authoritative for. This would eliminate the possibility of cache poisoning,
and simplify the administration of the registries. But it would also require
that the registries allow a single host (IP address) to have more than one name.
Finally, DNScache uses a configurable cache size, and will not exceed this limit. Records are normally expired according to the TTL given by the authority for
the domain. But if the cache size would exceed the admin's limit, records are
discarded in order of least-recently-used to make room for new ones. The
default size of 1Mb is probably too small for sites larger than a home DSL or
cable modem user. I'm using a cache size of 30Mb to service 2000 employees
and the production environment at CitySearch and Ticketmaster Online.
Our two DNS servers are refurbished Sun Ultra200E workstations with only 128Mb memory installed. Load never exceeds 0.5, even at the peak. Each DNS server runs
two instances of DNScache that are each listening on their own network segment.
Be aware that DNScache can be more stressful on a NAT device than BIND. It uses a random source port for each query, whereas BIND picks one source port at
startup and uses that for all queries. This means that each query made by DNScache
will be seen by a NAT device as a new session, even if it is to a nameserver that was just queried a moment ago. The sessions can mount up and
may overrun the resources of your NAT device. I am moving my NAT system to
the near side of our WAN link so that I can
run DNScache on the NAT system itself, and avoid creating 30,000 NAT sessions
on our IP-filter NAT box when
our weblog analyzer makes its daily romp through the log files.
This is the authoritative DNS server component. It reads zone data directly from
a fast hash database of Bernstein's design called
cdb or constant database. This
database is compiled from a text source file with a format that is easy for
programs (awk, sed, perl) to edit, and reasonably easy for humans to read and
edit. It's compact, and after a short period of use, I prefer it to BIND's
zone file format. Here's a sample zone file:
The 'Z' record signifies SOA. This is an optional record. If it is absent,
tinydns will create one for you. It uses the timestamp of the data.cdb database
as the serial number. Here, I have overridden the server and contact fields.
The serial, refresh, retry, maximum and other fields are created automatically
(and the defaults are very reasonable, so I don't worry about them).
The '.' records signify the NS, and also inform tinydns to set the
authoritative bit for NXDOMAIN responses for names underneath ticketmaster.com
that do not exist. In this example, I have also set the TTL to 5 days, though
if this is omitted, tinydns uses its default of 3 days for NS records.
This is in contrast to the '&' record, which in this example is a delegation
to our Alteon load-balancing gear (with a five minute TTL). Tinydns will
return the delegation, will not
set the authoritative flag, and will not return NXDOMAIN for names under
www.ticketmaster.com that do not exist.
There's a neat feature here that is obscured in my example. All you need
to setup your glue and your SOA is the '.' records. When the authority records
Tinydns automatically creates SOA, NS and A records corresponding to this in
BIND zone file format:
domain IN SOA a.ns.domain.com. hostmaster.domain.com.
( 962318946 16384 2048 1048576 2560 )
IN NS a.ns.domain.com.
IN NS b.ns.domain.com.
a IN A 220.127.116.11
b IN A 18.104.22.168
Likewise, the '@' record, signifying the MX for the domain, can setup in
one line all the records associated with an MX host:
This is equivalent to these BIND zone file records:
domain IN MX 10 a.mx.domain.com.
IN MX 20 b.mx.domain.com.
a IN A 22.214.171.124
b IN A 126.96.36.199
Note that in the ticketmaster.com example, I use out-of-zone MX and NS, so I leave the IP address
field blank, and just specify the fully qualified name of the NS and MX
hosts in the third field. I also specify priorities for the MX in the fourth
field. If this is omitted, tinydns supplies a priority of zero.
You'll notice that I specified authority for two in-addr.arpa domains. This enables the '=' record to create both A records and corresponding PTR records with
just one entry. The '+' record signifies only the A record, while the '^' record signifies a PTR.
There's another nifty feature that I want to touch on, which I have never
seen in another DNS server. You can specify a time in the future when a record
is to expire and be replaced by a new one. The timestamp is specified in
external tai64n format.
In this example, the domain www.heaven.af.mil will have the address 188.8.131.52
until 4000000038af1379 (2000-02-19 22:04:31 UTC), at which point it becomes
184.108.40.206. As that date approaches, the TTL of the expiring record is adjusted dynamically so that it will expire from caches at or shortly after the date of the timestamp.
DNScache includes utilities to convert tai64n to standard ISO format (useful for tailing dnscache log files, which also use the tai64n time format).
Performance and Operation
DNScache is easy to build. The build process is similar to that of Qmail. You
edit conf-home, conf-cc and conf-ld, and run make. The code is clean and well-formatted (I'm no C wizard, so take that assessment with a grain of salt :). It
compiles cleanly with no errors and few or no warnings on Linux, BSD, Solaris and Irix (in my experience), using either gcc or the vendor compiler. Any OS reasonably compliant with POSIX, and any compiler reasonably compliant with ANSI-C ought to suffice.
DNScache and tinydns are models of simplicity and economy. Even during
popular ticket sales at ticketmaster.com,
tinydns utilizes less than one percent of CPU time, and uses just 1688Kb of
memory on Solaris Sparc. Hundreds of thousands of visitors try all at once to login and buy tickets during popular on-sales (think Nsync or Ricky Martin).
Its memory footprint remains small (hence the tiny in tinydns)
regardless of how many domains it services. On average, tinydns services about
1.2 million DNS queries per day for all the domains I have converted to tinydns,
and none of the nameservers break a sweat. It has been completely reliable and
no trouble at all to operate. In addition, since all zone data are contained within a single hash database file, it is a simple matter to do away with zone transfers from the slave nameservers. I simply use rsync over SSH to send data.cdb to the slaves. Updates propagate instantly. One DNScache user has contributed a perl script to send NOTIFY messages to slaves that happen to run BIND. See
the DNScache FAQ for more information and
user-contributed patches, including IPv6 support.
Aside from the problem with excessive NAT sessions that I mentioned earlier, dnscache has performed like a champ. The mail relay for citysearch.com has been resolving queries through dnscache for three months now, and there have been no problems attributable to dnscache. This mail server relays over 35,000 newsletters, announcements and ordinary user-to-user messages each day. Granted, this volume doesn't approach that of, say Hotmail, but it's significant nonetheless, and
shows that the performance of dnscache is more than adequate for most installations.
In conclusion, I would say that DNScache is the first full-featured, non-proprietary replacement
for BIND I have encountered that addresses all the weaknesses of the program many of us love to hate.
Qmail showed that not all mail problems need to be solved by consulting the
"Bat Book". Likewise, DNScache shows that when you're in a BIND, you have other options than what are shown in the "Cricket Book".
It's a good thing that there are modern replacements for critical services, with design goals informed by past experience with the old standbys. DNScache easily deserves its place next to Qmail as one of those programs.