FreeBSD BIND-to-djbdns Migration Guide / HOWTO

Introduction

Why djbdns?

Why switch to djbdns? The majority of the internet uses ISC’s BIND for its dns server. BIND is the so-called „standard“ DNS server. But BIND has been plagued with security issues since it was written. ISC has recently made public their desire to make BIND security advisories semi-private, effectively limiting access to security information to those they deem worthy. There has never been a better time to switch to djbdns.

  • Unlike BIND, djbdns is secure. It runs un-privileged, under a chrooted, read-only user account. djbdns comes with a security guarantee.
  • Small memory footprint. djbdns, even when running a relatively maxed-out configuration, uses a surprisingly low amount of memory. BIND will keep using memory until it is all gone. You can tell djbdns exactly how much memory to use.
  • Zone file format is much easier to use, unlike the format that BIND uses, which is prone to typographical errors, and is very difficult to write automated scripts for, due to its convolution.

Requirements

Before even attempting to install djbdns, the following requirements must be met:

  • You must be running UNIX or a UNIX-like operating system. Most UNIX and UNIX-like operating systems are supported. The only UNIX-like OS explicitly not supported is SCO UnixWare.
  • You must have a working compiler (duh). If your compiler cannot be called using „cc“, you will have to edit the conf-* files in the djbdns source tree in order to tell make what to use.

Our djbdns installation

djbdns is extremely flexible. This document will concentrate on getting djbdns up and running in a minimal amount of time, with your BIND data files. It is not designed to be a hand-holding walkthrough. I will suggest places that you could possibly put your files, but the minutiae of your installation are really up to you.

This document will only discuss setting up dnscache, tinydns, and axfrdns. If you need to use the other programs that come with djbdns, I assume you are technical enough to figure out how to use them yourself.

This document assumes that:

  • You have at least a rudimentary knowledge of UNIX and how it works.
  • You have at least a rudimentary knowledge of DNS and how it works.
  • You know how to add users, and set up init files on your particular flavor/distribution.
  • You are using GNU tar / gzip / binutils / gcc and other utilities.

1. Important Concepts

djbdns differs from BIND in many ways (surprise). The most important difference is in how djbdns differentiates between a cache and an authoritative nameserver. Or rather, that djbdns DOES make this distinction, while BIND doesn’t. BIND is a jack-of-all-trades, keeping all of its functions in one monolithic program. djbdns is a collection of programs, which together can accomplish the same tasks as BIND. In this document we will be concentrating on three programs within djbdns, specifically:

  1. dnscache – a non-authoritative DNS cache. It receives recursive queries from hosts and collects responses from remote DNS servers. It caches these responses for later use.
  2. tinydns – an authoritative, UDP-only DNS server. It accepts queries from remote hosts and responds with locally configured information.
  3. axfrdns – a DNS zone-transfer server. axfrdns makes local DNS information available via TCP, to servers issuing zone-transfer requests.

2. RTFM

Before you actually attempt to install djbdns, you should read some of the docs that are available at cr.yp.to. To administer a DNS server takes technical knowledge and understanding, and in order to administer djbdns, you must fully understand many concepts, some of which I will explain in the next section.

3. Create djbdns user accounts.

Now we will create several user accounts. I prefer to create a different account for each service, although it is certainly possible to run all of them under the same account. So, we need to create users for dnscache, tinydns and axfrdns and a log account (for which I use dnslog). The group name should preferably be a group that doesn’t have access to any files, such as nofiles or nogroup.

The following commands should work on most Linux distributions, and Solaris:

# pw useradd dnscache -g nogroup -s /bin/false 
# pw useradd tinydns -g nogroup -s /bin/false 
# pw useradd axfrdns -g nogroup -s /bin/false  
# pw useradd dnslog -g nogroup -s /bin/false 

4. Downloading and unpacking the source.

The first step in installing djbdns is to install the necessary files from the Internet using FreeBSD Ports.

The packages you will need in order to follow this document are:

djbdns
ucspi-tcp
daemontools

(We’ll need to become root now.)

root:/root# cd /usr/ports/dns/djbdns ; make install

6. Set up daemontools.

Once you’ve compiled the daemontools programs, you need to create the daemontools service directory. Dan suggests /var/service, although people may have valid reasons for not wanting to use this. The good news is that your service directory can be anywhere you want it. I personally use /var/service, and that’s how this document will proceed.

First, install from ports:

    
root:/# usr/ports/sysutils/daemontools ; make install
root:/# echo 'svscan_enable="YES"' >> /etc/rc.conf
root:/# /usr/local/etc/rc.d/svscan.sh start

You can start up svscan.

7. Set up a local cache.

Thanks to djb, setting up a local cache is incredibly easy. You will probably want to do this first.

The first thing we will do is use dnscache-conf to create a local cache on 127.0.0.1:

root:/# dnscache-conf dnscache dnslog /etc/dnscache 127.0.0.1

After dnscache-conf is done, you should have something like this in /etc/dnscache:

root:/# ls -l /etc/dnscache/
total 5
drwxr-sr-x    4 dnscache users        1024 Jun 12  2000 log
drwxr-sr-x    4 dnscache users        1024 Mar 23  2000 root
-rwxr-xr-x    1 dnscache users         236 Mar 23  2000 run
-rw-------    1 dnscache users         128 Mar 23  2000 seed

The next part is tricky. We want to keep BIND running on the external interfaces, but start up dnscache on 127.0.0.1. In order to do this, you need to know exactly which IP’s that BIND needs to run on (or, all of the external IP’s on the box). Add these IP’s to the options {}; section of your named.conf in the following manner:

listen-on { a.b.c.d; e.f.g.h; etc... };

Make sure you put all important IP’s that BIND needs to listen on in this section. Once you’ve done that, you should issue an ndc restart. If you do this correctly, BIND should stop listening on 127.0.0.1, and we will be free to set up dnscache there. Of course, if you are not doing this on a server that is running an important BIND installation, you may want to shut down BIND altogether in order to avoid this unnecessary complication.

Once you have stopped BIND, you can link /etc/dnscache into your service directory as follows:

root:/# cd /var/service
root:/service# ln -s /etc/dnscache .

After you perform this step, assuming that svscan is up and running, you should have a dnscache instance running on 127.0.0.1 within a few seconds. You can test this using ps, or by issuing an nslookup. There is nothing else to configure – dnscache knows all about the loopback zone and does DNS for 127.0.0.1 and 1.0.0.127.in-addr.arpa automatically.

8. Set up an external cache.

After your local cache is up and running, you’ll probably want to set up an external cache to handle requests from clients. In order to do this you will need a spare external IP. You can repeat the named.conf procedure above to free up an IP.

Run dnscache-conf again, but this time use /etc/dnscachex instead of /etc/dnscache, and for the IP, put in your external IP instead of 127.0.0.1:

root:/# dnscache-conf dnscache dnslog /etc/dnscachex a.b.c.d

If all went well, you should now have a directory similar to /etc/dnscache in /etc/dnscachex. The only difference is that now you must manually enter /etc/dnscachex/root/ip and add the networks that you’d like to be able to query your server:

root:/# cd /etc/dnscachex/root/ip
root:/etc/dnscachex/root/ip# touch a.b.c
root:/etc/dnscachex/root/ip# touch x.y

This tells dnscache to allow queryes from a.b.c.* and x.y.*.* . See http://cr.yp.to/djbdns/faq/cachex.html#config for more information.

Once your cache has been configured, go ahead an link it into /service:

root:/# cd /var/service
root:/service# ln -s /etc/dnscachex .

A second dnscache process should start up within a few seconds. Test dnscachex by issuing queries locally and from other machines.

9. Set up an authoritative DNS server.

After both caches (internal and external) have been set up, you are now ready to install tinydns as your authoritative DNS server. This server should run on the current primary IP address that you use for BIND. The first step (as usual) is to create the tinydns directory:

root:/# tinydns-conf tinydns dnslog /etc/tinydns a.b.c.d

Now we will begin by moving over your BIND data files. The best way to do this is to make a list of all your zones, in a text file. We can then use a small script to pull each zone off of your BIND installation via a zone transfer. For this, we will use the axfr-get program. Here is an example of a script that will pull zone files (contained in file ‘foo’) from BIND:

#!/bin/sh
mkdir -p /root/djbdns
PATH=$PATH:/usr/local/bin
MASTER=a.b.c.d  # The IP address of the server we're getting the zones from

for ZONE in `cat foo`; do
        tcpclient "$MASTER" 53 axfr-get "$ZONE" "$ZONE" "$ZONE".tmp
        cat "$ZONE" | sort -ur > "$ZONE".tmp
        mv "$ZONE".tmp zones/"$ZONE"
done

When the script completes, you should now have a copy of each zone in a different file. In order for tinydns to use these zones, they must be concatenated into a file called ‘data’ in /etc/tinydns/root. Once this file has all of the needed information, run ‘make’ in /etc/tinydns/root to generate data.cdb, which is the file that tinydns actually reads from.

I wrote a small script called „combine.sh“

#!/bin/sh
# concatenates individual tinydns zone files into single „data“ file.

PATH=$PATH:/usr/local/bin
export PATH

cd /etc/tinydns/root

cat << EOF > data
# This is an automatically generated file.
# If you wish to change the contents please edit the files in
# /etc/tinydns/root/master/zones and
# /etc/tinydns/root/slave/zones

EOF
#cat master/zones/* >> data
#cat slave/zones/* >> data
cat /root/djbdns/zones/* >> data
make

# could do an rsync here

to concatenate my zone files into the tinydns master data file. I keep my master and slave zones separated in two different directories, but you don’t have to do that. You will need to modify combine.sh for your own use.

When I converted my personal systems, I took my time and went through each zone, and sanity checked it, before making the data file for tinydns. BIND gives a whole lot of extra information, and this all gets pulled into your djbdns zone files. It might (or might not) be worth your while to go through each and every zone and make sure that it is efficient as possible. I would highly suggest reading the documentation on the tinydns zone file format, especially if you will be the one admining DNS.

Once your zone files are ready and data.cdb is created, you are ready to switch your main DNS over to tinydns. I suggest you become familiar with the svc command before starting up tinydns, in case you need to stop the service for any reason. (For example, you screwed something up and need to restart BIND.)

Take a deep breath, and stop BIND by using your init script (or however your system happens to do it.) Once BIND is stopped, you are ready to link /etc/tinydns to /service:

root:/# cd /var/service
root:/service# ln -s /etc/tinydns .

tinydns should come up within a few seconds. You can check to make sure it is running with ps. I would suggest running dig and nslookup from several hosts to make sure it is working properly.

10. Set up a DNS zone-transfer server.

You will want to set up a zone-transfer (AXFR) server if you intend to use BIND for your secondary DNS services, or any secondary DNS servers that are not under your direct control. If you are running djbdns on all of your servers, you can skip this part, as there are plenty of more efficient ways of moving your DNS data between your master and slave servers (rsync, for example).

The first step in setting up a zone-transfer server is to create /etc/axfrdns using the axfrdns-conf program:

root:/# axfrdns-conf axfrdns dnslog /etc/axfrdns /etc/tinydns a.b.c.d

You should run axfrdns on the same IP address that you run tinydns on. Since axfrdns reads from tinydns’s data.cdb file, there is no more configuration necessary, except making sure that the axfrdns user account actually has permission to read /etc/tinydns/data.cdb. You can control access to zone transfers by editing /etc/axfrdns/tcp and adding access for the hosts you need. The format of „tcp“ is standard tcprules access control, and should be familiar to anyone running qmail with ucspi-tcp. The documentation for this format can be found at http://cr.yp.to/ucspi-tcp/tcprules.html. Once the rules are added, type „make“ in /etc/axfrdns to generate the cdb file.

Once everything looks good, link /etc/axfrdns to /service (as shown in the above examples), and the process should start shortly. Test your server and make sure zone transfers are working. You can use host -l domain or the dig program to make zone transfer requests.

The following are some other sites that should be of interest to anyone running djbdns: