cmd/tailscale,ipn,net/netutil: remove rp_filter strict mode warnings (#18863)
PR #18860 adds firewall rules in the mangle table to save outbound packet marks to conntrack and restore them on reply packets before the routing decision. When reply packets have their marks restored, the kernel uses the correct routing table (based on the mark) and the packets pass the rp_filter check. This makes the risk check and reverse path filtering warnings unnecessary. Updates #3310 Fixes tailscale/corp#37846 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
This commit is contained in:
@@ -5,7 +5,6 @@ package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -146,64 +145,6 @@ func CheckIPForwarding(routes []netip.Prefix, state *netmon.State) (warn, err er
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CheckReversePathFiltering reports whether reverse path filtering is either
|
||||
// disabled or set to 'loose' mode for exit node functionality on any
|
||||
// interface.
|
||||
//
|
||||
// The routes should only be advertised routes, and should not contain the
|
||||
// node's Tailscale IPs.
|
||||
//
|
||||
// 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(state *netmon.State) (warn []string, err error) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if state == nil {
|
||||
return nil, errors.New("no link state")
|
||||
}
|
||||
|
||||
// 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")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading global rp_filter value: %w", err)
|
||||
}
|
||||
|
||||
const (
|
||||
filtOff = 0
|
||||
filtStrict = 1
|
||||
filtLoose = 2
|
||||
)
|
||||
|
||||
// Because the kernel use the max rp_filter value, each interface will use 'loose', so we
|
||||
// can abort early.
|
||||
if allSetting == filtLoose {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, iface := range state.Interface {
|
||||
if iface.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
|
||||
iSetting, err := reversePathFilterValueLinux(iface.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading interface rp_filter value for %q: %w", iface.Name, err)
|
||||
}
|
||||
// Perform the same max() that the kernel does
|
||||
if allSetting > iSetting {
|
||||
iSetting = allSetting
|
||||
}
|
||||
if iSetting == filtStrict {
|
||||
warn = append(warn, fmt.Sprintf("interface %q has strict reverse-path filtering enabled", iface.Name))
|
||||
}
|
||||
}
|
||||
return warn, nil
|
||||
}
|
||||
|
||||
// ipForwardSysctlKey returns the sysctl key for the given protocol and iface.
|
||||
// When the dotFormat parameter is true the output is formatted as `net.ipv4.ip_forward`,
|
||||
// else it is `net/ipv4/ip_forward`
|
||||
@@ -235,25 +176,6 @@ func ipForwardSysctlKey(format sysctlFormat, p protocol, iface string) string {
|
||||
return fmt.Sprintf(k, iface)
|
||||
}
|
||||
|
||||
// rpFilterSysctlKey returns the sysctl key for the given iface.
|
||||
//
|
||||
// Format controls whether the output is formatted as
|
||||
// `net.ipv4.conf.iface.rp_filter` or `net/ipv4/conf/iface/rp_filter`.
|
||||
func rpFilterSysctlKey(format sysctlFormat, iface string) string {
|
||||
// No iface means all interfaces
|
||||
if iface == "" {
|
||||
iface = "all"
|
||||
}
|
||||
|
||||
k := "net/ipv4/conf/%s/rp_filter"
|
||||
if format == dotFormat {
|
||||
// Swap the delimiters.
|
||||
iface = strings.ReplaceAll(iface, ".", "/")
|
||||
k = strings.ReplaceAll(k, "/", ".")
|
||||
}
|
||||
return fmt.Sprintf(k, iface)
|
||||
}
|
||||
|
||||
type sysctlFormat int
|
||||
|
||||
const (
|
||||
@@ -305,32 +227,6 @@ func ipForwardingEnabledLinux(p protocol, iface string) (bool, error) {
|
||||
return on, nil
|
||||
}
|
||||
|
||||
// reversePathFilterValueLinux reports the reverse path filter setting on Linux
|
||||
// for the given interface.
|
||||
//
|
||||
// The iface param determines which interface to check against; the empty
|
||||
// string means to check the global config.
|
||||
//
|
||||
// This function tries to look up the value directly from `/proc/sys`, and
|
||||
// falls back to using the `sysctl` command on failure.
|
||||
func reversePathFilterValueLinux(iface string) (int, error) {
|
||||
k := rpFilterSysctlKey(slashFormat, iface)
|
||||
bs, err := os.ReadFile(filepath.Join("/proc/sys", k))
|
||||
if err != nil {
|
||||
// Fall back to the sysctl command
|
||||
k := rpFilterSysctlKey(dotFormat, iface)
|
||||
bs, err = exec.Command("sysctl", "-n", k).Output()
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("couldn't check %s (%v)", k, err)
|
||||
}
|
||||
}
|
||||
v, err := strconv.Atoi(string(bytes.TrimSpace(bs)))
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("couldn't parse %s (%v)", k, err)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func ipForwardingEnabledSunOS(p protocol, iface string) (bool, error) {
|
||||
var proto string
|
||||
if p == ipv4 {
|
||||
|
||||
@@ -8,9 +8,6 @@ import (
|
||||
"net"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/util/eventbus"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
@@ -68,21 +65,3 @@ func TestIPForwardingEnabledLinux(t *testing.T) {
|
||||
t.Errorf("got true; want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckReversePathFiltering(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skipf("skipping on %s", runtime.GOOS)
|
||||
}
|
||||
bus := eventbus.New()
|
||||
defer bus.Close()
|
||||
|
||||
netMon, err := netmon.New(bus, t.Logf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer netMon.Close()
|
||||
|
||||
warn, err := CheckReversePathFiltering(netMon.InterfaceState())
|
||||
t.Logf("err: %v", err)
|
||||
t.Logf("warnings: %v", warn)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user