mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-18 20:51:45 +00:00
net/netutil: only check Linux sysctls w/ procfs, assume absent means false
Fixes #7217 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
05adf22383
commit
2477fc4952
@ -9,7 +9,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -194,27 +193,28 @@ const (
|
|||||||
// given interface.
|
// given interface.
|
||||||
// The iface param determines which interface to check against, "" means to check
|
// The iface param determines which interface to check against, "" means to check
|
||||||
// global config.
|
// global config.
|
||||||
// It tries to lookup the value directly from `/proc/sys`, and falls back to
|
// This is Linux-specific: it only reads from /proc/sys and doesn't shell out to
|
||||||
// using `sysctl` on failure.
|
// sysctl (which on Linux just reads from /proc/sys anyway).
|
||||||
func ipForwardingEnabledLinux(p protocol, iface string) (bool, error) {
|
func ipForwardingEnabledLinux(p protocol, iface string) (bool, error) {
|
||||||
k := ipForwardSysctlKey(slashFormat, p, iface)
|
k := ipForwardSysctlKey(slashFormat, p, iface)
|
||||||
bs, err := os.ReadFile(filepath.Join("/proc/sys", k))
|
bs, err := os.ReadFile(filepath.Join("/proc/sys", k))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Fallback to using sysctl.
|
if os.IsNotExist(err) {
|
||||||
// Sysctl accepts `/` as separator.
|
// If IPv6 is disabled, sysctl keys like "net.ipv6.conf.all.forwarding" just don't
|
||||||
bs, err = exec.Command("sysctl", "-n", k).Output()
|
// exist on disk. But first diagnose whether procfs is even mounted before assuming
|
||||||
if err != nil {
|
// absence means false.
|
||||||
// But in case it doesn't.
|
if fi, err := os.Stat("/proc/sys"); err != nil {
|
||||||
k := ipForwardSysctlKey(dotFormat, p, iface)
|
return false, fmt.Errorf("failed to check sysctl %v; no procfs? %w", k, err)
|
||||||
bs, err = exec.Command("sysctl", "-n", k).Output()
|
} else if !fi.IsDir() {
|
||||||
if err != nil {
|
return false, fmt.Errorf("failed to check sysctl %v; /proc/sys isn't a directory, is %v", k, fi.Mode())
|
||||||
return false, fmt.Errorf("couldn't check %s (%v)", k, err)
|
|
||||||
}
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
on, err := strconv.ParseBool(string(bytes.TrimSpace(bs)))
|
on, err := strconv.ParseBool(string(bytes.TrimSpace(bs)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("couldn't parse %s (%v)", k, err)
|
return false, fmt.Errorf("couldn't parse %s: %w", k, err)
|
||||||
}
|
}
|
||||||
return on, nil
|
return on, nil
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package netutil
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,3 +52,16 @@ func TestOneConnListener(t *testing.T) {
|
|||||||
t.Errorf("nil Addr")
|
t.Errorf("nil Addr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIPForwardingEnabledLinux(t *testing.T) {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
t.Skipf("skipping on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
got, err := ipForwardingEnabledLinux(ipv4, "some-not-found-interface")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got {
|
||||||
|
t.Errorf("got true; want false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user