Dynamic DNS using Bind9

Next

I was looking to install some remote services to my server connected to my home ADSL line. The problem I have is that I have got a dynamic IP address with my DSL line. After trying a number of the public services with varying degrees of sucess and flexibility I decided to build my own solution.

Our companies DNS servers run Bind9 and also the server I run at home also runs Bind9 which means that could use the supplied dns update service with encryption.

Three things are required to achieve this :

1. Method of getting your public IP address
2. Adding a dynamic zone to a dns server (bind9) capable of receiving secure updates
3. Scripting at the ADSL site to tie it all together.

Step 1 – Getting public IP address

There are a number of ways of achieving this – for me I setup a script to return my IP address on our companies servers. Script as follows :

<? // getipaddress.php
 if( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] )) {
    $my_ip = $_SERVER['HTTP_X_FORWARDED_FOR’];
 } else {
    $my_ip =  $_SERVER['REMOTE_ADDR’];
 }
 echo $my_ip;
?>

Step 2 – Adding dynamic Zone

First you need to create a key for the zone on your DNS server :

cd /var/named/etc/namedb/ dnssec-keygen -b 512 -a HMAC-MD5 -n HOST dynamic.com

This will generate two files with names like :

Kdynamic.com.+157+34532.key Kdynamic.com.+157+34532.private

Create the zone file dynamic.com in the dynamic folder

$ORIGIN   dynamic.com.
$TTL      3600  ; 1 hour
@         IN SOA ns.domain.com. hostmaster.domain.com. (
            2009042001 ; Serial
            900        ; refresh (15 mins)
            600        ; retry (10 mins)
            86400      ; expire (1 day)
            3600       ; min (1 hour)
            )
            NS ns.domain.com.
$TTL      600    ; 10 mins

Add the keys and define the new zone by editing the named.conf file. For this you will need to open the .key file created using dnssec-keygen.

key "dynamic.com" { algorithm hmac-md5; secret "<key from .key file>"; };
zone "dynamic.com” {
 type master;
 file "dynamic/dynamic.com”;
 allow-update { key dynamic.com; };
};

Step 3 – Scripting on the client server tying it all together

Securely transfer the two generated key/private files to you home server and place them in the folder /etc/namedb

You need to ensure you have installed the CURL library with OpenSSL support. The following script is one I use to send the updates:

#!/usr/local/bin/php -q
<?
$hostname = "dynamic.com";
$keyfile = "Kdynamic.com.+157+34532.key";
$auto_update_delay = 3600; // 1 Hour
$userpwd = "Username:Password";
$dns_server = "100.100.100.100";
$url = "https://myserver.com/getipaddress.php?hostname=".$hostname;
$datfile = "/home/scripts/".$hostname.".nsupdate";
$nsupdate = "/usr/bin/nsupdate -k /var/named/etc/namedb/".$keyfile;
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL,$url );
curl_setopt( $ch, CURLOPT_HEADER, 0);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );
curl_setopt( $ch, CURLOPT_USERPWD, $userpwd );

$response = curl_exec( $ch );
if ( curl_errno($ch) ) {
 print curl_error($ch).”\n";
 exit;
} else {
 $ipaddress = curl_exec($ch);
}
if( $ipaddress == "" ) {
 echo "No ip address returned\n”;
 exit;
}
if ( strlen( $ipaddress ) > 15 ) {
 echo "We got garbage\\n”;
 exit;
}
$cmds = "server ".$dns_server.”\n”.
        "update delete ".$hostname.”\n”.
        "update add ".$hostname." 600 A ".$ipaddress.”\n”.
        “send\\n”;

$update = TRUE;
if( file_exists( $datfile )) {
 $fp = fopen( $datfile, "r" );
 if( $fp ) {
   $info = fstat( $fp );
   if( $info['ctime'] + $auto_update_delay < time()) {
     $update = TRUE;
   } else {
     $saved_cmds = fread( $fp, 1024 );
     if( $cmds == $saved_cmds ) {
      $update = FALSE;
     }
   }
   fclose( $fp );
 }
}
if( $update == TRUE ) {
 $fp = fopen( $datfile, "w" );
 fputs( $fp, $cmds );
 fclose( $fp );
 $cli = $nsupdate." < ".$datfile;
 system( $cli );
 echo $cli."n”;
 echo "Updated DNS - ".$hostname." = ".$ipaddress.”\n”;
} else {
 echo "No change DNS - ".$hostname." = ".$ipaddress.”\n”;
}
?>

I have called this script setipaddress.php and I have added it to my crontab and run this every two minutes.

Mick

© Mick Vaites 2018