For no good reason in particular, I started looking into IPv6 this week-end. The quick summary first: It works. It's not really difficult to set up. But it's not easy enough, either.
The first realization was that the Macintoshs on the network here had been hapiily chatting IPv6 among themselves while I wasn't looking; link-local addresses had configured themselves, and multicast DNS had glued things together seamlessly. Kudos to Apple for that.
Now, the first thing to try was of course telling the MacBook to open a 6to4 tunnel. That's supposedly all that's needed to connect a host to the ipv6 Internet, and it's really easy. Except, well, you need a publicly routed IPv4 address, static if you want to get routed ipv6 addresses from one of the tunnel brokers out there. Bummer.
Next thing to look at, the NAT box. It's actually in a reasonably good position to set up these things, but, alas! -- there's a plethora of firmware options out there, some without IPv6 support, some with broken IPv6 support, some with outdated documentation. The firmware that's installed doesn't support IPv6, and I wasn't in a device-bricking mood.
The solution that I went for was two-tiered: First, IPv6-enabling the server that runs this Web site. Second, setting up Debian on a spare machine here and connecting it to that server through OpenVPN.
Hurricane Electric's tunnel broker turns out to be a really easy way to get IPv6 address space, and to get it all up, I just needed to add the following to this Debian box's /etc/network/interfaces file:
iface sit0 inet6 static
address 2001:0470:1f0a:974::2
netmask 64
gateway ::216.66.80.30
Then, ifup sit0 and the machine had IPv6, as verified by showing ipv6.google.com in a command line browser.
Next, the home network: Hurricane Electric offers /48 prefixes (yes, we are talking of 2^80 IP addresses here). I got one of these delegations; the network is simply routed through the existing v6-over-v4 tunnel. The missing piece was a tunneling solution that only needs one fixed endpoint. My tool of choice, OpenVPN, running (on the local end) on an old Laptop with Debian.
It's reasonably easy to run. Parameters on the server side:
proto udp dev tun0 tun-ipv6 ifconfig 10.1.1.1 10.1.1.2 ping 10 up /root/ipv6-simpler ping-restart 60 persist-tun secret /root/openvpn.key
In other words, I'm using an encrypted tunnel, it can speak IPv6, and we use 10.1.1.1 and 10.1.1.2 as the addresses on the tunnel. For authentication purposes, a pre-shared key (created with openvpn --genkey is used.
The client-side configuration:
secret /root/openvpn.key proto udp dev tun0 tun-ipv6 ifconfig 10.1.1.2 10.1.1.1 remote newtoy.does-not-exist.org ping 10 up /root/ipv6-simple persist-tun ping-restart 60
That's pretty much the same as the server-side configuration, except that the "ifconfig" parameters are swapped, and the remote end is specified.
The important piece that remains here are the up scripts referenced in the two configurations, as these are where we actually set up the IPv6 part of the tunnel.
Server-side first:
ip addr add 2001:470:9aae:1::1/128 dev tun0 ip route add 2001:470:9aae:1::2/128 dev tun0 ip route add 2001:470:9aae:f100::/64 via 2001:470:9aae:1::2 sysctl -w net.ipv6.conf.all.forwarding=1
In other words, we add an IPv6 address (::1) within the /48 netblock to the tunnel interface, we add a host route to another address in that network (::2), and we route a /64 prefix (:f100::) through the other end of the tunnel.
Now, client-side:
ip addr add 2001:470:9aae:1::2/128 dev tun0 ip route add 2001:470:9aae:1::1/128 dev tun0 ip route add default via 2001:470:9aae:1::1 ip addr add 2001:470:9aae:f100::1/64 dev eth0 sysctl -w net.ipv6.conf.all.forwarding=1
This is (mostly) the same as the server, with roles reversed as far as the tunnel is concerned, and a default route pointing at the server's end of the tunnel.
At this point, the bridgehead machine is connected to the IPv6 internet as both ...:1::2 and ...:f100::1.
The final missing piece: Telling other machines on the local network that there is an IPv6 router. I'm using radvd, with a pretty simple configuration file:
interface eth0
{
AdvSendAdvert on;
prefix 2001:470:9aae:f100::/64
{
AdvAutonomous on;
AdvOnLink on;
AdvRouterAddr on;
};
};
radvd tells other hosts on the local networks that the bridgehead machine is an IPv6 router, and what the prefix is on that network. Thanks to IPv6 stateless autoconfiguration, IPv6 clients on that network will acquire addresses within the prefix that's assigned there, and will route through that machine.
That's really all: Devices on the local network with a functioning IPv6 stack will now acquire globally routable IPv6 addresses, and will be reachable from other IPv6 hosts without a NAT or anything of that order.