DNS Leak is commonly seen in vpn connections, when all the http traffic goes through the vpn tunnel, however the dns queries go directly to system/isp dns servers bypassing the vpn tunnel, which breaks the privacy protection offered by the vpn.
Unless dns leaks are fixed, you are not fully privacy guarded in the vpn connection (even though you might think you are). The best thing after setting up a vpn is to quickly test and check for leaks and fix them on time.
How to test for DNS Leaks in VPN
You can use the following websites to test for dns leak on your system:
If you see your isp/system dns servers being used, then there is a dns leak. If you see some other dns server (those provided by your vpn provider) then your dns queries are being tunnelled through vpn and you are protected.
OpenVPN has known issues of dns leaks on linux systems like Ubuntu and in this article we take a look at various methods to fix it. I recently setup surfshark vpn on my ubuntu system using the manual openvpn method and noticed that dns leaks were happening all the time.
OpenVPN DNS Leak Fix
We shall take a look at 3 simple techniques to try and fix the dns leak. If your linux system is using systemd-resolved like latest Ubuntu, then you probably need to use the last Method 3.
These methods should work on all Ubuntu and Debian based distros like Linux Mint, Elementary OS, Pop OS etc.
The first method is to use
OpenVPN ships with a script named "update-resolv-conf" which is supposed to over-write the nameservers in /etc/resolv.conf when it connects to a vpn, and restore them back when the vpn connection is closed.
It can typically be used like this:
$ sudo openvpn --config ovpn/us-kan.prod.surfshark.com_udp.ovpn --auth-user-pass pass.txt --verb 3 --script-security 2 --up /etc/openvpn/update-resolv-conf --down /etc/openvpn/update-resolv-conf --down-pre
However on many Ubuntu systems, the above command does not work. This happens specially when the system is using systemd-resolved service.
Check systemd-resolved dns configuration with the
resolvectl status command:
$ resolvectl status Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: stub Link 2 (enp0s3) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Current DNS Server: 220.127.116.11 DNS Servers: 18.104.22.168 22.214.171.124 192.168.1.1 Link 85 (tun0) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported DNS Servers: 126.96.36.199 188.8.131.52 $
On Fedora you can also use the
systemd-resolve --status command. It is not available on Ubuntu however.
In the above example both ethernet interface (enp0s3) and the vpn interface (tun0) have DNS scopes available and each is configured with their own dns servers.
Issues with systemd-resolved
If your system is using systemd-resolved, then the above command will not change the /etc/resolv.conf file. You can verify it by viewing the file contents after running the above command.
$ cat /etc/resolv.conf # This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8). # Do not edit. # # This file might be symlinked as /etc/resolv.conf. If you're looking at # /etc/resolv.conf and seeing this text, you have followed the symlink. # # This is a dynamic resolv.conf file for connecting local clients to the # internal DNS stub resolver of systemd-resolved. This file lists all # configured search domains. # # Run "resolvectl status" to see details about the uplink DNS servers # currently in use. # # Third party programs should typically not access this file directly, but only # through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a # different way, replace this symlink by a static file or a different symlink. # # See man:systemd-resolved.service(8) for details about the supported modes of # operation for /etc/resolv.conf. nameserver 127.0.0.53 options edns0 trust-ad search . $
In the above example the nameserver still points to 127.0.0.53 which is the internal dns server managed by systemd-resolved.
When using systemd-resolved the /etc/resolv.conf file is a symlink to another file.
$ ls /etc/resolv.conf -la lrwxrwxrwx 1 root root 39 Oct 23 11:24 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
There are known issues in systemd (check here and here and here) due to which the background services use the default network interface for dns queries which causes the dns queries to go directly to the dns server instead of via vpn tunnel.
The update-resolv-conf script invokes the "/sbin/resolvconf" script to make changes to dns servers. However in the presence of systemd-resolved the /sbin/resolvconf script points to resolvectl which works with systemd-resolved.service
$ ls -la /sbin/resolvconf lrwxrwxrwx 1 root root 19 Jan 5 17:25 /sbin/resolvconf -> /usr/bin/resolvectl $
Hence the dns changes will ultimately depend on systemd-resolved to take effect properly.
Method 2: openvpn-systemd-resolved
There is a little trick to fix the above problem and prevent dns leaks completely. First install the following package
sudo apt-get install openvpn-systemd-resolved
Now connect to vpn server with the following command
$ sudo openvpn --config ovpn/us-kan.prod.surfshark.com_udp.ovpn --auth-user-pass pass.txt --verb 3 --script-security 2 --up /etc/openvpn/update-systemd-resolved --down /etc/openvpn/update-systemd-resolved --down-pre
Method 3 - Force DNS servers
This particular solution has been highlighted on systemd-resolved site as well. It uses the DOMAIN-ROUTE directive to force all dns queries to be routed through a specific interface.
Adding the following option the configuration file seems to solve the problem.
dhcp-option DOMAIN-ROUTE .
$ sudo openvpn --config ovpn/us-kan.prod.surfshark.com_udp.ovpn --auth-user-pass pass.txt --verb 3 --script-security 2 --up /etc/openvpn/update-systemd-resolved --down /etc/openvpn/update-systemd-resolved --down-pre --dhcp-option DOMAIN-ROUTE .
Now if you check systemd dns policy, it should appear something like this:
$ resolvectl status Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: stub Link 2 (enp0s3) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Current DNS Server: 184.108.40.206 DNS Servers: 220.127.116.11 18.104.22.168 192.168.1.1 Link 87 (tun0) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported DNS Servers: 22.214.171.124 126.96.36.199 DNS Domain: ~. $
Note the last line
DNS Domain: ~.
It is this line that forces systemd to route all dns queries through the openvpn interface tun0, thereby eliminating dns leaks.
Shorter version of the command:
$ resolvectl dns Global: Link 2 (enp0s3): 188.8.131.52 184.108.40.206 192.168.1.1 Link 89 (tun0): 220.127.116.11 18.104.22.168 $
The above output shows each interface with its own configured dns server.
$ resolvectl domain Global: Link 2 (enp0s3): Link 89 (tun0): ~. $
The above output shows domains assigned to each interface for dns resolution.
Note that /etc/resolv.conf will continue to show the same nameserver systemd-resolved nameserver 127.0.0.53. This implies that dns queries will still be sent to systemd-resolved. However systemd-resolvd would now use dns servers via the vpn tunnel and now the ethernet interface which is directly connected to internet.
This stops dns leaks.
The dns leak if caused due to systemd-resolved, needs to be fixed using the above shown methods. However, there are other possible solutions as well.
An alternative would be to disable systemd-resolve and manually specify dns servers in
/etc/resolv.conf or through Network Manager gui utility. These will then be over-written by /etc/openvpn/update-resolv-conf script, thereby stopping dns leaks.
Links and Resources