DDNS updates

John Hascall john at iastate.edu
Tue Aug 1 15:14:22 UTC 2006

> IIRC the update is done as :
>    If there is no A record, perform an update and skip to step 3.
>    If there is an A record and the TXT record matches, perform the update.
>    If the A record update succeeds, update the PTR record.
> The A record update is done as a conditional script
>    If <condition>
>    then
>      delete fqdn A
>      delete fqdn TXT
>      insert fqdn A ipaddr
>      insert fqdn TXT hash-value

Actually, it goes like this:

The dhcp server computes a unique hash (called "id" below).
The first thing DHCP sends is essentially a mini-program
to the DNS server (expressed in psuedo-code below):

    if (exists(fqdn, A, any) == FALSE) { add(fqdn, A, ip); add(fqdn, TXT, id); }

if the DNS server returns "YXDOMAIN" (there was an fqdn A record) then DHCP
sends this mini-program:

    if (get(fqdn, TXT) == id) { delete(fqdn, A, any); add(fqdn, A, ip); }

if this fails (because there was no fqdn TXT record or it was there but was
not the same as id) then it concludes that the name is in use by somebody else
(and it checks for other odd failures of course).

if either the first or second DNS transactions above succeeded, then it
sends this mini-program:

    delete(ip, PTR, any); add(ip, PTR, fqdn);

Note that all the mini-programs are either completely successful or
completely unsuccessful -- the idea is that they can never half-complete
which would leave your DNS in an inconsistent state.

> >Furthermore, I have noticed that the dhcp server is NOT updating an A
> >record, if the appropriate TXT record is missing. Is there a way to "force"
> >the dhcp server to touch the record?
> No, this is a security mechanism - it prevents a malicious (or just 
> ignorant) user setting their hostname to "server" and your important 
> server named "server" just disappears because the DNS has been 
> changed.

    Well, you can force it to update by computing and manually
    adding (vis the nsupdate program) a correct TXT record, but
    this is sort of ugly.   Or you can delete the A record manually.

We found one place where this can be a problem.  And to be
honest, we are bending dhcp a fair bit here.  Our users pretty
much inisst that thier machines have the same dns name regardless
of whether they are using their wired or wireless NICs (something
to do with stupidity in Windows Active Directory).  And, of course,
Windows' use of dhcp client ids is also stupid (so much so that we
use the patch to ignore them entirely).  The means that DHCP can
update their DNS when they go from one NIC to the other because
the "id" in the text record is a hash of their NIC's mac address.

       machine bob gets IP using NIC 00:11:00:11:00:11
       so dhcp installs:
           bob A
           bob TXT hash(00:11:00:11:00:11)
  PTR bob

       bob switches to his wireless NIC (00:22:00:22:00:22) and gets
       do dhcp tries:
           if (exists(bob, A, any) == FALSE) {
               add(bob, A,; add(bob, TXT, hash(00:22:00:22:00:22));
       which fails because (bob,A, does exist.

       so then it tries:
           if (get(bob, TXT) == hash(00:22:00:22:00:22)) {
               delete(bob, A, any); add(bob, A,; }
       which also fails because get(bob,TXT) == hash(00:11:00:11:00:11)

What we did was modify the second transaction to be:
           if (exists(bob, TXT, any)) {
               delete(bob, A, any); add(bob, A,; }

so that if *any* TXT record is there then DHCP feels ok replacing the
A & PTR records.  This works for us because:
   a) only DHCP ever puts in (fqdn,TXT,...) records, so any TXT
      record was put in by it.
   b) who can update our DNS servers is tightly controlled so
      no rogue agent can install a TXT record for mischief making

The lazy (i.e., no configfile option) implementation of this turns
out to be a two line change to the routine ddns_update_a in the
common/dns.c file:

#ifdef  ANY_DHCID
        updrec -> r_data = (unsigned char *)0;
        updrec -> r_size = 0;
        updrec -> r_data = ddns_dhcid -> data;
        updrec -> r_size = ddns_dhcid -> len;
        updrec -> r_opcode = YXRRSET;


More information about the dhcp-users mailing list