diff --git a/net/dns/resolver/forwarder.go b/net/dns/resolver/forwarder.go index 2d626688a..6a630c033 100644 --- a/net/dns/resolver/forwarder.go +++ b/net/dns/resolver/forwarder.go @@ -25,6 +25,7 @@ import ( dns "golang.org/x/net/dns/dnsmessage" "inet.af/netaddr" "tailscale.com/hostinfo" + "tailscale.com/net/neterror" "tailscale.com/net/netns" "tailscale.com/net/tsdial" "tailscale.com/types/dnstype" @@ -482,7 +483,7 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe if err := ctx.Err(); err != nil { return nil, err } - if packetWasTruncated(err) { + if neterror.PacketWasTruncated(err) { err = nil } else { metricDNSFwdUDPErrorRead.Add(1) diff --git a/net/dns/resolver/neterr_darwin.go b/net/dns/resolver/neterr_darwin.go deleted file mode 100644 index a5a8748b6..000000000 --- a/net/dns/resolver/neterr_darwin.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package resolver - -import ( - "errors" - "syscall" -) - -// Avoid allocation when calling errors.Is below -// by converting syscall.Errno to error here. -var ( - networkDown error = syscall.ENETDOWN - networkUnreachable error = syscall.ENETUNREACH -) - -func networkIsDown(err error) bool { - return errors.Is(err, networkDown) -} - -func networkIsUnreachable(err error) bool { - return errors.Is(err, networkUnreachable) -} - -// packetWasTruncated returns true if err indicates truncation but the RecvFrom -// that generated err was otherwise successful. It always returns false on this -// platform. -func packetWasTruncated(err error) bool { return false } diff --git a/net/dns/resolver/neterr_other.go b/net/dns/resolver/neterr_other.go deleted file mode 100644 index e9d701711..000000000 --- a/net/dns/resolver/neterr_other.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !darwin && !windows -// +build !darwin,!windows - -package resolver - -func networkIsDown(err error) bool { return false } -func networkIsUnreachable(err error) bool { return false } - -// packetWasTruncated returns true if err indicates truncation but the RecvFrom -// that generated err was otherwise successful. It always returns false on this -// platform. -func packetWasTruncated(err error) bool { return false } diff --git a/net/dns/resolver/neterr_windows.go b/net/dns/resolver/neterr_windows.go deleted file mode 100644 index 7d0d2fb15..000000000 --- a/net/dns/resolver/neterr_windows.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package resolver - -import ( - "errors" - "net" - "os" - - "golang.org/x/sys/windows" -) - -func networkIsDown(err error) bool { - if oe, ok := err.(*net.OpError); ok && oe.Op == "write" { - if se, ok := oe.Err.(*os.SyscallError); ok { - if se.Syscall == "wsasendto" && se.Err == windows.WSAENETUNREACH { - return true - } - } - } - return false -} - -func networkIsUnreachable(err error) bool { - // TODO(bradfitz,josharian): something here? what is the - // difference between down and unreachable? Add comments. - return false -} - -// packetWasTruncated returns true if err indicates truncation but the RecvFrom -// that generated err was otherwise successful. On Windows, Go's UDP RecvFrom -// calls WSARecvFrom which returns the WSAEMSGSIZE error code when the received -// datagram is larger than the provided buffer. When that happens, both a valid -// size and an error are returned (as per the partial fix for golang/go#14074). -// If the WSAEMSGSIZE error is returned, then we ignore the error to get -// semantics similar to the POSIX operating systems. One caveat is that it -// appears that the source address is not returned when WSAEMSGSIZE occurs, but -// we do not currently look at the source address. -func packetWasTruncated(err error) bool { - return errors.Is(err, windows.WSAEMSGSIZE) -} diff --git a/net/neterror/neterror.go b/net/neterror/neterror.go index d122fa795..4224cc27a 100644 --- a/net/neterror/neterror.go +++ b/net/neterror/neterror.go @@ -40,3 +40,21 @@ func TreatAsLostUDP(err error) bool { } return false } + +var packetWasTruncated func(error) bool // non-nil on Windows at least + +// PacketWasTruncated reports whether err indicates truncation but the RecvFrom +// that generated err was otherwise successful. On Windows, Go's UDP RecvFrom +// calls WSARecvFrom which returns the WSAEMSGSIZE error code when the received +// datagram is larger than the provided buffer. When that happens, both a valid +// size and an error are returned (as per the partial fix for golang/go#14074). +// If the WSAEMSGSIZE error is returned, then we ignore the error to get +// semantics similar to the POSIX operating systems. One caveat is that it +// appears that the source address is not returned when WSAEMSGSIZE occurs, but +// we do not currently look at the source address. +func PacketWasTruncated(err error) bool { + if packetWasTruncated == nil { + return false + } + return packetWasTruncated(err) +} diff --git a/net/neterror/neterror_windows.go b/net/neterror/neterror_windows.go new file mode 100644 index 000000000..324e44fa2 --- /dev/null +++ b/net/neterror/neterror_windows.go @@ -0,0 +1,17 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package neterror + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +func init() { + packetWasTruncated = func(err error) bool { + return errors.Is(err, windows.WSAEMSGSIZE) + } +}