knuthaugen

Howto: Setting up dynamic DNS client and server

Toc

  1. Preface
    1. Abstract
    2. Target audience
    3. Prerequisites
    4. Misc
  2. The Dirty Work
    1. Step one – dynamic zone
    2. Step two – keys and configuration
    3. Step three – doing updates
    4. References

Author: knut (a) knuthaugen dot no, copyright 2004.
Legalese: Please read the copyright and the disclaimer wich apply to this document

Abstract

Guide on how to setup and use dynamic DNS from a Linux client and also aspects regarding configuring a bind9 DNS server for dynamic DNS. Dynamic DNS is cool if you're behind a DSL- or cable modem and your IP address change a lot. Dynamic DNS lets you maintain a consistent hostname with a changing IP address, without much work.

Target audience

Either DNS administrators running bind who want to offer dynamic DNS to customers, or Linux user wanting to use dynamic DNS either purely as a client or mucking about on your home network. If you're only after the client part, skip to step 2.

Prerequisites

You should know your way around a Linux system using system V startup and if you attempt the admin part, be well versed in the fine art of running bind and reading manuals :-). Setting up a dynamic zone isn't much harder than a normal one, but reading a few chapters on how DNS works won't do you any harm.

Misc

The following is done with the following configuration: Server running bind9 on Debian GNU/Linux and the clients running Fedora Core 1/2. Program names may vary if you're running older stuff, and the command line options may have changed. Read the manual if things seem strange. YMMV, as always.


First step – a dynamic zone (for bind admins)

This step is for administrators only and almost all of it requires root access to a host running bind. It's necessary to have the dynamic data in a zone of it's own, so you don't mix static DNS data and dynamic ones. A zone updated dynamically cannot be updated manually. Use CNAME records if you need the hosts in other zones. Our zone for the day will be ddns.knuthaugen.no, conveniently.

If you're trying to mix dynamic and static data – don't come crying to me for help.The bind server keeps the dynamic zone in memory and flushes it to disk now and then. Editing the file will not be cool. Therefore we only make a very minimal zone for our dynamic zone, because bind needs something to start with. This is called seeding the zone. A zone file like this should suffice:


$ORIGIN .
$TTL 60 ; 1 minute
ddns.knuthaugen.no          IN SOA  ns1.knuthaugen.no. hostmaster.knuthaugen.no. (
                                1         ; serial
                                10800     ; refresh (3 hours)
                                3600      ; retry (1 hour)
                                604800    ; expire (1 week)
                                60        ; minimum (1 minute)
                                )
$TTL 3600       ; 1 hour
                        NS      ns1.knuthaugen.no.
                        NS      ns2.knuthaugen.no.
                        NS      ns3.knuthaugen.no.
                        MX      5 mail.knuthaugen.no.
                        MX      10 mail-relay.mail.com.
$ORIGIN ddns.knuthaugen.no.

And the zone should be included in named.conf in a normal fashion, with the following configuration block:


zone "ddns.knuthaugen.no" {
        type master;
        file "ddns.knuthaugen.no";
};

Step two – -- Keys and configuration

Here we have several steps to complete. First we need to generate a key to use when updating the zone. This will be used to ensure that only machines with the appropriate signature (and key) can update our dynamic zone. This is done by the program dnssec-keygen(8)

  1. Create a directory for storing the key, i.e. /etc/ddns (as root on your local machine)
  2. run the command line cd /etc/ddns; dnssec-keygen -b 512 -a HMAC-MD5 -v 2 -n HOST jabber.ddns.knuthaugen.no.. Replace the hostname with the hostname you're creating a key for.

When dnssec-keygen completes successfully, it prints a string of the form Knnnn.+aaa+iiiii to the standard output. This is an identification string for the key it has generated. These strings can be used as arguments to dnssec-makekeyset.

Dnssec-keygen creates two file, with names based on the printed string. Knnnn.+aaa+iiiii.key contains the public key, and Knnnn.+aaa+iiiii.private contains the private key. The .key file contains a DNS KEY record that can be inserted into a zone file (directly or with a $INCLUDE statement). The .private file contains algorithm specific fields. For obvious security reasons, this file does not have general read permission. Both .key and .private files are generated for symmetric encryption algorithm such as HMAC-MD5, even though the public and private key are equivalent. The private key should only be readable by root!

The file /etc/ddns/Kjabber.ddns.knuthaugen.no.+157+59239.key looks like this (long line broken for readability. It should all be on one line and will not work if it's not):

jabber.ddns.knuthaugen.no. IN KEY 512 3 157 
Svu3MPB7TxgSBwg3j3+fNHNS8bbUWOwCJTsmerMRiJaUjk4DORyuODTu TPL92aLY0vkKgqn5FniJQeJw6vrJQA==

The file /etc/ddns/Kjabber.ddns.knuthaugen.no.+157+59239.private looks like this:

Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: Svu3MPB7TxgSBwg3j3+fNHNS8bbUWOwCJTsmerMRiJaUjk4DORyuODTuTPL92aLY0vkKgqn5FniJQeJw6vrJQA==

The .key file are in some sources reported to be on a format that bind will understand, but that is not the case with newer dnssec-keygen and bind9. We have to shape it so that bind9 will eat it without digestive problems. This is how it should look:

key jabber.ddns.knuthaugen.no. {
    algorithm "HMAC-MD5";
    secret "Svu3MPB7TxgSBwg3j3+fNHNS8bbUWOwCJTsmerMRiJaUjk4DORyuODTu TPL92aLY0vkKgqn5FniJQeJw6vrJQA==";
};

The "secret" part is from the public key, the .key file. This file on the above format must be included in the named.conf ofyour bind9. You can paste the above block directly into your named.conf, but it nice and clean to have one key per file and use bind's include-statement. This bind key file should only be readable by root on the bind host and you're friendly neighbourhood DNS administrator will have to include it for you, if you're not root yourself.

#in named.conf for your bind server.
include "keys/key-jabber.ddns.knuthaugen.no";

The DNS admin will also have to configure bind so that your key will be allowed to update the dynamic zone. The following portion of the zone definition allows our newly added key to update the dynamic zone. The "allow-update" part is of course the important one.


zone "ddns.knuthaugen.no" {
        type master;
        file "ddns.knuthaugen.no";
        allow-update {
                key jabber.ddns.knuthaugen.no;
        };
};

Bind has to be restarted/reloaded after these configuration changes and any missing file problems or other stuff caused by fat fingers on a keyboard will have to be fixed. Check the logfile for bind, normally daemon.log.

Step 3 – doing updates

Finally, some script work!

Now for the client part. We have a key installed on the server and want to add an A record for our workstation when we boot it or otherwise change the ip address. If you want this in detail, see the man page for the program nsupdate(8). This is the program used to send updates to the server, using our newly created key pair with TSIG and HMAC-MD5 encryption to provide our security. I have created a init.d script which does this on boot, or whenever i boot the machine. It's like this (works on Fedora Core 1 and 2 and should work on redhat. The sourcing of the functions file should be removed for Debian and possibly other distributions.):


#!/bin/sh
#
# chkconfig: 2345 26 74
# description: Starting a custom ddns thingie.
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# Source function library.
. /etc/init.d/functions

NAME="jabber.ddns.knuthaugen.no"
TTL=60
IP=`ifconfig eth0 | awk '/inet addr:/ { print $2; }' | sed 's/addr://'`

RETVAL=0

start() {
	echo -n $"Registering ddns entry: "
    #we add a RP record for good measure.
    #the blank line before EOF is important.
	nsupdate -k /etc/ddns/Kjabber.ddns.knuthaugen.no.+157+59239.private <<EOF
update delete $NAME
update add $NAME $TTL A $IP
update add $NAME $TTL RP knut.knuthaugen.no. . 

EOF
	RETVAL=$?
	if [ $RETVAL -eq 0 ]; then
		echo_success
	else
		echo_failure
		echo
	fi

}

stop() {
	echo -n $"Un-registering ddns entry: "
    #the blank line before EOF is important.
	nsupdate -k /etc/ddns/Kjabber.ddns.knuthaugen.no.+157+59239.private <<EOF
update delete $NAME

EOF

	RETVAL=$?
	if [ $RETVAL -eq 0 ]; then
		echo_success
		echo
	else
		echo_failure
		echo
	fi
}

restart() {
	stop
	start
	RETVAL=$?
}

# See how we were called.
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  restart|reload)
	restart
	;;
  *)
	echo "Usage: ddns {start|stop|restart|reload|}"
	exit 1
esac

exit $RETVAL

Symlink this baby in the runlevels you want, or even better use chkconfig(8) to do it and you're good to go.

References

Copyright © Knut Haugen 2004-05-12, last updated 2004-07-12, valid xhtml 1.0 strict