VPN routes don't work on Linux clients if IPv6 is disabled system-wide #1546

Closed
opened 2025-11-20 05:32:34 -05:00 by saavagebueno · 1 comment
Owner

Originally created by @heyzling on GitHub (Jan 8, 2025).

Hello!

I discovered that Netbird outbound routes don't work on Linux clients if IPv6 is disabled system-wide.

I have a peer configured with WSL2 in bridged mode where I have disabled IPv6. I'll refer to this as "The Problem Peer" from now on. 😊

  1. The client on the Problem Peer starts successfully.
  2. Mesh communication on the Problem Peer functions correctly. I can ping/curl/ssh to other peers and vice versa.
  3. Inbound network routes work. The Problem Peer serves as an entry point to the local network, and other peers can connect to it without any issues.
  4. Outbound network routes do not work. I have an exit peer elsewhere that serves the 0.0.0.0/0 network. Other peers work with this just fine. However, the Problem Peer goes straight to the Internet via the system's default route. I suspect that outbound routes don't function at all, not just for the exit node (see below).

Other symptoms on the Problem Peer:

  1. Table ip r show table netbird which should contain the default dev wt0 route, doesn't exist and throws an error.
  2. The client.log contains a unique error: ERRO client/internal/routemanager/client.go:370: Failed to recalculate routes for network [0.0.0.0/0]: add route: failed to add for key 0.0.0.0/0: add blackhole: netlink add unreachable route: operation not supported

Workaround:

  • Enable IPv6. It's that simple. 😊 I spent a lot of time figuring this out, so hopefully, it will be useful for someone else.

I found the culprit for this behavior: 9e6e34b42d/client/internal/routemanager/systemops/systemops_linux.go (L183)

The method addUnreachableRoute() is, as I understand it, a way to prevent IPv6 traffic from leaking by creating a "route to hell." However, for this to work, IPv6 must be enabled on the system. If IPv6 is not enabled, the method throws an exception and fails, preventing the next method, addRoute(), from being called, thus not creating the route.

It's ironic that to disable IPv6, you need IPv6 to be enabled. 😊 I suggest adding a check to this method to avoid creating a "blackhole" if IPv6 is disabled system-wide.

Originally created by @heyzling on GitHub (Jan 8, 2025). Hello! I discovered that Netbird outbound routes don't work on Linux clients if IPv6 is disabled system-wide. I have a peer configured with WSL2 in bridged mode where I have disabled IPv6. I'll refer to this as "The Problem Peer" from now on. 😊 1. The client on the Problem Peer starts successfully. 2. Mesh communication on the Problem Peer functions correctly. I can ping/curl/ssh to other peers and vice versa. 3. Inbound network routes work. The Problem Peer serves as an entry point to the local network, and other peers can connect to it without any issues. 4. Outbound network routes **do not work**. I have an exit peer elsewhere that serves the 0.0.0.0/0 network. Other peers work with this just fine. However, the Problem Peer goes straight to the Internet via the system's default route. I suspect that outbound routes don't function at all, not just for the exit node (see below). Other symptoms on the Problem Peer: 1. Table `ip r show table netbird` which should contain the `default dev wt0` route, doesn't exist and throws an error. 2. The `client.log` contains a unique error: `ERRO client/internal/routemanager/client.go:370: Failed to recalculate routes for network [0.0.0.0/0]: add route: failed to add for key 0.0.0.0/0: add blackhole: netlink add unreachable route: operation not supported` Workaround: - Enable IPv6. It's that simple. 😊 I spent a lot of time figuring this out, so hopefully, it will be useful for someone else. I found the culprit for this behavior: https://github.com/netbirdio/netbird/blob/9e6e34b42d5125f3a7287eb83f31e950d8de678a/client/internal/routemanager/systemops/systemops_linux.go#L183 The method `addUnreachableRoute()` is, as I understand it, a way to prevent IPv6 traffic from leaking by creating a "route to hell." However, for this to work, IPv6 must be enabled on the system. If IPv6 is not enabled, the method throws an exception and fails, preventing the next method, `addRoute()`, from being called, thus not creating the route. It's ironic that to disable IPv6, you need IPv6 to be enabled. 😊 I suggest adding a check to this method to avoid creating a "blackhole" if IPv6 is disabled system-wide.
saavagebueno added the clientroutes labels 2025-11-20 05:32:34 -05:00
Author
Owner

@lixmal commented on GitHub (Jan 8, 2025):

Thanks; this will be fixed in #3161. It turns out that the kernel throws a different error when the IPv6 module is not even loaded.

If you want, you can grab the binary from here https://github.com/netbirdio/netbird/actions/runs/12680021759

@lixmal commented on GitHub (Jan 8, 2025): Thanks; this will be fixed in #3161. It turns out that the kernel throws a different error when the IPv6 module is not even loaded. If you want, you can grab the binary from here https://github.com/netbirdio/netbird/actions/runs/12680021759
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SVI/netbird#1546