IPv6 Using Hurricane Electric's 6in4 Tunnel

IPv6 Playground

The goal is to have IPv6 Internet access available in a home network, not just on a single computer. Furthermore, any modifications and subsequent restarts of the IPv6 access part should not affect the stable IPv4 connectivity.

It should be also possible to monitor the IPv6 or IPv4 traffic separately to make troubleshooting easier.
IPv6 does currently not bring any benefit to the end user. This configuration is meant for testing and educational purposes.


To satisfy those requirements, I deployed a separate router to take care of the 6in4 tunnel. The Linksys WRT54GL is widely available, cheap and has excellent community support as well as a good choice of alternative feature rich firmware. I installed OpenWRT.

One option would be to use the existing IPv4 connectivity and connect the WAN (6in4 tunnel) and LAN (IPv6 only) sides of my tunnel machine to the existing LAN. But then there would be NAT...
Since my ISP allows multiple PPPoE sessions and I have ADSL modem and PPPoE router separated and thus the PPPoE interface openly available, a stricter separation of my stable network and the IPv6 domain is possible. The result is a more risk free playground configuration.

Separate Routers for v4 and v6 with own PPPoE

The Ethernet output of the ADSL modem is connected to the WRT54GL (running tomato) which provides PPPoE and NAT routing for basic IPv4 connectivity, and the experimental WRT54GL (running OpenWRT) which also establishes a IPv4 PPPoE session to my ISP (e.g. using a second IPv4 address) and takes care of the 6in4 tunnel.
This small PPPoE LAN requires a separate 3 port Ethernet switch, or better a part of an existing managed switch will be used as separated (untagged) VLAN. I chose the latter one, as this allows easily to monitor the WAN side using the port mirror feature.

The LAN side of the two routers connect both to the home LAN, providing IPv4 and IPv6 connectivity. I can freely reconfigure, restart or turn off and remove the IPv6 router without affecting the basic IPv4 connectivity.

Configuration of the WRT54GL as IPv6 access router over a 6in4 tunnel

There are several recipes on the Internet how to configure a 6in4 tunnel using Hurricane Electric. But I could not find any guide answering all my questions and explaining what is actually being done.
Therefore I want to publish my experience for my own reference and possibly for the benefit of others. It should work not only for my very special configuration, but as well if only one router is being used.

Attention: This is a step-by-step procedure, doing just one step at a time. This means the firewall part is done after the connectivity works. This means the 6in4 router, and potentially other connected nodes, depending on proceeding, are exposed to the IPv6 Internet without NAT protection.
As the WRT IPv6 router is an experimental box and this firewall-less state is transitional, this was acceptable for me.

Here is how it went:

Install OpenWRT

The 6in4 package is only available for "Backfire" 10.03.1-rc4 and later.
There are two possible releases for the WRT54GL, which has a Broadcom BCM3302 chip in it's 1.1 HW version:

  • brcm-2.4    kernel 2.4
  • brcm47xx  kernel 2.6

For whatever reason, I started with brcm-2.4. Everything went well until I configured the firewall. Some needed features (stateful inspection) are only available on the 2.6 kernel. So I recommend to install the brcm47xx FW, as I did in my second attempt. First flash over the original Linksys FW requires the WRT54G image with the .bin extension. Later on .trx images can be used.

Get the firmware here:

Flash the the FW using the original FW update option in Linksys' web GUI.

Add IPv6 and 6in4 tunnel support

For the rest we need to use a SSH terminal. OpenWRT has already quite extensive feature on the GUI, also packet installation. But I had a negative experience using the GUI for this. Therefore I recommend to to everything on command shell.

Check the interfaces before (only eth0 shown here):

root@OpenWrt:/# ifconfig
eth0      Link encap:Ethernet  HWaddr C0:C1:C0:1D:A5:E6
RX packets:823 errors:0 dropped:0 overruns:0 frame:0
TX packets:637 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:105444 (102.9 KiB)  TX bytes:171193 (167.1 KiB)

-> no IPv6

For IPv6 and the 6in tunnel we need following additional packages:

  • ip
  • kmod-ipv6
  • kmod-sit
  • kmod-iptunnel4
  • 6in4

In some guides, those packages are simply installed by giving their short names, e.g. "opkg install ip". The package source is somewhere defined. In my case it did not work for whatever reason. I had to specify the full path. Furthermore, in my attempt with brcm-2.4 release dependencies where resolved automatically. I needed to specify only the full path for 6in4 and all other packages have been installed automatically. This did not work on brcm47xx. Therefore I installed all packages one by one in the correct order of dependencies.

Install all basic module for IPv6 and 6in4 tunnel support and restart the network service:

root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm47xx/packages/kmod-iptunnel4_2.6.32.25-1_brcm47xx.ipk
root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm47xx/packages/kmod-sit_2.6.32.25-1_brcm47xx.ipk
root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm47xx/packages/kmod-ipv6_2.6.32.25-1_brcm47xx.ipk
root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm47xx/packages/ip_2.6.29-1-2_brcm47xx.ipk
root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm47xx/packages/6in4_8-1_all.ipk

Check the interfaces again:

root@OpenWrt:/# ifconfig
eth0      Link encap:Ethernet  HWaddr C0:C1:C0:1D:A5:E6
inet6 addr: fe80::c2c1:c0ff:fe1d:a5e6/64 Scope:Link
RX packets:1070 errors:0 dropped:0 overruns:0 frame:0
TX packets:657 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:269288 (262.9 KiB)  TX bytes:63248 (61.7 KiB)

-> One more line output. All interfaces got IPv6 addresses. Those are link-local addresses and not routable. They contain the MAC and can only be used to communicate between neighboring nodes, e.g. all nodes on the same L2 LAN.

Status now: IPv6 support is enabled, 6in4 tunnels are supported and can be configured.

Tests: A neighboring node with IPv6 support (most OS by default, e.g. Ubuntu) can be pinged with "ping6" and other nodes can ping the WRT54GL with IPv6. Attention: passing the link-local address to ping6 returns an "invalid argument" error. It can not be determined which interface to use. Using link-local addresses with ping6 is possible by specifying the interface, e.g.:

ping6 -I eth0 fe80::c2c1:c0ff:fe1d:a5e6

6in4 configuration

First of all the remote tunnel endpoint must be ready. For this, a user account at Hurricane Electric (HE) must be registered. Go to http://tunnelbroker.net, register and get the needed configuration data.
We need:
- The IPv4 address of the nearest point of presence of HE (Server IPv4 address)
- The IPv6 address of the local tunnel endpoint (client IPv6 address)
- The tunnel ID
- Username
- Password

The local IPv4 address needs to be known at both ends of the tunnel and could be specified in the local tunnel configuration and on the HE web site. But as these address changes usually, the 6in4 implementation includes a mechanism to update the local IPv4 address to both tunnel ends. Updating the remote tunnel end's IPv4 address works only with Hurricane Electric's tunnels. Only in this case the options 'tunnelid', 'username' and 'password' need to be given and the local IPv4 address can be omitted.

Attention! Username  and Password are NOT the same as used to login to HE's tunnelbroker web site!
The username can be found under the "Account Menu" / "Main Page". The password for tunnel updates is a MD5 hash of the password used for the HE web login.
It can be generated under Linux: echo -n <your_HE_password> | md5sum

The interface configuration is stored in /etc/config/network. We need to open this file with an editor, e.g. vi, and add a new section to create a new interfac

config 'interface' 'henet'
option 'proto' '6in4'
option 'peeraddr' ''
option 'ip6addr' '2001:470:xx:xxx::2/64'
option 'ipaddr' ''
option 'tunnelid' '11xxxx'
option 'username' 'tb4ddxxxxxxffc57.17xxxx88'
option 'password' '9e7a3c71d9xxxxxxxxxxff7a40196ef3'

The 'ipaddr' (own IPv4 address) is optional, if HE's API and auto configuration is used. If the tunnel does not come up, it's worth to try to configure the local IPv4 address first manually.
Saving the file and restarting the network service should bring our 6in4 tunnel up!

root@OpenWrt:/# etc/init.d/network restart

Listing all interfaces should show us a new one which got the name as specified in the "config interface" section, with a prefix "6in4-".

root@OpenWrt:/# ifconfig
6in4-hene Link encap:IPv6-in-IPv4  
inet6 addr: fe80::b634:530f/128 Scope:Link
inet6 addr: 2001:470:xx:xxx::2/64 Scope:Global
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

It should now be possible to ping the remote tunnel end point (HE server side) as well as other IPv6 hosts like ipv4.google.com.

In case of problems, check on the HE side, if the local IPv4 address has been updated to the server side of the tunnel. Try to change the HE side config manually, if the update does not work.

I came across a strange problem during my first run with brcm-2.4: I could ping the remote tunnel end point, but no other IPV6 addresses.
Checking the routing table for IPv6 revealed that besides a routing entry for the tunnel end point, there have been multiple default routes.

root@OpenWrt:/# ip -6 route show
2001:470:xxx:xxx::/64 via :: dev 6in4-henet  metric 256  mtu 1280 advmss 1220
fe80::/64 dev eth0  metric 256  mtu 1500 advmss 1220
fe80::/64 dev br-lan  metric 256  mtu 1500 advmss 1220
fe80::/64 dev eth0.1  metric 256  mtu 1500 advmss 1220
fe80::/64 via :: dev 6in4-henet  metric 256  mtu 1280 advmss 1220
ff00::/8 dev eth0  metric 256  mtu 1500 advmss 1220
ff00::/8 dev br-lan  metric 256  mtu 1500 advmss 1220
ff00::/8 dev eth0.1  metric 256  mtu 1500 advmss 1220
ff00::/8 dev 6in4-henet  metric 256  mtu 1280 advmss 1220
default dev eth0  proto kernel  metric 256  mtu 1500 advmss 1220
default dev br-lan  proto kernel  metric 256  mtu 1500 advmss 1220
default dev eth0.1  proto kernel  metric 256  mtu 1500 advmss 1220
default dev 6in4-henet  metric 1024  mtu 1280 advmss 1220

The ping echo requests were sent to the wrong interface!
I removed the wrong default routes:

root@OpenWrt:/# ip -6 route delete default
root@OpenWrt:/# ip -6 route delete default
root@OpenWrt:/# ip -6 route delete default

Only the last default route, pointing to the local IPv6 tunnel end point remains.

Now we have full IPv6 connectivity on the WRT54GL! Our fixed and permanent public IPv6 address is the "client IPv6 address", e.g. the local tunnel end point.

What's missing?

1) There is currently no firewall! Contrary to the usual IPv4 NAT configuration, we use public IPv6 addresses also on the LAN, and those are globally reachable. This is a benefit and a risk at the same time. The IP6TABLES firewall should be installed to control and limit incoming traffic.I will do this later after, as the iptables configuration can be complex. Until now only our router is exposed to the public IPv6 Internet. Make sure it has a secure password.

2) All hosts on the LAN should get global routable IPv6 addresses as well! For this, HE routes a complete subnet to our tunnel endpoint. By default it's a /64 prefix. Optionally a /48 prefix can be assigned. Those subnets are of a different address range than the tunnel endpoints.
The assigned networks / prefixes can be found under the tunnel data on HE's website ("Routed IPv6 Prefixes").

Making IPv6 available on the LAN

The LAN facing interface of our IPv6 router needs to get an address out of the routed IPv6 subnet assigned and forwarded by HE.

Add "option 'ip6addr' '2001:470:xx:xxx::1/64" to the LAN interface in the network configuration in /etc/config/network (lan). You can find the correct interface also by looking for the interface having the router's IPv4 address, e.g. as default.

We also have to allow the forwarding of IPv6 packets:
remove the comment mark in /etc/sysctl.conf and restart the network service:

remove  # net.ipv6.conf.all.forwarding=1 in  /etc/sysctl.conf

root@OpenWrt:/# /etc/init.d/network restart

The routing table is automaticall updates if an interface gets a new IP address. Now there should be a routing entry to forward all IPv6 addresses under this prefix to the br-lan interface.

We could now configure any IPv6 address out of our /64 subnet to a host on our LAN and we would have IPv6 connectivity. But it's easier. The NDP, Neighbor Discovering Protocol, lets neighboring hosts find the IPv6 router themselves and configure the IPv6 address also by themselves.

Advertise the routed IPv6 network to allow neigboring hosts to configure their IPv6 connectivity themselves

For this to work, the router must advertise which prefixes it can route.
This is done by the Router Advertising Daemon radvd.

root@OpenWrt:/# opkg install http://downloads.openwrt.org/backfire/10.03.1-rc4/brcm-2.4/packages/radvd_1.6-1_brcm-2.4.ipk

In the configuration file /etc/config/radvd we specify which routing prefixes should be advertised on which interfaces.
It should look like this:

root@OpenWrt:/# cat /etc/config/radvd 
config interface
option interface 'lan'
option AdvSendAdvert 1
option AdvManagedFlag 0
option AdvOtherConfigFlag 0
# option AdvLinkMTU 1452
option ignore 0
config prefix
option interface    'lan'
option prefix    '2001:470:xx:xxx::/64'
option AdvOnLink    1
option AdvAutonomous    1
option AdvRouterAddr
option ignore    0

The daemon should be permanently enabled and restarted after configuration changes:

root@OpenWrt:/# /etc/init.d/radvd enable
root@OpenWrt:/# /etc/init.d/radvd restart

After this, neighboring nodes should configure their own IPv6 addresses and are ready to go without any configuration work! Often the MAC address is used as part of the Interface ID to construct a unique IPv6 address. As the IPv6 address is forwarded globally and the MAC tells something about you and makes it possible to recognize when returning to a web site, some host have "privacy extensions" which use random numbers and change those frequently.
There is also DHCPv6 to get full centralized control over assigned addresses.

Dual Stack Routing Strategies

Now as we have IPv6 and IPv4 available on our hosts, which IP network would a host use?

First of all the application requests IP addresses for a specific domain (FQDN). On dual stack OS, usually both, IPv4 (A) and IPv6 (AAAA) record would be requested. The OS (resolver) returns a list of all available IP addresses. This list is sorted according to OS preferences. If an IPv6 address is available, it would be usually on top position and being the preferred one. This selection process is specified in RFC3484, but the rules can be changed.
If the packet can not be forwarded (ICMP returns an error), the next address in the list will be tried.

In other words, the OS configuration gives some preferences, but the application decides finally. Therefore its difficult to predict how a certain overall configuration behaves.

You have no rights to post comments

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.