Ramblings of an aging IT geek
← Ramblings of an aging IT geek
networking

getting ipv6 working at home, finally

How I got a working dual-stack setup at home over a 6in4 tunnel after my ISP kept promising native IPv6 and never delivering.

A bundle of patch cables behind a network rack

I have been waiting for native IPv6 from my ISP for what feels like the entire run of this decade. Every year there is a forum post promising a trial "soon". Every year soon arrives and leaves without me. So this weekend I stopped waiting and did the thing I should have done ages ago: I tunnelled.

The short version is that I now have a working dual-stack network at home. Every machine has a real, routable, globally unique address, the kind that makes you feel slightly powerful and slightly nervous in equal measure. It went better than I expected, and the parts that went badly were entirely my own fault.

why bother

The honest answer is curiosity. The slightly more respectable answer is that I want to actually understand IPv6 before it stops being optional, and the only way I learn anything properly is to break it in my own house where the only person I am annoying is me.

There is also a practical itch. NAT has been quietly lying to me for years. Port forwards, hairpin NAT that does not hairpin, the eternal joy of explaining to a service that no, it is not actually on a public address. With a /64 sat behind my router every device can have its own address and I can stop pretending the 1990s were a good idea.

the tunnel

I went with a 6in4 tunnel from Hurricane Electric's tunnelbroker.he.net. It is free, it has been around forever, and the documentation is the sort of plain HTML that ages well. You give them your IPv4 endpoint, they hand you a /64 (and a /48 if you ask, which I did, because future me will want subnets).

The setup on my Linux router is genuinely small. This is the whole tunnel:

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

The one thing that bit me, and I am embarrassed at how long it took to spot, is that 6in4 is protocol 41, not a TCP or UDP port. My firewall was happily dropping it because I had written rules thinking in terms of ports. Once I allowed proto 41 from the tunnel server's address the whole thing lit up at once. Pinging ipv6.google.com and getting a reply back is a small thing but I may have made a noise.

Racked equipment with a tangle of fibre and copper

handing addresses to the LAN

A tunnel to the router is half the job. The interesting bit is getting the rest of the house onto v6 without manually numbering everything like an animal.

I split the /48 into sensible /64s, one per VLAN, and ran radvd to advertise prefixes so machines could autoconfigure with SLAAC. Here is the relevant chunk for the main LAN:

interface eth1 {
    AdvSendAdvert on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    prefix 2001:470:7f08:1::/64 {
        AdvOnLink on;
        AdvAutonomous on;
    };
};

Within seconds every Linux and Mac box on the network had grabbed an address and was reachable. Windows behaved too, eventually. Android, predictably, took SLAAC but flatly refused DHCPv6, which is a religious war I have no intention of joining today.

The thing nobody warns you about is privacy extensions. By default modern stacks generate a temporary, rotating address for outbound connections so you are not trivially trackable by your interface's MAC. Sensible for a laptop on a café network, mildly annoying when you are trying to firewall a specific server and its address keeps changing under you. For the boxes that matter I pinned static addresses and left the laptops to wander.

There is also the small mental adjustment of having a routable address on everything. With v4 and NAT, the firewall was implicit: nothing was reachable from outside unless I forwarded a port, because nothing had a public address to begin with. With v6 every device is, in principle, reachable from the entire internet. That is the point, and it is also a responsibility. The default stance on the border has to be deny-inbound, and you open holes deliberately, the same way you would for a server on a real public address. It is not harder, it is just honest about what was always true.

what actually broke

Two things, both predictable in hindsight.

First, MTU. The tunnel adds overhead, so the usable MTU drops to 1480. A handful of sites just hung: connection established, then nothing. Classic path MTU discovery being eaten by some overzealous firewall out on the internet that drops ICMP. The fix is to clamp the MSS on the tunnel so TCP negotiates a sane segment size up front, and to stop blocking ICMPv6 on my own border, which you genuinely must not do because v6 leans on it far more than v4 ever did.

Second, happy eyeballs. Some software now races v4 and v6 and picks whichever answers first. When my tunnel had a bad latency moment, a few apps quietly fell back to v4 and I spent ten minutes convinced my routing was broken when actually it was working exactly as designed. The lesson: a tunnel is never going to be as quick as native, and the tooling already knows that better than I do.

was it worth it

Yes, easily. It is not native, it adds latency, and a tunnel through a third party is not something I would lean on for anything serious. But as a way to drag myself out of v4-only thinking it has been the best afternoon of homelab faffing I have had in months.

The real win is mental. I now reach for ip -6 without flinching, I understand why ICMPv6 matters, and I have a /48 sat waiting for the day my ISP finally delivers the native connectivity they have promised since roughly the Bronze Age. When that day comes I will tear the tunnel down without a hint of sentiment. Until then, it does the job, and every device in the house has an address it can call its own.