Synchronising Nameservers (Bind + FreeBSD) with Perl

A funny thing happened to a colleague’s name servers the other day. Whilst very diligent in almost every respect when it comes to failover, redundancy, etc, etc he was bitten by a simple yet overlooked ┬áissue. We all synchronise name servers with a script of some kind, whilst BIND itself takes care of zone updates, you have to update the secondary or backup servers manually or via script for adding and removing brand new zones. His issue was that the script required the primary server to respond with data to work, and when it didn’t respond due to a power outage, the secondary servers all overwrote their main BIND config file with a blank file, and effectively hosed the DNS system for his clients.

Currently we are using a shell script which is loaded on the primary server. This script produces a suitable file for a secondary name server and waits for it to be collected via FTP. A second script on the secondary server then routinely FTPs over the file and restarts BIND. Am i going to learn from my colleague’s pain – yes I am!

I’ve written a short Perl script to replace the shell script on the secondary server only, I’ll delete the primary script used before, the new script works as follows:

  1. Collect data from master server via SSH (nothing else happens if no data can be collected – thats the key point covered!).
  2. Open a temp text file for writing.
  3. Extract the domain names and create the secondary file, writing into the temp file.
  4. Compare the temp file with the current working file.
  5. Replace and restart if different.

Here it is:

#! /usr/bin/perl -w

use strict;
use File::Compare;
use File::Copy;

if ( my @dom_list = `ssh -l #username# #ip address# 'grep "^zone " /etc/namedb/domains.conf'`){
        open TMP, ">/home/dan/tempfile.txt";
        for (@dom_list){
                s/^zone \"//;
                print TMP "// Secondary domain for $_ \n";
                print TMP "Zone \"$_\" {\n";
                print TMP "  type slave;\n";
                print TMP "  file \"secondary/$\";\n";
                print TMP "  masters {\n";
                print TMP "    #ip address#;\n";
                print TMP "  };\n";
                print TMP "};\n\n";
        close TMP;
        if (compare("/home/dan/tempfile.txt","/etc/namedb/domains.conf")){
                system ("rndc reload");

Points to note:
Obviously you need to sort out your ssh keys for this method to work. Also I used a couple of File:: functions to make things easy such as the comparison function. I’ve cron’d this job in every 5 mins and it seems to be working fine.

This entry was posted in FreeBSD Administration, Perl and tagged , , . Bookmark the permalink.

Leave a Reply