Dynamic DNS for ipv6 in a mixed-stack environment

The Problem

We run a small network that anyone in the group can plug machines into. A `Machine' here could be anything from a mobile phone, to an experimental embedded system, to a server. We want all these things to have names, so we can

  1. ssh or telnet into them
  2. tell when we see problems which device is causing the problem.

The ISC-DHCP server can do dynamic DNS based on the FQDN or Host option sent from the clients. This works well; it's easy in most cases to get the dhcp client to send an appropriate identifier. But IPv6 addresses are auto-generated based on a router-advertisement prefix. So it's hard to assign names to these.

The Solution

The ISC-DHCP server can be configured to take action when it commits, expires,or deletes an ipv4v lease. At this point we know the MAC address so can generate an IPV6 address --- the same one that would be generated (assuming the anonymisation option is not turned on) by the client.

So here's what I did. It may not be ideal...

In /etc/dhcp/dhcpd.conf:

ddns-updates on;
ddns-update-style interim;
ddns-domainname "Our.internal.domain.name";
ignore client-updates; # always update the nameserver ourselves

on commit {
   if (not static) {
        set new-ddns-fwd-name = pick-first-value(ddns-hostname, host-decl-name);
        if (exists host-name and option host-name ~~ "^[a-z0-9.-]+$") {
                set new-ddns-fwd-name = option host-name;
        } elsif (exists dhcp-client-identifier and option dhcp-client-identifier ~~ "^[a-z0-9.-]+$") {
                set new-ddns-fwd-name = substring(option dhcp-client-identifier, 1, 50);
        } elsif (new-ddns-fwd-name = "") {
                set new-ddns-fwd-name = binary-to-ascii (16, 8, "-",
                                 substring (hardware, 1, 6));
        }
        set ddns-hostname = new-ddns-fwd-name;
        execute ("/usr/local/bin/ddns-ipv6", ddns-hostname, ucase(
                binary-to-ascii(16, 8, ":", substring(hardware, 1, 6))),
                binary-to-ascii(10, 8, ".", leased-address));
        unset new-ddns-fwd-name;
        on expiry or release {
                execute ("/usr/local/bin/ddns-ipv6", "-d",  ddns-hostname);
        }
   }
}

And /usr/local/bin/ddns-ipv6 contains:

#
# Add or delete an IPv6 address record via DDNS

#
# Adjust these for your network.
PFX="2001:db8:a:"
DOMAIN="Our.internal.domain.name"
KEYFILE=/etc/bind/Kdhcp_updater.+157+29564.private
TTL=7200

# DEBUG
#exec 2>> /tmp/ddns-ipv6-log >&2
#set -x

#echo >&2 "$@"

(


# May need /usr/local/[s]bin here too.
# But don't rely on the PATH handed in, because we may be
# run by a privileged user
PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

# Function to get auto-allocated EUI-64 address
# ipv6addr prefix ipv4 mac
ipv6addr()
{
        tail=`ipv6calc --action geneui64 --in mac $3 --out eui64`
        echo $1:$tail
}

# Error message
Usage()
{
        echo >&2 "Usage: `basename $0` -d name"
        echo >&2 "       `basename $0` name mac ipv4addr"
        exit 1
}


case "$1" in
-d)
        DELETE=1;
        shift
        ;;
-*)
        Usage
        ;;
*)
        ;;
esac


if [ "$DELETE" ]
then
        IPADDR=`host -t aaaa "$1" | sed -n s'/.*address \(.*\)$/\1/p'`
        [ "$IPADDR" ] || exit 1
        PTR=`ipv6calc --in ipv6addr --out revnibbles.arpa "$IPADDR"`
        nsupdate -k "$KEYFILE" <<-!
                 server localhost
                 update delete $1.$DOMAIN IN AAAA $IPADDR
                 update delete $PTR IN CNAME $1.$DOMAIN
                 send
!
else
        IPADDR=`ipv6addr $PFX $1 $2`
        # Windows machines (and some Linux machines) do anonymisation
        # so have a different ipv6 address.  so check if the one
        # we calculated is responding to pings.
        if [ "$IPADDR " ] && ping6 -c 1 $IPADDR > /dev/null 2>&1
        then
        PTR=`ipv6calc --in ipv6addr --out revnibbles.arpa "$IPADDR"`
        nsupdate -k "$KEYFILE" <<-!
                 server localhost
                 update add $1.$DOMAIN $TTL IN AAAA $IPADDR
                 update add $PTR $TTL IN CNAME $1.$DOMAIN
                 send
!
        fi
fi
) &
exit 0

IA64wiki: IPv6DDNS (last edited 2012-01-30 21:45:25 by PeterChubb)

Gelato@UNSW is sponsored by
the University of New South Wales National ICT Australia The Gelato Federation Hewlett-Packard Company Australian Research Council
Please contact us with any questions or comments.