unix: test anyToSockaddr without creating actual socket

Test_anyToSockaddr on linux needs to create a socket with the given
domain, type and protocol in order to test anyToSockaddr. Depending on
kernel version, permission and other factors, a given combination might
not be available on the system that runs the test, as is e.g. the case
for AF_CAN/SOCK_DGRAM/CAN_J1939 on several builders after CL 272767.

The only reason to create the socket is to be able to get the socket
protocol in anyToSockaddr using GetsockoptInt(..., SO_PROTOCOL). Move
this implementation into a wrapper func which can be overriden in tests
to with a func unconditionally returning the protocol under test. This
makes the test less dependent on the system it runs on and should fix
the builders broken by CL 272767.

While at it also removed the unused SocketSpec type in
syscall_internal_bsd_test.go and remove an unnecessary error var
declaration.

Change-Id: Ie8754cf795fa96980b29ae43777f698cd86ae863
Reviewed-on: https://go-review.googlesource.com/c/sys/+/274046
Trust: Tobias Klauser <tobias.klauser@gmail.com>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matt Layher <mdlayher@gmail.com>
diff --git a/unix/syscall_internal_bsd_test.go b/unix/syscall_internal_bsd_test.go
index 5e3e052..6a796c6 100644
--- a/unix/syscall_internal_bsd_test.go
+++ b/unix/syscall_internal_bsd_test.go
@@ -13,20 +13,12 @@
 	"unsafe"
 )
 
-// as per socket(2)
-type SocketSpec struct {
-	domain   int
-	typ      int
-	protocol int
-}
-
 func Test_anyToSockaddr(t *testing.T) {
 	tests := []struct {
 		name string
 		rsa  *RawSockaddrAny
 		sa   Sockaddr
 		err  error
-		skt  SocketSpec
 	}{
 		{
 			name: "AF_UNIX zero length",
@@ -80,19 +72,6 @@
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			fd := int(0)
-			var err error
-			if tt.skt.domain != 0 {
-				fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol)
-				// Some sockaddr types need specific kernel modules running: if these
-				// are not present we'll get EPROTONOSUPPORT back when trying to create
-				// the socket.  Skip the test in this situation.
-				if err == EPROTONOSUPPORT {
-					t.Skip("socket family/protocol not supported by kernel")
-				} else if err != nil {
-					t.Fatalf("socket(%v): %v", tt.skt, err)
-				}
-				defer Close(fd)
-			}
 			sa, err := anyToSockaddr(fd, tt.rsa)
 			if err != tt.err {
 				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
diff --git a/unix/syscall_internal_darwin_test.go b/unix/syscall_internal_darwin_test.go
index 529e977..e443144 100644
--- a/unix/syscall_internal_darwin_test.go
+++ b/unix/syscall_internal_darwin_test.go
@@ -55,7 +55,6 @@
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			fd := int(0)
-			var err error
 			sa, err := anyToSockaddr(fd, tt.rsa)
 			if err != tt.err {
 				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
diff --git a/unix/syscall_internal_linux_test.go b/unix/syscall_internal_linux_test.go
index 5a4f4f6..4c64f54 100644
--- a/unix/syscall_internal_linux_test.go
+++ b/unix/syscall_internal_linux_test.go
@@ -13,20 +13,17 @@
 	"unsafe"
 )
 
-// as per socket(2)
-type SocketSpec struct {
-	domain   int
-	typ      int
-	protocol int
+func makeProto(proto int) *int {
+	return &proto
 }
 
 func Test_anyToSockaddr(t *testing.T) {
 	tests := []struct {
-		name string
-		rsa  *RawSockaddrAny
-		sa   Sockaddr
-		err  error
-		skt  SocketSpec
+		name  string
+		rsa   *RawSockaddrAny
+		sa    Sockaddr
+		err   error
+		proto *int
 	}{
 		{
 			name: "AF_TIPC bad addrtype",
@@ -109,7 +106,7 @@
 				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
 				ConnId: 0x1234abcd,
 			},
-			skt: SocketSpec{domain: AF_INET, typ: SOCK_DGRAM, protocol: IPPROTO_L2TP},
+			proto: makeProto(IPPROTO_L2TP),
 		},
 		{
 			name: "AF_INET6 IPPROTO_L2TP",
@@ -135,7 +132,7 @@
 				ZoneId: 90210,
 				ConnId: 0x1234abcd,
 			},
-			skt: SocketSpec{domain: AF_INET6, typ: SOCK_DGRAM, protocol: IPPROTO_L2TP},
+			proto: makeProto(IPPROTO_L2TP),
 		},
 		{
 			name: "AF_UNIX unnamed/abstract",
@@ -185,7 +182,7 @@
 				RxID:    0xAAAAAAAA,
 				TxID:    0xBBBBBBBB,
 			},
-			skt: SocketSpec{domain: AF_CAN, typ: SOCK_RAW, protocol: CAN_RAW},
+			proto: makeProto(CAN_RAW),
 		},
 		{
 			name: "AF_CAN CAN_J1939",
@@ -205,7 +202,7 @@
 				PGN:     0xBBBBBBBB,
 				Addr:    0xCC,
 			},
-			skt: SocketSpec{domain: AF_CAN, typ: SOCK_DGRAM, protocol: CAN_J1939},
+			proto: makeProto(CAN_J1939),
 		},
 		{
 			name: "AF_MAX EAFNOSUPPORT",
@@ -219,27 +216,15 @@
 		// TODO: expand to support other families.
 	}
 
+	realSocketProtocol := socketProtocol
+
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			fd := int(0)
-			var err error
-			if tt.skt.domain != 0 {
-				fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol)
-				// Some sockaddr types need specific kernel modules running: if these
-				// are not present we'll get EPROTONOSUPPORT/EAFNOSUPPORT back when
-				// trying to create the socket.  Skip the test in this situation.
-				if err == EPROTONOSUPPORT {
-					t.Skip("socket family/protocol not supported by kernel")
-				} else if err == EAFNOSUPPORT {
-					t.Skip("socket address family not supported by kernel")
-				} else if err == EACCES {
-					// Some platforms might require elevated privileges to perform
-					// actions on sockets. Skip the test in this situation.
-					t.Skip("socket operation not permitted")
-				} else if err != nil {
-					t.Fatalf("socket(%v): %v", tt.skt, err)
-				}
-				defer Close(fd)
+			if tt.proto != nil {
+				socketProtocol = func(fd int) (int, error) { return *tt.proto, nil }
+			} else {
+				socketProtocol = realSocketProtocol
 			}
 			sa, err := anyToSockaddr(fd, tt.rsa)
 			if err != tt.err {
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index 1fdfe48..28be130 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -982,6 +982,10 @@
 	return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil
 }
 
+var socketProtocol = func(fd int) (int, error) {
+	return GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+}
+
 func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
 	switch rsa.Addr.Family {
 	case AF_NETLINK:
@@ -1032,7 +1036,7 @@
 		return sa, nil
 
 	case AF_INET:
-		proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+		proto, err := socketProtocol(fd)
 		if err != nil {
 			return nil, err
 		}
@@ -1058,7 +1062,7 @@
 		}
 
 	case AF_INET6:
-		proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+		proto, err := socketProtocol(fd)
 		if err != nil {
 			return nil, err
 		}
@@ -1093,7 +1097,7 @@
 		}
 		return sa, nil
 	case AF_BLUETOOTH:
-		proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+		proto, err := socketProtocol(fd)
 		if err != nil {
 			return nil, err
 		}
@@ -1180,7 +1184,7 @@
 		return sa, nil
 
 	case AF_CAN:
-		proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+		proto, err := socketProtocol(fd)
 		if err != nil {
 			return nil, err
 		}