Sponsored Links

Chrooted BIND on OS X

It seems that more often than not, when an ISP is having an outage, it's caused by the DNS servers being unresponsive. Let's cut them out of the loop.

In this article, I hope to show you how to set up BIND both as an authoritative and caching DNS server. These instructions will work with Mac OS 10.4.x and 10.5.x.

On my home network, BIND does two jobs: Firstly, it is authoritative for the domain stocksy.co.uk.
and secondly, I use it as a recursive name server to look up addresses of other computers, to do web browsing for example.

If you don't want to be authoritative for your domain, for example because someone else like your
ISP or hosting provider already looks after your domain, that's fine - you can just set up the caching name server.

At your firewall, you must open TCP and UDP port 53 incoming. The DNS server will need to make outgoing connections from any source port to destination port 53.

Starting BIND

The BIND daemon (called named) is already installed on OS X, you can confirm this:

$ named -v
BIND 9.2.2

Before BIND will start, it's necessary to create a new /etc/named.conf, since the
Apple-supplied one does not work well out of the box:

Update, 13th December 2008: Please take note that in previous versions
of this article, I used the option query-source address * port 53; in
my named.conf. Because of
the DNS vulnerability discovered by Dan Kaminsky, this is a very bad idea, since
the randomness of the UDP port is an important mitigating factor in the attack. If you
are currently using this option, you should disable it as soon as possible.

Those of you that have been paying attention will notice that named is running as root, this is a Really Bad Idea.
Lets take care of that...

Securing BIND

BIND has had a lot of security problems in the past, but its recent record is better. It's still considered
prudent to jail BIND and run it as its own user so that any vulnerabilities can't affect the rest of the system.

For OS X 10.4.x use niutil:

Use nireport to check for unused uid and gid values. I have chosen to start at 200 to avoid conflicts.

I dug around Google a bit and the prevailing theory seems to be that on OS X, named attempts an IPv6 lookup,
waits for this to timeout and then tries an IPv4 lookup. I tried adding listen-on-v6 { none; }; to the
/etc/named.conf options, but it made little difference. At this point, I lost patience and just compiled my own copy of BIND without IPv6 support:

Using Views

My web server is behind a firewall which NATs my internal network to private subnet. As a result, if I try and
visit my own web site to test it, the DNS server returns my external IP which does not work from inside. The way
around this is to use views, allowing BIND to return different answers depending on which IP is querying it.

Essentially, just create a new directory, /var/named/internal and copy all of your zone files into it.
All zones have to be in all views, regardless of whether you actually want to
offer different views for the zone:

Update, 13th December 2008: Please take note that in previous versions
of this article, I used the option query-source address * port 53; in
my named.conf. Because of
the DNS vulnerability discovered by Dan Kaminsky, this is a very bad idea, since
the randomness of the UDP port is an important mitigating factor in the attack. If you
are currently using this option, you should disable it as soon as possible.

This is just the /usr/local/sbin/named -c /etc/named.conf -u named -t /var/chroot/named but XMLised.
The -f option in the program arguments is needed to keep named in the foreground (i.e. don't daemonise),
otherwise launchd loses control of it.

As usual, check /var/log/system.log for any errors. If you feel like it, you could reboot to double check that
it really starts on boot.

1 Archived Comment

20th Jul 2010, 10:53:53 by huziaThis article's works to in SL (Snow Leopard) within my MBP (Macbook Pro), I've just tried it, though with a slight differences in killing named process. In the first named process killing, it should be replaced with:
kill -9 `cat /var/run/named/named.pid`

And in the second named process killing, it should be replaced with:
kill -9 `cat /var/chroot/named/var/run/named/named.pid`

After using launchd, if you want to kill named process, you should run this to minimize typing:
rm -r /var/run/named
rm -r /var/chroot/named/var/run/named
ln -s /var/chroot/named/var/run/named.pid /var/run/named.pid

Then if you want to kill/restart named, rather than going through the full path, you can go through the symbolic link instead:
kill -9 `cat /var/run/named.pid`

Oups, just don't forget to use sudo, or you can enable root if you want to.
Last word, Great post! :D