IPv6 for a Linux generation

IPv6 is nothing new – it was finally standardised back in 1998 in RFC 2460, and virtually all operating systems have supported it now for at least 5 years, so most people are in a position to give it a try.

If you’re one of the lucky ones, your ISP might provide native IPv6 connectivity (like AAISP), but for most of us, the main way to get connected to the rest of the IPv6 Internet is to use something we’ve already got – IPv4. And we’re going to tunnel over it.

The first thing we need to do is choose a tunnel broker, which is a fancy name for someone who’ll provide us with an IPv4 endpoint we can tunnel IPv6 over. Wikipedia has a list, but the main, globally available ones are Hurricane Electric and SixXS. Either of these will do, and some people prefer HE over SixXS, but that’s a purely personal choice – in my experience, both work equally as well. For this example, though, we’ll go with HE – so head on over to and create an account.

My first tunnel

Once you’ve created your account, log in and create a tunnel. For some reason, it always seems to pick their New York POP, so you might want to manually choose one geographically closer (in my case – and for our example – London, UK)

Creating a tunnel

The IP address you use as your local end of the tunnel will need to be a public IP address. It’s possible to use a machine behind a NAT device if it’s in a DMZ-style setup where all the traffic destined for the public IP address gets forwarded by the NAT device to the machine behind it, but your mileage may vary.

Once created, view the tunnel details, which should look something like this:-

Editing the tunnel details

Editing the tunnel details

Our tunnel has been created! At the bottom of the page, you’ll notice a little drop-down that generates the commands needed to bring up the tunnel. For this example, we’re using iproute2, so the commands go something like this:-


ip tunnel add he-ipv6 mode sit remote local ttl 255
ip link set he-ipv6 up
ip addr add 2001:470:1f08:810::2/64 dev he-ipv6
ip route add ::/0 dev he-ipv6

The first command creates an IPv6-in-IPv4 tunnel between us and HE, and the second command brings up that tunnel. The third command adds our IPv6 address to our end of the tunnel, and finally the fourth command sets the IPv6 default route to be down our newly-created tunnel.

And that’s it – we’re now connected to the global IPv6 internet. To test it, let’s try pinging something:-

mordor:~# ping6 -c 3
PING 56 data bytes
64 bytes from icmp_seq=1 ttl=58 time=375 ms
64 bytes from icmp_seq=2 ttl=58 time=257 ms
64 bytes from icmp_seq=3 ttl=58 time=255 ms
--- ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 255.562/296.218/375.628/56.158 ms

If you see something like the above, then give yourself a pat on the back, because it’s working!

Next steps

HE by default assigns you a /64 network, which is the smallest size intended to be allocated. This gives you 18,446,744,073,709,551,616 IPs, and whichever way you look at it that’s a lot of addresses. With this in mind, you might be wondering why HE will give you a /48 (that’s 1,208,925,819,614,629,174,706,176 IPs!). The reason is that each network is intended to have a /64, and a /48 allows you to carve up that space into a total of 65,536 separate /64 networks. Now this obviously sounds like overkill to the average user, but autoconfiguration tools such as radvd won’t work with networks smaller than /64, again because of the intentions mentioned previously. This means that if you have more than one network at home (say, a wired network and a wireless network, currently with separate IPv4 networks for each), you can assign a /64 to each one.

With this is mind, let’s ask HE for a /48 by clicking on Allocate in the ‘Routed /48′ section. After a few seconds, you’ll see something like this:-

Allocating our /48

In our example, we’ve been allocated 2001:470:90d3::/48, and now it’s time to plan our IP schema.

Laying it out

Taking my own home network as an example, I have three networks – one for general use (the ‘LAN‘), one for guest use over wireless (the ‘WLAN‘), and finally a DMZ (the… er, ‘DMZ‘). We could lay these out like this:-

  • LAN – 2001:470:90d3:1::/64
  • DMZ – 2001:470:90d3:2::/64
  • WLAN – 2001:470:90d3:3::/64

Nice and simple, and easy to remember. Assuming all three networks are connected to the same gateway machine, we can give the gateway the first IP in the range – 2001:470:90d3:1::1, 2001:470:90d3:2::1 and 2001:470:90d3:3::1.

Routing things further

Before we start, we need to enable IP forwarding for IPv6:-

sysctl -w net.ipv6.conf.all.forwarding=1

You’ll probably want to add this somewhere so it gets activated on bootup – under Debian this would be in /etc/sysctl.conf (which already has the entry, albeit commented out).

One way to provide connectivity to machines on the individual networks is to manually give each machine an IPv6 address, and to route it through our gateway:-

ip addr add 2001:470:90d3:1::2/64 dev eth0
ip route add ::/0 via 2001:470:90d3:1::1 dev eth0

Again, all being well, you should now be able to route to the wider IPv6 Internet from our newly-configured IPv6 node. More importantly, this also means that the wider IPv6 Internet can route back to you – which brings us to…

Security, not obscurity

Don’t be fooled into thinking that because of the immense range of possible IPv6 addresses that securing your new IPv6 setup isn’t required – IPv6 is no exception when it comes to the Internet Bad Guys, so implementing firewall rules is of the utmost importance.

The problem with IPv4 and NAT is that it’s allowed people to become somewhat complacent about security, because machines behind a NAT device are naturally unreachable from the global Internet. IPv6 does not have NAT, which means you don’t have this (rather lazy) safety net, so we have to do it properly.

Luckily, if you’re familiar with iptables, you’ll be glad to know that there’s an IPv6 equivalent – and it’s called (predicatably) ip6tables. The syntax is identical, and in fact the only noticeable difference is that you’re using IPv6 addresses and networks instead of IPv4 ones.

A quick example would go something like this:-

# Clear our INPUT, OUTPUT and FORWARD chains
ip6tables -F INPUT
ip6tables -F OUTPUT
ip6tables -F FORWARD

# Allow packets related to existing connections
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow link-local (for neighbour discovery)
ip6tables -A INPUT -s fe80::/10 -j ACCEPT

# Allow SSH inbound to our gateway from our LAN
ip6tables -A INPUT -i lan -s 2001:470:90d3:1::/64 -p tcp
   -m tcp --dport 22 -j ACCEPT

# Allow all outbound from our networks
ip6tables -A FORWARD -i lan -s 2001:470:90d3:1::/64 -j ACCEPT
ip6tables -A FORWARD -i dmz -s 2001:470:90d3:2::/64 -j ACCEPT
ip6tables -A FORWARD -i wlan -s 2001:470:90d3:3::/64 -j ACCEPT

# Allow all outbound from our gateway
ip6tables -A OUTPUT -j ACCEPT

# Allow SSH and HTTPS inbound to our DMZ
ip6tables -A FORWARD -i he-ipv6 -d 2001:470:90d3:2::/64 -p tcp
   -m multiport --dports 22,443 -j ACCEPT

# Set the default policy to drop
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP

So there you have it – IPv6 firewalling needn’t be difficult. If you want to make something more complex, you might want to take a look at my previous post about iptables and the ‘mark’ target, which also applies to ip6tables.

IPv6 – automatically

Just like DHCP for IPv4, there are autoconfiguration mechanisms for IPv6 – radvd and DHCPv6. Radvd is the older of the two, but both can be used for the same purpose. Configuration of radvd is relatively straightforward, and if we wanted to provide autoconfiguration on our example LAN, we can do something like this:-

interface lan
      AdvSendAdvert on;
      MinRtrAdvInterval 3;
      MaxRtrAdvInterval 10;
      AdvDefaultPreference low;
      AdvHomeAgentFlag off;

      prefix 2001:470:90d3:2::/64
            AdvOnLink on;
            AdvAutonomous on;
            AdvRouterAddr off;

Where next?

This only covers the start – there’s more involved in bringing an IPv6 network up to scratch, like setting up forward and reverse DNS, and configuring various daemons to talk over IPv6 as well as IPv4. If you’re interested, you might find some of the following links useful reading:-

Thanks to these commenters for pointing out errors in the original post where I’d mixed up two separate networks!

6 comments to IPv6 for a Linux generation

  • I’m trying to get IPv6 DHCP and DDNS working with a Red Hat Enterprise server and various clients. So far I’ve only been able to get both forward and reverse DDNS entries with RHEL 6 as both the client and server. Ubuntu Natty-Narwhal gets a forward entry but no reverse. Older versions of either don’t work.

    Have you had any luck getting DDNS working with IPv6 DHCP? Oh yeah, I haven’t gotten any combination to update resolv.conf with IPv6 nameserver information so same question on DHCP “info” (nameserver, NTP servers, etc.).

    I’ll have a new posting to my blog with how I got this far shortly. Any pointers or suggestions for getting Ubuntu to talk to RHEL would be appreciated.


    • Sorry Dave – apologies for not replying sooner…

      I’ve not had much of a play with DDNS or DHCPv6 – I’ve got radvd running on my network which is pretty straightforward, except for the DNS stuff :-/

  • avatar leeand00

    Given the following prefixes:

    – LAN – 2001:470:90d3:1::/64
    – DMZ – 2001:470:90d3:2::/64

    Shouldn’t this:

    # Allow all outbound from our networks
    ip6tables -A FORWARD -i dmz -s 2001:470:90d3:1::/64 -j ACCEPT
    ip6tables -A FORWARD -i lan -s 2001:470:90d3:2::/64 -j ACCEPT
    ip6tables -A FORWARD -i wlan -s 2001:470:90d3:3::/64 -j ACCEPT

    Be this?
    (switched lan and dmz prefixes)

    # Allow all outbound from our networks
    ip6tables -A FORWARD -i lan -s 2001:470:90d3:1::/64 -j ACCEPT
    ip6tables -A FORWARD -i dmz -s 2001:470:90d3:2::/64 -j ACCEPT
    ip6tables -A FORWARD -i wlan -s 2001:470:90d3:3::/64 -j ACCEPT

    Please let me know if I am mistaken or not.

  • avatar Tamas Pisch

    I don’t understand something:
    # Allow SSH and HTTPS inbound to our DMZ
    ip6tables -A FORWARD -i he-ipv6 -d 2001:470:90d3:1::/64 -p tcp
    -m multiport –dports 22,443 -j ACCEPT

    Why 2001:470:90d3:1::/64, and why not 2001:470:90d3:2::/64, because that is the DMZ network?

    • Hi Tamas,

      You’re right. As with the older comment above, the networks I used as an example are based on real ones I was using at the time, and I got the networks mixed up. Thanks for pointing it out, and I’ll edit the post!

Leave a Reply




You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>