Dynamic Dns on FreeBSD using Bind9
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