nettest: add SupportsRawSocket Also updates API docs. Change-Id: I0c744a286bf637270156101bfdee1e87e306fa5e Reviewed-on: https://go-review.googlesource.com/c/net/+/169539 Run-TryBot: Mikio Hara <mikioh.public.networking@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/nettest/nettest.go b/nettest/nettest.go index c75facf..717bbb0 100644 --- a/nettest/nettest.go +++ b/nettest/nettest.go
@@ -20,10 +20,11 @@ ) var ( - stackOnce sync.Once - ipv4Enabled bool - ipv6Enabled bool - aixTechLvl int + stackOnce sync.Once + ipv4Enabled bool + ipv6Enabled bool + rawSocketSess bool + aixTechLvl int aLongTimeAgo = time.Unix(233431200, 0) neverTimeout = time.Time{} @@ -41,12 +42,12 @@ ln.Close() ipv6Enabled = true } + rawSocketSess = supportsRawSocket() if runtime.GOOS == "aix" { out, err := exec.Command("oslevel", "-s").Output() - if err != nil { - return + if err == nil { + aixTechLvl, _ = strconv.Atoi(string(out[5:7])) } - aixTechLvl, _ = strconv.Atoi(string(out[5:7])) } } @@ -69,8 +70,17 @@ return ipv6Enabled } +// SupportsRawSocket reports whether the current session is available +// to use raw sockets. +func SupportsRawSocket() bool { + stackOnce.Do(probeStack) + return rawSocketSess +} + // TestableNetwork reports whether network is testable on the current // platform configuration. +// +// See func Dial of the standard library for the supported networks. func TestableNetwork(network string) bool { ss := strings.Split(network, ":") switch ss[0] { @@ -248,7 +258,6 @@ // LoopbackInterface returns an available logical network interface // for loopback test. -// It returns nil if no suitable interface is found. func LoopbackInterface() (*net.Interface, error) { ift, err := net.Interfaces() if err != nil { @@ -264,8 +273,6 @@ // RoutedInterface returns a network interface that can route IP // traffic and satisfies flags. -// It returns nil when an appropriate network interface is not -// found. // // The provided network must be "ip", "ip4" or "ip6". func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
diff --git a/nettest/nettest_stub.go b/nettest/nettest_stub.go new file mode 100644 index 0000000..2bb8c05 --- /dev/null +++ b/nettest/nettest_stub.go
@@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows + +package nettest + +func supportsRawSocket() bool { + return false +}
diff --git a/nettest/nettest_unix.go b/nettest/nettest_unix.go new file mode 100644 index 0000000..afff744 --- /dev/null +++ b/nettest/nettest_unix.go
@@ -0,0 +1,21 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package nettest + +import "syscall" + +func supportsRawSocket() bool { + for _, af := range []int{syscall.AF_INET, syscall.AF_INET6} { + s, err := syscall.Socket(af, syscall.SOCK_RAW, 0) + if err != nil { + continue + } + syscall.Close(s) + return true + } + return false +}
diff --git a/nettest/nettest_windows.go b/nettest/nettest_windows.go new file mode 100644 index 0000000..4939964 --- /dev/null +++ b/nettest/nettest_windows.go
@@ -0,0 +1,26 @@ +// Copyright 2019 The Go 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 nettest + +import "syscall" + +func supportsRawSocket() bool { + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx: + // Note: To use a socket of type SOCK_RAW requires administrative privileges. + // Users running Winsock applications that use raw sockets must be a member of + // the Administrators group on the local computer, otherwise raw socket calls + // will fail with an error code of WSAEACCES. On Windows Vista and later, access + // for raw sockets is enforced at socket creation. In earlier versions of Windows, + // access for raw sockets is enforced during other socket operations. + for _, af := range []int{syscall.AF_INET, syscall.AF_INET6} { + s, err := syscall.Socket(af, syscall.SOCK_RAW, 0) + if err != nil { + continue + } + syscall.Closesocket(s) + return true + } + return false +}