health: warn about reverse path filtering and exit nodes

When reverse path filtering is in strict mode on Linux, using an exit
node blocks all network connectivity. This change adds a warning about
this to `tailscale status` and the logs.

Example in `tailscale status`:

```
- not connected to home DERP region 22
- The following issues on your machine will likely make usage of exit nodes impossible: [interface "eth0" has strict reverse-path filtering enabled], please set rp_filter=2 instead of rp_filter=1; see https://github.com/tailscale/tailscale/issues/3310
```

Example in the logs:
```
2024/02/21 21:17:07 health("overall"): error: multiple errors:
	not in map poll
	The following issues on your machine will likely make usage of exit nodes impossible: [interface "eth0" has strict reverse-path filtering enabled], please set rp_filter=2 instead of rp_filter=1; see https://github.com/tailscale/tailscale/issues/3310
```

Updates #3310

Signed-off-by: Anton Tolchanov <anton@tailscale.com>
This commit is contained in:
Anton Tolchanov
2024-01-03 00:23:58 +00:00
committed by Anton Tolchanov
parent 7ef1fb113d
commit 8cc5c51888
6 changed files with 69 additions and 19 deletions

View File

@ -153,7 +153,7 @@ func CheckIPForwarding(routes []netip.Prefix, state *interfaces.State) (warn, er
// This function returns an error if it is unable to determine whether reverse
// path filtering is enabled, or a warning describing configuration issues if
// reverse path fitering is non-functional or partly functional.
func CheckReversePathFiltering(routes []netip.Prefix, state *interfaces.State) (warn []string, err error) {
func CheckReversePathFiltering(state *interfaces.State) (warn []string, err error) {
if runtime.GOOS != "linux" {
return nil, nil
}
@ -166,12 +166,6 @@ func CheckReversePathFiltering(routes []netip.Prefix, state *interfaces.State) (
}
}
// Reverse path filtering as a syscall is only implemented on Linux for IPv4.
wantV4, _ := protocolsRequiredForForwarding(routes, state)
if !wantV4 {
return nil, nil
}
// The kernel uses the maximum value for rp_filter between the 'all'
// setting and each per-interface config, so we need to fetch both.
allSetting, err := reversePathFilterValueLinux("all")
@ -205,7 +199,7 @@ func CheckReversePathFiltering(routes []netip.Prefix, state *interfaces.State) (
iSetting = allSetting
}
if iSetting == filtStrict {
warn = append(warn, fmt.Sprintf("Interface %q has strict reverse-path filtering enabled", iface.Name))
warn = append(warn, fmt.Sprintf("interface %q has strict reverse-path filtering enabled", iface.Name))
}
}
return warn, nil