How to do IPv6 over WireGuard (with LUCI)?

Hello all,

I have been unsucessfully trying to adapt the following WireGuard tunnel config to OpenWrt 21.02.0-rc3. Specifically, no matter what I tried, IPv6 traffic is still going through my ISP (and not the tunnel) - whereas IPv4 works as expected. This works fine on macOS, where both go through the VPN.

[Interface]
PrivateKey = (removed)
Address = 172.16.2.2/32, fd42:42:42::2/128
DNS = 8.8.8.8

[Peer]
PublicKey = (removed)
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = (server hostname):51820
PersistentKeepalive = 25

Note: I only have a /124 subnet (16 IPv6 addresses) available on the server, which is why I thought I go with unique local addresses for the VPN.

Any pointers for what I might want to try?


My relevant config:

[network]
config interface 'vpn'
	option proto 'wireguard'
	option private_key (removed)'
	option peerdns '0'
	list dns '8.8.8.8'
	option force_link '1'
	list addresses '172.16.2.7/32'
	list addresses 'fd42:42:42::7/128'
	option auto '0'

config wireguard_vpn
	option description 'VPN'
	option public_key '(removed)'
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::/0'
	option endpoint_host '(server hostname)'
	option persistent_keepalive '25'
	option route_allowed_ips '1'

[firewall]
config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wan'
	list network 'wan6'
	list network 'vpn'

After bringing up the VPN interface, I still see IPv6 routes for ::/0 from wan6, sourced from my ISP (metric 512), whereas the route from the VPN shows up at the bottom of the table with metric 1024.

(So far all my configuration have been done using LUCI, which worked quite well for me. Thank you for any thoughts on how to resolve this issue!)

1 Like

IPv6 may prefer GUA over ULA when accessing the internet.
Use a GUA prefix on the WG interface if you have an unused static one.

Or change the ULA to a pseudo-GUA:
https://openwrt.org/docs/guide-user/network/ipv6/ipv6_extras#using_ipv6_by_default

You can also try to specify metric manually:
https://openwrt.org/docs/guide-user/services/vpn/wireguard/extras#dynamic_connection

The default route with a lower metric should be preferred.

2 Likes

Thank you for your reply! I've tried a few options, unfortunately still without success:

I tried using a global unicast address (2604:...) for the VPN, following this gist. This again works on WireGuard on macOS but still gives me the default route via my ISP on OpenWrt.

I also tried forcing a lower metric by setting option metric '1' on the VPN interface. This shows up as expected under the Active IPv6 Routes, but I still see the traffic going through my ISP.

Any further ideas?

1 Like

Disable the ISP GUA prefix delegation and set up NAT6 on the router:

1 Like

Thank you, that got the IPv6 to go through the VPN now.

One issue, though: now when the VPN isn't active, I have no IPv6 connectivity altogether. I presume there isn't a way to do this by modifying the config of my VPN interface, rather than my LAN's (where I now have network.lan.ip6class="local") - so that this is conditional on the VPN interface being up?

(If this isn't achievable, then a way of completely blocking IPv6 when the VPN interface is up would also go a long way.)

You probably should disable source routing:
https://openwrt.org/docs/guide-user/network/ipv6/ipv6_extras#disabling_source_routing

Try to collect the relevant diagnostics to isolate the cause of the issue if it persists.

That didn't seem to work, unfortunately.

I'm not sure how the WireGuard on OpenWrt sets up the routing, but if it's like on the official website, nothing should leak through:


(sorry if I interpret these incorrectly)
ip -4 route add 0.0.0.0/0 dev demo table 51820
says create IPv4 table 51820 which says everything goes to interface "demo".
ip -4 rule add not fwmark 51820 table 51820
says packets not having a firewall mark of 51820 go to table 51820.
It should be similar for IPv6 with ip -6.
Not sure if it's related, I also tried to create an IPv6 table but it ends up not showing, and I saw somewhere saying that if it's not showing it's not active.

Thank you, @NAVras.

I found an explanation of this technique in WireGuard's documentation (they call it "Improved Rule-Based Routing"), which is what's implemented by wg-quick.

I think it'd be fantastic if WireGuard on OpenWrt would allow for such a feature. I'll give modifying wireguard.sh a try, but this is probably beyond my pay grade

That's just one of the corner cases for policy-based routing.
You can relatively simple configure it with UCI.
But WireGuard on OpenWrt is closely integrated with netifd.
So, there's no point to resort to traffic marking.
There are easier ways to achieve the same goal.

I still haven't found a way to accomplish what I hoped was easy: to have all traffic (IPv4/IPv6) go through the WireGuard interface if (and only if) it is up, while retaining normal connectivity while it is not.

So far the closest I've gotten was to set network.lan.ip6class="local", but that brakes IPv6 when the VPN interface isn't up.

For disabling source routing - just to clarify: is this setting indeed to be made on the wan6 interface?

Yep, otherwise it may allow only passthrough from IPv6 PD, but not ULA.

1 Like

Setting the tables for LAN/WAN/WAN6, like you suggested, almost works.

When the VPN is up, all traffic seems to get routed through it. (Even though the IPv6 IP is now back to being a ULA.) :sparkles:

However when the VPN interface is down, I am having connectivity issues esp. on IPv4 (websites just aren't loading). Anything else I need to do, besides the configuration changes you suggested?

I am also trying to understand: the default table seems to be main. What's the idea of setting those to 1 and 2? Do those get lower priority? Or is it to disable any rules that are associated with main?

There's another method based on PBR with IP rules that works for me quite well:
https://openwrt.org/docs/guide-user/network/ip_rules#examples

The major benefit is that most of the essential rules are created automatically by netifd.
This way basically overrides routing metric.
When the VPN is down, it allows failover to WAN with custom rules.
Connecting the VPN populates the main routing table and overrides the above rules.

1 Like

Thank you, @vgaetera for your kind help in figuring this out. Your suggestions helped me get this to work.

In summary (for anyone who comes across this later): in order to have all IPv6 traffic go through my WireGuard VPN, and not my ISP, I had to do the following steps:

uci set network.lan.ip4table="1"
uci set network.lan.ip6table="1"
uci set network.wan.ip4table="2"
uci set network.wan6.ip6table="2"
uci -q delete network.lan_wan
uci set network.lan_wan="rule"
uci set network.lan_wan.lookup="2"
uci set network.lan_wan.priority="40000"
uci -q delete network.lan_wan6
uci set network.lan_wan6="rule6"
uci set network.lan_wan6.lookup="2"
uci set network.lan_wan6.priority="40000"
uci commit network
/etc/init.d/network restart

With these steps, I now have IPv6 connectivity over an ULA. (I also tried with a single, /128, GLA address, but didn't make a difference for me. Unfortunately my hosting provider doesn't provide me with any IPv6 networks to use, so I can't say if these would have worked out of the box.)

1 Like

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