SIDE NOTE: You will see references to nsupdate -k below. Note that in recent versions of this program, the option you want has changed to nsupdate -y. You will find an example of the new format later in this post.

My first thoughts on these were a couple of year ago, and I foolishly tried changing my VPN from routing to bridging. I failed. Terribly. I was out of town and had to get a friend to drop by and reboot my gateway for me (thanks Jerry).

Why is having the DNS correct important to me? So my backups work. That’s just for starters. My laptop actually has two hostnames; dent and dent-vpn (assigned via the VPN). These IP addresses are on different subnets. At present, if I’m away and using the VPN, I go into the Bacula configuration files and change the FQDN in to reflect dent-vpn. This works, but there is a better solution. Dynamic DNS.

NOTE: backups in my world are controlled centrally. The backup server initiates backups and thus must know the IP address of each client.

Dynamic DNS allows you to update DNS records on the fly by sending commands to your name server.

Big WARNING

What I am doing here is updating my own name servers for my own domain. If you have a dynamic IP address at home, and you’re trying to use DYNDNS on that, this article is not what you want. You want a third party service, such as NOIP.com.

named.conf

The following steps were performed on my DNS server.

NOTE: Be aware: this will rewrite files on disk. That is, your existing zone files will be rewritten by named. If your zone files are under revision control, you should be aware of this. For example, my zone files looked like this after my testing below:

+$TTL 3600 ; 1 hour
+60 PTR dent.example.org.

I added these entries to named.conf (in my case, /var/named/etc/namedb/named.conf):

Testing nsupdate

I restarted named in a previous section. Now that we have everything else configured, it is time to start testing. Let’s see if named will accept updates via nsupdate, which is what the learn-address script will invoke.

Here is a very simple test which checks the current IP address, changes it, then checks it again. Keep in mind the following points:

The host I am on has 10.0.0.76 listed as the first nameserver in /etc/resolv.conf

The DNS server at 10.0.0.76 is authoriative for the domain example.org (the one I am changing)

Testing learn-address

The learn-address script, which I place in /usr/local/openvpn, will be invokved by OpenVPN whenever a clent connects. The primary purpose of this hook seems to be validation. If the script returns a non-zero result, the connection will be aborted. That is what the documentation seems to indicate. But it also seems to be a great place from which to update our DNS records.

In this section, we’ll make sure that learn-address works before we get OpenVPN to run it.

The script uses environment variables which are set by OpenVPN. For our testing, we need to test those variables. For testing, you can also set DEBUG to non-blank value.

The following test was performed with debugging enabled. There is another test immediately below, without debugging.

Connect your client

Now you should be able to connect your OpenVPN client and have your DNS updated automatically. Please, if this does not work, let me know in the comments and we'll get it working for you.

but no DHCID, not mine

When I first tried this, I started getting this error right away:

dhcpd: Forward map from laptop.example.org to 10.55.0.60 FAILED: Has an address record but no DHCID, not mine.

I wrote about this in the FreeBSD Forums. This problem is caused by my original A record still being in the zone file. I can delete that zone file with this command (which is similar to that used in my testing above)

ADDENDA - 16 Nov 2014

In order to get this working with pfSense 2.1.5-RELEASE, I had to make a few changes.

That version of pfSense uses an older version of nsupdate. As I found in this post, I had to create my keys with -C (compatability mode) to generate keys with dnssec-keygen for use with the old nsupdate.

I was getting this error before that:

could not read key from Kkey_name.+157+18051.private: private key is invalid

Next, thanks to this post, I found out I had to alter the script to invoke nsupdate with different options: