Posts tagged ‘powerdns’

DNS zone transfer scripts for PowerDNS to BIND

Our current setup is an internal PDNS server with the MySQL back-end and three BIND slaves scattered across the country, and this is how we transfer zones from the master to the slaves.

On the master

 
<?php
ob_start();
if(!isset($_SERVER['PHP_AUTH_USER'])
        || $_SERVER['PHP_AUTH_USER'] !== '%CLIENTUSER%'
        || $_SERVER['PHP_AUTH_PW'] !== '%CLIENTPASSWD%') die();
 
if(!isset($_REQUEST['hostname'])
        || empty($_REQUEST['hostname'])) die();
 
$configTarget = $_REQUEST['hostname'];
 
$masters_default = array('master.company.com' => 'XXX.XXX.XXX.XXX');
 
$internal_ns = array(
        'ns1.company.com' => 'XXX.XXX.XXX.XXX',
        'ns2.company.com' => 'XXX.XXX.XXX.XXX',
        'ns3.company.com' => 'XXX.XXX.XXX.XXX',
);
$external_ns = array(
        'external.othercompany.com' => 'XXX.XXX.XXX.XXX',
);
 
$mysql = new mysqli('%DBHOST%','%DBUSER%','%DBPASSWD%','%DBNAME%',%DBPORT%);
if($mysql->connect_error) die($mysql->connect_error);
 
$sql = 'SELECT DISTINCT d.name,d.account,GROUP_CONCAT(r.content SEPARATOR \';\') AS ns'
        . ' FROM domains AS d'
        . ' RIGHT JOIN records AS r ON d.id=r.domain_id'
        . ' WHERE r.name=d.name AND r.type=\'NS\''
        . 'GROUP BY d.id';
$result = $mysql->query($sql);
 
/*
 * Internal named.conf
 */
$result->data_seek(0);
while($domain = $result->fetch_object()) {
        $ns = split(';', $domain->ns);
        printf("# Domain: %s\n", $domain->name);
        //printf("# Account: %s\n", empty($domain->account) ? 'n/a' : $domain->account);
        if(!in_array($configTarget, $ns)) {
                printf("# WARNING: %s not in %s\n", $configTarget, $domain->name);
        }
        $masters = $masters_default;
        $allow_transfer = $internal_ns;
        unset($allow_transfer[$configTarget]);
        foreach($external_ns as $exthost => $extip) {
                if(in_array($exthost, $ns)) {
                        $allow_transfer[$exthost] = $extip;
                }
        }
 
        printf("zone \"%s\" {\n", $domain->name);
        printf("\ttype slave;\n");
        printf("\tfile \"slaves/%s\";\n", str_replace('/', '_', $domain->name));
        printf("\tnotify no;\n");
        printf("\tmasters { %s; };\n", implode('; ', $masters));
        printf("\tallow-transfer { %s; };\n", implode('; ', $allow_transfer));
        printf("\tallow-notify { %s; };\n", implode('; ', $allow_transfer));
        printf("};\n");
}
 
$output = ob_get_contents();
ob_end_clean();
printf("# %s %s\n%s",
        sha1($output),
        date('Y-m-d H:i:s'),
        $output);
?>

On the slaves

#!/bin/bash
ts=`date +%s`
hostname=`hostname`
url="https://%CLIENTUSER%:%CLIENTPASSWD%@master.company.com/getconfig.php?hostname=${hostname}"
 
tmpfile=`mktemp /tmp/download.XXXX`
newconf=`mktemp /tmp/${hostname}.named.conf.XXXX`
sysconf="/etc/named/master-zones.conf"
 
curl --cacert /etc/pki/tls/certs/master.crt  -s "${url}" > "${tmpfile}"
if [[ "$?" != "0" ]]; then
  echo "download failed"
  rm -f "${tmpfile}" "${newconf}"
  exit 1
fi
tail -n+2 "${tmpfile}" > "${newconf}"
 
hash1=`head -n1 ${tmpfile} | cut -d' ' -f2`
hash2=`sha1sum ${newconf} | cut -d' ' -f1`
 
if [[ "${hash1}" == "${hash2}" ]]; then
  cmp -s ${sysconf} ${newconf}
  if [[ "$?" != "0" ]]; then
    mv "${sysconf}" "${sysconf}-${ts}"
    install -m640 -o root -g named "${newconf}" "${sysconf}"
 
    named-checkconf "${sysconf}"
    if [[ "$?" == "0" ]]; then
      rndc reload
      diff -u "${sysconf}-${ts}" "${sysconf}"
    else
      echo "named-checkconf failed, aborting update"
      mv "${sysconf}-${ts}" "${sysconf}"
    fi
  fi
else
  echo "HASH FAIL. aborted."
  echo "hash1 $hash1"
  echo "hash2 $hash2"
fi
rm -f "${tmpfile}" "${newconf}"

Include the config file on the slaves, put this in /etc/named.conf

include "/etc/named/master-zones.conf";
MAILTO=logwatch@company.com
*/5 * * * * root /usr/local/system_scripts/update-zones.sh

Hopefully it’s pretty self-explanatory, if not, leave a comment or drop a mail.

  • Facebook
  • Twitter
  • Digg
  • del.icio.us
  • LinkedIn
  • RSS
  • StumbleUpon
  • Google Bookmarks
  • Yahoo! Buzz
  • email
  • MySpace
  • PDF
  • Print
  • Reddit
  • Tumblr