Getting IPv6 connectivity at home in 2007 means using a tunnel broker. I went with SixXS rather than Hurricane Electric because SixXS has PoPs in the UK (London and Manchester), which means lower latency. Here is how to get it running on a WRT54G/WRT54GL with DD-WRT v24.

SixXS account and tunnel

Register at SixXS and request a tunnel. You want an "AYIYA" tunnel type - this works behind NAT and with dynamic IPs, which is what most UK broadband connections have. SixXS will assign you a /64 for the tunnel endpoint and you can request a /48 subnet later for your LAN.

After approval (took about 2 days for me), you will have:

  • A tunnel ID (T12345)
  • A PoP endpoint (e.g. tic.sixxs.net)
  • Your IPv6 endpoint address (e.g. 2001:db8:1::2/64)
  • The PoP's IPv6 address (e.g. 2001:db8:1::1/64)

AICCU on DD-WRT

AICCU (Automatic IPv6 Connectivity Client Utility) is the SixXS client that sets up and maintains the tunnel. DD-WRT v24 standard and above includes AICCU. Enable it under Setup - IPv6:

IPv6: Enable
IPv6 Type: SixXS / AICCU
SixXS/AICCU Username: your-sixxs-username
SixXS/AICCU Password: your-sixxs-password
Tunnel ID: T12345

Save and apply. AICCU will connect to the TIC (Tunnel Information and Control) server, authenticate, and bring up the tunnel interface. You can check it is working from the command line:

# ifconfig sixxs
sixxs      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00
           inet6 addr: 2001:db8:1::2/64 Scope:Global
           UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1280
           RX packets:1547 errors:0 dropped:0 overruns:0 frame:0
           TX packets:1231 errors:0 dropped:0 overruns:0 carrier:0

Test connectivity to the PoP:

# ping6 -c 3 2001:db8:1::1
PING 2001:db8:1::1 (2001:db8:1::1): 56 data bytes
64 bytes from 2001:db8:1::1: seq=0 ttl=64 time=18.432 ms
64 bytes from 2001:db8:1::1: seq=1 ttl=64 time=17.891 ms
64 bytes from 2001:db8:1::1: seq=2 ttl=64 time=18.103 ms

Routing IPv6 to the LAN

The tunnel gives the router itself IPv6 connectivity, but LAN clients need addresses too. Request a /48 subnet from SixXS (under "Request Subnet" on your tunnel page). Once approved, you will get something like 2001:db8:abcd::/48.

Add the following to Administration - Commands as a Startup script (after the AICCU section):

#!/bin/sh
sleep 15

# Assign an IPv6 address to the LAN bridge
ip -6 addr add 2001:db8:abcd::1/64 dev br0

# Enable IPv6 forwarding
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding

# Add route for the subnet via the tunnel
ip -6 route add 2001:db8:abcd::/48 dev br0

# Start radvd for SLAAC
cat > /tmp/radvd.conf <<EOF
interface br0 {
    AdvSendAdvert on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    prefix 2001:db8:abcd::/64 {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr on;
    };
};
EOF
radvd -C /tmp/radvd.conf -p /tmp/radvd.pid

The sleep 15 is important - AICCU needs time to establish the tunnel before you start configuring routes. radvd handles SLAAC (Stateless Address Autoconfiguration), which means LAN clients will automatically pick up an IPv6 address without any manual configuration.

Verifying on a LAN client

On a Linux client:

$ ip -6 addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP>
    inet6 2001:db8:abcd::a1b2:c3d4:e5f6:7890/64 scope global dynamic
    inet6 fe80::211:22ff:fe33:4455/64 scope link

$ ping6 -c 3 ipv6.google.com
PING ipv6.google.com(2a00:1450:4009:803::1014) 56 data bytes
64 bytes from 2a00:1450:4009:803::1014: icmp_seq=1 ttl=56 time=24.7 ms

On Windows XP SP2, you may need to run ipv6 install first. Vista and above have IPv6 enabled by default.

Firewall rules for IPv6

This is the bit most guides skip. IPv6 on your LAN means every host has a globally routable address. Without firewall rules, the entire internet can reach your machines directly. That is the whole point of IPv6, but you still want a firewall.

DD-WRT v24 includes ip6tables. Add these to your Firewall script:

# IPv6 firewall rules
# Default policy: drop inbound, allow outbound
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT

# Allow loopback
ip6tables -A INPUT -i lo -j ACCEPT

# Allow established and related
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow ICMPv6 (required for IPv6 to work properly)
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A FORWARD -p icmpv6 -j ACCEPT

# Allow all outbound from LAN
ip6tables -A FORWARD -i br0 -j ACCEPT

# Allow inbound SSH to web server only
ip6tables -A FORWARD -d 2001:db8:abcd::10 -p tcp --dport 22 -j ACCEPT

# Allow inbound HTTP/HTTPS to web server
ip6tables -A FORWARD -d 2001:db8:abcd::10 -p tcp -m multiport \
    --dports 80,443 -j ACCEPT

# Log and drop everything else
ip6tables -A FORWARD -j LOG --log-prefix "IP6_FWD_DROP: " \
    -m limit --limit 5/min
ip6tables -A INPUT -j LOG --log-prefix "IP6_IN_DROP: " \
    -m limit --limit 5/min

The ICMPv6 rules are not optional. IPv6 uses ICMPv6 for neighbour discovery, path MTU discovery, and router advertisements. Block it and nothing works.

Performance and caveats

The AYIYA tunnel adds about 5-8ms of latency compared to native IPv4 to the same destination. Throughput is limited by the WRT54G's CPU doing the encapsulation - I measured about 8-10 Mbit/s which is fine for a home connection.

SixXS monitors tunnel usage and will disable tunnels that are idle for too long. AICCU sends heartbeat packets to prevent this, but if your router reboots frequently you may lose ISP (Internet Service Points) on your SixXS account. Keep the router up and your credit stays healthy.

One quirk: DD-WRT's AICCU sometimes fails to reconnect after a WAN IP change. I added a cron job that checks the tunnel every 10 minutes and restarts AICCU if it is down:

*/10 * * * * ping6 -c 1 -W 5 2001:db8:1::1 || /usr/sbin/aiccu stop; sleep 2; /usr/sbin/aiccu start

Not elegant, but it works. I have had uninterrupted IPv6 for the last three months with this setup.