djbdns is not a monolithic server, like BIND. It consists of an assortment of daemons and
support utilities. The most important for most people are: tinydns, an authoritative DNS server; and dnscache, a caching-only recursive
resolver.
BIND typically fills two roles where it is setup:
- authoritative name resolution (paranoia.kuro5hin.org -> "Yes, www.kuro5hin.org is 209.208.150.45"). tinydns does this.
- Recursive name resolving with caching of results and periodic pruning (dnscache -> . server -> com. server -> kuro5hin.org DNS server for kuro5hin.org zone info). dnscache does this (in a few hundred kilobytes of ram).
(Note: there are a few other programs included in the suite, such as: pickdns, walldns, and rbldns. They are not discussed in this article. Please consult the official djbdns website for information on them.)
djbdns allows clear separation of these roles because of its design. If you are a home user, or want to provide DNS resolution services to a set of boxen, you simply need to setup dnscache and point them to it. dnscache will resolve names happily, in a secure fashion (always going to the root servers first, then on to the authoritative servers) for your client.
On the query answering side, tinydns will return answers from its 'data.cdb' file. You can rebuild the file at any time, and never have to worry about HUPing the server -- it will begin to use the new answers immediately. This allows for easy replication of DNS data via a secure channel (such as cron+scp), rather than by the much less widely deployed, and rarely effective, domain signing of BIND.
Ahh, this all sounds good, doesn't it? What's the catch? The catch is that tinydns and dnscache don't use anything like the BIND named.conf and zonefiles. Thankfully, the configuration of tinydns and dnscache is fairly logical (especially once you stop thinking in terms of BIND), and much easier to manipulate from within automatic scripts and maintenance programs. There are also included programs for compatibility with legacy BIND systems (such as axfr-get, which lets you be a secondary for BIND servers).
But, before we get into configuring tinydns and dnscache, it's good to have a working install. The following is a shell script which sets up tinydns on an external IP and dnscache on the loopback (the typical situation for a single-interface equiped authoritative DNS server):
#!/bin/sh
# Note: originally adapted from koeln.ccc.de/~drt/dnscacheforthecluless.html :)
# UID to run servers as
SUID=named
# UID to run logging process as
LUID=named
# External IP for tinydns to bind to
EXTERNALIP=216.115.108.243
mkdir /usr/local/src
cd /usr/local/src
wget cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
# ^^ provides assorted utilties
wget cr.yp.to/daemontools/daemontools-0.70.tar.gz
# ^^ starts/monitors the daemons.
wget cr.yp.to/djbdns/djbdns-1.05.tar.gz
# ^^ djbdns :)
tar -zxf ucspi-tcp-0.88.tar.gz
tar -zxf daemontools-0.70.tar.gz
tar -zxf djbdns-1.05.tar.gz
( cd ucspi-tcp-0.88 && make setup check )
( cd daemontools-0.70 && make setup check )
( cd djbdns-1.05 && make setup check )
/usr/local/bin/tinydns-conf $SUID $LUID /etc/tinydns $EXTERNALIP
/usr/local/bin/dnscache-conf $SUID $LUID /etc/dnscache 127.0.0.1
# If you would rather have dnscache bound to an internal LAN IP on a dual homed machine, and
# want people on the lan to be able to access it, comment out the above dnscache-conf line,
# and uncomment the following two lines:
#/usr/local/bin/dnscache-conf $SUID $LUID /etc/dnscache 192.168.0.1
#touch /etc/dnscache/root/ip/192.168
# The following lines configure the daemontools for control of dnscache and tinydns
mkdir /service
chmod 755 /service
cd /service
ln -s /etc/dnscache
ln -s /etc/tinydns
To start the daemontools, see djb's docs on svscan. I merely put "env - PATH=/usr/local/bin:/usr/sbin:/usr/bin:/bin svscan /service &" in /etc/rc.d/rc.inet2. It's worked without a problem for me.
Configuring dnscache for using alternate name servers for some domains is easy. You merely add a file to '/etc/dnscache/root/servers' which is named for the zone (such as 'thock.com'), and contains IPs of authoritative name servers on each line. OpenNIC was an idea proposed on Kuro5hin, which
later became a reality. The following example scriptlet sets up dnscache to work with OpenNIC:
#!/bin/sh
cd /etc/dnscache/root
# Note: I have modified these slightly from the ones on OpenNIC's page
# to have the format which dnscache wants.
wget web.thock.com/Dylan/dns/opennic.tlds
wget web.thock.com/Dylan/dns/opennic.servers
cd servers
cat ../opennic.tlds | xargs -l ln ../opennic.servers
svc -t /service/dnscache
echo Done!
Ping ns1.dev.null to be sure it works.
That's it for configuration of dnscache, although tinydns requires some further configuration. If you just want dnscache, comment out the tinydns-conf line and /etc/tinydns linking line. If you need to provide both recursive resolving and name serving from one interface, it can be done with some config tweaks (you can even skip the daemontools if you want).
With tinydns installed, the next hurdles are the zonefiles and how to replicate your data to the outside world.
Zonefiles in tinydns are very different from the equivalent files which BIND uses. A lot of new djbdns users have problems with this. tinydns zone files are very script/program friendly by having well defined data fields and values. Once you understand it, the format is very easy to work with:
Go look at the chart of djbdns record types located in the unofficial djbdns FAQ. It will help you understand the examples (as will cr.yp.to/djbdns/frombind.html and cr.yp.to/djbdns/tinydns-data.html.):
The first example zone is for a theoretical "lan" zone.
Zlan:zephyr.lan:root.zephyr.lan
&lan::zephyr.lan
@lan::zephyr.lan:10
=zephyr.lan:192.168.0.1
=shadowgate.lan:192.168.0.2
+web.shadowgate.lan:192.168.0.2
+www.shadowgate.lan:192.168.0.2
=kaneda.lan:192.168.9.3
=zeitgeist.lan:192.168.0.4
=tetsuo.lan:192.168.0.50
These lines tell tinydns about items in the 'lan' and '0.168.192.in-addr.arpa' zones. The 'Z' lines tell tinydns to claim authority for the name in the first field and everything beneath it. The '&' line defines an authoritative name server (note: if you list your nameserver in the SOA line, you can combine the SOA and NS into one like: .lan::zephyr.lan). The '@' sets up an MX record for 'lan' of priority 10 pointing to 'zephyr.lan.' The following '=' lines generate A records for the hosts in the first fields pointing to the IPs in the second fields. Since we've also claimed authority for the corresponding arpa zones, tinydns-data also generates appropriate PTR records for those hosts. The '+' lines simply generate A records. Note that we could have used CNAMEs ('C' lines) for the two extra shadowgate hosts, but since the tinydns-data data file format is so easy to manipulate, we can save querying clients some traffic and provide them with an A record instead (saving an extra query).
Of course, you don't have to manually rebuild all your zonefiles for tinydns. The axfr-get utility included in the djbdns package provides an easy way to translate all of your BIND backend zonefiles to tinydns backend zonefiles (other people have also contributed utilities for this job). The proper commandline to use for axfr-get transfers is 'tcpclient $IP_OF_BIND_SERVER 53 axfr-get $ZONE_NAME zone-$ZONE_NAME zone-$ZONE_NAME.tmp' Make sure you have the BIND named.conf acls setup such that the machine you are using for this conversion is allowed to transfer the entire zones.
The output of the program will look a bit like this:
#2001021602 auto axfr-get
Ztaslug.org.au:taslug.org.au.:root.taslug.org.au.:2001021602:300:300:300:300:300
&taslug.org.au::freeloader.taslug.org.au.au.:300
since it includes all the values that BIND gives it which are non-default (such as the serial #). If you then hash these data files into the data.cdb ('cat pz/zone-* > data; make' in the /etc/tinydns/root directory, assuming all zonefiles are named zone-* and stored in /etc/tinydns/root/pz), tinydns will be indistinguishable to from BIND to the outside world -- well, except for the part where script kiddies can't break in anymore :)
For my systems, I created a pz and sz directory within the /etc/tinydns/root structure. I store all zone files in the form 'zone-$HOSTNAME' for easy scriptability. Each day at 05:00, I have cron run a script as the 'named' user. The 'named' user has write permissions to the /etc/tinydns/root/sz directory so that it can axfr-get any zones from its BIND secondaries, and add them to its 'data.cdb.' The user also has write access to 'data' and 'data.cdb' for obvious reasons :)
The script cats the primary zone files into the data file. It then grabs the secondary zones from the BIND servers via axfr-get, and appends their information to the 'data' file. A new 'data.cdb' is then generated and copied (via scp) to the secondaries, where the 'named' user has write access to the 'data.cdb' file only. Since tinydns doesn't, as stated earlier, require HUPing, changes go into effect immediately. The system is relatively self-maintaining when properly setup.
But what are the risks involved with djbdns? You may not remember my article about auditing Kuro5hin's server (back when it was just one server), way back in April of 2000. The break-in recorded there occured via BIND. Thanks to my precautions in using djbdns, chances are we won't ever have to face that possibility in the future. Should tinydns have a flaw, the attacker would merely be able to spoof DNS results for a while. As tinydns is chrooted and run as a non-privileged user, the damage is limited and would not be a system-wide rootkiting. And since tinydns ships configured to be secure like that, it takes less work to reach this level of trustability. There's even a guarantee provided by Mr. Bernstein, which is better than the ISC's equivalent.
djbdns is not all smooth sailing. The biggest caveat for most is that djb refuses to include manpages with djbdns. He claims that his web pages will always be more complete. While technically true, people aren't always deploying the software on networks which are going to be connected to the Internet, or have Internet connections which are sporadic/inaccessible (perhaps because of DNS or other issues). Thankfully, Gerrit Pape has gone and converted djb's HTML documentation into manpage format -- the tarballs are available via FTP. Hopefully Mr. Bernstein will address this by at least including manpages with bright, bold warnings about possibly updated information on the web in the future. In addition, djbdns falls under Mr. Bernstein's non-licence licence. Some people may have issues with deploying this software because of it. Yet another common complaint is because of the machine-friendly log file format. There exist logformatters which turn dnscache logfiles or tinydns logfiles into a human readable format.
This article, comprehensive as I've made it for those new to djbdns, does not cover all of the programs in the suite, nor is it the final authority on all things djbdns. For example, pickdns, walldns, and rbldns are not discussed, being only mentioned in passing. Other utilties (such as dnsq, dnsqr, and dnstrace) are not mentioned at all. djbdns will also naturally change over time, so please be sure to verify your information against the official source before implementing djbdns in a production environment.
Here are some additional links you may find useful: the official DJBDNS page; the migration from BIND page; the unofficial djbdns home page (lots of great patches are collected here); Deuteron's djbdns page (Deuteron helped me migrate on IRC, and provided help with a few questions :)); djbdns ease-of-use vs. bind page; DJB's BIND bugs page; life with djbdns; and BIND related humour :)