Dynamic DNS for the Home User

by Jason Bodnar

With the proliferation of broadband technologies such as cable modems and DSL, more and more people have systems "permanently" connected to the Internet. While many Internet Service Providers forbid users from providing services such as HTTP or FTP from their broadband-connected machines, eventually, you may find yourself away from home, needing access to your personal computer. But, unless you're one of the lucky few who received a static IP address from your ISP, your home machine may not be that easy to find. That is, if you are not using dynamic DNS.

What is Dynamic DNS?

Dynamic DNS, in the simplest terms, is the process of updating a nameserver with new information about a host or network. This task can be accomplished in quite a few different ways. If you prefer the hands-off approach or do not have your own domain or access to a nameserver you can use the services of a third-party dynamic DNS providers. If you have your own domain name and access to your primary authoritative nameserver you can take advantage of RFC 2136, DNS Dynamic Update, and some new features found in BIND 8 and 9.

Third-party Dynamic DNS Providers

Third-party Dynamic DNS providers (see Table 1 for a small list of providers) usually let you pick your own hostname within one or more domains that they control. Most of these providers offer this service free of charge or ask for a small fee in order to offset their costs. Some dynamic DNS service providers offer primary and secondary DNS hosting which will enable you to give your home computer a hostname in your own domain.

Table 1. Dynamic DNS Providers
URLHostnameHostname in your own domain
www.ez-ip.net$25/yearNot available
www.dyndns.orgFree$30 donation
www.ods.orgFreeFree
www.dyn.caFree$40 Canadian/year
www.tzo.com$25/year$59.95
www.easydns.com$35/year$35/year
www.dyns.cxFree15 EUR/year
www.hn.orgFreeFree
www.zoneedit.comN/AFree
www.dyndsl.comFreeNot Available

Once you have picked a provider and registered for your service you need to let the provider's nameservers know whenever your IP address changes. Most providers provide a web interface to your account where you can manually enter your IP address every time it changes. If that seems a little tedious some services let you set your web browser's start page to a URL that will automatically update your account with your new IP address every time you start your browser. While this automates the process, it doesn't help much if you don't start your browser or if your IP address changes after starting your browser.

What is needed is a way to automatically detect when your IP address changes and notifiy your dynamic DNS provider. Your service provider may point you to dynamic DNS clients that will work with their services and a quick search on Freshmeat.net for dynamic and DNS turns up dozens of applications that will do the job.

One of the best dynamic DNS clients available is ez-ipupdate (http://www.gusnet.cx/proj/ez-ipupdate). ez-ipupdate is a small C program that currently supports twelve dynamic DNS service providers. It can be run from the command line for manual updates or in daemon mode to monitor your IP address and notify your provider only when your IP address changes. (Dynamic DNS service providers like this as it cuts down on their network utilization and system resources.)

ez-ipupdate is available as source code or as an RPM. Once you've built and installed the package you will need to update /etc/ez-ipupdate.conf to specify which dynamic DNS service you're using and provide some other information on how you want ez-ipupdate to run.

Listing 1. /etc/ez-ipupdate.conf

01 #!/usr/local/bin/ez-ipupdate -c
02 #
03 # example config file for ez-ipupdate
04 #
05 # this file is actually executable!
06 #
07
08 service-type=dyndns
09 user=jbodnar:password
10 host=jbodnar.dyndns.org
11 interface=eth0
12 max-interval=2073600
13
14 # Please create this file and ensure that the user
15 # that ez-ipupdate is running as has write 
16 # permissions to it then uncomment this line, if 
17 # you don't your dyndns account will probably get
18 # banned. If you run ez-ipupdate as root (bad 
19 # idea, use "run-as-user") then you can just 
20 # uncomment this line.
21 #cache-file=/etc/ez-ipupdate.cache.eth1
22 
23 # For the mean time we'll just use a cache file in
24 # the temp directory
25 cache-file=/tmp/ez-ipupdate.cache
26
27 # Uncomment this once you have everything working
28 # how you want and you are ready to have 
29 # ez-ipupdate running in the background all the 
30 # time. To stop it you can use "killall -QUIT 
31 # ez-ipupdate" under Linux.
32 daemon
Looking at Listing 1, the first parameter you need to change is on line 8. service-type specifies the dynamic DNS service provider you are using. The accepted values are ezip, pgpow, justlinux, dhs, dyndns, dyndns-static, ods, tzo, gnudip, easydns, dyns, hn and zoneedit. Many of the providers use different protocols for updating their services. By specifying service-type, ez-ipupdate will pick the appropriate protocol for you.

The next parameter you're interested in is on line 9. This is where you specify the username and password you used to create your account with the service provider. Line 10 lists the hostname you have chosen for your dynamic IP address. Line 11 is especially important for people who are running gateway machines with multiple network interface cards. You need to enter the interface your machine uses to connect to the Internet (otherwise you may map your hostname to an IP address on your internal network which most likely is not what you want to do). Line 12 lists the maximum number of seconds ez-ipupdate will wait before it automatically updates your service. You should set this pretty high so you don't upset your service provider with frequent, unnecessary updates.

Line 25 lets you specify a cache file where ez-ipupdate will keep a record of when your IP address last changed and what it changed to. It uses this to make sure your service is only updated when your IP address changes or after the maximum interval between updates has expired.

Finally, line 32 tells ez-ipupdate to run in daemon mode, meaning it will remain an active process, monitoring your IP address and updating your service as necessary. Without this, ez-ipupdate would run once, update if needed and then exit.

After configuring ez-ipupdate you will need to configure your system to start ez-ipupdate at boot time. This can be as simple as adding /usr/local/bin/ez-ipupdate -c /etc/ez-ipupdate.conf to rc.local or creating a separate script for it in /etc/rc.d/initd and using chkconfig or creating symlinks to make sure it starts during the appropriate run levels.

Once you've finished editing your config file and creating your start script you can run /usr/local/bin/ez-ipupdate -c /etc/ez-ipupdate.conf from the command line to start the daemon and update your hostname with your current IP address.

Dynamic DNS with BIND 8/9

RFC 2136 updated the DNS protocol to include a new type of query - the update request. The update request allows local and remote hosts to provide new information about a domain to the primary authoritative DNS server for that zone. Updates can add or delete individual resource records (i.e. A, CNAME, MX, etc.) for a zone or even all the resource records in a zone. In addition, changes can be made conditional to the existence or absence of resource records.

In order to use DNS update requests you must be running BIND 8 or 9 (or another DNS server that supports update requests). To configure BIND to allow dynamic updates you must add the allow-update statement to the zone section for the domain you wish to have dynamic hostnames in /etc/named.conf (see Listing 2). (It is recommended that you do not use a zone that contains static DNS information as you could accidentally delete or modify important information about the zone or hosts within it.)

Listing 2. allow-update in /etc/named.conf

01 zone "d.shakabuku.org" {
02         type master;
03         file "masters/d.shakabuku.org";
04         allow-update { 192.168.1/24; };
05 };
On line 1 of Listing 2, a new zone is defined specifically for any dynamic hosts you wish to have. Lines 2-3 specify that this nameserver is the primary authoritative server for this zone. Line 4 turns on dynamic updates for the zone only allowing changes to be made by hosts on the 192.168.1/24 network. If your machine is connected to the Internet via DSL or a cable modem you most likely have a dynamically assigned IP address (which is why you want to use dynamic DNS in the first place). You may think that you should put the address of the subnet that your machine is on in the allow-update statement so you can update your DNS information any time your IP address changes. While that would work, you'd also be allowing any other host on that subnet to modify your DNS information (which is probably not a good thing).

TSIG-signed updates

BIND 8/9 implements RFC 2845, Secret Key Transaction Authentication for DNS (TSIG), which allows you to sign your update request with a secret key that is shared between your host and your nameserver. (You can also sign zone transfers between master and slave nameservers.) TSIG uses an HMAC-MD5 one-way hash function to create the DNS message's signature. The signature is not only based on the secret key but also the content of the DNS message. This allows the nameserver to authenticate the message (as the secret key should only be known by the updating host and the nameserver) and insures that the message has not been tampered with since it left the sender (since the signature is based on the content of the message).

Generating keys and configuring BIND

Several steps must be completed in order to use TSIG-signed updates. First, you must generate a secret key. This can be done on either the nameserver's machine or the machine that will be making the updates. BIND 8 includes a program called dnskeygen that can be used to create the key. BIND 9 includes a similar program called dnssec-keygen that uses a different syntax.

To create a key with BIND 8's dnskeygen you would execute the following command:

# dnskeygen -H 128 -h -n home-dns.shakabuku.org.
In the command above, -H specifies the key should be generated using the HMAC-MD5 algorithm and is followed by the size of the key and -h specifies that the key is a HOST key. (There are also ZONE keys for zone transfers and USER keys for email.) -n is followed by the name of the key. You should try to name the key to reflect the host and nameserver that will be sharing the key.

To create a key with BIND 9's dnssec-keygen you would execute the following command:

# dnssec-keygen -a HMAC-MD5 -b 128 -n HOST home-dns.shakabuku.org.
When using dnssec-keygen, -a specifies the algorithm, -b the key size and -n the key type. The final argument is the name of the key.

Both dnskeygen and dnssec-keygen create two files containing the key: K<key name>.+<algorithm number>.+<key fingerprint>.key and K<key name>.+<algorithm number>.+<key fingerprint>.private. In the examples above the files created would be similar to the following:

Khome-dns.shakabuku.org.+157+48378.key
Khome-dns.shakabuku.org.+157+48378.private
Both of these files should be readable only by root and should be kept with other DNS-related files (in /var/named perhaps). Once you have created your key, you need to securely transfer these two files to the nameserver machine (or host depending on which machine you created the keys on). SSH is an excellent way to get the key files from one machine to another.

On the nameserver you need to create a file that defines keys for BIND (see Listing 3). (Keys can be defined in /etc/named.conf but since many distributions install this file world-readable by default it is often better to put your keys in a separate file.)

Listing 3. /etc/dns.keys.conf

01 key home-dns.shakabuku.org. {
02         algorithm hmac-md5;
03         secret "1Vqo67OVy6f7I2xbyR903p==";
04 };
In Listing 3, line 1 defines the key name. Line 2 specifies the algorithm used to create the key. Line 3 is the key itself. You can copy the key from either the .key or .private files you created earlier. In your .key file, the key is the last field of the only line in the file. The .private file contains three records of the format "name: value". The key is the value of the last record.

Once your keys are in place you need to make a couple of changes to /etc/named.conf on the nameserver (see Listing 4).

Listing 4. /etc/named.conf for TSIG-signed updates

01 include "/etc/dns.keys.conf";
02 
03 zone "d.shakabuku.org" {
04   type master;
05   file "masters/d.shakabuku.org";
06   allow-update { key home-dns.shakabuku.org.; };
07 };
In Listing 4, line 1 includes the file containing statements defining the keys you are using. On line 6, replace the address of the subnet you're willing to accept updates from with the name of the key that must be used to sign updates.

Using nsupdate

Now that you've configured your DNS server to accept dynamic updates and have created keys to secure your updates, all that's left to do is to start sending update requests! You could do this by building the UDP packets yourself (yes, DNS uses UDP most of the time) or using the resolver libraries or even a scripting language's DNS library (such as Perl's Net::DNS). Fortunately, BIND 8/9 comes with a program, nsupdate, that allows you to simply and securely send updates to your DNS server.

nsupdate only takes one optional argument and has four command-line options. The optional argument is the name of a file containing commands to be sent to the DNS server. If called without an argument, nsupdate accepts commands on standard input. Commands are batched and sent after supdate reads a blank line. This allows you to send multiple groups of commands in one file or session and make changes dependent on certain prerequisites being present.

nsupdate accepts four options - d, y, k, v. -d makes nsupdate run in debug mode. -y allows you to specify a key name and the key itself on the command line. The format is -y keyname:secret. Using the -y option is discouraged because the secret key would then be available via ps or your history file. The preferred way to use a secret key is the -k option. With the -k option, nsupdate reads the key from the .private file that was created when you generated your key. According to the man page, the .key file must also be present in order to use the -k option. Finally, -v makes nsupdate use TCP to send the update. This may be necessary if you are sending a large batch of commands that are too big to fit in a single UDP packet.

nsupdate accepts quite a few commands but you will most likely only need to use the update command. update can be used to add or delete resource records in a zone.

When deleting a record, update's syntax is update delete domain-name [class] [type [data ...]]. class is only required if you are making updates to a zone that is not in the internet class. type specifies the type of resource record you want to delete (i.e., A, MX, CNAME). If data is present the delete will only take place if their is a resource record of type whose RDATA matches data.

To add a record, update's syntax is update add domain-name ttl [class] type data. ttl is the Time-to-Live for the record (just like you would specify in the zone file). When adding a record, type and data are required as they specify the resource record to be added.

In order to add an entry in DNS for your broadband-connected machine you'll want to add an A record specifying that your hostname has the IP address you received via dhcp. You probably also should delete any A record that currently exist for your hostname (perhaps from a previous update). An nsupdate session to do this would look like the following:

# nsupdate -k Khome-dns.shakabuku.org.+157+48378.private
> update delete home.d.shakabuku.org A
> update add home.d.shakabuku.org 86400 A 192.168.1.10
>
> ^C
The session listed above first deletes any A record that already exists for home.d.shakabuku.org. It then adds a new A record for home.d.shakabuku.org with a TTL of 86400 seconds (one day). This will make home.d.shakabuku.org resolve to the IP address 192.168.1.10. (But you wouldn't want to use an IP address like that since it is a reserved address and cannot be used on the Internet.)

Automating nsupdate

The final step in setting up dynamic DNS for your broadband-connected Linux box is to automate the update process. Ideally, you only want nsupdate to run whenever your IP address changes. If you're using dhcpcd this is very easy to do. dhcpcd will execute /etc/dhcpc/dhcpcd.exe any time the IP address of your dynamically configured interface changes. (pump users need not fear, it includes a similar feature. See the pump man page for more details.) When dhcpcd.exe is executed it is passed two arguments: a .info file containing details about the interfaces connection and the new state of the interface -- up, new and down. up and down are passed when the interface is brought up and down. new is passed when the interface receives a new IP address without being brought down first.

Listing 5. /etc/dhcpc/dhcpcd.exe

01 #!/bin/bash
02 
03 TTL=86400
04 KEYFILE=/var/named/Khome.d.shakabuku.org.+157+14660.key
05 NSUPDATE=/usr/bin/nsupdate
06
07 exec >> /var/log/dhcpcd.log 2>&1
08 
09 if [ $# -lt 2 ]; then
10   echo "$(date +\%b\ \%e\ \%H:\%M:\%S) dhcpcd.exe: wrong usage"
11   exit 1
12 fi
13
14 hostinfo=$1
15 state=$2
16
17 # Reading HostInfo file for configuration parameters
18 . $hostinfo
19
20 case $state in
21   up) echo "$(date +\%b\ \%e\ \%H:\%M:\%S) dhcpcd.exe: interface $INTERFACE has been configured with old IP=$IPADDR"
22       HOSTNAME=$(hostname)
23       delete="update delete $HOSTNAME A\n"
24       update="update add $HOSTNAME $TTL A $IPADDR\n\n"
25       update=${delete}${update}
26       ;;
27
28   new) echo "$(date +\%b\ \%e\ \%H:\%M:\%S) dhcpcd.exe: interface $INTERFACE has been configured with new IP=$IPADDR"
29        HOSTNAME=$(hostname)
30        delete="update delete $HOSTNAME A\n"
31        update="update add $HOSTNAME $TTL A $IPADDR\n\n"
32        update=${delete}${update}
33         ;;
34   down) echo "$(date +\%b\ \%e\ \%H:\%M:\%S) dhcpcd.exe: interface $INTERFACE has been brought down"
35         update="update delete $HOSTNAME A\n\n"
36         ;;
37 esac
38
39 echo -e $update | $NSUPDATE -k $KEYFILE
40
41 exit 0
Listing 5 shows a shell script dhcpcd will call whenever the IP address changes. Lines 3-5 define the TTL of the resource record you're adding, the location of your secret key file and the location of nsupdate. Line 7 directs stdout and stderr to a log file.

Lines 9-12 check to make sure the script was passed enough parameters. Lines 14 and 15 set some variables based on the parameters the script was passed. Line 18 sources the file containing information for the interface that has changed. That file contains the IP address, subnet mask, etc.

Lines 20-37 are the meat of the script. They act on the state change of the interface, building a command string that will update the dynamic DNS record. Line 39 wraps things up by calling nsupdate with the TSIG key file and piping the commands to nsupdate.

Summary

Dynamic DNS can be a valuable tool that gives you easy access to your broadband-connected Linux machine at home. If you don't have your own domain name or access to your nameserver there are many third-party dynamic DNS providers who will make it easy for you to give your computer a name. The new update request query found in BIND 8/9, nsupdate and a good dhcpd client will let you use your own domain name to give your machine a more personal name on the Net.

©2001, 2002 Jason Bodnar