Tunnelling your way to the future

In this longish and somewhat technical post, I’m going to tell you how to connect your home or office network to the brave new world of IPv6. Why would you want to do this, beyond the sheer joy of an educational experience, and having something cool to drop into the conversation at your next job interview? Well, if you haven’t seen it already, my previous post, ‘Banish Mavis and Connect to the Future’ , explains why this is more important than simply ensuring there are enough IP addresses to go around. At the end of the article, I’ll talk about some of the security issues you should be aware of in this brave new world!

The first thing to do is check that you haven’t got IPv6 connectivity already. Go to http://ipv6-test.com – a very handy site – and see what it says. It’ll probably tell you you’re connecting by IPv4 because, at the time of writing, very few ISPs have switched on IPv6 for their customers. If all goes well, you’ll be able to try this URL soon and get a different result!

Seeing IPv6 in action on your local network

On the other hand, you probably do have IPv6 capabilities on your local network, because most modern operating systems come with it enabled by default [1]. To see this for yourself, on Macs or other Unix-type machines, open a terminal window and type:


This will tell you about all your network interfaces; you can narrow it down by typing the name of the interface; for example, ifconfig en0 on the Mac or ifconfig eth0 on Linux will tell you about the first ethernet interface. Use en1 on Macs for a Wi-fi interface. What you’ll get is something like this (I’ve left out some of the unimportant bits):

$ ifconfig en0
en0: flags=...
   ether 00:23:df:fd:9d:9b 
   inet6 fe80::223:dfff:fefd:9d9b%en0 ... 
   inet netmask 0xffffff00 ...
   status: active

You can see your IPv4 address, which probably begins with 192.168, and the unique ‘ether’ hardware (MAC) address of your network interface which is, at the very lowest level, how the network distinguishes one device from another. But there’s also an inet6 line showing an IPv6 address:


In general, every network interface will have one of these fe80 addresses. They’re created automatically from the MAC address: if you look at the example above you’ll be able to see that some of the digit sequences occur in both the MAC address and the IPv6 address.

Now, you might quite reasonably think you could ping yourself using the ‘ping6’ command:

ping6 fe80::223:dfff:fefd:9d9b

but this probably won’t work. Why not?

Well, because all network interfaces, wherever they are, use the same fe80:: prefix for these automatically-generated addresses, we can’t use the normal routing mechanisms to work out automatically how to contact them. That’s why you’ll sometimes see addresses listed, as above, with a percent sign in them – it’s called a zone index and is generally followed by the local network interface you can use to contact that address. Try:

ping6 fe80::223:dfff:fefd:9d9b%en0

and you should see things happening. (Type Ctrl-C to stop it). You can ping the same address from another machine on the network but remember that the zone index – the name of the interface you’re going to use – may be different[2].

This is one of the many small cool features of IPv6 – there is at least one valid address that will let you contact a device on your local network, even if the device has never had one allocated by hand or by a DHCP server. This will be really handy in future when you need to set up some gadget out of the box by pointing a browser at it.

So, you have IPv6 on your local network, at least. It’s a bit like having a small railway system on your own island. But, until your ISP builds some bridges, you can’t use it to travel to the mainland unless you dig a tunnel. That’s what we’re going to do, and it is actually quite common at the moment, so don’t worry that you’re doing anything too eccentric!

So here’s the plan

The following process sounds a little complicated, but in fact it’s very easy once you understand what’s going on. The description is long, but the actions are few!

For the specific instructions I’m giving here, you need a couple of things:

  • A Linux machine on your local network – it doesn’t have to be anything special. These instructions assume a recent Debian/Ubuntu-type system.
  • A reasonably static public IPv4 address on your home router. If you’re on a cable connection, you probably have this. If not, you can still try it out, but you may need to tweak things manually or using a script whenever your public IP address changes, a bit like DynDNS.

If you don’t have these, don’t worry; most of what you’ll learn here can be tweaked to work on different systems. The important thing is to understand what’s going on.

To get connected, you’re going to need to setup three things:

  • First, you need someone to allocate you a chunk of the IPv6 address space, so you can give addresses to your machines, and for that someone to tell the world that they can handle data for those addresses (which they’ll forward to you through a special tunnel). There are several organisations that will do this, but we’re going to use the excellent free Tunnelbroker service from those nice people at Hurricane Electric.
  • So how will IPv6 packets get to you from the outside world? Tunnelbroker will put them inside IPv4 packets, send them to you (hence the need for a fairly static IP address), and your Linux box will unpack them and send them out on your local network. This is actually more efficient than it sounds, and there are Tunnelbroker endpoints in several different parts of the world, so the tunnel can be a short one!
  • Finally, we need a way for machines on your network to know what their IPv6 address is, and how to send packets back through the tunnel to the outside world. We’ll do this by running a bit of software on your Linux machine called radvd – the Router Advertisement Daemon – which is roughly the equivalent of DHCP.

Here’s what we’re going to set up:

The best thing about all this is that it runs alongside your normal IPv4 system, which just keeps working as before, so it will only kick into action when you’re using IPv6, and won’t get in the way otherwise.

Creating a tunnel

Go to http://tunnelbroker.net/ and register for an account, then click the ‘Create Regular Tunnel’ link. It’ll ask you for your IPv4 endpoint – this should normally be the public IP address of your router – that’s probably the IPv4 address you saw if you went to ipv6-test.com earlier. You’ll also need to give it a description, and pick a Tunnelbroker endpoint that’s close to you, for maximum efficiency.

Once you’ve created your tunnel, you can take a look at the details, which will be a page something like this:

Click for larger image

The important bits here relate to the diagram above – make sure you understand these next two paragraphs. Look at the section marked IPv6 Tunnel Endpoints, and the tunnel illustrated in the diagram above. The Server IPv4 Address is the address of the Tunnelbroker end of the tunnel and the Client IPv4 Address is the public address of your end of the tunnel, generally the address of your router. The server and client IPv6 addresses are the addresses of the IPv6 link within that tunnel, as indicated in the diagram by the red arrow within the blue tunnel.

The Routed IPv6 Prefixes section, on the other hand, shows the prefix for the addresses that will be used on your network; the addresses that Tunnelbroker is going to route to your machines. These are very similar to but not the same as the addresses within the tunnel. They even use bold to emphasise the difference but it’s easy to forget and use the wrong one. When we set up the tunnel we’ll be using the addresses with 1f38 in them, and when we use radvd to advertise the addresses to use on your network we’ll be configuring it with the 1f39 addresses. In all the following examples, of course, you’ll need to put in the addresses specific to your tunnel.

OK, given that information, let’s log in to the Linux machine and start by getting it to talk to tunnelbroker. Edit /etc/network/interfaces and add your equivalent of the following:

auto he-ipv6
iface he-ipv6 inet6 v4tunnel
    address 2001:470:1f38:1825::2
    netmask 64
    ttl 255
    gateway 2001:470:1f38:1825::1
    dns-nameservers 2001:470:20::2
    post-up ip -6 route add default dev he-ipv6
    pre-down ip -6 route del default dev he-ipv6

This sets up the tunnel and creates a local interface called he-ipv6 that represents this end of it. We won’t go through all of it, but the last couple of lines – post-up and pre-down – tell the system that the default route for contacting the IPv6 world should be through this tunnel interface (and not, for example, through the machine’s ethernet interface which soon have an IPv6 address of its own.

The ‘auto he-ipv6’ command means that the interface, and hence the tunnel, will be started automatically when the machine boots up. For now, though, you can start everything manually with:

sudo ifup he-ipv6

and if all goes well, you can then take a look at it:

$ ifconfig he-ipv6
he-ipv6   Link encap:IPv6-in-IPv4  
      inet6 addr: fe80::c0a8:1e/128 Scope:Link
      inet6 addr: 2001:470:1f38:1825::2/64 Scope:Global
      RX packets:52042 errors:0 dropped:0 overruns:0 frame:0
      TX packets:35526 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:0 
      RX bytes:53875839 (51.3 MiB)  TX bytes:5181848 (4.9 MiB)

This shows you your end of the tunnel, the IPv6 address ending ::2, and you can ping6 the other end, the address ending ::1.

$ ping6 2001:470:1f38:1825::1
PING 2001:470:1f38:1825::1(2001:470:1f38:18245::1) 56 data bytes
64 bytes from 2001:470:1f38:1825::1: icmp_seq=1 ttl=64 time=18.2 ms
64 bytes from 2001:470:1f38:1825::1: icmp_seq=2 ttl=64 time=17.0 ms

You can try connecting to other places too, for example:

$ ping6 ipv6.google.com

If you have login access to another IPv6-capable machine – I used the server on which this blog is hosted – you can try pinging your Linux box from there. Remember, your Linux machine is at the local tunnel address, ending :2…

$ ping6 2001:470:1f38:1825::2

Hurrah! Your Linux machine, at least, now has a public IP address.

Incidentally, some utilities, like ping, have their own IPv6 versions – like ping6. Others, like ssh, will just use IPv6 automatically if given a v6 address. And some, like netstat, ip and route, will do IPv6 things if you specify an option, usually –6. So, for example, you can see your IPv6 routing tables with:

$ netstat -6 -r -n

Connecting the rest of your network

OK, now we need to tell your Linux box to be a router for IPv6 traffic. There’s a line you need to add to /etc/sysctl.conf, and it may already be there but just be commented out. Uncomment it, or add it:


You can reboot to make sure this setting is loaded, or run

$ sudo sysctl -p

which just tells the system to re-read the file.

One side effect of turning on routing is that it will disable the magic autoconfiguration of IPv6 addresses for the ethernet interface on that machine. That makes sense, really: you want the router to have a fixed address, in the same way that you don’t want your DHCP server to have a DHCP-allocated address! So we need to pick a static IPv6 address for your ethernet interface. On my network, the Linux box has an IPv4 address of, so I picked an IPv6 address with the ‘8’ at the end of it too:


Note the 1f39 here – we’re now talking about the local network, so we want the prefix to come from the Routed IPv6 Prefixes section of the tunnel configuration. I added some extra lines to /etc/network/interfaces to allocate this additional address to eth0:

iface eth0 inet6 static
    address 2001:470:1f39:1825::8
    netmask 64

You’ll have a section for eth0 already – this can be added separately because it’s configuring it for ‘inet6’.

You need to restart the eth0 interface to pick this up. If you’re logged in at the console you can do :

    $ sudo ifdown eth0
    $ sudo ifup eth0

but if you’re logged in by ssh this won’t work because you’ll be logged out by the first command! So you need to do them both at once: I tend check the details carefully and then get a superuser shell and run them like this:

    $ sudo -s
    root#  ifdown eth0; ifup eth0
    [ short pause, then hit return to check you still have a prompt ]
    root#  exit

If it worked, you can use ifconfig eth0 to see the new address.

So now your Linux box has a fixed IPv6 address on your local network interface and another one on the tunnel interface, and should be able to route traffic between them. We just need to tell the other machines on the network which IPv6 addresses to use, and that they should send traffic for the outside world to this machine.

On the Linux box, you need to get and install radvd:

$ sudo apt-get update
$ sudo apt-get install radvd

and configure it to advertise itself, and your network prefix, on your ethernet interface. Edit /etc/radvd.conf to say something like this:

interface eth0
    AdvSendAdvert on;
    prefix 2001:470:1f39:1825::/64
        AdvOnLink on;
        AdvAutonomous on;

Again, remember to use the right (routed) prefix for your local network. Then start up radvd, which on Debian would be

    $ /etc/init.d/radvd start

or restart it if it’s already running.

And now, a magical thing will start happening! The other machines on your network will start to get, in addition to their `fe80:: addresses discussed earlier, automatically-allocated addresses in your own IPv6 prefix. Log on to another machine and have a look at ipconfig, or in the Advanced > TCP/IP section of System Preferences, or wherever, and you should see addresses beginning 2001.

In fact, each interface may have two of these addresses in addition to the automatic fe80 one. That’s because one of them is, like the fe80 range, based on the MAC address of the hardware. It is predictable and will always refer to that machine, and you can deduce the MAC address of the machine from it and vice versa. Some people are worried about the security implications of this: my laptop could be recognised as being mine, whichever IPv6 network I’m using it on. So on most systems there will also be a temporary address which is used by default for outgoing traffic and which is less traceable.

You should now find that the other machines on your network will show IPv6 connectivity if you use them to go to ipv6-test.com, or browse to ipv6.google.com, or indeed visit ipv6.statusq.org. And you’ll also find that they can be contacted from elsewhere; you can use an online ping test like this one to test it out. This is cool – you can setup a system to backup your webserver to your home much more easily now, for example. If you have a DNS domain, you can even go out and register a AAAA record for one of your home machines so you can contact it more easily from elsewhere, for example.

But the fact that your machines can be contacted from outside means we need to think about security.

Security Thoughts

If you decide to leave this system running, you need to be fairly confident about the security of your systems. Routers running NAT, for all their annoying limitations, did at least offer a convenient layer of security to your network, and you’ve now worked out a neat way to bypass that! I would certainly be cautious about doing this if you have machines on your network running elderly versions of Windows, or if you haven’t been keeping your machines in sync with the latest security updates.

I went around and turned on the firewalls on all of my machines – something I hadn’t bothered with beforehand, and I am now thinking more seriously about any file-sharing and other services I run on them. But I also have to balance any paranoia with the fact that almost all of my systems are Unix-based, and running very similar software to hundreds of thousands of publicly-accessible webservers out there, including mine.

The right way to deal with the security issues, of course, is to re-introduce filtering on the Linux machine that’s running your tunnel. You now have the option to let through any connections you like, to any machine on your network, but the default should probably be to block everything except perhaps ssh, and only open up extra options as and when required. This may feel like a return to the dark days of NAT, but in this case, when you do decide to allow, say, telephony traffic to your VoIP phone, you’re getting a proper end-to-end connection from one machine to another, and not depending on a cheap NAT router maintaing a table of temporary mappings.

Configuring Linux IP tables is not for the faint-hearted, though. I’ll have a look at whether there are any easy-to-manage systems out there that would be good for this kind of use. Any recommendations welcome!

Update: I’ve now added a tutorial on how to do this with Shorewall.

In the meantime, if you’re concerned and you’d like to disconnect when you’ve finished experimenting, just do an

    $ ifdown he-ipv6

on the Linux box, and comment out the ‘auto’ line in /etc/network/interfaces so it doesn’t start up again on reboot.


  1. On Windows XP you may need to install it first – it’s easy to find instructions on the web, but I won’t really focus on Windows here.  ↩

  2. On a Linux machine, for example, it will probably be %eth0 or %wlan0, on a Windows machine it will be something like %4, where the 4 indicates the number of the interface.  ↩

Enjoyed this post? Why not sign up to receive Status-Q in your inbox?


This is a great tutorial thanks.

Not having a suitably small and quiet Linux box that I want to leave on all the time, I’ll probably investigate using a router and OpenWRT. A quick search for IPv6 and OpenWRT produces the following helpful pages:


Yes, I’ve been wondering about doing it that way, but the standard DD-WRT builds that will fit in the 4MB my router has available don’t support IPv6. 🙁

Ah… my tiny router (TL-MR3020) probably isn’t going to be up to the job then either.

I noticed that Sysadminman’s TL-WR1043ND had 8MB flash. Potential purchase justification? 🙂

The USB port is very useful for lots of interesting things too (sensors + owfs or mosquito/mqtt etc).

Amazingly clear and readable tutorial, thank you!

a tiny edit: I think you mean: “the addresses that Tunnelbroker _is_ going to route to your machines”

    Thanks Kai – I’m glad you liked it!

    Ah yes, I should probably change the text as per your suggestion, but I tend to think of organisations as plural, as a group of people, and the packets are the things that they *are* going to send me. You’ll notice I refer to Tunnelbroker with a plural verb elsewhere in the piece. But there’s plenty of debate out there about whether singular or plural forms are more appropriate for organisations.

    In this case, you’re probably right, because it’s really the entity that’s doing the forwarding, and not a bunch of diligent workers kindly sticking new addresses on little envelopes, however much I might like to picture it that way!

    In fact, now I think of it, Tunnelbroker is the service, and Hurricane Electric is the company. So yes, I should fix it.

Got Something To Say:

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax


© Copyright Quentin Stafford-Fraser