April 26, 2010

Dynamic DNS with named

A recent change in ISP triggered a trade in of the static IP for my home network. Dynamic DNS helps hide this away and continue operations as normal.

Checks

Bind version

The version of named on the server has to correspond to nsupdate on the client. There are a few ways to determine the bind version but the simplest for modern implementations is a simple named -v.

Time

The dynamic update will only work if the clocks are in sync (~5min skew allowed at most). This shouldn’t have to be said, but use ntp.

Any attempt at syncing the clock manually is likely to end in tears. You know that the clock will go out of sync and stop updating the ddns entries at the exact moment you need to get to your machine.

Seed zone

$TTL 10 ; 10 seconds
dyn.example.org       IN SOA  ns1.example.org. ns2.example.org. (
                                2010012004 ; serial
                                10800      ; refresh (3 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                10         ; minimum (10 seconds)
                                )
$TTL 3600       ; 1 hour
                        NS      ns1.example.org.
                        NS      ns2.example.org.

$ORIGIN dyn.example.org.

Where:

This file belongs on the named server. named lives in /etc/namedb on my servers, and I normally place all my dynamic zone files in /etc/namedb/dynamic.

Securing zone updates

Next you want to generate keys for securing the zone updates.

On the named server, create a directory for storing your keys. I use /etc/namedb/keys.

From the directory run dnssec-keygen
# cd /etc/namedb/keys
# dnssec-keygen -b 512 -a HMAC-MD5 -v 2 -n HOST dyn.example.org.

You now have a pair of keys that will be used for the TSIG during the DNS update.

Configuring the zone

The first thing you need is the value of you private key.

# cat /etc/namedb/keys/Kdyn.example.org.+111.+11111.private
Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: [some really long string of characters]

Next, update named.conf to include your seed zone and the private key:


key dyn.example.org. {
        algorithm "HMAC-MD5";
        secret "[some really long string of characters from your private key]";
};

zone "dyn.example.org" {
        type master;
        file "dynamic/dyn.example.org";
        allow-update {
                key syn.example.org;
        };
};

Now you can restart bind and test.

# /etc/rc.d/named restart
To test (from named server) :
# dig @localhost dyn.example.org

Dig should give an answer showing the records for the name server and any other static records in the seed zone file.

Wiring it together

client preparation

Create a user:

# pw useradd ddns -s /sbin/nologin -d /home/ddns
# mkdir /home/ddns
# chown ddns /home/ddns

Copy keys from server, rsync/scp/copy and paste or whetever takes your fancy, but the keys need to end up in the home directory of your ddns user.

# ls -al /home/ddns
-r--------  1 ddns  wheel  121 Apr 14 17:38 Kdyn.example.org.+111.+11111.key
-r--------  1 ddns  wheel  156 Apr 14 17:39 Kdyn.example.org.+111.+11111.private

set-ddns.sh

Hack together a script to update the zone with the client ip details. There are two parts to the problem, determining your current public ip, and then calling nsupdate to push the details to named. I use an ultra simple script to do this as I run it on my router that owns the public interface.

#!/bin/sh
keyfile='Kdyn.example.org.+111.+11111.private'
nameserver='example.org.'
host='dyn.example.org'
ttl=10

####
# This is how I determine my ip, replace with a tailored solution.
####
ip=`ifconfig tun0 | grep inet | tail -n 1 | cut -c 7- | awk '{print $1}'`


/usr/bin/nsupdate -k $keyfile <<EOF
server $nameserver
update delete $host A
update add $host $ttl A $ip
show
send
EOF

If your client does not own the public interface then you will need to find an alternate mechanism to determine the ip. Normally mining one of the following sources with some combination of curl | grep | cut can be used (in order of the least likely to annoy someone a great deal):

  1. Most consumer routers have a web interface that can be scraped; or
  2. Public services like http://www.whatismyip.com/; or
  3. Sometimes ISPs provide a page that tells you your current ip.

rinse, wash, repeat

Add a crontab entry to execute the set-ddns script. crontab -u ddns -e and add the following entry to kick off the script every minute.

* * * * * /bin/sh /home/ddns/set-ddns.sh

Conclusion

DNS rocks.

Ref

http://www.freebsdwiki.net/index.php/BIND,_dynamic_DNS