Multiple OpenVPN clients with DNS leaks

Hello,
I have configured my OpenWRT 23.05.0-rc2 to have multiple OpenVPN connections at the same time. Everything works as expected but there is one issue - I am facing DNS leaks. The same issue was also on my Windows 11 machine but when I added "--block-outside-dns" flag to ovpn file, no dnsleaks were detected. I am using NordVPN so I should use these 2 addresses as DNS: 103.86.96.100 and 103.86.99.100. I have also tried to call I have spend days trying to fix this, could you help me guys?

My configuration

/etc/config/network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fdf5:0930:6ae8::/48'

config interface 'vpn_at'
        option proto 'none'
        option device 'tun_at'
        option force_link '1'
        option delegate '0'

config interface 'vpn_fi'
        option proto 'none'
        option device 'tun_fi'
        option force_link '1'
        option delegate '0'

config interface 'vpn_ca'
        option proto 'none'
        option device 'tun_ca'
        option force_link '1'
        option delegate '0'

config rule
        option src '192.168.2.160/27'
        option lookup '100'
        option in 'lan'

config rule
        option src '192.168.2.192/27'
        option lookup '101'
        option in 'lan'

config rule
        option src '192.168.2.224/27'
        option lookup '102'
        option in 'lan'

config route
        option target '0.0.0.0'
        option netmask '0.0.0.0'
        option table '100'
        option interface 'vpn_at'

config route
        option target '0.0.0.0'
        option netmask '0.0.0.0'
        option table '101'
        option interface 'vpn_fi'

config route
        option target '0.0.0.0'
        option netmask '0.0.0.0'
        option table '102'
        option interface 'vpn_ca'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.2.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config interface 'wan'
        option device 'wan'
        option proto 'dhcp'
        option peerdns '0'
        list dns '103.86.96.100'
        list dns '103.86.99.100'

config interface 'wan6'
        option device 'wan'
        option proto 'dhcpv6'
        option reqaddress 'try'
        option reqprefix 'auto'
        option peerdns '0'
        list dns '103.86.96.100'
        list dns '103.86.99.100'

config device
        option name 'tun_at'

config device
        option name 'tun_ca'

config device
        option name 'tun_fi'

config interface 'wlan'
        option proto 'static'
        option ipaddr '192.168.3.1'
        option netmask '255.255.255.0'

/etc/config/firewall

config defaults
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config zone
        option name 'vpn'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option mtu_fix '1'
        list network 'vpn_at'
        list network 'vpn_ca'
        list network 'vpn_fi'
        option masq '1'

config zone
        option name 'wlan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'wlan'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'
        list network 'wan6'

config forwarding
        option src 'wlan'
        option dest 'wan'

config forwarding
        option src 'lan'
        option dest 'vpn'

/etc/config/openvpn

config openvpn 'at128'
        option config '/etc/openvpn/at128.ovpn'
        option enabled '1'

config openvpn 'fi195'
        option config '/etc/openvpn/fi195.ovpn'
        option enabled '1'

config openvpn 'ca1508'
        option config '/etc/openvpn/ca1508.ovpn'
        option enabled '1'

/etc/config/dhcp

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option localservice '1'
        option ednspacket_max '1232'
        list server '103.86.96.100'
        list server '103.86.99.100'
        option noresolv '1'

config dhcp 'lan'
        option interface 'lan'
        option start '10'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

config dhcp 'wlan'
        option interface 'wlan'
        option start '100'
        option limit '150'
        option leasetime '12h'

config host
        option mac 'xxxx'
        option ip '192.168.2.220'
        option leasetime '0'

/etc/iproute2/rt_tables

100     vpn_at
101     vpn_fi
102     vpn_ca

128     prelocal
255     local
254     main
253     default
0       unspec

/etc/openvpn/ca1508.ovpn (others are almost the same, they differ only in dest address)

client
dev tun_ca
proto udp
remote 37.19.212.107 1194
resolv-retry infinite
remote-random
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
ping 15
ping-restart 0
ping-timer-rem
reneg-sec 0
comp-lzo no
verify-x509-name CN=ca1508.nordvpn.com

remote-cert-tls server

pull-filter ignore redirect-gateway
auth-user-pass /etc/openvpn/nord.auth
verb 3
pull
fast-io
cipher AES-256-CBC
auth SHA512
.... certificate

That's a Windows-only setting; to get the same result in Linux and Linux-derivatives such as OpenWRT, you need to call a script to update the resolver upon setup and teardown of the VPN.

https://forum.openwrt.org/search?expanded=true&q=update-resolv-conf may be of use to you.

I have tried that one, at least with created custom "update-resolv-conf" that sets dns to be 103.86.96.100 and 103.86.99.100 when called - really did not know what should I put there since it is not created automatically with openvpn installation.

I have also contacted NordVPN directly, went from live chat to communication with expert via email and the outcome was "As we can see from all of the information that you have provided, the router does establish the VPN connection, however, the DNS is not being routed through it". Isn't there any way I could redirect DNS request (correct me if I am wrong but it should be firewall rule for TCP/UDP ; dest. port = 53) from WAN to defined VPN tunnel? Since I know which source IP address it is requestenting (and so which vpn tunnel should be used) I could somehow be able to redirect these request to tunnel, right?

Here is my routing explained:
LAN has DHCP server in range 192.168.2.10 - 192.168.2.159 == No internet connection
.. so these IPs have to be manually set in Static leases to be make internet VPN working, othervise no internet connection for device: 192.168.2.160/27 - at vpn, 192.168.2.192/27 - fi vpn, 192.168.2.224/27 ca vpn

Maybe I am complicating things and "update-resolv-conf" might work for me and I just don't understand it well. I tried to go through forums and googled it with no luck how to configure that file.

Any help would be appreciated :slight_smile:

Assuming the "update-resolv-conf" scripts are working and your VPN DNS servers in resolv.conf are indeed replaced by the DNS servers form NordVPN then it could be a routing problem as your default route seems via the WAN.

To make sure the VPN servers are also routed via the VPN you can add in the OpenVPN config:

route 103.86.96.100 255.255.255.255 vpn_gateway
route 103.86.99.100 255.255.255.255 vpn_gateway

This will route those DNS servers via the VPN.

It might be even possible (and advisable) to add it directly to the up and down scripts but then just use the variables

Hope this helps

Thanks for quick reply :slight_smile: I might be still missing something, I wasn't sure which value use as "vpn_gateway" so I put vpn server ip address there, this is my .ovpn configuraion (it shouldn't have sensitive data since it is possible to download them from NordVPN website):

client
dev tun_at
proto udp
remote 37.19.195.32 1194
resolv-retry infinite
remote-random
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
ping 15
ping-restart 0
ping-timer-rem
reneg-sec 0
comp-lzo no
verify-x509-name CN=at128.nordvpn.com

remote-cert-tls server

pull-filter ignore redirect-gateway
auth-user-pass /etc/openvpn/nord.auth
route 103.86.96.100 37.19.195.32
route 103.86.99.100 37.19.195.32

verb 3
pull
fast-io
cipher AES-256-CBC
auth SHA512

# the rest is just certificate

.... similar configuration goes for other VPNs. You can note I have removed update-resolv-conf up / down part since I had no idea what to put there. I've created this script but it might be something totally different from what I want to achieve:

#!/bin/sh

case $script_type in
  up)
    uci del_list network.$dev.dns='103.86.96.100'
    uci del_list network.$dev.dns='103.86.99.100'
    uci add_list network.$dev.dns='103.86.96.100'
    uci add_list network.$dev.dns='103.86.99.100'
    uci commit network
    /etc/init.d/network reload
    ;;
  down)
    uci del_list network.$dev.dns='103.86.96.100'
    uci del_list network.$dev.dns='103.86.99.100'
    uci commit network
    /etc/init.d/network reload
    ;;
esac

If there is any way to get this script, or at least example of it so I have some starting point, it would be very helpful for me (and maybe others facing the same issue).

I can share some of my configuration in LuCi, there might (and probably will) be something that is not setted up properly.

Luci screenshots

Network > Interfaces

Network > Interfaces > [vpn instance]

Network > Firewall

Network > Firewall > vpn



.. no special rules / port forwarings are set

Network > DHCP and DNS



... I can set up here in "Static Leases" ip in range that will have access to the internet using VPN

I am not sure how would the router know which vpn use since all of them will add "103.86.96/99.100" as DNS with its gateway? Wouldn't it cause that for instance when I am connected through Finnish VPN it might forward to DNS request to Canadian VPN?

I have tried dnsleaktest from both Windows and Linux machine, still having Frankfurt DNS leak even when connecting from Canada / Finland

About the routing in your vpn config, vpn_gateway is a reserved word which translates to the vpn gateway (vpn_gateway is the default so you can even omit it, the default gateway can be set with net_gateway)

I forgot the netmask so the solution to route your DNS servers via the tunnel should be:

route 103.86.96.100 255.255.255.255 vpn_gateway
route 103.86.99.100 255.255.255.255 vpn_gateway

The problem with your script might be that you are adding DNS servers to the already existing ones instead of replacing them so iIdo not think this is going to work.

The original script replaces your DNS server with the ones which are pushed from your provider.
I just added that original script to my own router, I needed to adapt it slightly as my default resolv seems to be /tmp/resolv.conf.d/resolv.conf.auto but otherwise it is working fine in my case.

Note you can use it for only one VPN client and the DNS servers from that VPN client are than used so in your case you have to choose :frowning:

1 Like

Oh finaly I am getting something else than Frankfurt :smiley: thank you very much @egc! I have tried from my Windows laptop on FIN vpn and I've got Finnish DNS server and on my Ubuntu desktop on CAN vpn have also Finnish DNS server, so you were right :slight_smile:

I am going to try find out how can I configure it so I can use all 3 VPNs at once - I still want to have multiple devices on VPN at the same time. I will share my findings here but if there is someone that has experience with this / hints how to do that, it would be apreciated :slight_smile:

I will mark your answer as solution but don't want to close the topic by marking it as solved so I can share (or others if I'll be fortunate enough :slight_smile: ) how to make it work with multiple vpn clients.

Great to hear you are making progress

You can use multiple tunnels but regarding DNS it will use only one tunnel in this construction.

You can use option 6 for DNSMasq together with tagging to have different clients use different DNS servers, e.g. you have clients for Frankfurt use 9.9.9.9 and clients using the Finnish server use 1.1.1.1.
Then on the Frankfurt config file add:

route 9.9.9.9 255.255.255.255 vpn_gateway

For Finland add in the finnish openvpn config:

route 1.1.1.1 255.255.255.255 vpn_gateway

Alternatively you can also use the PBR package from @stangri to setup the routes of the DNS servers via the respective tunnels.

Also using iptables with redirection of port 53 is a good option.

Below I have an updated version of the update-resolv-conf script which automatically should also route the DNS servers via the tunnel, not tested but if you want you can try

Have fun

#!/bin/sh
# File name: update-resolv-conf-3
# Description: Script to grab DNS servers from the tunnel for exclusive use by DNSMasq and routes those via the tunnel to prevent DNS leaks
# Version: 270723
# Fundamentals:
#  Gets the pushed DNS servers and DNS servers manually set in conf file with: dhcp-option DNS <ip-address-of-DNS-server>
#  DNS servers are set in a new resolv file which is used exclusively by DNSMasq to prevent DNS leaks.
#  Sets route for the DNS servers via the tunnel, necessary when using PBR
#  To stop getting the pushed DNS servers by the OpenVPN server add to conf file: pull-filter ignore "dhcp-option DNS"
# Install:
#  Copy this cript to /etc/openvpn
#  Make executable: chmod +x /etc/openvpn/update-resolv-conf-3
#  Add in the OpenVPN config file:
#   up /etc/openvpn/update-resolv-conf-3
#   down /etc/openvpn/update-resolv-conf-3
#   script-security 2

#set -x
#(

VPN_RESOLVF="/tmp/resolv.conf.vpn"
DEF_RESOLVF="/tmp/default_resolv"

case $script_type in
up)
	#env > /tmp/vpn_env_var_up
	# Get DNS servers and DNS servers manually set in conf file
	env | grep 'dhcp-option DNS' | awk '{ print "nameserver " $3 }' > $VPN_RESOLVF
	if [[ ! -s "$VPN_RESOLVF" ]]; then
		logger -t $(basename $0)[$$] -p user.warning "No VPN DNS servers found, using default servers!"
		rm -fr "$VPN_RESOLVF" >/dev/null 2>&1
		return 0
	fi
	# Make sure DNS servers are always routed via the tunnel e.g. in case of PBR
	if [[ -s $VPN_RESOLVF ]]; then
		while read dns; do
			ip route add $(echo $dns | awk '{print $2}') dev $dev
		done < $VPN_RESOLVF
	fi
	
	# Save default resolv file
	uci get dhcp.@dnsmasq[0].resolvfile > $DEF_RESOLVF
	# Replace default resolv file
	uci set dhcp.@dnsmasq[0].resolvfile=$VPN_RESOLVF
	uci commit dhcp
	/etc/init.d/dnsmasq restart &
	logger -t $(basename $0)[$$] -p user.notice "Exclusively using OpenVPN DNS server(s) from $VPN_RESOLVF"
	;;
down)
	#env > /tmp/vpn_env_var_down
	# Restore dns, deleting the resolv file path will use default
	if [[ -s $DEF_RESOLVF ]]; then
		uci set dhcp.@dnsmasq[0].resolvfile=$(cat $DEF_RESOLVF)
	elif [[ -e $DEF_RESOLVF ]]; then
		uci del dhcp.@dnsmasq[0].resolvfile
	else	#no DNS servers present so did not run
		return 0
	fi
	#uci set dhcp.@dnsmasq[0].resolvfile="/tmp/resolv.conf.d/resolv.conf.auto"
	uci commit dhcp
	/etc/init.d/dnsmasq restart &
	# Remove routing of DNS servers, often redundant as the routes are removed anyway if the interface disappears
	if [[ -s $VPN_RESOLVF ]]; then
	while read dns; do
		ip route del $(echo $dns | awk '{print $2}') dev $dev
	done < $VPN_RESOLVF
	fi
	# Remove vpn resolv file
	rm -fr "$VPN_RESOLVF" >/dev/null 2>&1
	rm -fr "$DEF_RESOLVF" >/dev/null 2>&1
	logger -t $(basename $0)[$$] -p user.notice "Default DNS server(s) restored"
	;;
esac
exit 0
#) 2>&1 | logger -t $(basename $0)[$$] &

What is output of:
cat /tmp/resolv.conf.d/resolv.conf.auto
?

I have just recovered backup and restarted router, I am getting this:

# Interface vpn_at
nameserver 103.86.96.100
nameserver 103.86.99.100
# Interface vpn_ca
nameserver 103.86.96.100
nameserver 103.86.99.100
# Interface wan
# Interface wan6
nameserver 2a01:c840:110:c1cb::1
nameserver 2a01:c840:130:c1ca::1

yeah seems like that's the case... I have spent almost all day digging through openvpn documentation and trying to configure network / ovpn file with so many different combinations I believe I tried everything my brain can create with no luck :frowning:


Yeah I have tried that also, couldn't find correct way to configure PBR to redirect these 2 IPs correctly, everytime I removed / replaced routing you suggested previously in ovpn files:

route 103.86.96.100 255.255.255.255 vpn_gateway
route 103.86.99.100 255.255.255.255 vpn_gateway

I've got Frankfurt again.


Thank you very much for putting effort into this! But sadly it did not helped and I've had connections issues when I tried that might the download downgraded from 250Mbps to 7Mbps and upload did not work.. Might been another misconfiguration too - I might forgot to recover backup image before trying something new.
update: I found out that I have this slow connection also without the script when going throught VPN. I have tried the same ovpn file on windows and got ~170Mbps download vs ~7Mbps on the router.
update 2: So I've been searching about this and it is normal speed on OpenWRT routers. Probably CPU problem, even on my Xiaomi AX9000 which should be quite powerful.

Anyway guys thank you for helping me, I don't know if I could do anything now... If you don't have any other tips what could I do to solve this I will mark @egc reply as solution as it helped me partialy solving DNS leak issue :slight_smile: proposed solution will definitely be useful for people with using 1 VPN :slight_smile:

It is expected, concerning nameservers for interfaces?

yes, these are interface names :slight_smile:

I have screenshots of LuCi configuration here:

and configuration files in the first message:

If you assign to the clients 103.86.96.100 and 103.86.99.100 as nameservers (using DHCP option 6), they will send the DNS queries directly to the provider's DNS servers and the requests should be forwarded through the correct interface due to the custom routing tables you have created.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.