D. J. Bernstein
Internet publication
djbdns

Upgrading from BIND

So you're tired of dealing with BIND's bugs. You've decided to switch to djbdns. Here's what you should do.

As you go through this process, please keep notes of exactly what you did and exactly what the computer did. Include the notes with any questions that you send to the dns mailing list.

Your current configuration

This page assumes that you have two BIND machines and two more machines ready to run DNS software:
IP address Name Running on port 53
1.8.7.33 dns1.panic.mil BIND server+cache
1.8.7.55 dns2.panic.mil BIND server+cache
1.8.7.91 Nothing yet
1.8.7.92 Nothing yet

The machines dns1.panic.mil and dns2.panic.mil have two functions:

Install the software

I assume that you have already installed ssh and rsync.

Download ucspi-tcp-0.88.tar.gz, daemontools-0.70.tar.gz, and djbdns-1.05.tar.gz in /usr/local/src on each machine, and install everything:

     gunzip < ucspi-tcp-0.88.tar.gz | tar -xf -
     ( cd ucspi-tcp-0.88; make setup check )
     gunzip < daemontools-0.70.tar.gz | tar -xf -
     ( cd daemontools-0.70; make setup check )
     gunzip < djbdns-1.05.tar.gz | tar -xf -
     ( cd djbdns-1.05; make setup check )

Then create /service and start svscan.

New caches: strategy 1

Strategy 1 assumes that you can easily change /etc/resolv.conf on all your machines. Here's the plan:
IP address Name Running on port 53
1.8.7.33 dns1.panic.mil BIND server
1.8.7.55 dns2.panic.mil BIND server
1.8.7.91 dnscache1.panic.mil dnscache
1.8.7.92 dnscache2.panic.mil dnscache

The first step is to run an external cache on IP address 1.8.7.91:

Do the same on IP address 1.8.7.92. For future reference, set up names dnscache1.panic.mil and dnscache2.panic.mil for 1.8.7.91 and 1.8.7.92.

Unlike BIND, dnscache uses a limited cache size; it smoothly discards old cache entries when the cache fills up. The default cache size is 1 megabyte. You can increase the cache size. You can also come back later and measure the effect of the cache size.

You can also configure dnscache to consult your DNS servers for panic.mil and other local domains. This will keep local domains accessible even if your connection to the Internet is down.

The second step is to put

     nameserver 1.8.7.91
     nameserver 1.8.7.92
into /etc/resolv.conf on every machine, replacing the previous nameserver lines. Start by changing /etc/resolv.conf on a single machine; try sending mail, using a web browser, etc. Once you're confident that dnscache works, change /etc/resolv.conf on the other machines.

New caches: strategy 2

Strategy 2 assumes that it's a pain to change /etc/resolv.conf. Perhaps you're an ISP and you've given your cache IP address to thousands of machines. Here's the plan:
IP address Old name New name Running on port 53
1.8.7.33 dns1.panic.mil dnscache1.panic.mil dnscache
1.8.7.55 dns2.panic.mil dnscache2.panic.mil dnscache
1.8.7.91 dns1.panic.mil BIND server
1.8.7.92 dns2.panic.mil BIND server

The first step is to separate your DNS service from your DNS caching:

This separation is recommended for all sites, even sites running BIND, so that caching can't interfere with incoming queries. It is already standard procedure at large sites. It is required for djbdns.

The second step is to replace the BIND cache on 1.8.7.33 with dnscache:

Then do the same on 1.8.7.55.

As in strategy 1, you may want to increase the dnscache cache size, and you may want to configure dnscache to consult your DNS servers for local domains.

New servers

Now it's time to replace the BIND servers with tinydns. The following description assumes for simplicity that you do not have any incoming zone transfers. You transfer zones from dns1.panic.mil to dns2.panic.mil, and perhaps to third-party servers, but you do not provide secondary service for zones whose primaries are at other sites.

The first step is to create a DNS service and a zone-transfer service on dns1.panic.mil:

Repeat the same steps on dns2.panic.mil, using the IP address of dns2.panic.mil instead of the IP address of dns1.panic.mil.

The second step is to arrange for replication of /service/tinydns/root/data from dns1.panic.mil to dns2.panic.mil. Edit /service/tinydns/root/Makefile on dns1.panic.mil to use rsync:

     remote: data.cdb
             rsync -az -e ssh data.cdb 1.8.7.55:/service/tinydns/root/data.cdb

     data.cdb: data
             /usr/local/bin/tinydns-data
Replace 1.8.7.55 with the IP address of dns2.panic.mil. Also edit /service/tinydns/root/data on dns2.panic.mil to remind yourself that dns2.panic.mil is replicated from dns1.panic.mil:
     # Do not edit data on dns2! data.cdb is copied from dns1.
     # The following line protects data.cdb by stopping make.
     9

The third step is to build /service/tinydns/root/data on dns1.panic.mil with all the host information from your BIND configuration files. Transfer the panic.mil zone from BIND:

     cd /etc/tinydns/root
     tcpclient dns1.panic.mil 53 axfr-get panic.mil zone-panic zone-panic.tmp
Do the same for all your other zones: e.g., axfr-get 8.1.in-addr.arpa zone-8 zone-8.tmp. Merge the zones into a data file, and compile the data file into a hashed database for tinydns:
     sort -u zone* > data
     make
You can use tinydns-get (on dns1 or dns2) to see exactly what information tinydns will provide in response to a query. You can also use dnsq to see what information BIND is providing:
     cd /service/tinydns/root
     tinydns-get a www.panic.mil
     dnsq a www.panic.mil dns1.panic.mil

The fourth step is to replace BIND with tinydns on dns1.panic.mil. Find and kill the BIND process. Then tell svscan about the new services:

     ln -s /etc/tinydns /etc/axfrdns /service
The services will start within five seconds. You don't have to rush; caches will talk to dns2.panic.mil when dns1.panic.mil isn't responding. Then make sure that BIND will not be restarted after reboot; under BSD it's enough to set named_flags=NO in /etc/rc.conf.

The fifth step is to replace BIND with tinydns on dns2.panic.mil.

Congratulations! You have escaped your BINDs.

Administration

After you make changes to data, type make to tell tinydns to publish the new information. If there's a syntax error, make will print a message on your screen, and tinydns will continue using the old information.

You can maintain data the same way you maintained your BIND zone files. Each line produced by axfr-get (except for the initial # ... auto axfr-get line, which you can remove) corresponds to a line in a BIND zone file:

     # panic.mil. 3600 IN SOA dns1.panic.mil. hostmaster.panic.mil. 10455 7200 3600 604800 3600
     Zpanic.mil:dns1.panic.mil.:hostmaster.panic.mil.:10455:7200:3600:604800:3600:3600
     # panic.mil. 86400 IN NS dns1.panic.mil.
     &panic.mil::dns1.panic.mil.:86400
     # panic.mil. 86400 IN MX 0 mail.panic.mil.
     @panic.mil::mail.panic.mil.:0:86400
     # www.panic.mil. 86400 IN A 1.8.7.99
     +www.panic.mil:1.8.7.99:86400
     # 99.7.8.1.in-addr.arpa. 86400 IN PTR www.panic.mil.
     ^99.7.8.1.in-addr.arpa:www.panic.mil.:86400
However, you can make your data much more concise and easier to manage by taking advantage of more features of tinydns-data, as described below.

Automatic serial numbers. With BIND-style administration, you have to increase the serial number in your Z line, 10455 in the above example, every time you change another line. (You don't have to worry about this if you aren't transferring zones to third-party servers; server replication through rsync to dns2.panic.mil doesn't rely on serial numbers.)

You can instead replace :10455: by :: and let tinydns-data generate a serial number from the modification time of the data file. WARNING: If your serial number is around 2000000000, you'll have to set it to 4000000000, and wait for your secondary servers to get the new zone, before you switch to the tinydns-data serial number. See RFC 2182, section 7, for further discussion of this silly procedure. (You don't have to worry about this if your secondary servers are using axfr-get for zone transfers.)

Automatic TTLs. You can remove the time-to-live field at the end of each line: e.g., +www.panic.mil:1.8.7.99: instead of +www.panic.mil:1.8.7.99:86400. tinydns-data will generate sensible TTLs for you.

Automatic colons. You can remove any colon at the end of a line: e.g., +www.panic.mil:1.8.7.99 instead of +www.panic.mil:1.8.7.99:.

Combined A and PTR records. You can merge +www.panic.mil:1.8.7.99 and ^99.7.8.1.in-addr.arpa:www.panic.mil. into =www.panic.mil:1.8.7.99. This also tells add-host to avoid reusing that host name or IP address.

Combined MX and A records. You can merge @panic.mil::mail.panic.mil.:0 and +mail.panic.mil:1.8.7.88 into @panic.mil:1.8.7.88:mail.panic.mil.:0.

Automatic MX preferences. You can omit MX preferences of 0: e.g., @panic.mil:1.8.7.88:mail.panic.mil. instead of @panic.mil:1.8.7.88:mail.panic.mil.:0.

Automatic final dots. mail.panic.mil and mail.panic.mil. are equivalent: e.g., @panic.mil:1.8.7.88:mail.panic.mil instead of @panic.mil:1.8.7.88:mail.panic.mil.. The final dot doesn't matter in any name that has a dot in the middle. A name without any dots, such as z, will be interpreted as z.mx.panic.mil in this context.

Combined NS and A records. You can merge &panic.mil::dns2.panic.mil and +dns2.panic.mil:1.8.7.55 into &panic.mil:1.8.7.55:dns2.panic.mil.

Automatic SOA timers. In your Z line you can replace the timers by blanks: e.g., Zpanic.mil:dns1.panic.mil:hostmaster.panic.mil instead of Zpanic.mil:dns1.panic.mil:hostmaster.panic.mil::7200:3600:604800:3600. tinydns-data will choose sensible timers for you.

More automatic SOA information. A simple Zpanic.mil means Zpanic.mil:a.ns.panic.mil:hostmaster.panic.mil. It isn't worth changing the server names for existing zones, but you can take advantage of the abbreviation for new zones.

Combined SOA, NS, and A records. You can merge Zpanic.mil and &panic.mil:1.8.7.55:dns2.panic.mil into .panic.mil:1.8.7.55:dns2.panic.mil.