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.

Don't forget to copy the dynamic linker, or the shared libraries will not
get loaded.

# cp -p /usr/libexec/ld-elf.so.1 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:

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:

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.