Using a Local Root Zone with djbdns
Posted: Sun, 7 August 2011 | permalink | No comments
In my continuing war on the effects of [craptastic mobile Internet connectivity](http://hezmatt.org/~mpalmer/blog/2011/07/13/wireless-internet-is-the-future-my-arse.html), I came across a suggestion to [host a local copy of the root zone alongside your local DNS resolver](http://www.ietf.org/mail-archive/web/dnsop/current/msg00091.html). It's an interesting idea, so I've decided to give it a go, despite the potential problems (I'm confident I can manage the risks). I was surprised to find that nobody had a guide on setting this up using djbdns[^djbdns] so... I've written one. [^djbdns]: For all it's oddities, it's a very tidy piece of software, and takes up so little resources on a modern system that it's presence is practically invisible -- it uses less memory than `init`. If you're thinking of doing this yourself, heed some words of caution: It is *imperative* that you keep your local cache up to date. If you set this up, and don't maintain it, you will have a slow, gradual degradation of Internet service as the live root zone diverges from your local, out-of-date cache. If you set this up locally, just for yourself, that's one thing; all you're doing is breaking your own machine. If you want to do this for the ISP you run, though, you're doing your customers a grave disservice if you don't automate the cache update, and **setup some means of monitoring that your cache is kept up to date** (a SOA check against the live roots, or at least a check to make sure that your `data.cdb` file is no more than a couple of days old). # The Design For simplicity, I decided to run a dedicated `tinydns` instance that *only* serves the root zone. This makes it easy to periodically refresh the root zone that I serve with a script, which I run daily, without needing to integrate with the database of any other `tinydns` instances I've got running (I have a couple on my laptop for testing). I've set this up on an arbitrary loopback address (`127.53.53.53`), so it's inaccessable from anywhere other than localhost, and so my local `dnscache` instance just forwards root zone requests to it. # Setup the infrastructure * Install gnupg (make sure you've also got the `gpgv` utility) and the necessary tools to build a minimal C program (such as `build-essential` on Debian). * As the user you're going to run the daily update script as, run the following: gpg --primary-keyring ~/.gnupg/trustedkeys.gpg --recv-keys 20E3C425 * Build/install `https://github.com/derat/bind-to-tinydns`, because the root zone is provided in BIND zonefile format, and... we don't want that. git clone git://github.com/derat/bind-to-tinydns.git btt cd btt make sudo cp bind-to-tinydns /usr/local/bin/ * Setup your local root-zone-only tinydns (these commands assume my local structure for daemontools-using programs; adapt to suit) sudo tinydns-conf tinydns tinydns /var/lib/service/tinydns-root 127.53.53.53 sudo ln -s /var/lib/service/tinydns-root /etc/service/tinydns-root * Since some root zone records can be too large for a standard DNS UDP packet, you'll need to have an `axfrdns` running as well; this is pretty straightforward too: sudo axfrdns-conf tinydns tinydns \ /var/lib/service/axfrdns-root /var/lib/service/tinydns-root 127.53.53.53 echo 127.0.0.1:allow |sudo tee /var/lib/service/axfrdns-root/tcp sudo tcprules /var/lib/service/axfrdns-root/tcp.cdb \ /var/lib/service/axfrdns-root/tcp.tmp < /var/lib/service/axfrdns-root/tcp sudo ln -s /var/lib/service/axfrdns-root /etc/service/axfrdns-root * Let the user who will be running the daily update script update the `data.cdb` file: sudo touch /etc/service/tinydns-root/root/data.cdb sudo chown someuser /etc/service/tinydns-root/root/data.cdb You've now got a minimal `tinydns` suitable for serving a local cache of the root zone to anyone on your local machine who asks. But where's the data? # Script the root zone processing The following script should do the job nicely. Drop it somewhere useful and `chmod a+x` it. If you put your `tinydns` somewhere else, change the `TINYDNS_DATA` variable at the top. Run it once by hand to "seed" your root cache, then add it to cron for a nightly update. #!/bin/sh set -e TINYDNS_DATA="/etc/service/tinydns-root/root/data.cdb" ########################################################################### WORKDIR="$(mktemp -d)" trap "rm -rf ${WORKDIR}" EXIT cd "$WORKDIR" wget -q http://www.internic.net/domain/root.zone.gz wget -q http://www.internic.net/domain/root.zone.gz.sig if ! gpgv root.zone.gz.sig root.zone.gz >/dev/null 2>&1; then echo "Root zone signature validation failed -- this is probably really bad" >&2 exit 1 fi gzip -d root.zone.gz egrep -v '[[:space:]]IN[[:space:]]+(RRSIG|DNSKEY|DS|NSEC)[[:space:]]' root.zone \ | /usr/local/bin/bind-to-tinydns . data btttmp tinydns-data cp data.cdb "${TINYDNS_DATA}" # Test The simplest test, to make sure you've got everything running, is just to request something from the root zone: dig @127.53.53.53 com IN NS If you get something useful (compare against `dig com IN NS` for a sanity check) then everything's probably working well. # Point dnscache to your local root server echo 127.53.53.53 >/etc/service/dnscache/root/servers/@ svc -k /etc/service/dnscache And you're away.
Post a comment
All comments are held for moderation; markdown formatting accepted.