IPv6 NAT issue on WireGuard interface

Hi, i had some problems with my wireguard config and i'm not fully sure what the real problem is and how to fix.
I've use some wireguard VPN and want to NAT the IPv6 (yes i know ...) - but it does not work as aspect, it work some times for example if i stop the wan6 interface, but it does not work if i disable the wan6 interface and reboot the router, my guess is some strange routing behavior.
It work as desired if i use openvpn instead of wireguard. Here is my config
firewall:

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

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

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

config zone
	option name 'mullvad'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option mtu_fix '1'
	option masq '1'
	option masq6 '1'
	list network 'mv_malmoe'
	list network 'mv_zurich'
	list network 'MV_OPVN_ZURICH'

config forwarding
	option src 'lan'
	option dest 'mullvad'

interfaces:

config interface 'wan'
    option proto 'dhcp'
    option device 'eth0.2'
    option peerdns '0'
    list dns '192.168.1.5'
    list dns '10.20.40.1'
    list dns '9.9.9.9'
    list dns '192.168.178.1'
    option metric '100'

config interface 'wan6'
    option proto 'dhcpv6'
    option reqaddress 'try'
    option reqprefix '56'
    option device 'eth0.2'
    option peerdns '0'
    list dns 'fd00:1337:0:1::5'
    list dns '2620:fe::fe'


config interface 'mv_malmoe'
    option proto 'wireguard'
    option private_key '*************'
    list addresses '10.64.196.XXX/32'
    list addresses 'fc00:bbbb:bbbb:bb01::1:XXX/128'
    option metric '10'
    list ip6class 'local'
    option auto '0'

config wireguard_mv_malmoe
    option description 'Mullvald Malmö'
    option public_key '********'
    list allowed_ips '0.0.0.0/0'
    list allowed_ips '::0/0'
    option endpoint_host '193.138.218.130'
    option endpoint_port '51820'
    option persistent_keepalive '25'
    option route_allowed_ips '1'

config interface 'mv_zurich'
    option proto 'wireguard'
    option private_key '*******'
    list addresses '10.64.196.XXX/32'
    list addresses 'fc00:bbbb:bbbb:bb01::1:XXX/128'
    option delegate '0'
    option metric '10'

config wireguard_mv_zurich
    option description 'Mullvad Zurich'
    option public_key ******''
    list allowed_ips '0.0.0.0/0'
    list allowed_ips '::0/0'
    option route_allowed_ips '1'
    option endpoint_host '193.32.127.70'
    option persistent_keepalive '90'

config interface 'MV_OPVN_ZURICH'
    option proto 'none'
    option device 'tun0'
    option metric '10'
    option delegate '0'
    option auto '0'

Routes on the router:

ip -6 r
2a04:XXXX:XXXX:XXX1::/64 dev eth1.1 proto kernel metric 256 expires 3945sec pref medium
2a04:XXXX:XXXX:XXX2::/64 dev phy0-ap0 proto kernel metric 256 expires 3945sec pref medium
2a04:XXXX:XXXX:XXX3::/64 dev phy1-ap0 proto kernel metric 256 expires 3945sec pref medium
fc00:bbbb:bbbb:bb01::1:c3ff dev mv_zurich proto static metric 10 pref medium
fd00:1337:0:1::/64 dev eth1.1 proto static metric 1024 pref medium
fd00:1337:0:2::/64 dev phy0-ap0 proto static metric 1024 pref medium
fd00:1337:0:3::/64 dev phy1-ap0 proto static metric 1024 pref medium
unreachable fd00:1337::/48 dev lo proto static metric 2147483647 pref medium
fe80::/64 dev eth1 proto kernel metric 256 pref medium
fe80::/64 dev eth1.1 proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev eth0.2 proto kernel metric 256 pref medium
fe80::/64 dev phy1-ap0 proto kernel metric 256 pref medium
fe80::/64 dev phy0-ap0 proto kernel metric 256 pref medium
default dev mv_zurich proto static metric 10 pref medium

ip  r
default dev mv_zurich proto static scope link metric 10
default via 192.168.178.1 dev eth0.2 proto static src 192.168.178.10 metric 100
10.64.196.0 dev mv_zurich proto static scope link metric 10
192.168.1.0/24 dev eth1.1 proto kernel scope link src 192.168.1.1
192.168.2.0/24 dev phy0-ap0 proto kernel scope link src 192.168.2.1
192.168.3.0/24 dev phy1-ap0 proto kernel scope link src 192.168.3.1
192.168.178.0/24 dev eth0.2 proto static scope link metric 100
193.32.127.70 via 192.168.178.1 dev eth0.2 proto static metric 100

on example system:

karloff-VirtualBox:~$ ip a
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:dc:37:21 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.119/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
       valid_lft 258785sec preferred_lft 258785sec
    inet6 2a04:XXXX:XXXX:XXX1::bbb/128 scope global dynamic noprefixroute
       valid_lft 6709sec preferred_lft 3109sec
    inet6 fd00:1337:0:1::bbb/128 scope global dynamic noprefixroute
       valid_lft 258787sec preferred_lft 3109sec
    inet6 fe80::a775:2436:8f7f:a3e/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

karloff-VirtualBox:~$ ip r
default via 192.168.1.1 dev enp0s3 proto dhcp metric 100
169.254.0.0/16 dev enp0s3 scope link metric 1000
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.119 metric 100

karloff-VirtualBox:~$ ip -6 r
::1 dev lo proto kernel metric 256 pref medium
2a04:XXXX:XXXX:XXX1::/64 dev enp0s3 proto ra metric 100 pref medium
fd00:1337:0:1::bbb dev enp0s3 proto kernel metric 100 pref medium
fd00:1337:0:1::/64 dev enp0s3 proto ra metric 100 pref medium
fd00:1337::/48 via fe80::7ad2:94ff:fe52:2984 dev enp0s3 proto ra metric 100 pref medium
fe80::/64 dev enp0s3 proto kernel metric 1024 pref medium
default via fe80::7ad2:94ff:fe52:2984 dev enp0s3 proto ra metric 100 pref medium

karloff-VirtualBox:~$ ping -6 ccc.de
PING ccc.de(web.ber.ccc.de (2001:67c:20a0:2:0:164:0:39)) 56 data bytes
From 2a04:4540:654c:a481::1 (2a04:4540:654c:a481::1) icmp_seq=1 Destination unreachable: Port unreachable
From 2a04:4540:654c:a481::1 (2a04:4540:654c:a481::1) icmp_seq=2 Destination unreachable: Port unreachable

karloff-VirtualBox:~$ ip -6 r get 2001:67c:20a0:2:0:164:0:39
2001:67c:20a0:2:0:164:0:39 from :: via fe80::7ad2:94ff:fe52:2984 dev enp0s3 proto ra src 2a04:XXX:XXX:XX1::bbb metric 20100 pref medium

why did this work when i use ovpn connection and what are the real problem here, i guess it is some routing stuff but i'm not sure how to fix and why it is a problem.

ubus call system board

{
	"kernel": "5.15.150",
	"hostname": "sagan",
	"system": "ARMv7 Processor rev 0 (v7l)",
	"model": "Netgear Nighthawk X4S R7800",
	"board_name": "netgear,r7800",
	"rootfs_type": "squashfs",
	"release": {
		"distribution": "OpenWrt",
		"version": "23.05.3",
		"revision": "r23809-234f1a2efa",
		"target": "ipq806x/generic",
		"description": "OpenWrt 23.05.3 r23809-234f1a2efa"
	}
}

If i miss some need information, please ask

I am not the greatest IPv6 expert, but it could be related to the use of source routing for IPv6.
There is no standard default route and so it is not overridden by the default route via the VPN.

I also use Mullvad and what works for me is to use as allowed IPs instead of ::0/0:

::/1
8000::/1

Alternatively disabling source filter: might also work.

Summary

If you decide to go the source filter route you als0 have to change metrics as the the default ipv6 metric is 1024 and the default route via the WAN has a metric of 512.
However that will get you in trouble with IPv4 routing as the default IPv4 route has a metric of 0 (which is the IPv4 default) so you also have to change the IPv4 default route to be above the metric of the VPN interface

BTW why are you using metrics?
If it is for redundancy then that does not work for me as the tunnel stays up if the server is not responding.
For redundancy i use a fail-over script which brings down a non functioning tunnel and starts the next.

Thank you very much!
Chancing the allowed v6 Addresses work.

But i don't get it ... why does this work and what does 8000::/1 made here?
Had you some further information about how and why this work and why this fix the problem?

Oh yes the metrics, i play a bit with it and then i don't remove it.
in the firewall my lan can only forward to the wireguard and not to wan, so there does nothing and now i removed it.
How did you detect non functional tunnels?

The problem seems to be the use of source routing with IPv6 that has priority over a plain default route.
The use of ::0/1, 8000::/1 which actually encompasses everything, so results in default routing, has priority over the source routing as the prefix is smaller (/1)

This "trick" is already a long time in use also for IPv4 (0.0.0.0/1, 128.0.0.0/1) and used by OpenVPN preserving the existing default route but still getting priority (it is from the pre metric era)

You can disable source routing but then you also have to adjust metrics as the default route made for the VPN has a default 1024 metric and existing default route has a metric of 512, but that also adjust the metric for IPv4 which in turn you have to adjust also.

I am no IPv6 expert so there might be a better approach but at least using ::0/1, 8000::/1 seems to be the easiest :slight_smile:

Although Mullvad is very solid, once in a while (maintenance, failure etc) a Mullvad server is down.
I use a script to detect this and the script switches to my next Mullvad tunnel.
The script I use: https://github.com/egc112/OpenWRT-egc-add-on/tree/main/wireguard-watchdog

1 Like

Thank you for taking the time to explaining who this work and sharing your script.
I don't know this "trick" but now it makes sense and i learn something new :smiley:
thanks for that.

1 Like

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