Skip to content

Running a secure DDNS service with BIND

This article will give you a short introduction to DDNS, and will only apply to a precise example. I will not detail the reasons of my choice. However, the links provided at the end of the document will allow you further understand the uses that can be made of DDNS.

Requirements

  • 2 machines running GNU/Linux: one at home with a dynamic IP, the other elsewhere with a fix IP
  • BIND 9.2.0 or newer should be installed on the external machine (and act as primary DNS for your domain – the setup won’t be detailed here)
  • the nsupdate utility on your router at home. This comes as part of the dnsutils Debian package.

Generating the key

Updates being initiated from the client, the process needs to be secured by a TSIG key:”(TSIG keys are symmetric HMAC-MD5 keys; although asymmetric SIG keys can also be used, the set up is a bit more complicated)”:.

On the external machine running BIND 9, run as root:

dnssec-keygen -a HMAC-MD5 -b 512 -n HOST <keyname>

where <keyname> should be replaced by a whatever name you want, and 512 is the key size (512 is the maximum with the HMAC-MD5 algorithm).

This will generate 2 files like Kkeyname.+157+12505.key and Kkeyname.+157+12505.private. Both files should remain private (remember, we work with symmetric key).

On the server side

Both files created before do contain the secret key, which needs to be set up on the BIND configuration file (eg.named.conf or named.conf.local in Debian) as follows:

key "keyname." {
  algorithm hmac-md5;
  secret "v9BhsbwDu4q95g/Gf/EiXA==";
};

Once this is defined, you can start using this shared secret in the definition of your zone:

zone "example.com" {
  type master;
  file "master/db.example.com";
  allow-update { key "keyname."; };
};

The BIND service should obviously be reloaded to start using the new configuration:

# /etc/init.d/bind9 reload

On the client site

Updating the zone when your DSL provider IP changes – nsupdate

If you can’t get a fix IP address from your xDSL provider and still want to host your server at home, you can use third services companies like DynDNS.org or Zonedit.com, but did you know you can set up a secure DDNS service using the BIND DNS server and the nsupdate utility. Still, you need to have control on a machine with a static IP somewhere on the public Internet.

nsupdate is the tool needed to update the IP on the DNS server. You can use it manually whenever you want (see manpage for additional information), or in scripts run automatically by cron or, better, directly by ppp through the ppp-ip facilty.

In Debian, save the following script as /etc/ppp/ip-up.d/ddupdate, change the options at the top of the file and make it executable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/bash
# Script to update DNS zones on a remote server
# Copyright © 2005-2007 - Julien Valroff <julien@kirya.net>
# Parts of the script Copyright © 2001-2002 - Dag Wieers <dag@wieers.com>
 
KEY="/root/Kkeyname.+157+29630.private"
SERVER="ns.domain.com"
LOGFILE="/var/log/syslog"
PPP_IFACE="ppp0"
 
if [ "$PPP_LOCAL" != '' ]; then
   if [ "$PPP_IFACE" != "$PPP_IFACE" ]; then
      echo "$(LANG=C date +'%b %e %X') $(hostname) ddupdate[$$]: ABORTED: Not updating dynamic IP \
        address $PPP_LOCAL (already done for $(ip addr show $PPP_IFACE | awk '/inet/ { print $2 }'))" >>$LOGFILE 2>&1
      exit 0
   fi
   IPADDR=$PPP_LOCAL
   sleep 3
else
   IPADDR=$(ip addr show $PPP_IFACE | awk '/inet/ { print $2 }')
fi
 
(
cat <<EOF | nsupdate -k "$KEY"
server $SERVER
zone example.com
update delete example.com. A
update add example.com. 60 A $IPADDR
update delete mail.example.com. A
update add mail.example.com. 60 A $IPADDR
send
EOF
 
  RC=$?
 
  if [ $RC != 0 ]; then
    echo "$(LANG=C date +'%b %e %X') $(hostname) ddupdate[$$]: FAILURE: Updating dynamic IP $IPADDR on $SERVER failed (RC=$RC)"
    (
        echo "Subject: DDNS update failed"
        echo
        echo "Updating dynamic IP $IPADDR on $SERVER failed (RC=$RC)"
    ) | /usr/sbin/sendmail root
  else
    echo "$(LANG=C date +'%b %e %X') $(hostname) ddupdate[$$]: SUCCESS: Updating dynamic IP $IPADDR on $SERVER succeeded"
  fi
) >>$LOGFILE 2>&1
 
exit $RC

Next time your connection will be restarted, the IP will be updated on your DNS server, and you’ll see an entry in your log file:

Mar 12 18:43:26 athena ddupdate[14507]: SUCCESS: Updating dynamic IP 81.13.52.124 on ns.domain.com succeeded

An e-mail will alert the system administrator in case the update fails.

Remember to use low TTL for the zone which is meant to be updated, 60 seconds seems to be a good value.

Updating the DNS with dynamic IP on your local network – dhcpd

DDNS can also be used in conjunction with dhcpd to dynamically update the DNS when a machine is given an IP. A very detailed article was written by Adam Trickett for debian-administration.org to explain this setup.

Combine both methods with a roadwarrior client

I plan to combine the methods described earlier to allow a roadwarrior to be reachable by its name wherever it is located.

When out of the company, the roadwarrior is connected to the network through a secure OpenVPN tunnel. Thanks to the --client-connect and --client-disconnect directives, the OpenVPN server can update the DNS entry for the given host (cf. ifconfig_pool_remote_ip and common_name environmental variables in OpenVPN man page).

When directly connected to the local network, the roadwarrior gets an IP from the DHCP server which updates the DNS.

I haven’t yet worked on this setup, and am not sure it would be very useful, but this is an example of use of dynamic DNS.

Other (more detailed) articles on DDNS

As usual, here are some external resources which helped me writing this article, and which will allow you to study the DDNS methods in details: