net/dns: prep for writing manager_linux tests; pull some stuff out

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-08-30 13:48:35 -07:00
parent 3f1317e3e5
commit 09a47ea3f1
3 changed files with 46 additions and 18 deletions

View File

@ -23,7 +23,7 @@ func NewOSConfigurator(logf logger.Logf, _ string) (OSConfigurator, error) {
switch resolvOwner(bs) { switch resolvOwner(bs) {
case "resolvconf": case "resolvconf":
return newResolvconfManager(logf) return newResolvconfManager(logf, getResolvConfVersion)
default: default:
return newDirectManager(), nil return newDirectManager(), nil
} }

View File

@ -8,7 +8,6 @@
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"time" "time"
@ -28,6 +27,31 @@ func (kv kv) String() string {
} }
func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurator, err error) { func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurator, err error) {
return newOSConfigurator(logf, interfaceName, newOSConfigEnv{
fs: directFS{},
ReadFile: os.ReadFile,
resolvOwner: resolvOwner,
resolvedIsActuallyResolver: resolvedIsActuallyResolver,
dbusPing: dbusPing,
nmIsUsingResolved: nmIsUsingResolved,
nmVersionBetween: nmVersionBetween,
getResolvConfVersion: getResolvConfVersion,
})
}
// newOSConfigEnv are the funcs newOSConfigurator needs, pulled out for testing.
type newOSConfigEnv struct {
fs wholeFileFS
ReadFile func(name string) ([]byte, error)
resolvOwner func(resolvConfContnets []byte) string
resolvedIsActuallyResolver func(wholeFileFS) error
dbusPing func(string, string) error
nmIsUsingResolved func() error
nmVersionBetween func(v1, v2 string) (safe bool, err error)
getResolvConfVersion func() ([]byte, error)
}
func newOSConfigurator(logf logger.Logf, interfaceName string, env newOSConfigEnv) (ret OSConfigurator, err error) {
var debug []kv var debug []kv
dbg := func(k, v string) { dbg := func(k, v string) {
debug = append(debug, kv{k, v}) debug = append(debug, kv{k, v})
@ -39,7 +63,7 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
logf("dns: %v", debug) logf("dns: %v", debug)
}() }()
bs, err := ioutil.ReadFile("/etc/resolv.conf") bs, err := env.ReadFile("/etc/resolv.conf")
if os.IsNotExist(err) { if os.IsNotExist(err) {
dbg("rc", "missing") dbg("rc", "missing")
return newDirectManager(), nil return newDirectManager(), nil
@ -48,7 +72,7 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
return nil, fmt.Errorf("reading /etc/resolv.conf: %w", err) return nil, fmt.Errorf("reading /etc/resolv.conf: %w", err)
} }
switch resolvOwner(bs) { switch env.resolvOwner(bs) {
case "systemd-resolved": case "systemd-resolved":
dbg("rc", "resolved") dbg("rc", "resolved")
// Some systems, for reasons known only to them, have a // Some systems, for reasons known only to them, have a
@ -56,20 +80,20 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
// header, but doesn't actually point to resolved. We mustn't // header, but doesn't actually point to resolved. We mustn't
// try to program resolved in that case. // try to program resolved in that case.
// https://github.com/tailscale/tailscale/issues/2136 // https://github.com/tailscale/tailscale/issues/2136
if err := resolvedIsActuallyResolver(); err != nil { if err := env.resolvedIsActuallyResolver(env.fs); err != nil {
dbg("resolved", "not-in-use") dbg("resolved", "not-in-use")
return newDirectManager(), nil return newDirectManagerOnFS(env.fs), nil
} }
if err := dbusPing("org.freedesktop.resolve1", "/org/freedesktop/resolve1"); err != nil { if err := env.dbusPing("org.freedesktop.resolve1", "/org/freedesktop/resolve1"); err != nil {
dbg("resolved", "no") dbg("resolved", "no")
return newDirectManager(), nil return newDirectManagerOnFS(env.fs), nil
} }
if err := dbusPing("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/DnsManager"); err != nil { if err := env.dbusPing("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/DnsManager"); err != nil {
dbg("nm", "no") dbg("nm", "no")
return newResolvedManager(logf, interfaceName) return newResolvedManager(logf, interfaceName)
} }
dbg("nm", "yes") dbg("nm", "yes")
if err := nmIsUsingResolved(); err != nil { if err := env.nmIsUsingResolved(); err != nil {
dbg("nm-resolved", "no") dbg("nm-resolved", "no")
return newResolvedManager(logf, interfaceName) return newResolvedManager(logf, interfaceName)
} }
@ -125,10 +149,10 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
dbg("rc", "resolvconf") dbg("rc", "resolvconf")
if _, err := exec.LookPath("resolvconf"); err != nil { if _, err := exec.LookPath("resolvconf"); err != nil {
dbg("resolvconf", "no") dbg("resolvconf", "no")
return newDirectManager(), nil return newDirectManagerOnFS(env.fs), nil
} }
dbg("resolvconf", "yes") dbg("resolvconf", "yes")
return newResolvconfManager(logf) return newResolvconfManager(logf, env.getResolvConfVersion)
case "NetworkManager": case "NetworkManager":
// You'd think we would use newNMManager somewhere in // You'd think we would use newNMManager somewhere in
// here. However, as explained in // here. However, as explained in
@ -143,10 +167,10 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
// anyway, so you still need a fallback path that uses // anyway, so you still need a fallback path that uses
// directManager. // directManager.
dbg("rc", "nm") dbg("rc", "nm")
return newDirectManager(), nil return newDirectManagerOnFS(env.fs), nil
default: default:
dbg("rc", "unknown") dbg("rc", "unknown")
return newDirectManager(), nil return newDirectManagerOnFS(env.fs), nil
} }
} }
@ -194,8 +218,8 @@ func nmIsUsingResolved() error {
return nil return nil
} }
func resolvedIsActuallyResolver() error { func resolvedIsActuallyResolver(fs wholeFileFS) error {
cfg, err := newDirectManager().readResolvConf() cfg, err := newDirectManagerOnFS(fs).readResolvConf()
if err != nil { if err != nil {
return err return err
} }

View File

@ -13,8 +13,12 @@
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
func newResolvconfManager(logf logger.Logf) (OSConfigurator, error) { func getResolvConfVersion() ([]byte, error) {
_, err := exec.Command("resolvconf", "--version").CombinedOutput() return exec.Command("resolvconf", "--version").CombinedOutput()
}
func newResolvconfManager(logf logger.Logf, getResolvConfVersion func() ([]byte, error)) (OSConfigurator, error) {
_, err := getResolvConfVersion()
if err != nil { if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 99 { if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 99 {
// Debian resolvconf doesn't understand --version, and // Debian resolvconf doesn't understand --version, and