Matt Simerson (

v0.9 - 09.08.2004 - Added Google Ads
v0.8 - 11.09.2002 - Updated for Jaguar

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 Mac OS X computer.

The latest release of this document can be found at x.shtml
For an introduction to DNS, go read

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 Mac OS X 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 sub-delegations 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.


1. Computer running Mac OS X.
2. Developer Tools must be installed
3. Two IP addresses on your computer. Can be aliased, separate nics, or one can be loopback.
4. Internet connection: A dial-up will do.
5. An hour of time.


get root! (sudo su)
curl -O
/Library/StartupItems/DJBware/DJBware start

You might want to look over the install script. It's straight forward if you can real Perl at all. If anything goes awry, fix it and run the script again. It's a smart script, it'll pick up where it left off and won't do anything unnecessary.

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. The echo line adds a call to start it up at boot time. 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:

IPs 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
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 daemon daemon /usr/local/dnscache
ln -s /usr/local/dnscache /service/dnscache
echo "nameserver" > /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. Of course this setup will work best if you have a static IP configuration. If you choose to use DHCP for your IP then you'll have to frequently update your network settings to use the local dns cache.

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 use my G3's internal 100BaseT port at en0. It's got an IP address of so we'll create a dnscache service bound to that:

dnscache-conf daemon daemon /usr/local/dnscache
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 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" > /etc/resolv.conf

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

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 daemon daemon /usr/local/tinydns
axfrdns-conf daemon daemon /usr/local/axfrdns /usr/local/tinydns
vi /usr/local/axfrdns/tcp; (and add the following line above the :deny statement)


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.


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 daemon multilog -*
logging onlyexec setuidgid daemon multilog t '-*' +'*stats *' ./main
log + slurpexec setuidgid daemon 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. :-)