DNS Leaks with Network Namespaces
If you use a Virtual Private Network (VPN) in a network namespace, your DNS requests may be leaked to your DNS provider if you use systemd-resolvd as a DNS resolver. These DNS requests can expose the sites you are visiting or your general geographic location whilst using your VPN.
In general, a DNS leak is when DNS requests that should be sent to your VPN provider for name resolution are sent to your otherwise regular DNS provider. Tools such as DNS Leak Test can show you who is resolving your DNS requests. For a properly setup and secured VPN, the only servers responding to your DNS requests should be owned by your VPN provider.
When running a system-wide VPN, DNS leaks may be prevented by simply ensuring your system is using your VPN provider’s DNS servers. Generally this means checking NetworkManager or
/etc/resolv.conf points to the right IP addresses.
However, as mentioned in my Wireguard article, a network namespace may be used to run your VPN in a parallel and isolated networking stack such that only certain applications may use the VPN. Essentially, when an application is launched in that network namespace, the sole way for that application to access the network is through the VPN’s tunneling network adapter. So if the application can only access the network via the VPN how do DNS requests bypass it? Afterall, DNS requests are just simple network requests.
To understand, we must first discuss how an application resolves a host or domain name. Generally speaking, on GNU/Linux systems, most applications use the GNU C (glibc) library at some point to resolve host and domain names. The GNU C library decides how to resolve that name by reading the Name Service Switch configuration file at
Below is an example of
/etc/nsswitch.conf configuration file:
In this file we see many name categories (
hosts, etc.) and then a list of name resolution methods (
dns, etc.) for each category.
Of interest is the
hosts name category. The
hosts name category tells the GNU C library how to resolve host or domain names.
In this example there are 5 methods the GNU C library will try, in sequence, to resolve a host or domain name. They are:
files, resolve a host or domain name using
mymachines, if the host name is for a container registered with systemd-machined, resolve the IP of that container
myhostname, resolve the requesting system’s host name
resolve, resolve the host or domain name using systemd-resolvd
dns, resolve the domain name using the DNS servers in
Take note of
resolve, this method resolves the host or domain name using systemd-resolvd. It accomplishes this by making a name resolution request to the systemd-resolvd daemon over D-Bus. D-Bus is an inter-process communication mechanism (a method by which two independant process can communicate) that is not isolated by a network namespace.
Therefore, what is happening is that inside the network namespace an application makes a name resolution request. The
myhostname methods fail to resolve the name, so we reach the
resolve method. The request is made to systemd-resolvd over D-Bus. Since systemd-resolvd is not running in the network namespace it resolves the domain name using the DNS servers in
/etc/resolv.conf over your unencrypted internet connection.
Aha! Now how do we solve this?
This is actually pretty simple to solve. Within a network namespace, the file
/etc/netns/<name>/nsswitch.conf is bind mounted to
/etc/nsswitch.conf. Essentially, applications running in the network namespace will see the contents of
/etc/netns/<name>/nsswitch.conf when reading
/etc/nsswitch.conf. So simply copy your
/etc/nsswitch.conf file to
<name> is the name of your network namespace, and remove the
resolve [!UNAVAIL=return] method in the
hosts category. Now name resolution will fallback to the
dns method which uses the DNS servers in
/etc/resolv.conf to resolve the name and performs this resolution in the application process within the network namespace!
Below is a corrected
/etc/netns/<name>/nsswitch.conf configuration file:
But wait! What if
/etc/resolv.conf contains your ISP’s DNS servers? This can still leak your requests even if they come from a VPN. For example, your ISP can see that you have one connection to your VPN server, and that server is sending DNS requests to your ISP. Theoretically, your requests could be correlated through timing. Not ideal.
We can solve this the same way we solved the previous problem. Within a network namespace, the file
/etc/netns/<name>/resolv.conf is bind mounted to
/etc/resolv.conf. So simply create
<name> is the name of the network namespace, and populate it with your VPN provider’s DNS servers. Alternatively, sufficiently large and public DNS servers such as or Cloudflare’s
184.108.40.206 can be used if your VPN provider does not provide DNS servers.
Below is an example
With these modifications, your DNS requests will not be leaked inadventently when using a VPN within a network namespace.