Skip to content

fix: make WireGuard killswitch bridge-aware#15

Open
jmpareja wants to merge 1 commit into
ProtonVPN:stablefrom
jmpareja:fix/wireguard-killswitch-bridge-aware
Open

fix: make WireGuard killswitch bridge-aware#15
jmpareja wants to merge 1 commit into
ProtonVPN:stablefrom
jmpareja:fix/wireguard-killswitch-bridge-aware

Conversation

@jmpareja
Copy link
Copy Markdown

@jmpareja jmpareja commented May 4, 2026

Summary

On hosts where the primary uplink is a NetworkManager-managed Linux bridge (e.g. br0 with a NIC enslaved), connecting to a WireGuard server with the killswitch enabled crashes with:

AttributeError: 'NoneType' object has no attribute 'get_num_routes'

NMClient.get_physical_devices() enumerates all ETHERNET/WIFI devices in ACTIVATED state but does not skip slaves of a bridge/bond/team. The slave NIC is ACTIVATED, yet its connection profile carries no IPv4 setting — IP config lives on the controller. The killswitch then dereferences a None NMSettingIP4Config.

This PR makes the killswitch bridge-aware:

  • get_physical_devices() now also accepts NM.DeviceType.BRIDGE and excludes any device whose active connection has a controller. Detection uses NMSettingConnection.get_controller() with a fallback to the deprecated get_master() for older libnm builds.
  • _add_ipv4_route and _remove_ipv4_routes raise GatewayNotFoundError with a descriptive message instead of AttributeError when get_setting_ip4_config() returns None — defense in depth in case a device without IPv4 config still slips through.

No existing behavior changes for hosts whose default route is on a plain ethernet/wifi NIC: such devices are not enslaved and continue to be picked up exactly as before.

Test plan

  • Unit tests in tests/.../wireguard/ covering: bridge controller picked up, enslaved NIC skipped, plain ethernet still picked up, None IP4 setting raises GatewayNotFoundError.
  • Manual: connect / disconnect WireGuard with killswitch enabled on a host whose default route lives on br0 (bridge) with a NIC enslaved — connection succeeds and routes are added/removed against the bridge.
  • Manual: same flow on a plain ethernet host to confirm no regression.

`get_physical_devices()` enumerated only ETHERNET/WIFI devices and did
not exclude slaves of a bridge controller. On hosts where the primary
uplink is a NetworkManager-managed Linux bridge (e.g. `br0` with
`enp12s0` enslaved), the slave NIC is ACTIVATED but its connection
profile has no IPv4 setting — its IP config lives on the bridge. The
killswitch then called `config.get_num_routes()` on a `None` IPv4
setting and raised `AttributeError` on connect.

Changes:
- `get_physical_devices()` now also accepts `NM.DeviceType.BRIDGE` and
  excludes any device whose active connection has a controller (slave
  of a bond/bridge/team). Uses `get_controller()` with a fallback to
  the deprecated `get_master()` for older libnm.
- `_add_ipv4_route` / `_remove_ipv4_routes` raise `GatewayNotFoundError`
  with a clear message when `get_setting_ip4_config()` returns `None`,
  instead of crashing with `AttributeError`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant