Policy Based Routing and Mullvad

So, I'm struggeling a bit with Policy Based Routing and Mullvad VPN.

I want to achive the following:

Route all traffic through the Mullvad/VPN client and subsequent interface per default. Exclude local devices (per IP) and route through WAN (to anywhere and specific remote addresses).

I have archived the latter part. Any device added is surely routed through WAN (see AppleTV and Ipad policy).

The first part? Nearly, with OpenVPN client/interface Up every other devices is routed through OpenVPN.

However, even with "Strict Enforce policies" enabled, whenever I stop the OpenVPN client and/or interface everything from the VPN policy in PBR gets routed through the WAN and "leaks".

Any ideas what I'm missing?

I'm on a Turris Omnia and configs as below:

network.loopback=interface
network.loopback.proto='static'
network.loopback.ipaddr='127.0.0.1'
network.loopback.netmask='255.0.0.0'
network.loopback.device='lo'
network.globals=globals
network.globals.ula_prefix='fdd4:80aa:c61c::/48'
network.lan=interface
network.lan.proto='static'
network.lan.ipaddr='192.168.1.1'
network.lan.netmask='255.255.255.0'
network.lan.ip6assign='60'
network.lan.device='br-lan'
network.wan=interface
network.wan.proto='dhcp'
network.wan.ipv6='1'
network.wan.device='eth2'
network.wan.peerdns='0'
network.guest_turris=interface
network.guest_turris.enabled='1'
network.guest_turris.proto='static'
network.guest_turris.ipaddr='10.111.222.1'
network.guest_turris.netmask='255.255.255.0'
network.guest_turris.device='br-guest-turris'
network.guest_turris.ip6assign='64'
network.wan6=interface
network.wan6.proto='dhcpv6'
network.wan6.device='@wan'
network.br_lan=device
network.br_lan.name='br-lan'
network.br_lan.bridge_empty='1'
network.br_lan.type='bridge'
network.br_lan.ports='lan0' 'lan1' 'lan2' 'lan3' 'lan4'
network.br_guest_turris=device
network.br_guest_turris.bridge_empty='1'
network.br_guest_turris.type='bridge'
network.br_guest_turris.name='br-guest-turris'
network.MLVPN=interface
network.MLVPN.device='tun0'
network.MLVPN.proto='none'
firewall.@defaults[0]=defaults
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@defaults[0].synflood_protect='1'
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].sentinel_dynfw='1'
firewall.@zone[1].sentinel_minipot='1'
firewall.@zone[1].sentinel_fwlogs='1'
firewall.@zone[1].network='wan' 'wan6' 'MLVPN'
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.guest_turris=zone
firewall.guest_turris.enabled='1'
firewall.guest_turris.input='REJECT'
firewall.guest_turris.forward='REJECT'
firewall.guest_turris.output='ACCEPT'
firewall.guest_turris.name='tr_guest'
firewall.guest_turris.network='guest_turris'
firewall.guest_turris_forward_wan=forwarding
firewall.guest_turris_forward_wan.enabled='1'
firewall.guest_turris_forward_wan.name='guest to wan forward'
firewall.guest_turris_forward_wan.dest='wan'
firewall.guest_turris_forward_wan.src='tr_guest'
firewall.guest_turris_dns_rule=rule
firewall.guest_turris_dns_rule.enabled='1'
firewall.guest_turris_dns_rule.name='guest dns rule'
firewall.guest_turris_dns_rule.proto='tcpudp'
firewall.guest_turris_dns_rule.dest_port='53'
firewall.guest_turris_dns_rule.target='ACCEPT'
firewall.guest_turris_dns_rule.src='tr_guest'
firewall.guest_turris_dhcp_rule=rule
firewall.guest_turris_dhcp_rule.enabled='1'
firewall.guest_turris_dhcp_rule.name='guest dhcp rule'
firewall.guest_turris_dhcp_rule.proto='udp'
firewall.guest_turris_dhcp_rule.src_port='67-68'
firewall.guest_turris_dhcp_rule.dest_port='67-68'
firewall.guest_turris_dhcp_rule.target='ACCEPT'
firewall.guest_turris_dhcp_rule.src='tr_guest'
firewall.wan_ssh_turris_rule=rule
firewall.wan_ssh_turris_rule.name='wan_ssh_turris_rule'
firewall.wan_ssh_turris_rule.enabled='0'
firewall.wan_ssh_turris_rule.target='ACCEPT'
firewall.wan_ssh_turris_rule.dest_port='22'
firewall.wan_ssh_turris_rule.proto='tcp'
firewall.wan_ssh_turris_rule.src='wan'
firewall.wan_http_turris_rule=rule
firewall.wan_http_turris_rule.name='wan_http_turris_rule'
firewall.wan_http_turris_rule.enabled='0'
firewall.wan_http_turris_rule.target='ACCEPT'
firewall.wan_http_turris_rule.dest_port='80'
firewall.wan_http_turris_rule.proto='tcp'
firewall.wan_http_turris_rule.src='wan'
firewall.wan_https_turris_rule=rule
firewall.wan_https_turris_rule.name='wan_https_turris_rule'
firewall.wan_https_turris_rule.enabled='0'
firewall.wan_https_turris_rule.target='ACCEPT'
firewall.wan_https_turris_rule.dest_port='443'
firewall.wan_https_turris_rule.proto='tcp'
firewall.wan_https_turris_rule.src='wan'
firewall.turris_wan_6in4_rule=rule
firewall.turris_wan_6in4_rule.enabled='0'
firewall.bcp38=include
firewall.bcp38.type='script'
firewall.bcp38.path='/usr/lib/bcp38/run.sh'
firewall.bcp38.family='IPv4'
firewall.bcp38.reload='1'
firewall.miniupnpd=include
firewall.miniupnpd.type='script'
firewall.miniupnpd.path='/usr/share/miniupnpd/firewall.include'
firewall.miniupnpd.family='any'
firewall.miniupnpd.reload='1'
firewall.guest_turris_Allow_DHCPv6=rule
firewall.guest_turris_Allow_DHCPv6.src='tr_guest'
firewall.guest_turris_Allow_DHCPv6.proto='udp'
firewall.guest_turris_Allow_DHCPv6.src_ip='fe80::/10'
firewall.guest_turris_Allow_DHCPv6.src_port='546-547'
firewall.guest_turris_Allow_DHCPv6.dest_ip='fe80::/10'
firewall.guest_turris_Allow_DHCPv6.dest_port='546-547'
firewall.guest_turris_Allow_DHCPv6.family='ipv6'
firewall.guest_turris_Allow_DHCPv6.target='ACCEPT'
firewall.guest_turris_Allow_MLD=rule
firewall.guest_turris_Allow_MLD.src='tr_guest'
firewall.guest_turris_Allow_MLD.proto='icmp'
firewall.guest_turris_Allow_MLD.src_ip='fe80::/10'
firewall.guest_turris_Allow_MLD.family='ipv6'
firewall.guest_turris_Allow_MLD.target='ACCEPT'
firewall.guest_turris_Allow_MLD.icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.guest_turris_Allow_ICMPv6_Input=rule
firewall.guest_turris_Allow_ICMPv6_Input.src='tr_guest'
firewall.guest_turris_Allow_ICMPv6_Input.proto='icmp'
firewall.guest_turris_Allow_ICMPv6_Input.limit='1000/sec'
firewall.guest_turris_Allow_ICMPv6_Input.family='ipv6'
firewall.guest_turris_Allow_ICMPv6_Input.target='ACCEPT'
firewall.guest_turris_Allow_ICMPv6_Input.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.@forwarding[1]=forwarding
firewall.@forwarding[1].dest='wan'
firewall.@forwarding[1].src='lan'
firewall.sentinel_firewall=include
firewall.sentinel_firewall.type='script'
firewall.sentinel_firewall.path='/usr/libexec/sentinel/firewall.sh'
firewall.sentinel_firewall.family='any'
firewall.sentinel_firewall.reload='1'
pbr.config=pbr
pbr.config.procd_reload_delay='1'
pbr.config.verbosity='0'
pbr.config.resolver_set='dnsmasq.ipset'
pbr.config.ipv6_enabled='0'
pbr.config.dest_ipset='0'
pbr.config.src_ipset='0'
pbr.config.webui_enable_column='0'
pbr.config.webui_protocol_column='0'
pbr.config.webui_chain_column='0'
pbr.config.webui_show_ignore_target='0'
pbr.config.webui_sorting='1'
pbr.config.webui_supported_protocol='tcp' 'udp' 'tcp udp' 'icmp' 'all'
pbr.config.rule_create_option='add'
pbr.config.enabled='1'
pbr.config.strict_enforcement='1'
pbr.@policy[0]=policy
pbr.@policy[0].src_addr='192.168.1.167'
pbr.@policy[0].name='AppleTV'
pbr.@policy[0].interface='wan'
pbr.@policy[1]=policy
pbr.@policy[1].name='Ipad'
pbr.@policy[1].interface='wan'
pbr.@policy[1].src_addr='192.168.1.155'
pbr.@policy[2]=policy
pbr.@policy[2].name='VPN'
pbr.@policy[2].interface='MLVPN'
pbr.@policy[2].src_addr='192.168.1.100/30 192.168.1.104/29 192.168.1.112/28 192.168.1.128/25'

OpenVPN client:

client
dev tun
resolv-retry infinite
nobind
persist-key
persist-tun
verb 3
remote-cert-tls server
ping 10
ping-restart 60
sndbuf 524288
rcvbuf 524288
cipher AES-256-GCM
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
proto udp
auth-user-pass /etc/openvpn/mullvad_client.auth
reneg-sec 0
tun-ipv6
fast-io
remote-random
remote 185.65.135.83 1196 # se-sto-ovpn-004
remote 185.65.135.82 1196 # se-sto-ovpn-003
remote 185.65.135.80 1196 # se-sto-ovpn-001

Just assign your vpn interface a separate firewall zone and you should be good to go… don’t forget to enable masquerading on your newly created firewall zone.

Just adding it straight up makes no difference. Per below. Missing something else or wrong zone config?

firewall.@zone[3]=zone
firewall.@zone[3].name='MLVPN'
firewall.@zone[3].input='REJECT'
firewall.@zone[3].forward='REJECT'
firewall.@zone[3].masq='1'
firewall.@zone[3].network='MLVPN'
firewall.@zone[3].output='ACCEPT'
firewall.sentinel_firewall=include
firewall.sentinel_firewall.type='script'
firewall.sentinel_firewall.path='/usr/libexec/sentinel/firewall.sh'
firewall.sentinel_firewall.family='any'
firewall.sentinel_firewall.reload='1'

Sorry, I probably did not read your configs carefully enough and also it’s a bit tough reading trough the configs in uci format.

I guess with the setup you have now one way would be to just create 2 local networks (For example Lan A and Lan B) with their own firewall zones and allow forwarding only to wan or vpn zone. For example, LanA should be routed through the vpn and Lan B trough wan.

Zone Forwardings:

Lan A -> VPN
Lan B -> WAN

Seems a bit obtrusive for this issue.

I would think the Strict Enforce policies should do it.

I will tinker on.