Tuesday, 27 May 2014
Updating dynamic DNS on FreeBSD with ldns-update(1)
Because of the many UI/feature regressions in AirPort Utility 6 and lack of attention to AirPort Extreme firmware bugs (currently, my family’s one-generation-old AirPort Extreme has issues with dynamic DNS updating and drops SIP traffic), I’m in the process of migrating to an embedded router platform, PC Engines’ apu1c.
This migration has been a trying process, between buggy firmware, discovering too late that OpenBSD doesn’t support 802.11n, and FreeBSD PF bugs/lack of documentation (FreeBSD PF diverged significantly from OpenBSD PF a while back). I just ran into a fun problem where the wireless card comes up with a bizarre PCI ID that doesn’t configure:
none1@pci0:5:0:0: class=0x020000 card=0x00000000 chip=0xff1c168c rev=0x01 hdr=0x00 vendor = 'Atheros Communications Inc.' device = 'AR5008 Wireless Network Adapter' class = network subclass = ethernet
versus the correct information I got after a power cycle:
ath0@pci0:5:0:0: class=0x028000 card=0x3099168c chip=0x002a168c rev=0x01 hdr=0x00 vendor = 'Atheros Communications Inc.' device = 'AR928X Wireless Network Adapter (PCI-Express)' class = network
Hopefully this is not indicative of the wireless card dying.
I’m still using ipfw/natd for the moment, though I will try again with PF at some point because I’m unaware of a way to make UPnP and NAT-PMP work otherwise.
As I mentioned above, the AirPort Extreme implementation of RFC 2136 dynamic DNS has problems. In addition to the updating-every-few-seconds bug above, Apple’s NTP servers were returning times far enough off correct that the signature was failing. You can’t even configure the NTP server in AirPort Utility 6, of course, but thankfully I was able to hack AirPort Utility 5.6.1 into working on current OS X versions.
FreeBSD 10 no longer ships BIND and its nsupdate utility. Instead it includes LDNS and Unbound, but not LDNS’s associated “example” utilities, notably the dynamic DNS updater ldns-update. So I installed the LDNS package and promptly discovered several bugs in ldns-update. Thanks to some generous help, I was able to get the FreeBSD-packaged version of ldns-update to work—with one exception: dynamic DNS updates being sent to port 5353 rather than 53.
Until the port change makes it into a LDNS release, here’s a patched amd64 package built on FreeBSD 10.0.
Finally, here’s my /etc/dhclient-exit-hooks that updates the IP address on DHCP address changes:
#!/bin/sh -ef case .$reason in .BOUND | .REBOOT) ;; *) exit 0 esac HOST=hostname_goes_here ZONE=zone.goes.here KEY='KEY_GOES_HERE' update() { # ldns-update domain [zone] ip tsig_name tsig_alg tsig_hmac # this script assumes the zone is the same as the tsig_name /usr/local/bin/ldns-update $HOST.$ZONE $ZONE $1 $ZONE hmac-md5 $KEY } update none update $new_ip_address
Note that the usage message you get from running ldns-update is more useful than the man page: it includes the important none and zone options.
Update, 6 December 2014: Fixes for the above issues (including an updated man page) have been integrated into LDNS, though not yet into a release. I rebuilt my FreeBSD package, also incorporating the FreeBSD port changes: here you go.