How To Pretect Against IPv6 Leakage in an IPv4 VPN Environment – Part 2 (Server Side Changes)

While being excited about the availability of IPv6 from my mobile network operator of choice the disadvantage that comes along with it is IPv6 leakage when using Witopia’s VPN service with OpenVPN on Ubuntu. For some strange reason they answer IPv6 DNS AAAA requests even though their product only tunnels IPv4 packets. My OpenVPN server setup at home on a Raspberry Pi had the same behavior so far but as it is under my own control I started looking for ways to change that.

At first it looked as if it would be a straight forward thing to implement. But the first look was a bit deceiving and in the end it took a bit of more tinkering before the DNS server queried through the VPN tunnel only returned DNS responses for IPv4 A-requests and empty results for IPv6 AAAA-requests.

The OpenVPN Server setup I have linked to above relies on a DNS server already present in the server’s network to also answer queries from remote OpenVPN clients. As there was no way for me to change that DNS server’s behavior I had to setup a separate DNS server on the OpenVPN Server Raspi and then reconfigure OpenVPN to point clients to that DNS server.

Bind Comes To The Rescue

On Linux, “bind” is one of the most popular DNS server. While it is probably overkill to use “bind” just as a DNS request forwarder it does offer a nice option to return an empty result for IPv6 AAAA-requests when sent over IPv4. Here’s some more background information on the option. For this option to work, bind needs to be compiled with a special flag to recognize the “filter-aaaa-on-v4 yes;” configuration option. Unfortunately, bind on Raspian does not come configured with it so I had to compile bind from scratch. That sounds more difficult than it is, however.

But perhaps your distribution set the correct flag before bind was compiled so my advice is to install bind from the repositories first and see if it works with the “filter-aaaa-on-v4” option. If it doesn’t it can be uninstalled before downloading and compiling bind from it’s source. Also, it has the benefit that all configuration files are already in place which are perhaps not put into the right directories when compiling from source.

Installing Bind From The Repositories

Installing bind from the repositories works with a simple “sudo apt-get upate && sudo apt-get install bind9” command. Afterward, uncomment and modify the following section in “/etc/bind/named.conf.options” to enable DNS query forwarding to the upstream DNS server used in the network:

    forwarders {
         8.8.8.8;
    };

Once done, restart bind to see if the configuration change has been accepted: “sudo service bind9 restart“. If no error messages are shown on the console, bind is up and running.

Check If the IPv6 Option Works

In the next step add the IPvt6 filter option to the same configuration file and also allow queries from other networks by inserting the two additional lines marked in orange below. This is necessary as the OpenVPN clients get IPv4 address from a subnet that is different from the subnet that the OpenVPN Server uses on the backhaul link:

options {
    directory “/var/cache/bind”;

    //…

    forwarders {
         8.8.8.8;
    };

    //…

    dnssec-validation auto;

    auth-nxdomain no;    # conform to RFC1035
    listen-on-v6 { any; };

    filter-aaaa-on-v4 yes;
    allow-query {any;};
};

Once done, do another restart of bind. If an error message is shown that the filter option is not supported some extra work is required. Otherwise, you are almost good to go and the only thing that is required for OpenVPN clients to query this DNS server instead of the previous one is to change the DNS option in the OpenVPN config file as shown at the end of this post.

Compile and Install Bind From Source

Before proceeding, uninstall bind again with “apt-get remove bind9“. While this removes the binaries, it leaves the configuration files including the one we have modified in place. Now download and install bind with the following commands as described here. As there might be a more up to date version of bind at the time you read this it might be worthwhile to modify the version number in the commands accordingly.

apt-get install build-essential openssl libssl-dev libdb5.1-dev
mkdir bind-install
cd bind-install
wget ftp://ftp.isc.org/isc/bind9/9.9.7/bind-9.9.7.tar.gz
tar zxvf bind-9.9.7.tar.gz

fakeroot ./configure –prefix=/usr –mandir=/usr/share/man –infodir=/usr/share/info –sysconfdir=/etc/bind –localstatedir=/var –enable-threads –enable-largefile –with-libtool –enable-shared –enable-static –with-openssl=/usr  –with-gnu-ld –with-dlz-postgres=no –with-dlz-mysql=no –with-dlz-bdb=yes –with-dlz-filesystem=yes  –with-dlz-stub=yes  CFLAGS=-fno-strict-aliasing –enable-rrl –enable-newstats –enable-filter-aaaa

make install

Some patience is required as the process takes around 45 minutes. But once done everything is ready and an “/etc/init.d bind9 start” will start the service, this time with the ipv6 filter in place as the configuration file we modified further above is still in place.

OpenVPN modification

The last step now is to tell the OpenVPN server to point new clients to this DNS server. This is done by modifying the push “dhcp-option DNS x.x.x.x” option in “/etc/openvpn/server.conf” file, with x.x.x.x being the IP address of the Raspberry Pi. A “sudo service openvpn restart” activates the change.

Verifying That Everything Works

The next time an OpenVPN client device connects to the server, all DNS requests for AAAA records are getting an empty response. This can be verified e.g. by typing in “dig youtube.com AAAA” which should return an empty result and not an IPv6 address. Another option is using Wireshark for the purpose.

And that solves my OpenVPN IPv6 leakage issue without any modification on the client side!