Dave Lugo
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
version 1.03 updated March 5, 2000
On a firewall system it may be desireable to run dual dns servers. This allows internal clients to have a local view of a domain (mydomain.com for example), while external (Internet) clients have a different view, being served from a different name server daemon/zone file.
The servers are chrooted for security reasons. It's a good practice on a firewall to run chrootable services chrooted, and with minimal priviliges.
The internal server daemon listens on the internal network interface. It has whatever zone files that it needs to provide an intranet's local dns needs. For internal dns queries that don't refer to a local host, it forwards the request to the external named daemon.
The external server daemon listens on the external network interface and the loopback interface. It handles dns queries from external clients, as well as handling the forwarded requests from the internal named daemon.
Please note that these instructions are for a Redhat 6.0 install. Minimal tweaking may be needed for other Linux distributions which is not covered here.
Download what you need
What you'll need to grab to do this:
The latest production source for BIND from www.isc.org
For getting syslogged data out of the chroot tree, you have 2 choices:
If your syslogd supports the "-a <socket>" option , you can use that. A quick look at a few Redhat systems I have leads me to believe that you should be fine as long as your version of Redhat is at least 5.1. Check the man page or do a "syslogd -v " and check the output. If it is 1.3-3 or higher you should be ok.
If you can't or don't want to use the syslogd option, you can use holelogd. It is part of the utils-1.0 package at www.obtuse.com. This document covers both methods.
Building what you need and creating the chroot area
First, if you're using holelogd, extract and build the utils-1.0 package. You may see some warning messages when you compile the package, but as long as holelogd itself compiles ok, we're happy. Don't do a make install, as we'll be copying the newly-produced holelogd executable into the chrooted tree later.
If you're planning on using syslogd , this would be a good time to look at the man page for syslogd, because in a few minutes you'll need to edit your /etc/rc.d/init.d/syslog script.
Next, extract and build BIND. If you do a "make install" after building you _may_ want to go back and delete the newly-installed named and named-xfer daemons, as we'll be installing those in the chrooted tree.
Now we need to create the directory tree, for this example we'll set up everything under /usr/local/bind:
mkdir /usr/local/bind cd /usr/local/bind mkdir dbfiles_external mkdir dbfiles_internal mkdir dev mkdir etc mkdir lib mkdir sbin
The dev directory will need a null device file. I originally didn't bother with this, but for some reason zone-xfers would fail if this was missing.
mknod -m 666 /usr/local/bind/dev/null c 1 3
The etc directory will need a few things: passwd and group files with only one entry each - the named user and named group. You should make sure the UID and GID you use are unique. Don't forget to add the chroot named user/group to your non-chrooted /etc/passwd and /etc/group, so that an "ls -l" in the chroot area will show name and group instead of UID/GID. You'll also need copies of /etc/ld.so.cache and /etc/localtime. At this point you should also chown the dbfiles_* dirs.
The lib directory will need libc and a few other things. The list here is what works for me under RedHat 6.0, your mileage may vary. You *can* use strace to assist in debugging, see troubleshooting (at the end of this document).
We'll need to copy over the holelogd (if you're using it instead of passing the "-a <socket>" option to syslogd), named, and named-xfer executables. Depending on where you compiled them you may need to adjust the cp commands. Copying holelogd to a different name (as below) makes things easier if you run multiple holelogd instances (as you might if you chroot other things).You can also strip the executables to save space:
cd /usr/local/bind/sbin cp /usr/src/bind-8.2.2p5/src/bin/named/named . cp /usr/src/bind-8.2.2p5/src/bin/named-xfer/named-xfer . cp /usr/src/utils-1.0/holelogd holelogd.named (or not, if using syslogd) strip named named-xfer holelogd.named
We'll need a named.conf in each of the dbfiles directories. The domain name we use (on both internal and external servers) will be identical, but because we run two named daemons, the external named can have different data for the same domain.
We also lock things down a bit, using the allow-query and allow-transfer statements available as part of BIND.
Disclaimer: This document is not a primer on BIND. You should buy the book, it's worth it.
Disclaimer#2: The example files here have bogus domain name and address values. You will need to provide correct ones.
Our domain name will be somedomain.com
#====================================================== # named.conf for dbfiles_external directory. # # NOTE: Comments in this file begin with a # symbol. # # NOTE: Remember we're chrooted. Don't break the paths # below by forgetting that. #====================================================== options { directory "/dbfiles_external"; pid-file "/dbfiles_external/external.pid"; named-xfer "/sbin/named-xfer"; # # depending on how/if you packet filter, you may # want this. AFAIK, it doesn't hurt. query-source address * port 53; # # global options set to only allow queries from # us. We explicitly allow our served zones to be # queried on a per-zone basis later in this file. allow-query { 192.168.1.0/24; 127.0.0.1; 172.16.10.1; }; # # specify the external IP and loopback addresses here. listen-on { 172.16.10.1; 127.0.0.1; }; };
controls{ unix "/dbfiles_external/ndc_external" perm 0600 owner 0 group 0; };
zone "somedomain.com" in { type master; file "db.somedomain.com"; allow-query { any; }; allow-transfer { 172.16.12.10; 10.0.0.1; }; };
zone "10.16.172.in-addr.arpa" in { type master; allow-query { any; }; file "db.172.16.10"; allow-transfer { 172.16.12.10; 10.0.0.1; }; };
zone "0.0.127.in-addr.arpa" in { type master; allow-query { any; }; file "db.127.0.0"; };
zone "." in { type hint; file "db.cache"; };
Our internal IP address is 192.168.1.1 Our external IP address is 172.16.10.1
Once you've created all the zone files in your dbfiles_internal and dbfiles_external directories, you should end up with something like this when you do an ls (adjust zonefile names per your network):
ls -lR /usr/local/bind/dbfiles_*
/usr/local/bind/dbfiles_external: total 18 -rw-r--r-- 1 root root 678 Nov 14 22:28 db.127.0.0 -rw-r--r-- 1 root root 690 Nov 14 22:29 db.172.16.10 -rw-r--r-- 1 root root 2769 Aug 1 12:55 db.cache -rw-r--r-- 1 root root 1508 Nov 14 22:46 db.somedomain.com -rw-r--r-- 1 root root 1425 Nov 19 22:29 named.conf
/usr/local/bind/dbfiles_internal: total 18 -rw-r--r-- 1 root root 669 Nov 14 22:30 db.127.0.0 -rw-r--r-- 1 root root 800 Nov 14 22:30 db.192.168.1 -rw-r--r-- 1 root root 2769 Aug 1 12:54 db.cache -rw-r--r-- 1 root root 1062 Nov 14 22:31 db.somedomain.com -rw-r--r-- 1 root root 1004 Nov 19 22:38 named.conf
Modify/create an /etc/rc.d/init.d/dns startup script. One is provided below that works on a Redhat 6.0 system. You'll need to set up symlinks from the rc.* directories. See the man page for chkconfig (for Redhat systems). Make sure the script is executable once you've copied it to the init.d directory.
Don't forget to disable your old named startup script. Read the man page for chkconfig, or look at the symlinks in the /etc/rc.* dirs and rename or remove the ones that point to the old script. On a Redhat 6.0 system, the old script is /etc/rc.d/init.d/named
#!/bin/sh # # dns Start/Stop the internal and external name daemons # # description: dns is a script for starting/stopping/etc DNS servers # version 1.02 # chkconfig: 345 14 58 # processname: named
# Source function library. . /etc/rc.d/init.d/functions
# See how we were called. case "$1" in start) echo -n "Starting DNS services: " # # uncomment the following line if you're using holelogd for logging. #daemon /usr/local/bind/sbin/holelogd.named /usr/local/bind/dev/log daemon chroot /usr/local/bind /sbin/named -b /dbfiles_internal/named.conf -u named -g named daemon chroot /usr/local/bind /sbin/named -b /dbfiles_external/named.conf -u named -g named echo ;; stop) echo -n "Stopping DNS services: " killall named # # uncomment the following line if you're using holelogd for logging. #killproc holelogd.named echo ;; status) status named # # uncomment the following line if you're using holelogd for logging. #status holelogd.named ;; restart) /etc/rc.d/init.d/dns stop /etc/rc.d/init.d/dns start ;; reload-ext) ndc -c /usr/local/bind/dbfiles_external/ndc_external reload ;; reload-int) ndc -c /usr/local/bind/dbfiles_internal/ndc_internal reload ;; reconfig-ext) ndc -c /usr/local/bind/dbfiles_external/ndc_external reconfig ;; reconfig-int) ndc -c /usr/local/bind/dbfiles_internal/ndc_internal reconfig ;; *) echo "Usage: dns {start|stop|status|restart|reload-ext|reload-int|reconfig-ext|reconfig-int}" exit 1 esac
exit 0
If you decided to use syslogd, you'll need to edit the /etc/rc.d/init.d/syslog script and change one line. Note that these are the changes that I did on my system, your system (depending on which distribution and other factors) may be different.
Old line: daemon syslogd -m 0
New line: daemon syslogd -a /usr/local/bind/dev/log -m 0
/etc/rc.d/init.d/syslog restart
Don't forget to restart syslogging with the new options:
Assuming you've done everything correctly, try starting the dns servers.
/etc/rc.d/init.d/dns start
The named daemons should create pid and ndc files (per the named.conf files) in each of your dbfiles directories. You should also notice a new file called "log" in the chrooted dev directory that holelogd/syslogd uses to pipe log data to /var/log/messages.
You may also want to adjust your /etc/resolv.conf file so that clients on the same system use the internal server for dns resolution. The "forwarders" line in the internal daemons's named.conf file will handle queries for non-local data.
search somedomain.com nameserver 192.168.1.1
Troubleshooting
If the daemon doesn't start correctly, you can use strace as a diagnostic aid. Change the daemon lines in the dns script so they are similar to the following (change internal to external as needed), and you'll have strace files in /tmp to help you figure out what's missing.
daemon strace -o /tmp/dns.strace -f -ff chroot /usr/local/bind /sbin/named -b /dbfiles_internal/named.conf -u named -g named
You can of course have named produce debug output. RTFM