Stupid OpenWRT ipv6 tricks

So, if you’re like me you find yourself wondering why your broadband provider has a /32 IPv6 prefix assigned, and yet chooses not to use it, forcing one to either be IPv4-only (how 20’th century) or use an IPv6-over-IPv4 tunnel solution.

Fortunately there is a simple and free solution out there, courtesy of Hurricane Electric’s rather fabulous tunnelbroker service. Obtaining an IPv6 prefix and setting up the tunnel is covered, extensively, so I won’t go into it. It’s also rather easy to set the tunnel up on an OpenWRT based router, like mine. The default setup is rather nice, but there are some changes you can make to your router configuration that will make it even nicer.

Remove the “ULA Prefix”

OpenWRT creates, by default, a ULA prefix – a deprecated “site-local” prefix. While these are perfectly valid, I’ve found that non-globally routable IPv6 addresses tends to confuse the heck out of Android-based phones, resulting in certain operations taking forever while various network operations time out, and are then retried with globally routable addresses. They’re also pointless, as we don’t do IPv6 NAT (don’t even think it), so just remove it. Your phone will thank you.

A note about firewalls

It’s worth repeating: we don’t do IPv6 NAT. Assuming you’ve removed the ULA prefix, every non-link-local IPv6 address assigned will be globally routable, meaning, among other things, that you can’t just rely on NAT to be your firewall, you’ll actually have to use your router as a firewall as well.

This is also well documented, and left as an exercise for the reader. …one I rather suspect you’ve already completed, as, well, you’re using OpenWRT, aren’t you?

More than one network? Get a /48!

By default, HE will give you a /64 routed prefix: this is the pool of addresses your LAN-connected devices will draw from. If you ask – that is, hit the “assign /48” button on your tunnel’s configuration page – HE will also give you a /48. Why would you do this? Well, while you can subdivide your /64 up and route it however you want, most IPv6 tech presumes the smallest network it will ever encounter is a /64. If you choose to, say, make your wired and wireless networks distinct and route rather than bridge between the two the canonical approach is to use one /64 for the wired network, and a second, different /64 for your wireless. (The same logic applies if you wish to also delegate prefixes to hosts on your network – say a /64 to some box you have running a bunch of VM’s or docker containers on.)

But how to set this up easily? Remember that “ULA prefix” option, above? Just put the /48 prefix HE assigned you in there, and everything will Just Work. Delegating specific /64’s to interfaces can be done with “hints” in the interface configuration, and each internal interface will receive a /64 from your /48 automatically.

Yes, this means at least one of your internal networks will have two /64 prefixes addresses can be assigned/chosen from. Don’t sweat it: your device should pick up an address from each /64, and things will Just Work.


OpenWRT uses dnsmasq to provide DNS, and because of this we can do some neat things. If you edit your /etc/dnsmasq.conf appropriately, you can get:

Hostnames for the ips assigned to our interfaces, automatically

# hostnames for our interface ips!


$ host lan.router
lan.router has address
lan.router has IPv6 address 2001:470:XXXX:1::1
lan.router has IPv6 address 2001:470:1f11:XXXX::1

“Synthetic” hostnames

That is, a deterministic hostname for every ip on a given subnet that dnsmasq doesn’t already know a hostname for.

# Apparently /48 breaks dnsmasq more than a bit


$ host 2001:470:1f11:XXX::2 domain name pointer 2001-470-1f11-XXXX--2.ip.lan.

Note this “synthetic hostname” will only be returned if dnsmasq lacks a better name, e.g.:

$ host 2001:470:1f11:XXX::1 domain name pointer lan.router.

AAAA records

While OpenWRT does not use dnsmasq for router advertisements, we can still use it’s rather nifty “match info from DHCPv4 requests against the DID/MAC the device would use for SLAAC” functionality to enable it to return both A (IPv4) and AAAA (IPv6) records when asked for an internal hostname:

$ host mfc.lan
mfc.lan has address
mfc.lan has IPv6 address 2001:470:...
$ ping6 mfc.lan
PING mfc.lan(mfc.lan) 56 data bytes
64 bytes from mfc.lan: icmp_seq=1 ttl=64 time=0.490 ms
64 bytes from mfc.lan: icmp_seq=2 ttl=64 time=46.5 ms

Enable with the somewhat cryptic:

# serve AAAA records based off DID/MAC and DHCPv4 requests

…or some permutation thereof, if you’ve altered the topology of your internal network.

Strip AAAA records for Netflix

Sigh. Yes, apparently we need to do this. Lame. Basically, Netflix thinks it doesn’t know where you are located, so will refuse to serve content to any address that HE has delegated to you via tunnelbroker (e.g. your /64, /48). Fortunately, this is a problem others have already elegantly resolved: OpenWRT workaround against Netflix blocking IPv6 requests from tunnel brokers.

Basically, the solution is to build and install a bind package that supports the strip-aaaa option, then have dnsmasq delegate any lookups for * to the bind server. Clean, simple, and easily extensible to any other service that may choose to do the same thing in the future.

With this hack in place, without impacting any other domain your lookups will go from this:

$ host
Using domain server:
Aliases: has address has address has address has address has address has address has address has address has IPv6 address 2406:da00:ff00::34cf:6f90 has IPv6 address 2406:da00:ff00::34ca:21dd has IPv6 address 2406:da00:ff00::34c8:ef2b has IPv6 address 2406:da00:ff00::36a4:da76 has IPv6 address 2406:da00:ff00::34ce:44b0 has IPv6 address 2406:da00:ff00::3655:55f6 has IPv6 address 2406:da00:ff00::34cb:53f8 has IPv6 address 2406:da00:ff00::34cd:591a

…to this:

$ host has address has address has address has address has address has address has address has address

These are little things, yes (hence the “stupid … tricks” appellation), but every little bit helps when trying to figure out a problem.

…or, you know, appease Netflix :)