Disabling IPv6 when an IPv4 only wireguard config is up
On June 01, 2023 by Sosthène Guédon
It's not easy to reliably prevent this. Here is how to do it with NetworManager.
A standard wireguard IPv4 only config looks like this (
xxx marks redacted data):
PrivateKey = xxx
Address = 10.0.0.2/32
DNS = 10.0.0.1
PublicKey = xxx
AllowedIPs = 0.0.0.0/0
Endpoint = 22.214.171.124
Whereas an interface supporting IPv6 will have an additional IPv6 address configured:
Address = 10.0.0.2/32,fc00:0000:0000:0000:0000:0000:0002/128
AllowedIPs = 0.0.0.0/0, ::0/0
In the first case, IPv6 traffic will not go through the VPN.
The best solution is to have a VPN server that supports IPv6, in which case a config similar to the second will work. However, this may not be a possibility. In that case, it is required to disable IPv6 when connecting to a VPN which does not support it.
The easiest way to solve the issue is to completely disable IPv6 on the machine by adding
ipv6.disable=1 to your kernel boot parameters, but it is not an ideal solution as it makes you lose IPv6 support even when the VPN is disabled.
A more flexible solution is to use the NetworkManager dispatcher.
This works by adding scripts to
/etc/NetworManager/dispatcher.d/, which are run each time NetworkManager performs some actions.
The following script will run every time the
down), to deactivate (or reactivate) IPv6 for all other running interfaces.
Save it to
/etc/NetworkManager/dispatcher.d/99-wg-ipv6-leak-protection.sh and it will disable IPv6 when the VPN is up (don't forget to enable the dispatcher, with
systemctl enable --now NetworkManager-dispatcher).
However this would not fully solve the problem.
If you reconnect to your network, it will re-enable IPv6 for the connection, since the
sysctl configurations are ephemeral.
The solution for this is to instead check every time an interface is
up whether the VPN is running. If it is, disable IPv6 for the interface again:
elif [ || [ # It is normal for wireguard interfaces to be in the "unknown" state