Router setup for native IPv6 from Get.no

As of June, the large Norwegian ISP Get let most customers sign up for a native IPv6 test program.

The only information Get give you when you sign up to their IPv6 test program, is that they:

  • use DHCPv6 to delegate addresses and prefixes to the customer,
  • SLAAC (Stateless Address Autoconfiguration) is not supported, and
  • you’ll get a /60 prefix, e.g. 16 prefixes of size /64.

By popular demand, and since there is little other information available on how to do this, here is how I’ve set up my Linux router to use native IPv6 from Get. I’m running Ubuntu 12.04 on my router, so you may have to adjust a bit for your setup.

Thanks to André Tomt, who provided his working setup, which this is based on.

Get a DHCPv6 client

You need a DHCP client with DHCPv6 support:

sudo apt-get install isc-dhcp-server

The ISC DHCP server will set the MTU on your upstream interface to the MTU specified by Get’s DHCP. As far as I know, most other DHCP servers ignores the provided MTU. Since Get’s DHCP specifies an MTU of 576 bytes (the minimum for IPv4), which is below the 1280 bytes required for IPv6 to work, your system will probably turn off IPv6 support on your upstream interface. To make the ISC DHCP client ignore the provided MTU, remove interface-mtu from the request setting in /etc/dhcp/dhclient.conf.

Connect the dots

I’m using /etc/network/interfaces to run the required commands when the interfaces are taken up and down:

# Local network interface
auto eth1
iface eth1 inet static
    # CHANGEME: Replace with your IPv4 setup
    address 10.37.3.1
    netmask 255.255.255.0
iface eth1 inet6 static
    # CHANGEME: Pick an address from one of your /64 IPv6 prefixes.
    # Here I've used the first /64 block in the /60, so I've just
    # appended "1" and removed "/60" from the prefix.
    address 2a02:fe0:cf12:30::1
    netmask 64

# Internet interface
auto eth2
iface eth2 inet manual
    # Setup
    up sysctl -w net.ipv6.conf.eth2.accept_ra=2
    up sysctl -w net.ipv6.conf.eth2.autoconf=1
    up sysctl -w net.ipv6.neigh.eth2.base_reachable_time_ms=300000
    up ifconfig eth2 up

    # IPv6 DHCPv6 prefix delegation
    up dhclient -6 -P -nw -pf /var/run/dhclient6.eth2.pd.pid -lf /var/lib/dhcp/dhclient6.eth2.pd.leases eth2
    down dhclient -x -pf /var/run/dhclient6.eth2.pd.pid || true

    # IPv6 DHCPv6 stateless info
    up dhclient -6 -S -nw -pf /var/run/dhclient6.eth2.pid -lf /var/lib/dhcp/dhclient6.eth2.leases eth2
    down dhclient -x -pf /var/run/dhclient6.eth2.pid

    # IPv6: Don't route traffic to our own prefix
    # CHANGEME: Change to your /60 prefix
    up ip -6 route replace unreachable 2a02:fe0:cf12:30::/60

    # IPv4 DHCP
    up dhclient -4 -nw -pf /var/run/dhclient.eth2.pid -lf /var/lib/dhcp/dhclient.eth2.leases eth2
    down dhclient -x -pf /var/run/dhclient.eth2.pid || true

    # IPv4 NAT
    up iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE
    up iptables -A FORWARD -i eth2 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
    up iptables -A FORWARD -i eth1 -o eth2 -j ACCEPT
    down iptables -t nat -D POSTROUTING -o eth2 -j MASQUERADE
    down iptables -D FORWARD -i eth2 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
    down iptables -D FORWARD -i eth1 -o eth2 -j ACCEPT

    # Teardown
    down ifconfig eth2 down

You may need to change eth1 and eth2 to match the upstream and downstream interfaces on your router.

As you can see, I have entered my /60 prefix and the /64 prefix I use on my local network to /etc/network/interfaces by hand (the parts marked with “CHANGEME”). If Get decides to delegate another prefix to me when their IPv6 service leaves the test period, the configuration must manually be updated. This isn’t perfect, but it works.

Get the prefix from DHCPv6

To figure out what your /60 prefix is, just ifup your upstream interface (ifup eth2 in my case), so that dhclient6 will be started. If you’re in luck, it will get a lease and write the lease details to /var/lib/dhcp/dhclient6.eth2.pd.leases. It will look something like this:

lease6 {
  interface "eth2";
  ia-pd 3b:21:0a:bc {
    starts 1347749217;
    renew 302400;
    rebind 483840;
    iaprefix 2a02:fe0:cf12:30::/60 {    <- my delegated /60 prefix
      starts 1347749217;
      preferred-life 604800;
      max-life 1209600;
    }
  }
  option dhcp6.client-id 0:1:0:1:17:a3:c8:66:0:13:3b:21:a:bc;
  option dhcp6.server-id 0:1:0:1:17:3f:80:8c:0:15:17:37:e0:3e;
  option dhcp6.name-servers 2a02:fe0:1:2:1:0:1:110,2a02:fe0:1:2:1:0:1:111;
}

Now, update your /etc/network/interfaces with an address from within your prefix (typically, you’ll add “1” to the end of the prefix) and update the ip -6 route add unreachable line with the prefix. Then ifdown and ifup the interface to apply the new config.

If this works, you should now have working native IPv6 on your router. You can test it by running:

ping6 vg.no

To get the rest of your local network on IPv6, you need to advertise a /64 prefix to your local network. To do so, you need a router advertisement daemon:

sudo apt-get install radvd

You’ll need to configure radvd by editing /etc/radvd.conf. Here’s my complete configuration:

interface eth1 {
    AdvSendAdvert on;
    prefix ::/64 {
        AdvOnLink on;
        AdvAutonomous on;
    };
};

You’ll need to replace eth1 with the network interface towards your local network.

Note that the prefix is just defined as ::/64. This is a special case in radvd, which makes radvd advertise all non-link-local prefixes assigned to the interface. In other words, we’ll get away with just hard coding the prefix in /etc/network/interfaces.

When you’re done, restart radvd:

sudo service radvd restart

Once radvd is running, any IPv6 enabled computer on your local network should quickly pick IPv6 addresses from your /64 prefix. Again, you can verify by doing:

ping6 vg.no

Updated 2012-09-17: Added note about ISC DHCP client and too low MTU.

Updated 2012-10-09: Updated dhclient shutdown commands so that they also shut down the one getting stateless information from DHCPv6. Changed the route command from using add to replace, so that it doesn’t fail if the route already exists.