net/dnscache: use Go DNS resolver on Windows

Go 1.19 introduced Resolver.PreferGo which allows the Go resolver
to be used on Windows.

See https://github.com/golang/go/issues/33097.

Fixes https://github.com/tailscale/tailscale/issues/5161

Signed-off-by: Thomas Way <thomas@6f.io>
pull/7942/head
Thomas Way 2023-04-21 21:31:20 +01:00
parent 6f521c138d
commit 0860c7a355
No known key found for this signature in database
GPG Key ID: F6A871CA5DB9406C
2 changed files with 77 additions and 10 deletions

View File

@ -31,19 +31,19 @@ import (
var zaddr netip.Addr
var single = &Resolver{
Forward: &net.Resolver{PreferGo: preferGoResolver()},
Forward: &net.Resolver{PreferGo: preferGoResolver(runtime.GOOS)},
}
func preferGoResolver() bool {
func preferGoResolver(goos string) bool {
// There does not appear to be a local resolver running
// on iOS, and NetworkExtension is good at isolating DNS.
// So do not use the Go resolver on macOS/iOS.
if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
if goos == "darwin" || goos == "ios" {
return false
}
// The local resolver is not available on Android.
if runtime.GOOS == "android" {
if goos == "android" {
return false
}
@ -140,12 +140,7 @@ func (r *Resolver) dlogf(format string, args ...any) {
// cloudHostResolver returns a Resolver for the current cloud hosting environment.
// It currently only supports Google Cloud.
func (r *Resolver) cloudHostResolver() (v *net.Resolver, ok bool) {
switch runtime.GOOS {
case "android", "ios", "darwin":
return nil, false
case "windows":
// TODO(bradfitz): remove this restriction once we're using Go 1.19
// which supports net.Resolver.PreferGo on Windows.
if !preferGoResolver(runtime.GOOS) {
return nil, false
}
ip := cloudenv.Get().ResolverIP()

View File

@ -37,6 +37,78 @@ func TestDialer(t *testing.T) {
c.Close()
}
func TestPreferGoResolver(t *testing.T) {
// List of all known GOOS values as of Go 1.20.
//
// https://github.com/golang/go/blob/go1.20.3/src/go/build/syslist.go#L14-L33
testCases := []struct {
goos string
preferred bool
}{{
goos: "aix",
preferred: true,
}, {
goos: "android",
preferred: false,
}, {
goos: "darwin",
preferred: false,
}, {
goos: "dragonfly",
preferred: true,
}, {
goos: "freebsd",
preferred: true,
}, {
goos: "hurd",
preferred: true,
}, {
goos: "illumos",
preferred: true,
}, {
goos: "ios",
preferred: false,
}, {
goos: "js",
preferred: true,
}, {
goos: "linux",
preferred: true,
}, {
goos: "nacl",
preferred: true,
}, {
goos: "netbsd",
preferred: true,
}, {
goos: "openbsd",
preferred: true,
}, {
goos: "plan9",
preferred: true,
}, {
goos: "solaris",
preferred: true,
}, {
goos: "wasip1",
preferred: true,
}, {
goos: "windows",
preferred: true,
}, {
goos: "zos",
preferred: true,
}}
for _, tc := range testCases {
t.Run(tc.goos, func(t *testing.T) {
preferred := preferGoResolver(tc.goos)
if preferred != tc.preferred {
t.Fatalf("%s: got %t, want %t", tc.goos, preferred, tc.preferred)
}
})
}
}
func TestDialCall_DNSWasTrustworthy(t *testing.T) {
type step struct {
ip netip.Addr // IP we pretended to dial