Problem
If you host a couple of DNS zones using named on a few servers (a master and a few slave), its no problem to keep the slaves updated when you change the zones on the master. But what if you want to add/remove zones on the master, and replicate it down to the slaves? Then you have to manually add the zones in the master named.conf, and same on the slaves. This can be a lot of work if you add/remove zones often and/or you want other people to be able to add/remove zones themself without having to ask you to update the configuration files.
It would be very much easier if one (only trusted persons ofcourse) could put their zone file in a directory, and that would be it! It would be automagicly "pushed" out the new zone to the master and the slaves.
Solution
To solve this problem, I've used the regular DNS update notification features, combined with two scripts and an extra "fake" DNS zone.
The master will have a directory (master-repl) in its named etc dir (ie /var/named/etc/namedb/master-repl) along with the regular master/slave/named.conf dirs/files. In this directory we place all zones we'd like to replicate down to the slaves and automaticly include in the master.
Among the regular zones, we will have a "fake" DNS zone called replication.zone (or whatever you like, configureable). This zone is used to distribute the "known zones" list to all our slaves. It contains a list of the zones we know about, and if this knowledge changes, we update this zone and its serial, and then this is zone is transfered down to our slaves with the normal DNS notification mechanism.
To let named know about the zones we manage, we have a file master-repl.inc too, this file is automaticly created and the admin has to include it in his named.conf (using include "master-repl.inc";).
Master
The master.pl script, a perl script, is used to scan the master-repl directory for new changes (new zones, removed zones). This script has to be run periodicly (or manually by the DNS admin upon request). If it sees a change, for example a new zone, it will update the replication.zone file (which is also in the master-repl dir) and the master-repl.inc file. Then it will issue a rndc reload command to let named reload the zones. When named gets reloaded, it will reload its configuration files and check the serial numbers in all the known zones. It will now notice the new zone we added. And it will also notice the change in replication.zone and push this change down to the slaves.
Slave
The slave consists of another script, slave.pl. This is run periodicly too (this has to be periodicly, otherwise it would be no use.. The admin shouldnt need to touch the slaves).
The slaves needs one manual configuration done at setup time, the add of a zone section in named.conf. The zone in question is replication.zone. We need to add a this slave zone with our master as master (duh..). This is needed so the slave.pl script got something to read its list of known zones from.
Just as the master we got a include file here, slave-repl.inc. This is included from named.conf so named knows which zones we care about.
When the script is run it will check for changes since last execution in the replication.zone file. If it finds any changes, it will make sure that the slave got the same zones as the master (ie what is in replication.zone). Ie. if a new zone is added in replication.zone a new section in the slave-repl.inc file is added and then named is reloaded. Similarly if a zone is removed we will remove the corresponding section in named.conf and the old zone file we had (we dont need that anymore).
Setup
To set this up one needs 2 or more boxes running named. This script is used on FreeBSD boxes running named, and the configuration files are located in /var/named/etc/namedb/. When named is executed it is chrooted to /var/named. From now on I will use the just mentioned path as root. Change as appropriate.
First, download the files located in http://svn.stromnet.se/repos/misc/trunk/dns-replication/
Master
- Create /var/named/etc/namedb/master-repl (a directory) and make sure named can read it.
- Create /var/named/etc/namedb/master-repl.inc (an empty file) and make sure named can read it.
- Add the directive include "master-repl.inc"; to your named.conf
- Place the master.pl script and the master.conf script somewhere appropriate.
- Modify the master.conf script as the comments indicate. The $namedConfRoot dir is in this vase /var/named/etc/namedb, and the $zoneFilesDir is master-repl. For $stateFile you can use /var/named/etc/namedb/master-repl.state. The @replicationNS list should contain ALL the slaves participating in the replication. This is used to create the replication zone.
- Place all your zones that you want replicated in the /var/named/etc/namedb/master-repl dir. The should be named by zone name, ie if you have zone "mydomain.com" in the named.conf file normaly, the file has to be named mydomain.com.
- Test the master.pl script by executing /path/to/master.pl /var/named/etc/namedb/master-repl.conf. If all is OK this will print a few notices about new zones found (or more if you have debugging enabled).
- Add a cron job (as root or named user) that runs /path/to/master.pl /var/named/etc/namedb/master-repl.conf every 15 minutes (or whatever you think is appropriate).
Slave
- Create /var/named/etc/namedb/slave-repl (a directory) and make sure named can read it.
- Create /var/named/etc/namedb/slave-repl.inc (an empty file) and make sure named can read it.
- Add a zone directive for the replication zone in named.conf:
zone "replication.zone" { type slave; file "slave-repl/replication.zone"; masters{172.28.1.2;}; };Make sure the masters IP is the correct one! If you change the $replicationZone in master-repl.conf/slave-repl.conf you have to change the zone/file-name here too! - Add the directive include "slave-repl.inc"; to your named.conf
- Issue a rndc reload here so the replication.zone file is fetched from the master. Make sure it is retrieved and located in slave-repl/replication.zone (or whatever you used).
- Place the slave.pl script and the slave.conf script somewhere appropriate.
- Modify the slave.conf script as the comments indicate.
- Try to run the /path/to/slave.pl /var/named/etc/namedb/slave-repl.conf command and make sure all the zones appear in slave-repl/. Make sure that the slave-repl.inc file is updated too!
- Add a cron job (as root or named user) that runs /path/to/slave.pl /var/named/etc/namedb/slave-repl.conf every 15 minutes (or whatever you think is appropriate, use something similar to the master or shorter if you want faster updates).
Now you should be done :)
Details
The replication "fake" zone consists of a regular SOA section, a number of NS records (one for the master and each slave), and a number of A records. A sample file could look like this:
$TTL 1h
@ IN SOA ns1.stromnet.se. johan.stromnet.se. (
16
21600
1728000
43200
86400
)
IN NS ns1.stromnet.se.
IN NS ns2.stromnet.se.
stromnet.org.replication.zone. IN A 172.28.1.2
stromnet.se.replication.zone. IN A 172.28.1.2
0.2.f.f.8.d.6.1.1.0.0.2.ip6.arpa.replication.zone. IN A 172.28.1.2
1.28.172.IN-ADDR.ARPA.replication.zone. IN A 172.28.1.2
2.28.172.IN-ADDR.ARPA.replication.zone. IN A 172.28.1.2
7.6.d.c.3.4.5.d.2.0.0.2.ip6.arpa.replication.zone. IN A 172.28.1.2
4.28.172.IN-ADDR.ARPA.replication.zone. IN A 172.28.1.2
3.28.172.IN-ADDR.ARPA.replication.zone. IN A 172.28.1.2
5.28.172.IN-ADDR.ARPA.replication.zone. IN A 172.28.1.2
The important thing in the above zone is the A records. For each zone we know about, the master.pl script inserts a <zone>.replication.zone. entry. For example the stromnet.se.replication.zone. The A record value is the IP address of the master. The NS records are the slaves that we want to participate in the replication. These will be notified when this file is updated (by master.pl) and thus the slave.pl script can get an updated view of the known zones.
The master-repl.inc file could look something like this:
# named config file, generated from master.pl
# Do not edit this file!
zone "stromnet.org"
{
type master;
file "master-repl/stromnet.org";
allow-transfer { 172.28.1.2; 172.28.1.6; };
};
zone "stromnet.se"
{
type master;
file "master-repl/stromnet.se";
allow-transfer { 172.28.1.2; 172.28.1.6; };
};
zone "0.2.f.f.8.d.6.1.1.0.0.2.ip6.arpa"
{
type master;
file "master-repl/0.2.f.f.8.d.6.1.1.0.0.2.ip6.arpa";
allow-transfer { 172.28.1.2; 172.28.1.6; };
};
zone "1.28.172.IN-ADDR.ARPA"
{
type master;
file "master-repl/1.28.172.IN-ADDR.ARPA";
allow-transfer { 172.28.1.2; 172.28.1.6; };
};
For the slave it looks similar, but instead it is type slave and there is a masters{} section.
