6.5. djbdnsIf after reading or skimming my BIND hints you're still suspicious of BIND's size, complexity, and history, you may wish to try djbdns, Daniel J. Bernstein's lightweight but robust alternative. While this section makes particular note of djbdns's security features, the intent is to provide a general primer on djbdns use. This is (hopefully) justified for two reasons. First, the very act of choosing djbdns rather than BIND has positive security ramifications, if for no other reason than it "diversifies the DNS gene pool." Second, while widely used, djbdns hasn't yet received much treatment in the print media, so this primer is one of the first of its kind (if not the first). If neither of these assumptions seems compelling to you, you needn't feel guilty for sticking with BIND (provided you run Version 9 and take the time to configure, secure, and maintain it carefully). For what it's worth, I'm a BIND v9 user myself. 6.5.1. What Is djbdns?BIND can be considered the nuclear-powered kitchen sink, blender, and floor polisher of DNS software. It gurgles busily in the corner and occasionally springs a leak or explodes. Despite its market share, it's an old machine with spotty maintenance records. djbdns, then, is the set of tools that you'd find at a DNS specialty store: simple, secure, fast, and safe when used as directed. Almost unnoticed, this package serves millions of domain names every day at large Internet domain-hosting companies and other busy sites, such as DirectNIC, NameZero, Interland, and TicketMaster. You may be surprised to learn that tinydns (the public nameserver component of djbdns) is the second most used nameserver on the Internet. A 2002 survey of 22 million .com domains (http://cr.yp.to/surveys/dns1l) showed that 70% were served by BIND, and 8% by tinydns. A 2004 survey of almost 38 million domains (http://mydbs.bboy.net/survey/), which included .com, .net, .org, .info, and .biz domains, showed a 15.5% share for tinydns. On average, tinydns handled more domains per server (446) than BIND (72) or Microsoft DNS Server (21).The software is very reliable. It just keeps running without human intervention, other than to modify domain data. Memory use is limited, processes are monitored and restarted when needed, and logs are automatically rotated to avoid filling up the disk. I rarely have to worry about it, which says a lot. Like BIND, djbdns is free software for Unix and Unix-like systems. djbdns can replace BIND or coexist as a primary or secondary nameserver. djbdns comprises servers, clients, libraries, and helper services (see Table 6-2). We'll discuss how to install and configure the main components shortly. First, let's see why djbdns was written and what problems it solves. 6.5.1.1 Why not BIND?In a nutshell, djbdns was written in response to problems with BIND's security, complexity, and performance. It therefore makes sense to talk about what djbdns is in the context of how it relates to BIND. Table 6-3 shows such a comparison.
6.5.2. Choosing djbdns Servicesdjbdns is modular by design: you choose and run only the parts you need on a given system. There are three main servers and one client in djbdns, corresponding to each of its major functions: dnscache A caching (or proxy) nameserver. It has no data of its own but manages a local DNS cache for local clients such as web browsers. DNS queries from clients are directed to dnscache; dnscache in turn asks the public root nameservers, follows the trail to delegated (authoritative) nameservers, gets the results, and caches these results locally to speed up later queries. It can serve a single machine or a group. It is never authoritative for a domain. dnscache accepts only recursive queries. tinydns An authoritative (or content) nameserver. It serves information about your domains to machines on the public Internet. It does not cache and does not return information about domains for which it has no authority. tinydns answers iterative queries. axfrdns Transfers zone data from a primary tinydns nameserver to a secondary nameserver, such as BIND. axfr-get Requests zone-data transfers from a primary nameserver such as BIND to a secondary tinydns nameserver. The separation of these functions in djbdns requires you to decide what name services you want to provide and where. Here's a guide for the most common situations: If you have one Unix machine and you only want to provide caching name services to local client programs, install an internal DNS cache with dnscache. If you have multiple machines, you can install an internal DNS cache with dnscache on each machine or an external DNS cache on one machine (dnscachex) to serve its neighbors. If you manage some domains and want to provide lookup services to these for the Internet, install the authoritative DNS server, tinydns. If you manage some domains and want redundancy, install tinydns on more than one server and transfer data among them with rsync and ssh. If you install tinydns but also need to transfer zone data to BIND (with tinydns as a primary or master server), install axfrdns. If you install tinydns but also need to accept zone data from BIND (with tinydns as a secondary or slave server), install axfr-get. 6.5.3. How djbdns WorksFigure 6-3 shows the components and data flow for dnscache. This server uses only a memory cache. If the record is found in the cache and has not expired, it's returned directly. Otherwise, dnscache looks it up. For a new domain, it starts with the most authoritative servers and follows the delegations down. This avoids cache poisoning (bad data in a DNS cache) from following a forged glue record (shortcut server name resolution). Figure 6-3. dnscache architecture and data flow![]() Figure 6-4 shows tinydns, axfrdns, and axfr-get, each performing separate functions: Figure 6-4. tinydns family architecture and data flow![]() A Adds or modifies a nameserver record for a host like www.example.com. If you provide authoritative host data to the Internet for example.com, this is where you'd work. B Queries an authoritative tinydns nameserver for a www.example.com record. External clients and servers looking up example.com hosts would follow this path. C Transfers zone data for www.example2.com to a secondary nameserver like BIND. axfrdns may send a notify request to the secondary to encourage it to request the data now rather than waiting for an expiration time. D Transfers zone data for www.example3.com from a primary nameserver like BIND. The data is saved to a local file in tinydns-data format but is not automatically merged with the main datafile used by functions A or B. Note that there is no connection between dnscache and any of these. 6.5.4. Installing djbdnsOnce you've decided which role or roles your djbdns nameserver is to fill, you can install the appropriate packages. All djbdns installations have certain packages in common. 6.5.4.1 Installing the service manager: daemontoolsThe standard installation of djbdns requires daemontools to be installed first. These utilities start the djbdns servers and keep them running. Why another set of tools? These also were written in response to bugs and inconsistencies in popular Unix utilities like syslogd and inetd. The daemontools are simple to install and very reliable, so try them and see how you like them. Although there are RPMs from various sources, installing from source is recommended and well documented. Here's how: Using wget (or your favorite HTTP client), download the daemontools tarball (see http://cr.yp.to/daemontools/installl for the latest version): $ wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz Unpack the distribution: $ tar xvzf daemontools-0.76.tar.gz $ rm daemontools-0.76.tar.gz $ cd admin/daemontools-0.76 As root, compile and configure: # ./package/install This installation script does the following: Compiles the programs. Creates the directory /command and fills it with some programs. Creates symbolic links from /usr/local/bin to programs in /command. Creates the directory /service. Adds this line to the file /command/svscanboot: SV:123456:respawn:/command/svscanboot This starts /command/svscan, which monitors the /service directory for something to do. We'll give it something to do shortly.
6.5.4.2 Installing djbdns itselfOnce daemontools is compiled and in place, it's time to install djbdns proper: Download the latest tarball (see http://cr.yp.to/djbdns/installl for the latest version information): $ wget http://cr.yp.to/djbdns/djbdns-1.05.tar.gz Unpack the distribution: $ tar xvzf djbdns-1.05.tar.gz $ rm djbdns-1.05.tar.gz $ cd djbdns-1.05 If your system has glibc 2.3.x or higher (e.g., Red Hat 9, Fedora), you need to change the declaration of errno, since it is no longer a simple global integer. Near the top of the file error.h, change: extern int errno; to #include <errno.h> Compile: $ make Become root, and install the programs under /usr/local/bin: # make setup check 6.5.4.3 Installing an internal cache: dnscacheIf you want to offer DNS caching services to one or more local machines, then you will need to install dnscache. Create a user for dnscache and another user for logging: # adduser -s /bin/false dnscache # adduser -s /bin/false dnslog Decide what IP address to use for dnscache. If the DNS cache is only for your local machine, a good choice is your localhost address, 127.0.0.1. (This is also the default if you don't supply an address.) To provide a DNS cache for multiple machines, see the upcoming section on dnscachex. Choose a directory for the server and its associated files. The conventional one is /etc/dnscache. Create the dnscache service directory dir, and then associate the server with the dnscache account acct, with the log account logacct, and with port 53 (UDP and TCP) on address ip. This is the command to do all of this (except creating the service directory, which you must do manually): dnscache-conf acct logacct dir ip Using our example choices, we get the following: # /usr/local/bin/dnscache-conf dnscache dnslog /etc/dnscache 127.0.0.1 The addresses of some of the ICANN root servers (*.root-servers.net) have changed since djbdns 1.0.5 was released. The djbdns root servers file (/etc/dnscache/root/servers/@) needs to be changed to reflect this. It contains one address per line. You can edit the file directly, using these addresses, which were current in early 2004: 198.41.0.4 192.228.79.201 192.33.4.12 128.8.10.90 192.203.230.10 192.5.5.241 192.112.36.4 128.63.2.53 192.36.148.17 192.58.128.30 193.0.14.129 198.32.64.12 202.12.27.33 Or you can use the djbdns tools to get them: dnsip `dnsqr ns . | awk '/answer:/ { print $5 ; }' | sort` > /etc/dnscache/root/servers/@ Still another way is to download ftp://ftp.internet.net/domain/named.root, yank the server addresses from the A records, and save them to /etc/dnscache/root/servers/@. Tell daemontools to manage the new service: # ln -s /etc/dnscache /service Make sure your local resolver uses the new server. Edit the file /etc/resolv.conf to reflect the fact that you are now running dnscache: nameserver 127.0.0.1 That's it! You are now the proud owner of a caching nameserver. Run some applications that will call your system's resolver libraries. djbdns includes the utilities dnsqr, dnsip, and dnsname (these are all described later in this chapter). You can also use ping or host, but avoid nslookup, which is unpredictable in this context. To see what's happening under the hood, let's have a look at what turns up in the dnscache logs after we look up the address for www.slashdot.org: $ tail /service/dnscache/log/main/current @400000003bd238e539184794 rr 401c4337 86400 ns slashdot.org. ns1.andover.net. @400000003bd238e539185f04 rr 401c4337 86400 ns slashdot.org. ns2.andover.net. @400000003bd238e53918728c rr 401c4337 86400 ns slashdot.org. ns3.andover.net. @400000003bd238e539188614 rr 401c4337 86400 cname www.slashdot.org. slashdot.org. @400000003bd238e539189d84 cached 1 slashdot.org. @400000003bd238e53918a93c sent 627215 64 @400000003bd238f62b686b4c query 627216 7f000001:1214:a938 12 20.113.25.24.in-addr. arpa. @400000003bd238f62b689644 cached 12 20.113.25.24.in-addr.arpa. @400000003bd238f62b68a9cc sent 627216 88 The log is ASCII, but it's not very human-readable. The first field is a TAI64 timestamp, which is mighty impressive: it has a one-second resolution and a range of billions of years (Unix time will overflow a signed 32-bit integer in the year 2038). The other fields encode various aspects of the DNS messages. Run the logs through a filter such as tinydns-log.pl (available at http://tinydns.org/tinydns-log.pl.txt) to see a more useful format: 10-20 21:54:19 rr 64.28.67.55 086400 a slashdot.org. 64.28.67.150 10-20 21:54:19 rr 64.28.67.55 086400 ns slashdot.org. ns1.andover.net. 10-20 21:54:19 rr 64.28.67.55 086400 ns slashdot.org. ns2.andover.net. 10-20 21:54:19 rr 64.28.67.55 086400 ns slashdot.org. ns3.andover.net. 10-20 21:54:19 rr 64.28.67.55 086400 cname www.slashdot.org. slashdot.org. 10-20 21:54:19 cached a slashdot.org. 10-20 21:54:19 sent 627215 10-20 21:54:36 query 627216 127.0.0.1:4628:43320 ptr 20.113.25.24.in-addr.arpa. 10-20 21:54:36 cached ptr 20.113.25.24.in-addr.arpa. 10-20 21:54:36 sent 627216 6.5.4.4 Installing an "external" cache: dnscachexIf you want to provide a DNS cache to more than one machine in a local network, you need to choose an address that all of these machines can access. This address is "external" to the client machines but within your firewall. If you are within a protected network, you can use the address of the machine. You cannot run dnscache and tinydns on the same address, since both use UDP port 53. It's conventional to call the service dnscachex when serving multiple clients, and dnscache for a single client. For this example, assume the service address is 192.168.100.9 and the local network serves 192.168.100 addresses: Create users dnscache and dnslog as described earlier for dnscache: # adduser -s /bin/false dnscache # adduser -s /bin/false dnslog Create the dnscachex service directory: # /usr/local/bin/dnscache-conf dnscache dnslog /etc/dnscachex 192.168.100.9 Start dnscachex by connecting it to daemontools: # ln -s /etc/dnscachex /service Permit other machines in the local network to access this external cache: # touch /etc/dnscachex/root/ip/192.168.100 You don't need to restart the server. Modify the /etc/resolv.conf file on each machine that will be using the dnscachex server: nameserver 192.168.100.9 Test the client machines with ping or other applications as described earlier for dnscache. 6.5.4.5 Installing an "external" forwarding cacheFor each machine running dnscache, you need to poke a hole in your firewall for UDP port 53. Using a single external cache (dnscachex) limits exposure to a single machine. You can also chain caches so that a dnscache inside your firewall talks only with a dnscache outside your firewall or in your DMZ. If you've set up a dnscachex server inside your firewall, run this command on the client machines: echo 1 > /service/dnscache/env/FORWARDONLY Do not do this on the dnscachex server. Just change the nameserver address in /etc/named.conf to that of the dnscache server on the other side of your firewall. 6.5.4.6 Split horizonYou may want to offer a split horizon DNS service, giving clients within your network access to internal and external nameservers. To borrow a phrase from the Perl community, there's more than one way to do it: Use a forwarding cache. For each internal domain that you want to handle specially, create a file of the same name under /service/dnscache/root/servers and use the IP address of the content server for that domain as that file's content. For example, if you have an internal nameserver at address 192.168.1.23 describing the mighty internal network at hackenbush.com, do this: echo 192.168.1.23 > /service/dnscache/root/servers/hackenbush.com Use tagged records in your internal tinydns nameservers. These are similar to BIND views, and are described later under tinydns. 6.5.4.7 Installing a DNS server: tinydnsIf you want an authoritative nameserver for your domains, install tinydns: Create a user for tinydns and another user for its logging (if you installed dnscache, you already have the second user): # adduser -s /bin/false tinydns # adduser -s /bin/false dnslog Pick a public IP address for tinydns. dnscache and tinydns must run on different IP addresses, since they both use UDP port 53. If you're running both on one machine, use the loopback address (127.0.0.1) for dnscache and the public address for tinydns. If you're running dnscachex on the machine's public address, allocate another IP with ifconfig and use that for tinydns. The tinydns-conf syntax is similar to dnscache-conf: tinydns-conf acct logacct dir ip Assuming that you've chosen to use the public address 208.209.210.211, configure the service like this: # /usr/local/bin/tinydns-conf tinydns dnslog /etc/tinydns 208.209.210.211 Activate the service by giving svscan a link on which to act: # ln -s /etc/tinydns /service tinydns will now be running, but without any data to serve. Let's do something about that. 6.5.5. Running tinydnsNow it's time to add some data to your nameserver. You can do this in two ways: Use tinydns's helper applications. These are shell scripts that call tinydns-edit with default values and check the database for consistency as you make modifications. Edit the tinydns datafile directly. This gives you more control but less automatic checking. 6.5.5.1 Helper applicationsLet's use the helpers first. These all modify the text file data while checking with the authoritative database file, data.cdb: Become root. Go to the tinydns data directory: # cd /service/tinydns/root Add a primary nameserver entry for your domain: # ./add-ns hackenbush.com 192.193.194.195 Add a secondary nameserver entry for your domain: # ./add-childns hackenbush.com 200.201.202.203 Add a host entry: # ./add-host hugo.hackenbush.com 192.193.194.200 Add an alias for the same address: # ./add-alias another.hackenbush.com 192.193.194.200 Add a mail server entry: # ./add-mx mail.hackenbush.com 192.193.194.201 Make these additions public (convert data to data.cdb): # make tinydns will serve these immediately. Let's see what these helper applications actually did, and then we can learn how to modify the results by hand. 6.5.5.2 The tinydns-data formatThe helper applications modify the data file, a text file that uses the tinydns-data format. This format is simple, compact, and easy to modify. Here are the lines created by the helper-application examples in the previous section: .hackenbush.com:192.193.194.195:a:259200 &hackenbush.com:200.201.202.203:a:259200 =hugo.hackenbush.com:192.193.194.200:86400 +another.hackenbush.com:192.193.194.200:86400 @mail.hackenbush.com:192.193.194.201:a::86400 Rather than using the helper applications, we could have created the lines with a text editor and used the default ttl values: .hackenbush.com:192.193.194.195:a &hackenbush.com:200.201.202.203:a =hugo.hackenbush.com:192.193.194.200 +another.hackenbush.com:192.193.194.200 @mail.hackenbush.com:192.193.194.201:a If the primary nameserver was within our domain (at a.ns.hackenbush.com) but a secondary nameserver was at ns.flywheel.com, here's how to specify it: .hackenbush.com:192.193.194.195:a &hackenbush.com::ns.flywheel.com If the primary nameserver was at ns.flywheel.com, here's how to specify that: .hackenbush.com::ns.flywheel.com A few characters perform a lot of work and help avoid some common sources of error in BIND zone files: Records starting with a dot (.) create an SOA record, an NS record, and an A record if an IP address was specified. Records starting with an equals sign (=) create A and PTR records. 6.5.5.3 tinydns-data referenceEach record (line) in a tinydns-data (formatted) file starts with an identifying character. Fields are separated by colons. Trailing fields and their colons may be omitted, and their default values will be used. Table 6-4 describes some fields common to many types of tinydns-data records.
The next table, Table 6-5, shows the correspondence between tinydns helper applications and equivalent lines in data; you can specify your data either way. Notice that the helper applications require IP addresses rather than names; if you wish to specify a name insteador the ttl, ts, or loc fieldsyou need to edit the data file. The less common record types shown in Table 6-6 have no helper applications. After making changes to a datafile, type make. This runs the tinydns-data program to convert data to data.cdb. The conversion will only overwrite the existing database if the source data is consistent. tinydns will start serving the new data immediately. Some tinydns-backed sites actually keep their zone data in databases (SQL or LDAP) or separate files for ease of editing, and generate the tinydns datafile when needed. 6.5.6. Running djbdns client programsIn addition to its server daemons and support processes, djbdns includes client utilities (Table 6-7). These perform the same functions as BIND's old utilities, nslookup and dig, and are useful for troubleshooting and testing your DNS infrastructure. They work with any nameserver, not just tinydns. 6.5.7. Coexisting with BINDYou may decide to install some components of djbdns on your servers to handle name-service duties. By choice or necessity, you may need to share these duties with an existing BIND installation. This section describes how to exchange zone data between nameservers running djbdns and BIND. 6.5.7.1 Installing ucspi-tcpYou first need to install a small external toolkit, also written by Bernstein, called ucspi-tcp. This contains the tcpserver and tcpclient programs. Similar to inetd, they manage external access to TCP-based clients and servers, but they do so more reliably due to better load and resource controls. Follow these steps to install ucspi-tcp: Using wget (or the HTTP tool of your choice), download the latest tarball from http://cr.yp.to/ucspi-tcp/installl: $ wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz Extract: $ tar xvzf ucspi-tcp-0.88.tar.gz Fix errno.h, if needed: $ cd ucspi-tcp.0.88 $ vi error.h Change: extern int errno; to: #include <errno.h> Build: $ make As root, install under /usr/local/bin: $ make setup check 6.5.7.2 Running axfr-getThe axfr-get client requests a zone transfer from a nameserver via AXFR. The syntax is as follows: axfr-get dom file tmpfile This requests a zone transfer for domain dom. The data are first written to the file tmpfile in tinydns-data format. The first line written to tmpfile is a comment with the zone's serial number. If the transfer is successful, tmpfile is renamed to file. Make sure you request only data for zones where your tinydns server is a secondary server. Merge this data with that for which your tinydns server is primary in the tinydns datafile /service/tinydns/root/data. A simple solution is this addition to /service/tinydns/root/Makefile. Our sample tinydns server is a.ns.hackenbush.com, and we are providing secondary name services for the domain flywheel.com, whose nameserver is ns.flywheel.com: all: data.cdb flywheel.data: /usr/local/bin/tcpclient -i a.ns.hackenbush.com 53 /usr/local/bin/axfr-get flywheel.com flywheel.data flywheel.tmp data: hackenbush.data flywheel.data cat *.data > data data.cdb: data /usr/local/bin/tinydns-data Run make as often as necessary to get flywheel's data. Axfr-get does not support NOTIFY (RFC 1996) or IXFR (RFC 1995). It does not automatically send an AXFR request to the primary external nameserver when the SOA's refresh timeout expires; you need to ensure that axfr-get is called often enough (such as in an hourly cron job). It will first get the SOA and check its serial number. If it's larger than the local value, then it will request the zone data via AXFR. It would be nice to have a server version of axfr-get that handles BIND primaries the same way as BIND secondaries. Then we would have a complete drop-in replacement for a BIND secondary (unless you're using DNSSEC or an experimental protocol). 6.5.7.3 Installing axfrdnsaxfrdns uses TCP port 53, so it can share an IP with tinydns, which uses UDP port 53. Assuming you'll use the IP 192.193.194.195, follow these steps: Create the service directory: # axfrdns-conf axfrdns dnslog /etc/axfrdns /etc/tinydns 192.193.194.195 # cd /etc/axfrdns Edit the tcp file to allow zone transfers from 200.201.202.203 for hackenbush.com and its reverse: 200.201.202.203:allow,AXFR="hackenbush.com,194.193.192.in-addr.arpa" Get tcp into a binary format: # make Tell daemontools about the service: # ln -s /etc/axfrdns /service 6.5.7.4 Running axfrdnsThe secondary server will request a zone transfer from axfrdns when the TTL of the zone's SOA record expires. axfrdns will serve the zone from the same authoritative database used by tinydns: data.cdb. You can also cause the secondary server to request a zone transfer immediately by sending it a notify message. Although not a part of standard djbdns, the Perl script tinydns-notify (available online at http://www.sericyb.com.au/tinydns-notify) can be used for this. axfrdns only responds to AXFR requests, and it transfers whole zones. If an external nameserver like BIND makes an IXFR request to axfrdns, it will fail. RFC 1995 says the requester should then try AXFR (RFC 1995), but a bug in some versions of BIND prevents this. The problem is fixed by any of these: Patch axfrdns to accept IXFR; get http://www.fefe.de/dns/djbdns-1.05-ixfr.diff.gz. Upgrade BIND to Version 9.2 or higher. Configure BIND with request-ixfr no;. For incremental and secure transfers, Bernstein recommends using rsync and ssh instead of AXFR and IXFR. 6.5.8. Encrypting Zone Transfers with rsync and sshIf you're using djbdns on all your servers, you don't need to transfer domain data with AXFR. Instead, you can use rsync and ssh for incremental secure transfers: If you haven't already, install the rsync and ssh servers and clients. Start the rsync and sshd daemons on the secondary server. Give the primary server permission to write to the secondary server via ssh. Edit /service/tinydns/root/Makefile. If your secondary server's address is 192.193.194.195, your Makefile should look like this: remote: data.cdb rsync -az -e ssh data.cdb 192.193.194.195:/service/tinydns/root/data.cdb data.cdb: data /usr/local/bin/tinydns-data You will normally be prompted for a passphrase by ssh. To avoid this, create a key pair and copy the public key to the user's directory on the secondary server. Details can be found in the SSH sections of Chapter 4. That's it! Now, whenever you make changes to tinydns, whether through the helper applications or by directly editing zone files and typing make to publish them, the database data.cdb will be copied to the secondary server. Using rsync guarantees that only changed portions will be copied. Using ssh guarantees that the data will be encrypted in transit and protected against snooping or modification. Alternatively, you can rsync the datafile rather than the data.cdb database and then run make on the secondary server to create the database. 6.5.9. Migrating from BINDIf you are only using BIND as a caching server, then installing dnscache will replace BIND completely. Don't forget to turn off the named process. If BIND is serving data on your domains and it's configured like most, it can be replaced by tinydns. Some newer features like DNSSEC and IXFR are not supported, but ssh and rsync provide simpler and better functionality. Bernstein describes at length how to migrate your site from BIND to tinydns in http://cr.yp.to/djbdns/frombindl. This description includes the following: Using axfr-get to get zone data from a BIND server and convert it to tinydns-data format Replacing serial numbers and TTLs with automatic values Merging record types Testing your setup while BIND is running and replacing it gracefully |