IPv6 IP address leak using policy-based routing

ah, maybe because the policy-based rule includes the mullvad interface? How would I solve that, should it be the case?

Let's have a look in the configuration:
uci export vpn-policy-routing; /etc/init.d/vpn-policy-routing support

package vpn-policy-routing

config vpn-policy-routing 'config'
	option verbosity '2'
	option strict_enforcement '1'
	option boot_timeout '30'
	list supported_interface 'wan'
	list supported_interface 'mullvad'
	list ignored_interface 'wgserver'
	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 src_ipset '0'
	option ipv6_enabled '1'
	option iptables_rule_option 'append'
	option iprule_enabled '0'
	option webui_enable_column '0'
	option webui_chain_column '0'
	option webui_sorting '1'
	option webui_protocol_column '1'
	option enabled '1'

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'

config policy
	option chain 'PREROUTING'
	option name 'Family'
	option src_addr '192.168.30.1/24'
	option proto 'tcp udp'
	option interface 'mullvad'

vpn-policy-routing 0.2.1-13 running on OpenWrt 19.07.3. WAN (IPv4): wan/dev/62.3.80.17.
============================================================
Dnsmasq version 2.80  Copyright (c) 2000-2018 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC no-ID loop-detect inotify dumpfile
============================================================
Routes/IP Rules
default         losubs.subs.bng 0.0.0.0         UG    0      0        0 pppoe-wan
IPv4 Table 201: default via 62.3.80.17 dev pppoe-wan
10.0.0.0/24 dev br-guest proto kernel scope link src 10.0.0.1
192.168.20.0/24 dev br-streaming proto kernel scope link src 192.168.20.1
192.168.30.0/24 dev br-family proto kernel scope link src 192.168.30.1
192.168.99.0/24 dev wgserver proto kernel scope link src 192.168.99.1
IPv4 Table 201 Rules:
32739:	from all fwmark 0x10000/0xff0000 lookup 201
IPv4 Table 202: default via 10.99.57.166 dev mullvad
10.0.0.0/24 dev br-guest proto kernel scope link src 10.0.0.1
192.168.20.0/24 dev br-streaming proto kernel scope link src 192.168.20.1
192.168.30.0/24 dev br-family proto kernel scope link src 192.168.30.1
192.168.99.0/24 dev wgserver proto kernel scope link src 192.168.99.1
IPv4 Table 202 Rules:
32738:	from all fwmark 0x20000/0xff0000 lookup 202
IPv6 Table 201: default from 2a02:8010:672e::/48 via fe80::d2f0:dbff:fe6c:e000 dev pppoe-wan proto static metric 512 pref medium
IPv6 Table 201: default from 2a02:8011:d000:71f::/64 via fe80::d2f0:dbff:fe6c:e000 dev pppoe-wan proto static metric 512 pref medium
IPv6 Table 201: 2a02:8011:d000:71f::/64 dev pppoe-wan proto static metric 256 pref medium
IPv6 Table 201: fe80::/10 dev pppoe-wan metric 1 pref medium
IPv6 Table 201: fe80::/10 dev pppoe-wan proto kernel metric 256 pref medium
IPv6 Table 202: fc00:bbbb:bbbb:bb01::39a6 dev mullvad proto kernel metric 256 pref medium
IPv6 Table 202: default dev mullvad proto static metric 1024 pref medium
============================================================
IP Tables PREROUTING
-N VPR_PREROUTING
-A VPR_PREROUTING -s 192.168.30.0/24 -p udp -m comment --comment Family -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -s 192.168.30.0/24 -p tcp -m comment --comment Family -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -s 192.168.10.0/24 -p udp -m comment --comment Private -c 25 3608 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -s 192.168.10.0/24 -p tcp -m comment --comment Private -c 457 344915 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -m set --match-set mullvad dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IP6 Tables PREROUTING
-N VPR_PREROUTING
-A VPR_PREROUTING -s fc00:bbbb:bbbb::/48 -p udp -m comment --comment Private -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_PREROUTING -s fc00:bbbb:bbbb::/48 -p tcp -m comment --comment Private -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
============================================================
IP Tables FORWARD
-N VPR_FORWARD
-A VPR_FORWARD -m set --match-set mullvad dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_FORWARD -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IPv6 Tables FORWARD
-N VPR_FORWARD
============================================================
IP Tables INPUT
-N VPR_INPUT
-A VPR_INPUT -m set --match-set mullvad dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_INPUT -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IPv6 Tables INPUT
-N VPR_INPUT
============================================================
IP Tables OUTPUT
-N VPR_OUTPUT
-A VPR_OUTPUT -m set --match-set mullvad dst -c 0 0 -j MARK --set-xmark 0x20000/0xff0000
-A VPR_OUTPUT -m set --match-set wan dst -c 0 0 -j MARK --set-xmark 0x10000/0xff0000
============================================================
IPv6 Tables OUTPUT
-N VPR_OUTPUT
============================================================
Current ipsets
create wan hash:net family inet hashsize 1024 maxelem 65536 comment
create mullvad hash:net family inet hashsize 1024 maxelem 65536 comment
============================================================
Your support details have been logged to '/var/vpn-policy-routing-support'. [✓]

By the way, I've removed option append_src_rules '! -d 192.168.0.0/16' from the VPN-PBR config, since this threw errors with the IPv6 PBR (which makes sense; but is something I will need to have working at some point).

Thanks, as ever, for your continued help.

have just spotted this. Potentially related?

Thu Jun  4 09:48:34 2020 daemon.warn odhcpd[3581]: A default route is present but there is no public prefix on lan thus we don't announce a default route!

I guess this could be. Can you ping from the OpenWrt an IPv6 address using the mullvad vpn?
ping6 -I mullvad ipv6.google.com
If yes, then add the following:

uci set dhcp.lan.ra_default='1'
uci commit dhcp
service dnsmasq restart

Thanks. Yes, ping6 from the router works (but fails on a client with "No route to host"). Have added ra_default='1' so that the stanza now looks as follows; but still no IPv6 Connectivity. I also see:

Thu Jun  4 11:02:39 2020 daemon.err dnsmasq[6556]: failed to send packet: Host is unreachable

and the 'default route / no lan prefix' warning from odhcpd

/etc/config/dhcp
config dhcp 'lan'
	option instance 'main'
	option interface 'lan'
	option start '100'
	option limit '150'
	option dhcpv6 'server'
	option ra 'server'
	option ra_management '1'
	option leasetime '168h'
	option ra_default '1'

Check the ipv6 routing table of the client . Does it have a default route? With the latest addition it should, so maybe you need to restart the networking on the client?

One more thing:
the mullvad IP overlaps with the lan network, so change the lan address to something else. For example fc00:bbbb:bbbb:bba1::1/60
You can use IPv6 assignment hint for that bba1

OK, so changes made:

added to /etc/config/network:

config globals 'globals'
	option ula_prefix 'fc00:bbbb:bbbb:bba1::1/60'

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

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

added to /etc/config/dhcp:

config dhcp 'lan'
	...
	option ra_default '1'
    ...

modified vpn-pbr rule:

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::1/60'

rebooted router, restarted network on client.

This works on the router

 ping -I mullvad ipv6.google.com

but on the client, I now get:

PING6(56=40+8+8 bytes) fc00:bbbb:bbbb:bba0:6402:67dc:227f:8194 --> 2404:6800:4003:c04::8b

Routing table shows a site local address as default:

Destination                             Gateway                         Flags         Netif Expire
default                                 fe80::20d:b9ff:fe51:2639%en0    UGc             en0       
default                                 fe80::%utun0                    UGcI          utun0       
default                                 fe80::%utun1                    UGcI          utun1       
default                                 fe80::%utun2                    UGcI          utun2       
default                                 fe80::%utun3                    UGcI          utun3       
::1                                     ::1                             UHL             lo0 

utterly stumped. IPv6 connectivity through my ISP is fine; it's just getting out through Mullvad that's problematic)

traceroute6 ipv6.google.com

from the router shows a route through Mullvad...

Here you can have the whole prefix that mullvad has assigned to you.
Then you can fine tune the interface prefixes either statically or with hints.

That is correct, as this is the link local of the br-lan interface.
Do a tcpdump and verify that ping packet is leaving from the router:
tcpdump -i mullvad -vn icmp6

I think I follow:

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

and then add: option ip6prefix fc00:bbbb:bbbb:bba1::1/60 to the config interface lan stanza.

Careful there, you must use the prefix that has been assigned to you.

oh, good catch. /48'. Will give it a whirl and let you know.

sorry, I'm making a fudge of this.

Mullvad has given me fc00:bbbb:bbbb:bb01::39a6/128

I've got:

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

and

config interface 'lan'
	...
	option ip6prefix 'fc00:bbbb:bbbb:bb01::1/60'

with a VPN-PBR rule of:

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::1/60

When I ping6 from a client, it looks like the prefix is incorrect:

PING6(56=40+8+8 bytes) fc00:bbbb:bbbb:bb00:c866:d21b:85de:d638 --> 2404:6800:4003:c04::8b

When I check the IPv6 addresses assigned to the client, there are 5:

  • Two beginning fc00:bbbb:bbbb:bb00
  • One beginning fc00:bbbb:bbbb:bb01
  • Two beginning fd...

This is for delegation to downstream routers.

Verify the IPv6 of the lan interface with ip -6 addr most likely it is using a different one since you reserved the bb01 for delegation.

Ah, I see. I misunderstood the docs, then. That being the case; how to I ensure the lan network doesn't overlap with the Mullvad IP? Can I set option ip6prefix on the wan interface?

UPDATE: or option ip6addr on the lan interface

You can assign the ip with ip6addr directly.
Or you can use the ip6hint to let it take a chunk from the whole /48 and use the hint suffix for network. Check here.

thanks. I'm going to reset all the changes so far so I'm back in the initial state (IPv4 obeying the vpn-pbr and IPv6 through my ISP), and then make changes one-by-one.

no luck, I'm afraid. Same situation: ping6 from the router over the mullvad interface is fine; but nothing from clients.

I'm going to 'sleep on it' and see if a fresh pair of eyes on it helps.

Thanks for all your assistance.

One last thing, you didn't try the tcpdump. I am curious where the packets are dropped.