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, I came across a suggestion to host a local copy of the root zone alongside your local DNS resolver. 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 djbdns1 so… I’ve written one.
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 asbuild-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.
-
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
. ↩
Post a comment
All comments are held for moderation; markdown formatting accepted.