Mixing static and dynamic DNS entries using CNAMEs

A problem I have been working on for quite some time is mixing static (but changing) and dynamic DNS entries witin the same zone. In my case static means a mappings of IP addresses to host names where changes do occure but come from an external source. For those entries the resulting zone files can easily be generated from an IPAM1 system. Hosts that get their IP address from a (DHCP) pool are often left with dummy entries (such as dhcp001234) in such systems. I will refer to the entries needed for those hosts as dynamic. They are not handled by the IPAM since it won't know which IP the host will be assigned.

Simply putting static and dynamic entries in the same zone and having the DHCP server update DNS records is not viable: once a change in the IPAM happens, the dynamic changes are lost because the export scripts typically generate new zone files.

The solution is to split dynamic entries into a differnt zone and use CNAME records. The forward zone for example could look like this:

RIGIN example.com. @ IN SOA ns.example.com. hostmaster.example.com. ( 2017020501 ; serial 1h ; refresh 15min ; retry 1w ; expiry 1h ) ; negative cache ; static entries IN NS ns.example.com. ns IN A 192.0.2.2 www IN A 192.0.2.5 ; subdomain for dynamic entries dyn IN NS ns.example.com. ; dynamic entries host1 IN CNAME host1.dyn host2 IN CNAME host2.dyn

The zone-file for dyn.example.com in this case would be populated by the dhcp daemon. The only draw-back here is that host names must be known in advance. In my case they are known to the IPAM.

For the reverse zone the setup looks similar:

$ORIGIN 2.0.192.in-addr.arpa.
@           IN SOA      ns.example.com. hostmaster.example.com. (
                        2017020501  ; serial
                        1h          ; refresh
                        15min       ; retry
                        1w          ; expiry
                        1h )        ; negative cache
; static entries
2           IN PTR      ns.example.com.
5           IN PTR      www.example.com.
; dynamic entries
11          IN CNAME    11.2.0.192.rev.example.com.
; ... lots more entries
40          IN CNAME    12.2.0.192.rev.example.com.

In order for the DHCP daemon to be able to update your zone you will need to create a key:

$ dnssec-keygen -a HMAC-MD5 -b 128 -r /dev/urandom -n USER DDNS
$ grep Key Kddns.*.private
Key: UMq/fhNubt9w618dq1I5Lg==

The key and zone should be setup in your named.conf as follows:

# ...
key DDNS {
    algorithm HMAC-MD5;
    secret "UMq/fhNubt9w618dq1I5Lg==";
};
# ...
zone "dyn.example.com" in {
    type master;
    file "dyn/dyn.example.com";
    allow-update { key "DDNS"; };
}
zone "rev.example.com" in {
    type master;
    file "dyn/rev.example.com";
    allow-update { key "DDNS"; };
}

The dhcpd.conf should contain the following:

# ...
ddns-updates on;
ddns-update-style interim;
ddns-domainname "dyn.example.com";
ddns-rev-domainname "rev.example.com";
ignore client-updates;
update static-leases off;
# ...
key DDNS {
    algorithm HMAC-MD5;
    secret "UMq/fhNubt9w618dq1I5Lg==";
};
#
zone dyn.example.com {
    primary 127.0.0.1; # or a different IP if you nameserver is not on the same server
    key DDNS;
}
zone rev.example.com {
    primary 127.0.0.1; # or a different IP if you nameserver is not on the same server
    key DDNS;
}
# ...
# host entry is optional but enforces the correct forward entry to be used
host host1 {
    hardware ethernet 00:A2:B4:C6:D8:E0;
    ddns-hostname host1;
}

To confirm that everything is working as intended, check your DHCP logs and query your DNS server for the IP given to the client:

# nslookup 192.0.2.23
Server:         127.0.0.1
Address:        127.0.0.1#53

23.2.0.192.in-addr.arpa       canonical name = 23.2.0.192.rev.example.com.
23.2.0.192.rev.example.com.   name = host1.dyn.example.com.

# nslookup host1.example.com
Server:         127.0.0.1
Address:        127.0.0.1#53

host1.example.com canonical name = host1.dyn.example.com
Name:   host1.dyn.example.com
Address: 192.0.2.23

  1. IP address management