How to put BIND in jail
How to put BIND in jail
Ruben de Groot, 30-5-2002

This howto describes how the jail(8) command in FreeBSD can help you secure your nameserver by putting the nameserver and its configuration files in a restricted and separate environment.

Explanation of the jail environment
(from the manpage of jail)
Once a process has been put in a prison, it and its decendants cannot escape the prison. It is not possible to add a process to a preexisting prison.
Inside the prison, the concept of "superuser" is very diluted. In general, it can be assumed that nothing can be mangled from inside a prison which does not exist entirely inside that prison. For instance the directory tree below ``path'' can be manipulated all the ways a root can normally do it, including ``rm -rf /*'' but new device special nodes cannot be created because they reference shared resources (the device drivers in the kernel).
All IP activity will be forced to happen to/from the IP number specified, which should be an alias on one of the network interfaces.

Setting up the jail
First we need to create the directory tree where the jailed programs will live in. For this example we will use JAIL=/usr/local/jail as the root of our jail. Since nothing outside the jail can be reached by anything inside, we will have to put all the programs, libraries and configuration files needed in subdirectories of $JAIL.
The most important program to have in our jail is the nameserver daemon itself. We will use FreeBSD's stock /usr/sbin/named for this. We will also include /usr/libexec/named-xfer, so our nameserver will be able to transfer zoneinfo to and from other nameservers. Since ndc is used for interactively communicating with the nameserver and we ourselves will be outside the jail, ndc is not needed in the jail.
   # cd $JAIL
   # mkdir -p usr/sbin usr/libexec
   # cp -p /usr/sbin/named usr/sbin/
   # cp -p /usr/libexec/named-xfer usr/libexec/
Now we must check what libraries these two progams depend upon...
   # ldd /usr/sbin/named /usr/libexec/named-xfer
  => /usr/lib/ (0x280dd000)
  => /usr/lib/ (0x2809c000)
And copy these as well.
   # mkdir -p usr/lib
   # cp -p /usr/lib/ usr/lib/
Don't forget to copy the dynamic linker, or the shared libraries will not get loaded.
   # cp -p /usr/libexec/ usr/libexec/
Now that we have our programs in place it's time to think about the configuration files. Since the named program expects its main configuration file in /etc/namedb, we will create this directory in the jail and put our named.conf and zonefiles in there.
BIND will expect to be able to write to /dev/null, so we will create this too in the jail.
We will also need a user and group database in the jail. This doesn't need to be the same as in the "real" system, in fact, only the bind user and group should be included, since that's the user and group our nameserver will run as.
Finally, the named program will try to open two sockets in /var/run; one to communicate with the ndc program, and one for logging, read by syslogd. We will therefore create the var/run directory in the jail and make sure bind has write permissions in this directory.
The above can be archieved by executing the following commands:
   # mkdir -p etc/namedb dev
   # cp -p /dev/null dev/
   # echo "bind:*:53:" > etc/group
   # echo "bind:*:53:53::0:0:Bind Sandbox:/:/sbin/nologin" \
         > etc/master.passwd
   # pwd_mkdb -d $JAIL/etc $JAIL/etc/master.passwd
   # mkdir -p var/run && chown bind var/run
I will leave it up to you to populate the etc/namedb directory with your own named.conf and zonefiles.

Starting the jail
That's it. We've build our jail. Now it's time to get it up and running. Supposing w.x.y.z is the IP address you want your nameserver to listen on and HOSTNAME is the hostname of your nameserver, the command to start the jail is:
   # /usr/sbin/jail $JAIL $HOSTNAME w.x.y.z /usr/sbin/named -u bind -g bind
Communicating with the jail
As you might recall, named opens two sockets for communication with syslogd and ndc respectively. Since these sockets are now inside the jail subtree, we'll have to tell syslog and ndc not to look for these sockets in their usual location ( /var/run ), but in their corresponding location inside the jail. For example:
   # /usr/sbin/ndc -c $JAIL/var/run/ndc status
will give you the status of the nameserver. In the same way, as long as you use the "-c" option as indicated, you can use reload, reconfig and stop. The only thing you cannot do is (re)start the nameserver this way, because if you shut it down you will have shutdown the entire jail and only the jail command can start that again.
Finally, to enable logging to syslog, we must tell syslogd to listen on an extra socket, $JAIL/var/run/log, for logging information from our nameserver. The way to do this permanently is to add the option "-l /usr/local/jail/var/run/log" to the variable syslogd_flags in /etc/rc.conf.