tailscale / tailscale/tailscale

Mullvad exit node: disabling leaves RouteAll=true with no exit node, breaking WireGuard data plane

Open
#18,923 3 comments 1 reaction 0 assignees View on GitHub
Dominant language
Go
Stars
36.5k
Forks
3.2k
Avg merge
2d 3h
Merged PRs (30d)
123

Description

## Summary

Disabling Mullvad exit nodes on macOS leaves `RouteAll: true` with an empty `ExitNodeID`, creating a broken state where the WireGuard data plane stops working while the control plane (TSMP pings) continues to work — making the issue hard to diagnose.

## Environment

- Tailscale 1.94.2, macOS 15.7.3 (Mac App Store build)
- Peer: Tailscale 1.94.1, Ubuntu Linux

## Steps to reproduce

1. Enable Mullvad exit node via Tailscale on macOS
2. Disable Mullvad (toggle off in Tailscale UI)
3. Try to ping/SSH another Tailscale peer on the same LAN

## Observed behavior

- `tailscale debug prefs` shows `RouteAll: true` with `ExitNodeID: ""`
- `tailscale ping ` succeeds (TSMP works)
- `ping ` fails — 100% packet loss on the WireGuard data plane
- `tailscale status` shows the peer as `active; direct` with `rx 0` — air sends WireGuard packets but receives none back
- Peer's `tailscale status` shows healthy bidirectional counters (tx/rx both >0), and its `tcpdump` confirms reply packets are on the wire
- Pattern: occasionally 1-2 ICMP replies get through on fresh handshake, then all subsequent packets are lost

## Additional issues found

1. **`tailscale set --exit-node=` does not clear `RouteAll`** — had to use `tailscale up --exit-node="" --reset` to set `RouteAll: false`
2. **Stale WireGuard session on peer**: Even after fixing the local config and restarting Tailscale on the affected node, the peer retained a stale session. Data plane only recovered after restarting `tailscaled` on the *peer* — suggesting the peer's WireGuard state wasn't properly renegotiated.
3. **`tailscale ping` masking data plane failures**: Since TSMP pings work while the data plane is broken, `tailscale ping` gives a false sense of connectivity. This is misleading for diagnostics.

## Expected behavior

- Disabling Mullvad should clear `RouteAll` (or set a valid exit node)
- `tailscale set --exit-node=` should clear `RouteAll`
- A broken `RouteAll=true` + empty exit node state should not be possible
- `tailscale status` or `tailscale ping` should warn when the data plane is degraded

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.