Online.net IPv6 prefix discovery using KAME-dhcp6c

(update: 2015-12-09, see bottom)

This tutorial is for FreeBSD 10.0 on online.net dedicated servers. I assume it also works for dhcp6c on Linux, but I haven't tested it.

You're going to need dhcp6c(8) which is part of the net/dhcp6 port.

The tricky part is getting the DUID into dhcp6c. dhcp6c uses a binary file to store the DUID where the first two bytes are the length of the DUID in network byte order (big endian) and the actual DUID in host byte order (little endian on x86). It does not provide any utilities to write such a file.

Step 0: Enable IPv6

This will automatically configure the link-local address which will be needed to do speak DHCPv6, if it hasn't happened yet.

# ifconfig em0 inet6 -ifdisabled accept_rtadv up

Your ethernet device may have a different name.

Step 1: Creating the DUID file

For this, I used a small awk hack that assumes the DUID is exactly 10 bytes long (which seems to be true for all DUIDs generated by online). This is where the "0a 00" in the awk command comes from, which is the number ten in big endian.

xxd -r is used to convert the hexadecimal numbers into binary.

echo 00:03:XX:XX:... | awk '{ gsub(":"," "); printf "0: 0a 00 %s\n", $0 }' | xxd -r > /var/db/dhcp6c_duid

That's it.

Step 2: Configure dhcp6c

I used this configuration file, which is similar to the example file provided by dhcp6c:

id-assoc pd {
        prefix-interface em0 {
        };      
};

id-assoc na {
};

interface em0 {
    send ia-pd 0;
    send ia-na 0;
    #request domain-name-servers;  # optional
    #request domain-name;          # optional
};

Step 3: Test it

# dhcp6c -Df -c /usr/local/etc/dhcp6c.conf em0

"-D" means debugging, "-f" prohibits forking to background and prints diagnostic messages to stderr.

Look out for a success message in this format:

May/21/2014 13:09:00: get DHCP option IA_PD prefix, len 25
May/21/2014 13:09:00:   IA_PD prefix: 2001:bc8:XXXX:XXXX::/56 pltime=3800 vltime=10800
May/21/2014 13:09:00: get DHCP option status code, len 37
May/21/2014 13:09:00:   status code: success

Step 4: Check your interface's assigned addresses

# ifconfig em0 inet6
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=4219b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4,WOL_MAGIC,VLAN_HWTSO>
        inet6 fe80::YYYY%em0 prefixlen 64 scopeid 0x1 
        inet6 2001:bc8:XXXX:XXXX::1 prefixlen 128 
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

The first one is a link-local address. The second one belongs to the prefix that was just negotiated with the online.net DHCPv6 server.

Step 5: Default route

For this one I checked the IPv6 neighbor addresses obtained via neighbor discovery protocol. The first two are your own addresses, the third is the router.

# ndp -a
Neighbor                             Linklayer Address  Netif Expire    S Flags
2001:bc8:XXXX:XXXX::1                 YYYY                em0 permanent R 
fe80::YYYY%em0                        YYYY                em0 permanent R 
fe80::ZZZZ%em0                        ZZZZ                em0 23h44m27s S R

Now add the route:

# route add -inet6 default fe80::ZZZZ%em0

Ping test:

# ping6 ipv6.google.com
ping6 ipv6.google.com
PING6(56=40+8+8 bytes) 2001:bc8:XXXX:XXXX::1 --> 2a00:1450:400c:c00::8b
16 bytes from 2a00:1450:400c:c00::8b, icmp_seq=0 hlim=56 time=5.754 ms

It works!

But I'll be using router advertisements instead in the next step, in case the router address ever changes.

Step 6: Permanently add IPv6 to rc.conf

Append your settings to /etc/rc.conf:

ifconfig_em0_ipv6="inet6 -ifdisabled accept_rtadv up"
# Your static aliases here:
ifconfig_em0_ipv6_alias0="inet6 alias 2001:bc8:XXXX:XXXX::1:2:3:beef prefixlen 128"
dhcp6c_enable="YES"
dhcp6c_interfaces="em0"
rtsold_enable="YES"

Reboot to test if it comes up as expected.

Update (2015-12-09): Corrected an rc.conf variable

The original document mentioned a variable called ipv6_enable_all_interfaces. This variable does not seem to exist in the default rc.conf provided by FreeBSD. The correct name is ipv6_activate_all_interfaces, so this variable was effectively a no-op, since ifconfig_em0_ipv6 is assigned for the interface, which enables it. I've therefore decided to remove the variable.

Send an email to mw at this domain to contact me. Questions or feedback welcome.