This article assumes you fave a few things:

  1. A Linux server with:
    • root SSH access
    • BIND installed
    • a domain already set up and working with BIND
  2. An OpenWrt router at home to send updates

The OpenWrt router isn’t strictly necessary.  You could, of course do the dynamic DNS updates with a cheap Linux firewall, but I’ll cover the configuration for OpenWrt.

DNS Server Configuration

The file naming conventions used here are for a BIND installation on Debian. Your distribution may use a different naming convention, however, the concepts should be the same.

On the DNS server (as root):

# dnssec-keygen -C -a HMAC-MD5 -b 512 -n HOST sub.domain.com.

You can use your domain name (or subdomain) as the key name if you’d like. That’s what I did in this example – it helps me keep things straight. The -C switch is for compatibility mode since it’s likely the nsupdate binary on OpenWrt will be older than the BIND installation on your DNS server. The contents of the key file will look something like this:

# cat Ksub.domain.com.+157+54658.key
sub.domain.com. IN KEY 512 3 157 GWruXog5QO20QSB2YvLJp60DwlfJhq0hQ9KiAXFRNDHlrhSSjGBtGlM8 wSJpWNlUbhdkBnV3Or41s1iedLoDwg==

I like to keep BIND’s key configuration in a separate file to make sure it doesn’t get overwritten with software upgrades, so I created a file called /etc/bind/keys.conf. Using the MD5 from the key file (the cryptic string(s) that ends in ‘==’, after the sets of numbers), create a keys.conf file:

key sub.domain.com.
{
	algorithm HMAC-MD5;
	secret "GWruXog5QO20QSB2YvLJp60DwlfJhq0hQ9KiAXFRNDHlrhSSjGBtGlM8 wSJpWNlUbhdkBnV3Or41s1iedLoDwg==";
};

Then in /etc/bind/named.conf, add this at the top:

include "/etc/bind/keys.conf";

In my /etc/bind/named.conf.local (which has all of the zones actually hosted on the server), the zone for the domain I want to make dynamic has the following:

zone "domain.com" IN {
        type master;
        file "/etc/bind/db.domain";
        update-policy {
               grant sub.domain.com. name sub.domain.com. A TXT;
        };
        notify no;
};

You would substitute your domain for “domain.com” and “sub.domain.com,” and have your own zone file in a different file named after your domain (/etc/bind/db.yourdomainname).

The “update-policy” section is the part that is added.  The first parameter to the “grant” statement is the name of the key, and the “name” parameter is the domain name – which I’ve made the same in this case. There’s nothing different about /etc/bind/db.domain than any of my other zone db files, except it’s owned by the “bind” user & group — that way when it receives a DNS update, it can change the file (dynamically!).

Also the /etc/bind directory should be owned by group “bind” so that it can create /etc/bind/db.domain.jnl — a journal file BIND will use.

OpenWrt Configuration

Install the “bind-client” package on your OpenWrt router.  I like to use the LuCI web interface.  In LuCI you can find it by searching under the software administration menu.

SCP the private & key files you created on your DNS server to your OpenWrt router.  I keep my DNS files in root’s home directory: /root.

Create a hotplug file to update the DNS when the WAN interface obtains an address. Put it in /etc/hotplug.d/iface/30-nsupdate:

[ "$INTERFACE" != "wan" ] && ( [ "$ACTION" != "ifup" ] || [ "$ACTION" != "update" ] ) && exit 0

rdate -s time.nist.gov
include /lib/network
scan_interfaces
config_get ipaddr wan ipaddr

echo "server your.bindserver.com
zone domain.com
update delete sub.domain.com A
update add sub.domain.com. 86400 A $ipaddr
show
send" | nsupdate -k /root/Ksub.domain.com.+157+54658.key -v

Again, Replace “domain.com” with the name of your zone, and “sub.domain.com” with the name of your dynamic domain (they could be named the same).  Replace “your.bindserver.com” with the name or IP of your DNS server.  The rdate command is in there to make sure your time is set correctly before running nsupdate.  BIND will complain if the time difference between the client & server differs too much.  While only the key file is referenced in the script, both files need to be present (usually in the same directory as each other) for nsupdate to make a valid request.

You can (and should) test the script without disrupting your network connection by SSHing into your OpenWrt router and running the following command:

# ACTION=update INTERFACE=wan /sbin/hotplug-call iface

Often BIND will complain about time, permissions, auth keys, etc. Running the test above is the best way to find out what’s going on. If there’s no output, the update probably went through. Try to ping your dynamic domain name and see if all is well.

Leave a Reply