IPv6 IP address leak using policy-based routing

Good afternoon,

My ISP (Zen Internet, UK) has just enabled IPv6 support on my connection.

I've had a (Mullvad) Wireguard connection set-up on my router for a while, used in conjunction with policy-based routing. When visiting sites, my public IPv4 address is that of the VPN connection (as expected), but my IPv6 address shows as my ISP's.

I'm unsure where to start to investigate and resolve this. I'm not sure if it's a limitation of the Mullvad Wireguard offering; or whether I've set-up something incorrectly using @stangri 's vpn-policy-routing package. The following may be a good place to start:

/etc/config/vpn-policy-routing

config vpn-policy-routing 'config'
	option verbosity '2'
	option strict_enforcement '1'
	option boot_timeout '30'
	list ignored_interface 'wgserver'
	option append_src_rules '! -d 192.168.0.0/16'
	option dest_ipset 'ipset'
	list webui_supported_protocol 'tcp'
	list webui_supported_protocol 'udp'
	list webui_supported_protocol 'tcp udp'
	list webui_supported_protocol 'icmp'
	list webui_supported_protocol 'all'
	option enabled '1'
	option src_ipset '0'
	option iptables_rule_option 'append'
	option iprule_enabled '0'
	option webui_enable_column '0'
	option webui_protocol_column '0'
	option webui_chain_column '0'
	option webui_sorting '1'
	list supported_interface 'wan'
	list supported_interface 'mullvad'
	list supported_interface 'wan6'
	option ipv6_enabled '1'
	
config policy
	option chain 'PREROUTING'
	option name 'Private'
	option src_addr '192.168.10.1/24'
	option proto 'tcp udp'
	option interface 'mullvad'

/etc/config/network

config globals 'globals'
	option ula_prefix 'redacted::/48'

config interface 'lan'
	option type 'bridge'
	option proto 'static'
	option ip6assign '60'
	option netmask '255.255.255.0'
	option ipaddr '192.168.10.1'
	option ifname 'eth1 eth2'

config interface 'wan'
	option proto 'pppoe'
	option ifname 'eth0'
	option ipv6 'auto'
	option peerdns '0'
	option dns '185.228.168.9 185.228.169.9'
	option username 'redacted'
	option password 'redacted'

config interface 'wan6'
	option ifname '@wan'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'
	option peerdns '0'
	option dns '2a0d:2a00:1::2 2a0d:2a00:2::2'

Thanks in advance

Does Mulvad offer IPv6 connectivity?
If not you'll have to disable the IPv6 on your router. IPv6 takes precedence over IPv4 when both are available.

I believe so (though, I have just asked to check); config below:

[Interface]
PrivateKey = redacted
Address = redacted/32,::xxx/redacted
DNS = 193.138.218.74

[Peer]
PublicKey = TMOEAxpcv5xz+PvcvqP0Iy4+px+hrCJUJHGcy45DVQI=
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = 185.200.118.100:51820

Yes, definitely. To test: I disconnected from my home network, and connected to Mullvad - using the same WG config - using the Wireguard client app on my phone. In doing so, both my IPv4 and IPv6 address are that of Mullvad; not my ISP.

When I connect back-up to my network, my IPv4 address is Mullvad's; IPv6 is my ISP's. So, perhaps I've configured something incorrectly with the policy-based routing?

Is the IPv6 from Mullvad ULA (private) or GUA (public)?
The first start wth fc or fd. The second start with 200X

ULA.

I'm wondering if the single /128 IPv6 address is the problem and that's forcing LAN clients over my ISP's IPv6 connection rather than through the VPN tunnel. That-being-the-case, something like Unable to get IPv6 to work with Mullvad VPN WireGuard should work; but it doesn't (quite possibly because I've screwed something up along the way).

First of all you should be delegating some prefix from Mullvad to the lan. But if the prefix is also ULA, the hosts in the lan will prefer to use the GUA prefix from your provider. So you would have to drop the prefix from your provider to force the hosts to use the address from Mullvad.

Thanks; feared as much. I'll see if I can get something working with nat6.

If Mullvad is providing you a ULA prefix, then they are doing NAT6 on it so you don't need to do it again.

Sorry, a bit out of my depth here. Does that mean setting the ULA prefix in the network config to the prefix provided by Mullvad?

config globals 'globals'
	option ula_prefix '<mullvad prefix goes here>::/48'

This would be an option and I think it is the easiest.
Use ip6class local in downstream configuration to let only local addresses be assigned to lan hosts.

Perfect; thanks. The mullvad prefix is fc00:bbbb:bbbb:bb01, so I'll do this:

config globals 'globals'
	option ula_prefix 'fc00:bbbb:bbbb:bb01::/48'

and then in /etc/config/network, the following stanza:

config interface lan
        ...
        list ip6class local
        ...
       

Will let you know how I get on. Thanks for your assistance.

No dice, unfortunately:

I can see that my client has an IPv6 address with the correct prefix. However, there's no IPv6 connectivity; ping6 openwrt.org fails ('no route to host', for instance and I can't load https://ipv6.am.i.mullvad.net.

Any chance we're looking at a mis-configuration with my policy-based rules?

What is the output of the following?
ip -6 addr; ip -6 ru; ip -6 ro; ifstatus mullvad

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
5: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::20d:b9ff:fe51:2638/64 scope link 
       valid_lft forever preferred_lft forever
6: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::20d:b9ff:fe51:2639/64 scope link 
       valid_lft forever preferred_lft forever
90: br-family: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::20d:b9ff:fe51:2639/64 scope link 
       valid_lft forever preferred_lft forever
92: br-guest: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::20d:b9ff:fe51:2639/64 scope link 
       valid_lft forever preferred_lft forever
94: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fc00:bbbb:bbbb:bb01::1/60 scope global noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::20d:b9ff:fe51:2639/64 scope link 
       valid_lft forever preferred_lft forever
95: br-streaming: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::20d:b9ff:fe51:2639/64 scope link 
       valid_lft forever preferred_lft forever
99: pppoe-wan: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1492 state UNKNOWN qlen 3
    inet6 2a02:8011:d000:71f::1/64 scope global dynamic noprefixroute 
       valid_lft 17987sec preferred_lft 1787sec
    inet6 fe80::1/10 scope link 
       valid_lft forever preferred_lft forever
100: mullvad: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 state UNKNOWN qlen 1000
    inet6 fc00:bbbb:bbbb:bb01::39a6/128 scope global 
       valid_lft forever preferred_lft forever
0:	from all lookup local 
32746:	from all fwmark 0x20000/0xff0000 lookup 202 
32747:	from all fwmark 0x10000/0xff0000 lookup 201 
32766:	from all lookup main 
4200000001:	from all iif lo failed_policy
4200000005:	from all iif eth0 failed_policy
4200000090:	from all iif br-family failed_policy
4200000092:	from all iif br-guest failed_policy
4200000094:	from all iif br-lan failed_policy
4200000095:	from all iif br-streaming failed_policy
4200000098:	from all iif wgserver failed_policy
4200000099:	from all iif pppoe-wan failed_policy
4200000099:	from all iif pppoe-wan failed_policy
4200000099:	from all iif pppoe-wan failed_policy
4200000100:	from all iif mullvad failed_policy
default from 2a02:8010:672e::/48 via fe80::d2f0:dbff:fe6c:e000 dev pppoe-wan proto static metric 512 pref medium
default from 2a02:8011:d000:71f::/64 via fe80::d2f0:dbff:fe6c:e000 dev pppoe-wan proto static metric 512 pref medium
unreachable 2a02:8010:672e::/48 dev lo proto static metric 2147483647 error 4294967183 pref medium
2a02:8011:d000:71f::/64 dev pppoe-wan proto static metric 256 pref medium
fc00:bbbb:bbbb:bb01::39a6 dev mullvad proto kernel metric 256 pref medium
fc00:bbbb:bbbb:bb01::/64 dev br-lan proto static metric 1024 pref medium
unreachable fc00:bbbb:bbbb::/48 dev lo proto static metric 2147483647 error 4294967183 pref medium
fe80::/64 dev eth1 proto kernel metric 256 pref medium
fe80::/64 dev br-lan proto kernel metric 256 pref medium
fe80::/64 dev br-streaming proto kernel metric 256 pref medium
fe80::/64 dev br-family proto kernel metric 256 pref medium
fe80::/64 dev br-guest proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/10 dev pppoe-wan metric 1 pref medium
fe80::/10 dev pppoe-wan proto kernel metric 256 pref medium
{
	"up": true,
	"pending": false,
	"available": true,
	"autostart": true,
	"dynamic": false,
	"uptime": 24,
	"l3_device": "mullvad",
	"proto": "wireguard",
	"updated": [
		"addresses"
	],
	"metric": 0,
	"dns_metric": 0,
	"delegation": true,
	"ipv4-address": [
		{
			"address": "10.99.57.166",
			"mask": 32
		}
	],
	"ipv6-address": [
		{
			"address": "fc00:bbbb:bbbb:bb01::39a6",
			"mask": 128
		}
	],
	"ipv6-prefix": [
		
	],
	"ipv6-prefix-assignment": [
		
	],
	"route": [
		
	],
	"dns-server": [
		
	],
	"dns-search": [
		
	],
	"neighbors": [
		
	],
	"inactive": {
		"ipv4-address": [
			
		],
		"ipv6-address": [
			
		],
		"route": [
			
		],
		"dns-server": [
			
		],
		"dns-search": [
			
		],
		"neighbors": [
			
		]
	},
	"data": {
		
	}
}

Try this script to add a default gateway:

source /lib/functions/network.sh
network_find_mullvad NET_IF6
network_get_gateway6 NET_GW6 "${NET_IF6}"
uci add network route6
uci set network.@route6[-1].interface="${NET_IF6}"
uci set network.@route6[-1].target="::/0"
uci set network.@route6[-1].gateway="${NET_GW6}"
uci commit network
service network reload

thanks. Not keen on the network_find_mullvad function:

 network_find_mullvad: not found

This looks odd to me; might be 'wild goose' rather than 'golden goose', though:

root@OpenWrt:~# ping6 -I mullvad openwrt.org
PING openwrt.org (2a03:b0c0:3:d0::1af1:1): 56 data bytes
ping6: sendto: Permission denied

solved that one with the following, but still no luck directing IPv6 traffic over the mullvad interface

config route6
	option target '::/0'
    option interface 'mullvad'

Which policy do you have in VPN-PBR for the IPv6 traffic?

This is my VPN-PBR rule. Current status is: 'no IPv6 connectivity at all'; not even via my ISP.

config policy
	option chain 'PREROUTING'
	option name 'Private'
	option proto 'tcp udp'
	option interface 'mullvad'
	option src_addr '192.168.10.1/24 fc00:bbbb:bbbb:bb01::/48'

and this is the diff since my initial post (forcing lan clients to use the prefix supplied by Mullvad and the route6 stanza):

/etc/config/network
config globals 'globals'
        option ula_prefix 'fc00:bbbb:bbbb:bb01::/48'

config interface 'lan'
        option type 'bridge'
        option proto 'static'
        option ip6assign '60'
        list ip6class local           
        option netmask '255.255.255.0'
        option ipaddr '192.168.10.1'
        option ifname 'eth1 eth2'

config route6
	option target '::/0'
    option interface 'mullvad'