NOTE: this was originally written for OpenWRT, but I have since added comments pointing out what things need to be done differently for LEDE.

Due to the lack of IPv6 connectivity at our ISP (#NoIPv6AtComHem #InTheYear2016NoLess #PublicShaming), we use the awesome IPv6 tunnel service from Hurricane Electric in our household. To our surprise we were able to watch the US program of Netflix for a short while, even though our tunnel endpoint is in Sweden. But sadly that did not last long, as Netflix, in their quest to annoy paying customers an attempt to follow the stupid rules of the content industry, recently started considering HE’s tunnel brokering service a ‘proxy service’ and outright blocks watching when coming from these IPs.

Our main Netflix viewing device, the PS3, remained unaffected, as it also lives in the past and knows nothing of IPv6. All other devices try IPv6 first and get a timely response containing the proxy error message from Netflix. While this satisfies the happy eyeballs algorithm, it does fall a bit short when it comes to actually making my eyeballs happy.

So, how do I keep both my IPv6 connectivity and the ability to watch Netflix on all capable devices in the household? I solved this by setting my OpenWRT router up in a way that it strips the IPv6 addresses from DNS responses for netflix.com, leaving the client no other option than to connect via IPv4.

Credit goes to jmwhite, whose instructions I based this article on.

Please note that this workaround will only restore your ability to watch what Netflix allows you to watch in your country.

Instructions

OpenWRT uses dnsmasq as DNS resolver and DHCP server by default. This is very convenient and simplifies the name resolution of local devices. But dnsmasq lacks the capabilities to manipulate DNS responses in the way that is desired in this case. What it can do however, is hand DNS requests for certain domains over to another DNS resolver. One such resolver, bind9, conveniently offers the option filter-aaaa-on-v4, which strips the AAAA records (i.e. the IPv6 addresses) from DNS responses to requests that come in via IPv4.

The bind-server package from the official OpenWRT repositories was not built with that option turned on, so the first thing we have to do is build the package.

On LEDE the filter-aaaa-on-v4 is enabled by default and we don’t have to build the package ourselves - they can be installed straight from the repositories of the LEDE project. After that we can go straight to configuring.

Building the bind-server and bind-lib package for OpenWRT

To that end, we fetch the OpenWRT sources. I use the 15.05 release ‘Chaos Calmer’.

mkdir openwrt-build
cd openwrt-build
git clone https://git.openwrt.org/15.05/openwrt.git .

Next, we need to fetch the packages’ sources.

./scripts/feeds update -a
./scripts/feeds install -a

Now we need to run make menuconfig to select the Target System (in my case ‘Atheros AR7xxx/AR9xxx’) and select bind-server for building (NetworkIP Addresses and Namesbind-server). If you are unsure which platform your router uses, you can SSH into the router and have a look at /etc/openwrt_release where the variable DISTRIB_TARGET tells you what platform your router is running on.

We have to change the build configuration of bind so that it includes the desired filter-aaaa-on-v4 option. To that end, we edit the Makefile in feeds/packages/net/bind/Makefile and add the flag --enable-filter-aaaa to the CONFIGURE_ARGS:

CONFIGURE_ARGS += \
	--enable-shared \
	--enable-static \
	--with-randomdev="/dev/urandom" \
	--disable-threads \
	--disable-linux-caps \
	--with-openssl="$(STAGING_DIR)/usr" \
	--with-libtool \
	--with-libxml2=no \
	--enable-epoll=yes \
	--with-gost=no \
	--with-gssapi=no \
	--with-ecdsa=no \
	--with-readline=no \
	--enable-filter-aaaa

Before we can build the package, the OpenWRT build system has to be installed, for that we need to run

make tools/install
make toolchain/install

This can take quite a while, depending on the beefiness of your CPU. Once the tools are built, we can finally build the bind-server package

make package/bind/compile
make package/bind/install

Installing the packages on the router

When the build process is finished, you will find a bind-lib and a bind-server package in bin/ar71xx/packages/packages/. Copy these two to your router (remember to replace 192.168.0.1 with your router’s IP address).

scp bin/ar71xx/packages/packages/bind-* root@192.168.0.1:/tmp/

Now SSH into the router and install the packages. The --force-checksum flag is necessary, as our modified packages obviously don’t match the checksum of the official packages.

opkg install --force-checksum /tmp/bind-*

Caution: this will automatically start bind in its default configuration and cause your router to be unable to resolve local names until we fix the configuration and restart bind and dnsmasq.

After successful installation you can delete both .ipk files from /tmp.

Configuring bind and dnsmasq

Change /etc/bind/named.conf on the router to the following.

options {
    directory "/tmp";

    forwarders {
	// OpenDNS - replace this with the DNS servers you want to use. Or leave it.
	208.67.222.222;
	208.67.220.220;
    };
    forward only;

    dnssec-enable no;

    auth-nxdomain no;
    // run bind on the local loopback interface only and listen on port 2053
    listen-on port 2053 { 127.0.0.1; };
    listen-on-v6 port 2053 { ::1; };
    filter-aaaa-on-v4 yes;
    allow-query { any; }; // If running a on a public IP
    allow-recursion { any; }; // If running a on a public IP
    allow-query-cache { any; }; // If running a on a public IP
};

Note: in an older version of this tutorial I had listen-on-v6 port commented out. On LEDE this caused bind to listen on port 53 on IPv6, as that is the default if nothing else is specified. This in turn prevented dnsmasq from starting, because it could not listen on port 53. There is no harm in bind listening on ::1 as well.

Finally, dnsmasq needs to be told to forward requests for netflix.com to bind. This can be done by adding /netflix.com/127.0.0.1#2053 in the web interface in the DNS forwardings field under NetworkDHCP and DNS (don’t forget to Save & Apply). Alternatively you can manually add a line list server '/netflix.com/127.0.0.1#2053' to the section config dnsmasq in /etc/config/dhcp.

Now we only need to restart both bind and dnsmasq and we are all set.

/etc/init.d/named restart
/etc/init.d/dnsmasq restart

You can test if it works, by issuing the following from a machine that sits behind the router (replace 192.168.0.1 with the IP of your router).

dig @192.168.0.1 netflix.com AAAA
dig @192.168.0.1 netflix.com

The first should yield an empty response and the second should return a number of IPv4 addresses.