dig netmess.org

If you operate a name server, you know you should have at least two of them. But how do you keep them in sync? “Easy, this is done with zone transfers!” you say? But what if you have a changing set of zones? Wonder how you can easily populate this zones to the slave server? Wonder no more!

This article is written along a Debian/Ubuntu flowered Linux. If you run any other distribution, it may happen that you can’t find a config file at the location I refer to here, but the principle is the same.

Before you get going, install the required software so you can later just go on. On Debian or Ubuntu, type this:

# apt-get install bind9 curl xml2 mktemp

Now you’re ready. On the master server, add this to /etc/bind/named.conf.options in between options {}:

#master
allow-transfer { ip of slave server; };
notify yes;
version "Not available";
recursion no;

Of course you need to replace “ip of slave server” with the actual IP of the slave server. The version setting is not really needed, it just hides the bind version you’re running and therefore makes it harder for an attacker to tell what DNS server you are running. After you did the changes, restart bind:

# service bind9 restart

Then, edit the same file on the slave server:

#slave
allow-notify { ip of master server; };
version "Not available";
recursion no;

Also on the slave, add a directory where your zones are stored and set correct owner:

# mkdir /var/cache/bind/slave
# chown bind.bind /var/cache/bind/slave

The bind configuration files are very flexible. You can point to files to include them into the main config file. This allows you to organize your config and makes it cleaner. We use that, so a script can later generate a file containing slave zones only – without the whole rest of the config. On the slave, add this to /etc/bind/named.conf:

include "/etc/bind/named.conf.myzones";

With this setup you can already transfer zones. There is just one problem: The slave server does not know what zones he is responsible for. We change that with the magic of a simple shell script that creates the /etc/bind/named.conf.myzones file. Put the following in /usr/local/sbin/bind-zone-sync.sh on the slave server:

#!/bin/bash
# config
master=ip of master server
myzonesfile="/etc/bind/named.conf.myzones"
remotehost=$master
remoteuser=user of master server that can access /var/cache/bind/
# helpers
tmpfile=$(mktemp)
bkpfile=$(mktemp)
#code :)
logger -t bind-zone-sync "starting bind zone sync."
for zone in $(ssh $remoteuser@$remotehost "echo /var/cache/bind/*"); do
	echo "zone \"$(basename ${zone%%???})\" {" >>$tmpfile
	echo "	type slave;" >>$tmpfile
	echo "	masters { $master; };" >>$tmpfile
	echo "	file \"slave/$(basename ${zone%%???}).bdb\";" >>$tmpfile
	echo "};" >>$tmpfile
	echo >>$tmpfile
done
if [ ! -e $myzonesfile ]; then
	cp $tmpfile $myzonesfile
	service bind9 restart
	logger -t bind-zone-sync "first run: generated $myzonesfile."
	exit
fi
if [ "$(md5sum $myzonesfile | cut -d" " -f1)" != "$(md5sum $tmpfile | cut -d" " -f1)" ]; then
	cp $myzonesfile $bkpfile
	cp $tmpfile $myzonesfile
        service bind9 restart
	logger -t bind-zone-sync "done. backup of $myzonesfile is in $bkpfile."
	exit
fi
rm -f $tmpfile
logger -t bind-zone-sync "done. no changes detected."

Set the correct values according to your environment below the “#config” marker. Then, make the script executable:

# chmod +x /usr/local/sbin/bind-zone-sync.sh

If you wish to automatically sync the zones, create an ssh key to allow automatic login to the master server. This is now very brief, ask if the stuff below doen’t work. Run this on the slave server and just press return on all questions unless you know why to change the proposed values:

# ssh-keygen

This creates a new key pair for you. The public key has to be copied to the master server, so he knows you’re allowed to login. As “remoteuser” you must take the same user you defined in the shell script above:

# ssh-copy-id remoteuser@masterserver

When you got the auto login running, add a cronjob on your slave server to schedule the sync. Insert this into /etc/cron.d/bind-zone-sync:

* */15 * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /usr/local/sbin/bind-zone-sync.sh

Now, your zones will be synced every 15 minutes to the slave server. Bind is only restarted if you added or removed a zone. Simply modifying records on the master wont trigger a bind restart but will be synced immediately to the slave without a restart.

If everything is working fine, you may want to monitor your bind DNS server with Zabbix?