Skip to content

Instantly share code, notes, and snippets.

Created Oct 3, 2016
What would you like to do?
Setting up ISC dhclient on debian / ubuntu for prefix delegation

My ISP (Time Warner Cable) hands out IPv6 addresses with DHCPv6; it will delegate a /56 if asked. So long as I keep refreshing the lease, it won't renumber me. I have my cable modem set to bridge, and do all the firewalling, NATing, etc., on a Debian box. In what follows, eth0 is the internal interface.

The dhclient that ships with debian/ubuntu does not support asking for a prefix delegation, so I had to build one from sources.

  • Get the ISC dhcp source.
  • Get patches.
  • Build, and install the client as /sbin/dhclient6 if you don't want to do an actual make install, which would probably also require to figure out how to apply the Debian packaging changes.

Next, change the stanza for your external interface (in my case, eth1) in /etc/network/interfaces to this:

iface eth1 inet dhcp
    up /sbin/dhclient6 -v -6 -P -Pl 56  -pf /run/ -lf /var/lib/dhcp/dhclient6.eth1.leases eth1
    down killall dhclient6
    down service radvd stop

(there are many other ways to skin this particular cat, I opted for the one that involved the least amount of blood!)

Install ipv6 in /etc/dhcp/dhclient-enter-hooks.d/, and in /usr/local/sbin/.

Make sure the following sysctl variables are set correctly:


(you need the first one so you can get the LL address of the default route from your ISP; at least I do).

ifdown eth1; ifup eth1 should do the trick.

In my case, I'm asking for a /56, I allocate a /64 to each of my interfaces, vlans, etc. I'm only showing one interface here, of course.

#!/usr/bin/env python3
import ipaddress
import logging
import os
import sys
import textwrap
reason = os.getenv('reason')
if reason not in ['BOUND6', 'REBIND6']:'Reason was %s, exiting ip6 hook', reason)
new_prefix = os.getenv('new_ip6_prefix')
pfx, pfxlen = new_prefix.split('/')
if int(pfxlen) != 56:
logging.fatal('Prefix length %s is not 56', pfxlen)
os.system('service radvd stop')
delegation = ipaddress.IPv6Network(new_prefix)
all_subnets = list(delegation.subnets(prefixlen_diff=8))
external_subnet = all_subnets[-1]
external_address = ipaddress.IPv6Address(int(external_subnet.network_address) + 1)
os.system('ip -6 addr add {}/64 dev {}'.format(external_address, os.getenv('interface')))
internal_subnet = all_subnets[0]
internal_address = ipaddress.IPv6Address(int(internal_subnet.network_address) + 1)
os.system('ip -6 addr add {}/64 dev {}'.format(internal_address, 'eth0'))
with open('/etc/radvd.conf', 'w') as fd:
interface eth0 {
AdvSendAdvert on;
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {};
prefix %s {
AdvOnLink on;
AdvAutonomous on;
''') % internal_subnet)
os.system('service radvd start')

This comment has been minimized.

Copy link

@jeffsf jeffsf commented Sep 15, 2017

Thrashing through the compiled-in ::/64 prefix-length problem with dhclient I came across

DHCP 4.3.1, 4.2.7, and 4.1-ESV-R10 added DHCLIENT_DEFAULT_PREFIX_LEN in includes/site.h, and a user who wants a different default can edit this file and recompile.

This looks like a reasonable alternative to the complex patch, assuming that a single changed prefix-length hint is sufficient

The Debian packaging isn't as bad as it once was, with pbuilder or the like keeping things a lot cleaner.

_Edit: I haven't had any luck getting ISC dhclient to send an ia-prefix hint in the Solicit message, even after changing that #define _

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment