No, use *my* DNS. (aka Netflix vs

Google DNS is being hardcoded into a significant number of devices now. Which is nice, because it pretty much always works.

…except when you’re trying to use Netflix and you have a tunnelbroker IPv6 tunnel. Ugh.

So, this is a brief followup to Stupid OpenWRT tricks. Or maybe “Getting Netflix to work when your ISP doesn’t support IPv6 yet” is a better way to put it…

Anyways. In the previous post it I talked about how to use a local instance of bind to strip ipv6 addresses (AAAA records) from responses. (Again, I can’t take credit for that, though I like the way the person who came up with the idea thinks!) That solution works fabulously.

…unless your device decides it’s going to ignore your DNS servers, and go hit up or (or 2001:4860:4860::8888 or 2001:4860:4860::8844) directly. That’s going to fail. Ugh.

DNAT to the rescue! (Some NAT, like some cholesterol, moderate alcohol intake, and not staying up all night too often, is actually incredibly useful to downright fun. Particularly when staying up all night and the moderate alcohol intake are combined with writing ip6tables DNAT rules.)

The problem is that we have clients bypassing our DNS in favor of servers out on the public Internet. Our solution? Find anything that’s headed in through our lan interface (typically br-lan) and is headed to 53/udp, and DNAT it so that it’s headed to our router’s lan ip address. We don’t need to try to capture or reroute DNS traffic to etc, because we don’t really want any of our clients doing direct DNS queries. (At least, I can’t think of a good reason.)

OpenWRT makes this pretty easy. While the Network->Firewall->Traffic Rules page doesn’t support DNAT, it’s easy enough to craft a custom rule and plug it in on the not very deceptively named “Custom Rules” page. OpenWRT also has a rather nice setup of iptables chains, including ones for user-defined rules, so you can add rules without their being trashed every time the firewall is reloaded.

For our purposes, this will do the trick:

iptables -t nat -A prerouting_lan_rule -p udp --dport 53 -j DNAT --to -m comment --comment 'dns capture and redirect DNAT'

Note we’re using the user rule prerouting_lan_rule; this rule already only has packets coming in on br-lan, so we can omit the -i br-lan from our rule we’d otherwise need.

Once you’ve saved this, you either need to reboot or just ssh into your router and run the command directly, and you should be able to watch Netflix again. You can run host from a client box to see that no AAAA records are returned.

While we’re here, we should probably do this for IPv6 as well, just in case. First you’re going to need to install a couple additional packages: kmod-ipt-nat6, and if your lan interface is a bridge you’ll also need kmod-ebtables-ipv6. Then this rule should do it:

ip6tables -t nat -A PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 2001:470:XXXX:XXXX::1 -m comment --comment 'dns capture and redirect DNAT'

Note OpenWRT does not set up any chains in the IPv6 nat table, because you should never use NAT in IPv6.

Um, aside from this, naturally.


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 🙂