Split OpenVPN tunnelling - DNS leaks

Hello OpenWrt community!

I recently installed OpenWrt on my Netgear R6220 and to achieve the following configuration:

  1. WAN port on R6220 is chained to another router (192.168.1.x subnet) as a DHCP client. Gateway 192.168.1.1.
  2. Disable IPv6 on all interfaces.
  3. Run OpenVPN (NordVPN) on one of the wireless SSIDs - 5Ghz wifi (11.0.0.x subnet) on VPN, 2.4 GHz + LAN ports without VPN (10.0.0.x subnet).
  4. Delete default gateway pushed by OpenVPN and add VPN traffic (devices in 11.0.0.x) to a routing table 'vpn'.

In the default OpenVPN route configuration, VPN works and also DNS requests are made from the new IP address, making no leaks evident as shown in the image below (sharing IPs since these are assigned by VPN, privacy is not a concern)

However, once I delete the default routes, my DNS requests on ipleak.net show up from random countries, similar to using the nord DNS addresses on a non-vpn connection:

Here is the routing table as soon as VPN starts up along with default routes:

root@OpenWrt:~# ip route show
0.0.0.0/1 via 10.8.8.1 dev tun0
default via 192.168.1.1 dev eth0.2 proto static src 192.168.1.2
10.0.0.0/24 dev br-lan proto kernel scope link src 10.0.0.1
10.8.8.0/24 dev tun0 proto kernel scope link src 10.8.8.33
11.0.0.0/24 dev br-lan2 proto kernel scope link src 11.0.0.1
89.238.150.151 via 192.168.1.1 dev eth0.2
128.0.0.0/1 via 10.8.8.1 dev tun0
192.168.1.0/24 dev eth0.2 proto kernel scope link src 192.168.1.2

Here is how the route looks like after I delete the default routes pushed by OpenVPN through the following commands:

Commands:
root@OpenWrt:~# ip route del 0.0.0.0/1 via 10.8.8.1 dev tun0
root@OpenWrt:~# ip route del 128.0.0.0/1 via 10.8.8.1 dev tun0
root@OpenWrt:~# ip rule add from 11.0.0.0/24 table vpn
root@OpenWrt:~# ip rule add to 11.0.0.0/24 table vpn
root@OpenWrt:~# ip route add default table vpn dev tun0
root@OpenWrt:~# ip route add 11.0.0.0/24 dev br-lan2 src 11.0.0.1 table vpn
root@OpenWrt:~# ip route show table main
default via 192.168.1.1 dev eth0.2 proto static src 192.168.1.2
10.0.0.0/24 dev br-lan proto kernel scope link src 10.0.0.1
10.8.8.0/24 dev tun0 proto kernel scope link src 10.8.8.33
11.0.0.0/24 dev br-lan2 proto kernel scope link src 11.0.0.1
89.238.150.151 via 192.168.1.1 dev eth0.2
192.168.1.0/24 dev eth0.2 proto kernel scope link src 192.168.1.2

root@OpenWrt:~# ip route show table vpn
default dev tun0 scope link
11.0.0.0/24 dev br-lan2 scope link src 11.0.0.1

I'm trying to figure out if it is possible to route DNS from non-vpn devices via my ISP's nameservers and those on VPN via nordvpn servers simultaneously. I realize I may have to set up two dnsmasq instances, but I plan to proceed to do so only after the DNS requests from VPN clients are correctly routed. I am still learning, please guide me if any of my assumptions are wrong.

Below are my config files:

uci show network; uci show firewall; uci show dhcp

network.loopback=interface
network.loopback.ifname='lo'
network.loopback.proto='static'
network.loopback.ipaddr='127.0.0.1'
network.loopback.netmask='255.0.0.0'
network.globals=globals
network.globals.ula_prefix='fdff:986e:d4fe::/48'
network.lan=interface
network.lan.type='bridge'
network.lan.ifname='eth0.1'
network.lan.proto='static'
network.lan.netmask='255.255.255.0'
network.lan.ipaddr='10.0.0.1'
network.lan.ipv6='off'
network.lan_eth0_1_dev=device
network.lan_eth0_1_dev.name='eth0.1'
network.wan=interface
network.wan.ifname='eth0.2'
network.wan.proto='dhcp'
network.wan.peerdns='1'
network.wan_eth0_2_dev=device
network.wan_eth0_2_dev.name='eth0.2'
network.@switch[0]=switch
network.@switch[0].name='switch0'
network.@switch[0].reset='1'
network.@switch[0].enable_vlan='1'
network.@switch_vlan[0]=switch_vlan
network.@switch_vlan[0].device='switch0'
network.@switch_vlan[0].vlan='1'
network.@switch_vlan[0].ports='0 1 2 3 6t'
network.@switch_vlan[1]=switch_vlan
network.@switch_vlan[1].device='switch0'
network.@switch_vlan[1].vlan='2'
network.@switch_vlan[1].ports='4 6t'
network.lan2=interface
network.lan2.proto='static'
network.lan2.type='bridge'
network.lan2.netmask='255.255.255.0'
network.lan2.ipaddr='11.0.0.1'
network.lan2.ipv6='off'
network.vpn0=interface
network.vpn0.ifname='tun0'
network.vpn0.proto='none'
firewall.@defaults[0]=defaults
firewall.@defaults[0].syn_flood='1'
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@zone[0]=zone
firewall.@zone[0].name='lan'
firewall.@zone[0].input='ACCEPT'
firewall.@zone[0].output='ACCEPT'
firewall.@zone[0].forward='ACCEPT'
firewall.@zone[0].network='lan'
firewall.@zone[1]=zone
firewall.@zone[1].name='wan'
firewall.@zone[1].input='REJECT'
firewall.@zone[1].output='ACCEPT'
firewall.@zone[1].forward='REJECT'
firewall.@zone[1].masq='1'
firewall.@zone[1].mtu_fix='1'
firewall.@zone[1].network='wan'
firewall.@rule[0]=rule
firewall.@rule[0].name='Allow-DHCP-Renew'
firewall.@rule[0].src='wan'
firewall.@rule[0].proto='udp'
firewall.@rule[0].dest_port='68'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[0].family='ipv4'
firewall.@rule[1]=rule
firewall.@rule[1].name='Allow-Ping'
firewall.@rule[1].src='wan'
firewall.@rule[1].proto='icmp'
firewall.@rule[1].icmp_type='echo-request'
firewall.@rule[1].family='ipv4'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[2]=rule
firewall.@rule[2].name='Allow-IGMP'
firewall.@rule[2].src='wan'
firewall.@rule[2].proto='igmp'
firewall.@rule[2].family='ipv4'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[3]=rule
firewall.@rule[3].name='Allow-DHCPv6'
firewall.@rule[3].src='wan'
firewall.@rule[3].proto='udp'
firewall.@rule[3].src_ip='fc00::/6'
firewall.@rule[3].dest_ip='fc00::/6'
firewall.@rule[3].dest_port='546'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[4]=rule
firewall.@rule[4].name='Allow-MLD'
firewall.@rule[4].src='wan'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].src_ip='fe80::/10'
firewall.@rule[4].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[4].family='ipv6'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[5]=rule
firewall.@rule[5].name='Allow-ICMPv6-Input'
firewall.@rule[5].src='wan'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].family='ipv6'
firewall.@rule[5].target='ACCEPT'
firewall.@rule[6]=rule
firewall.@rule[6].name='Allow-ICMPv6-Forward'
firewall.@rule[6].src='wan'
firewall.@rule[6].dest='*'
firewall.@rule[6].proto='icmp'
firewall.@rule[6].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[6].limit='1000/sec'
firewall.@rule[6].family='ipv6'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[7]=rule
firewall.@rule[7].name='Allow-IPSec-ESP'
firewall.@rule[7].src='wan'
firewall.@rule[7].dest='lan'
firewall.@rule[7].proto='esp'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[8]=rule
firewall.@rule[8].name='Allow-ISAKMP'
firewall.@rule[8].src='wan'
firewall.@rule[8].dest='lan'
firewall.@rule[8].dest_port='500'
firewall.@rule[8].proto='udp'
firewall.@rule[8].target='ACCEPT'
firewall.@include[0]=include
firewall.@include[0].path='/etc/firewall.user'
firewall.@zone[2]=zone
firewall.@zone[2].forward='REJECT'
firewall.@zone[2].name='vpn'
firewall.@zone[2].output='ACCEPT'
firewall.@zone[2].masq='1'
firewall.@zone[2].mtu_fix='1'
firewall.@zone[2].input='REJECT'
firewall.@zone[2].network='vpn0'
firewall.@forwarding[0]=forwarding
firewall.@forwarding[0].dest='vpn'
firewall.@forwarding[0].src='lan'
firewall.@zone[3]=zone
firewall.@zone[3].network='lan2'
firewall.@zone[3].input='ACCEPT'
firewall.@zone[3].name='lan2'
firewall.@zone[3].output='ACCEPT'
firewall.@zone[3].forward='ACCEPT'
firewall.@forwarding[1]=forwarding
firewall.@forwarding[1].dest='wan'
firewall.@forwarding[1].src='lan'
firewall.@forwarding[2]=forwarding
firewall.@forwarding[2].dest='vpn'
firewall.@forwarding[2].src='lan2'
firewall.@forwarding[3]=forwarding
firewall.@forwarding[3].dest='wan'
firewall.@forwarding[3].src='lan2'
dhcp.@dnsmasq[0]=dnsmasq
dhcp.@dnsmasq[0].domainneeded='1'
dhcp.@dnsmasq[0].localise_queries='1'
dhcp.@dnsmasq[0].rebind_protection='1'
dhcp.@dnsmasq[0].rebind_localhost='1'
dhcp.@dnsmasq[0].local='/lan/'
dhcp.@dnsmasq[0].domain='lan'
dhcp.@dnsmasq[0].expandhosts='1'
dhcp.@dnsmasq[0].authoritative='1'
dhcp.@dnsmasq[0].readethers='1'
dhcp.@dnsmasq[0].leasefile='/tmp/dhcp.leases'
dhcp.@dnsmasq[0].localservice='1'
dhcp.@dnsmasq[0].confdir='/tmp/dnsmasq.d'
dhcp.@dnsmasq[0].resolvfile='/tmp/resolv.conf.vpn'
dhcp.lan=dhcp
dhcp.lan.interface='lan'
dhcp.lan.start='100'
dhcp.lan.limit='150'
dhcp.lan.leasetime='12h'
dhcp.lan.dhcpv6='disabled'
dhcp.wan=dhcp
dhcp.wan.interface='wan'
dhcp.wan.ignore='1'
dhcp.odhcpd=odhcpd
dhcp.odhcpd.maindhcp='0'
dhcp.odhcpd.leasefile='/tmp/hosts/odhcpd'
dhcp.odhcpd.leasetrigger='/usr/sbin/odhcpd-update'
dhcp.odhcpd.loglevel='4'
dhcp.lan2=dhcp
dhcp.lan2.start='100'
dhcp.lan2.leasetime='12h'
dhcp.lan2.limit='150'
dhcp.lan2.interface='lan2'
root@OpenWrt:~# ls -l  /etc/resolv.* /tmp/resolv.*; head -n -0 /etc/resolv.* /tmp/resolv.*


lrwxrwxrwx    1 root     root            16 May 17 00:02 /etc/resolv.conf -> /tmp/resolv.conf
-rw-r--r--    1 root     root            32 Jul  1 02:18 /tmp/resolv.conf
-rw-r--r--    1 root     root            39 Jul  1 02:16 /tmp/resolv.conf.auto
-rw-r--r--    1 root     root            50 Jul  1 03:01 /tmp/resolv.conf.vpn
==> /etc/resolv.conf <==
search lan
nameserver 127.0.0.1

==> /tmp/resolv.conf <==
search lan
nameserver 127.0.0.1

==> /tmp/resolv.conf.auto <==
# Interface wan
nameserver 192.168.1.1

==> /tmp/resolv.conf.vpn <==
nameserver 103.86.96.100
nameserver 103.86.99.100

Any help is appreciated - I have tried VPN policy based routing as well without success.

Hi, check out this post

First of all the 11.0.0.0/24 is not private, change it to 10.11.0.0/24
Second you have enabled forwardings in firewall zones from lan to both wan and vpn and from lan2 to both wan and vpn. I presume you wanted to restrict access and not let anyone access everywhere.
Third there is no separation of dnsmasq instances, but I would only add the dhcp option 6 in lan2 interface with the dns servers of the vpn provider and keep the OpenWrt with the default ISP nameservers.

1 Like

Thank you @trendy and @sammo for your responses!

I have made the suggested changes to lan2 subnet and firewall. Also, I was able to resolve the DNS leak issue by a combination of things -

  • Instead of deleting the default route created by OpenVPN, use VPN policy routing to route traffic from 10.0.0.0/24 via WAN, while 10.11.0.0/24 stays linked to default route.
  • Create a two dnsmasq instances lan and lan2 - with nameservers manually defined in /etc/resolv.conf.lan (192.168.1.1 gateway with ISP DNS) and /etc/resolv.conf.lan2 (VPN DNS).

One question though - Using dhcp option 6 for lan2 and also allowing WAN to get DNS from gateway ( option peerdns '1') results in /tmp/resolv.conf.auto being populated with 3 nameservers: 2 from VPN and the 192.168.1.1 gateway itself, leading to leaks. This is why I am manually defining the servers and not linking my resolv.conf.lan and resolv.conf.lan2 to /tmp/resolv.conf.auto.

Is there a better way to deal with this?

Well, I don't claim that this way is better, however it is certainly a simpler method, which is to push a globally-routed DNS provider via DHCP.
Considering that major DNS providers utilize geolocation-based load balancing it should work good enough for both WAN and VPN traffic.

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