DJBDNS on FreeBSD HOW-TO
Matt Simerson (msimerson@interland.com)
v.4, Dec 28, 2001


This document gives an overview of the roles of dns resolvers, caching name servers, and authoritative name servers. It then describes a step by step installation procedure for installing djbdns on a FreeBSD server.

The latest release of this document can be found at http://matt.simerson.net/computing/dns/djbdns-freebsd.shtml
For an introduction to DNS, go read http://www.lifewithdjbdns.org.

For the purposes of this How-To you need to understand what a dns resolver, cache, and server are and how they relate to each other. A dns resolver is a client program that runs on your host computer and figures out where a dns cache is that it can query for name resolution. Our resolver on FreeBSD is a set of C libraries (man resolver). By default (/etc/host.conf) the libraries check /etc/hosts for hostname to ip mappings. Then they check /etc/resolv.conf and query the nameservers listed therein.

A dns cache is a program that listens for requests for name resolution and they goes off to the internet and finds the answers. Caching name servers are normally recursive and will query first the root name servers, then the TLD servers, the domains delegated servers, and any subdelegations they have. The dns cache will also save the results until their TTL expiration or the limits of the cache are reached.

A dns server is a program that, when queried, returns authoritative answers for the zones for which it's authoritative.



Requirements

1. Computer: 486/33, 16MB RAM, 100MB storage. Recommended: P200/32/2GB
2. OS: FreeBSD 4 or higher.
3. Two IP addresses on your computer. Can be aliased or separate nics or one can be loopback.
4. Clue. (reasonable knowledge of Unix or Unix like OS's) Recommended: One competent system administrator.
5. Internet connection: A dialup will do.
6. Two hours of time. (It's not that hard, I'm just a verbose writer).


Installation

This is the easy part:

cd /usr/ports/sysutils/ucspi-tcp/; make install clean
cd /usr/ports/sysutils/daemontools/; make install clean
cd /usr/ports/net/djbdns; make install clean

One caveat to above instructions: If you are using dnscache on a very busy network with lots of queries, you're going to want to make some manual tweaks. How will you know? Check out the section below on setting up a huge network cache and pay particular attention to the section on logging.

At this point you have all the binaries on your system but they aren't doing anything.


Configuration

We're going to have daemontools supervising our processes and keeping them in line. To start with we'll create our /service directory and get it ready for population:

mkdir /service
fetch -o /usr/local/etc/rc.d/services.sh http://matt.simerson.net/computing/mail/toaster/services.txt
chmod 755 /usr/local/etc/rc.d/services.sh
ln -s /usr/local/etc/rc.d/services.sh /usr/local/sbin/services
rehash; services start

We should now have a process lurking around named "svscan". It watches the /service directory and starts up any services that have directories in there. Now we'll go ahead and get some services up and running. This is where things tend to start getting confusing to people. Rather than explain all the options, I'm going to simply present several types of configurations and you can select the one that fits you best:

Title
Duty
Example
IP's required
host cache Resolve queries only for itself. colocated server 1 public
network cache Resolve dns queries for my network Recursive server on small network. 1 public
huge network cache Resolve dns queries for my network Recursive caching server on very large network. 1 public
DNS + host cache Serve dns requests for zones we own and resolve dns queries for itself.. colocate dns server 1 public
DNS + net cache Serve dns requests for zones we own and resolve dns queries for our network(s). small network with domain(s). 2 public
Split horizon DNS + cache We have an internal network. The public internet needs to see only our external network addresses and hosts inside our network need to see our internal name space.We also want a caching server. Bastion hosts.

1 public
1 private

Once you've configured your dns servers and caches, you may want to do some twiddling. Scroll on down to the knobs and buttons section for more details. :-)


Host Cache

In this case we're only going to handle looking up requests for the host we're running on. Because of that, we'll only listen to requests on our fastest interface, loopback. We create our dnscache config by executing the following command:

dnscache-conf bind bin /usr/local/dnscache 127.0.0.1
ln -s /usr/local/dnscache /service/dnscache
echo "nameserver 127.0.0.1" > /etc/resolv.conf

Within 5 seconds svscan sees the symlink in /service and will start up dnscache. You're done, do a few lookups to test things out and you're finished.


Network Cache

Here we have a network of computers that we're going to point at this host for recursive name resolution. This means we can't go putting our dnscache on the loopback interface and must instead use an interface the hosts on our network can talk with. In this example, we just happen to have an Intel Pro100+ NIC card at fxp0 that we'll use. It's got an IP address of 192.168.254.1 so we'll create a dnscache service bound to that:

dnscache-conf bind bin /usr/local/dnscache 192.168.254.1
ln -s /usr/local/dnscache /service/dnscache

We have our dnscache up and running now but we need to tell it to accept connections from the rest of our network. By default, dnscache only listens to requests on the loopback interface. To tell it to listen to 192.168.254.0/24 we execute the following command:

touch /usr/local/dnscache/root/ip/192.168.254

Now any host in the 192.168.254 network can use our cache. We'll go ahead and tell the host we're on to use our new dnscache:

echo "nameserver 192.168.254.1" > /etc/resolv.conf

Do a few lookups from your host and a couple others on your network to test it out.


Huge Network Cache

Here we have a large network of computers that generate more requests in a day than most dns servers will see in a year. It's pretty much the same install process as Network cache above except with a few additional steps. Start by installing the cache as directed for "Network Cache". After installing, do the folloing:

cd /usr/local/dnscache
vi env/CACHESIZE

    524288000
vi env/DATALIMIT
    528288000

What that does is tell's dnscache to use 512 megs of RAM. I'm assuming if you have that large a network, 512 is a pretty minimal amount of RAM and you'll want to save bandwidth by building up a large cache.

We also want to bump up the maximum number of file descriptors (TCP/UDP Sockets) that dnscache can use. See the Max connections below in the knobs section.

And last but not least, you want to make sure your FreeBSD kernel will allow as many open file descriptors as you anticipate using. You can do this with FreeBSD by setting the maxusers parameter in your kernel config file and rebuilding your kernel. On FreeBSD 4.4 and later, maxusers is configurable at boot time. Another option is to simply bump up kern.maxfiles with sysctl (sysctl -w kern.maxfiles=20000). If you change your maxfiles, make sure to place a corresponding entry in /etc/sysctl.conf so that it gets increased after reboots.


DNS & host cache

First, create a dnscache for our local host to use for resolution as instructed above in "host cache". Then we'll set up a DNS server using tinydns.

Since we've already installed djbdns, we've got an authoritative servers "tinydns" already installed. We just need to set it up. We're going to install djbdns on our servers public interface so the rest of the world can talk to tinydns:

tinydns-conf bind bin /usr/local/tinydns 216.122.1.4
axfrdns-conf bind bin /usr/local/axfrdns /usr/local/tinydns 216.122.1.4
vi /usr/local/axfrdns/tcp; (and add the following line above the :deny statement)

:allow,AXFR=""

cd /usr/local/axfrdns; make; cd $owd
ln -s /usr/local/tinydns /service/
ln -s /usr/local/axfrdns /service/

You will, of course, need to substitute your machines IP address for the one I used in the example. Now we have tinydns listening to the UDP port of our external IP and axfrdns listening on the TCP port. The vast majority of requests will arrive via UDP and be served by tinydns but for some rare and practical reasons we also want to serve TCP requests as well.

There are a few things now that are important. By default axfrdns does not serve anything via TCP. We edited the tcp file and added the allow line so that if any of your DNS packets are larger than 512 bytes you'll be able to serve them. The other, and important feature of axfrdns is the ability to allow zone transfers (it's main purpose). This feature is off by default and you'll need to edit the "tcp" file appropriately to enable zone transfers.

The last step is to configure some data for tinydns to serve.


Knobs and Buttons

Most sysadmins like knobs and buttons to twiddle to milk every last drop of performance from their server. Djbdns has it's share of tools and settings you can tweak to make your shiny new server rocket across the NOC in a blazing trail of sparks.

Logging

By default, tinydns has pretty reasonable logging defaults but dnscache is very verbose and spits out reams of logs. If you have a quiet server this won't offend you much but on a busy network with lots of requests that translates into one very busy hard drive and a lower MTBF. So, we have a very simple solution. We can either disable logging completely or log selectively. I typically run with logging disabled and enable stats when I want to see them.

To change your log settings, edit the /service/dnscache/log/run file and change the the exec line to match one of the lines in the table below.

Logging stateLog line
disabledexec setuidgid bin multilog -*
logging onlyexec setuidgid bin multilog t '-*' +'*stats *' ./main
log + slurpexec setuidgid bin multilog t '-*' +'*stats *' +'*dump *' +'*slurp *' ./main

It should also be noted that you are still piping logs from dnscache to multilog which then discards them. If your CPU is pegged and you want a bit more of a performance tweak, edit the dnscache/run file and change "exec 2>&1" to "exec 1>/dev/null 2>&1". That entirely disables any and all logging.

What does those stats lines mean? The first number is the cache motion, the second is the number of bytes written to the cache, the third is outstanding UDP queries, and the fourth is outstanding TCP queries.

Maximum simultaneous connections

The number of maximum simultaneous connections dnscache can receive is controlled by the number of file descriptors (TCP/UDP Sockets) that dnscache is allocated. To increase that we need to edit the dnscache run file and increase the -o parameter. Bump -o up to something fun like a 1000.

After restarting dnscache it will accept up to 1000 simultaneous UDP requests. That should be sufficient for all but but the busiest of networks. I currently run with a value of 1500 which keeps my CPU warm and busy 90% of the time. :-)