Files
sys/unix/syscall_internal_linux_test.go
Tobias Klauser 760e229fe7 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>
2020-11-30 17:19:29 +00:00

689 lines
14 KiB
Go

// 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 linux
package unix
import (
"reflect"
"strings"
"testing"
"unsafe"
)
func makeProto(proto int) *int {
return &proto
}
func Test_anyToSockaddr(t *testing.T) {
tests := []struct {
name string
rsa *RawSockaddrAny
sa Sockaddr
err error
proto *int
}{
{
name: "AF_TIPC bad addrtype",
rsa: &RawSockaddrAny{
Addr: RawSockaddr{
Family: AF_TIPC,
},
},
err: EINVAL,
},
{
name: "AF_TIPC NameSeq",
rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SERVICE_RANGE,
Scope: 1,
Addr: (&TIPCServiceRange{
Type: 1,
Lower: 2,
Upper: 3,
}).tipcAddr(),
}),
sa: &SockaddrTIPC{
Scope: 1,
Addr: &TIPCServiceRange{
Type: 1,
Lower: 2,
Upper: 3,
},
},
},
{
name: "AF_TIPC Name",
rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SERVICE_ADDR,
Scope: 2,
Addr: (&TIPCServiceName{
Type: 1,
Instance: 2,
Domain: 3,
}).tipcAddr(),
}),
sa: &SockaddrTIPC{
Scope: 2,
Addr: &TIPCServiceName{
Type: 1,
Instance: 2,
Domain: 3,
},
},
},
{
name: "AF_TIPC ID",
rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SOCKET_ADDR,
Scope: 3,
Addr: (&TIPCSocketAddr{
Ref: 1,
Node: 2,
}).tipcAddr(),
}),
sa: &SockaddrTIPC{
Scope: 3,
Addr: &TIPCSocketAddr{
Ref: 1,
Node: 2,
},
},
},
{
name: "AF_INET IPPROTO_L2TP",
rsa: sockaddrL2TPIPToAny(RawSockaddrL2TPIP{
Family: AF_INET,
Addr: [4]byte{0xef, 0x10, 0x5b, 0xa2},
Conn_id: 0x1234abcd,
}),
sa: &SockaddrL2TPIP{
Addr: [4]byte{0xef, 0x10, 0x5b, 0xa2},
ConnId: 0x1234abcd,
},
proto: makeProto(IPPROTO_L2TP),
},
{
name: "AF_INET6 IPPROTO_L2TP",
rsa: sockaddrL2TPIP6ToAny(RawSockaddrL2TPIP6{
Family: AF_INET6,
Flowinfo: 42,
Addr: [16]byte{
0x20, 0x01, 0x0d, 0xb8,
0x85, 0xa3, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x2e,
0x03, 0x70, 0x73, 0x34,
},
Scope_id: 90210,
Conn_id: 0x1234abcd,
}),
sa: &SockaddrL2TPIP6{
Addr: [16]byte{
0x20, 0x01, 0x0d, 0xb8,
0x85, 0xa3, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x2e,
0x03, 0x70, 0x73, 0x34,
},
ZoneId: 90210,
ConnId: 0x1234abcd,
},
proto: makeProto(IPPROTO_L2TP),
},
{
name: "AF_UNIX unnamed/abstract",
rsa: sockaddrUnixToAny(RawSockaddrUnix{
Family: AF_UNIX,
}),
sa: &SockaddrUnix{
Name: "@",
},
},
{
name: "AF_UNIX named",
rsa: sockaddrUnixToAny(RawSockaddrUnix{
Family: AF_UNIX,
Path: [108]int8{'g', 'o', 'p', 'h', 'e', 'r'},
}),
sa: &SockaddrUnix{
Name: "gopher",
},
},
{
name: "AF_IUCV",
rsa: sockaddrIUCVToAny(RawSockaddrIUCV{
Family: AF_IUCV,
User_id: [8]int8{'*', 'M', 'S', 'G', ' ', ' ', ' ', ' '},
Name: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
}),
sa: &SockaddrIUCV{
UserID: "*MSG ",
Name: " ",
},
},
{
name: "AF_CAN CAN_RAW",
rsa: sockaddrCANToAny(RawSockaddrCAN{
Family: AF_CAN,
Ifindex: 12345678,
Addr: [16]byte{
0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
},
}),
sa: &SockaddrCAN{
Ifindex: 12345678,
RxID: 0xAAAAAAAA,
TxID: 0xBBBBBBBB,
},
proto: makeProto(CAN_RAW),
},
{
name: "AF_CAN CAN_J1939",
rsa: sockaddrCANToAny(RawSockaddrCAN{
Family: AF_CAN,
Ifindex: 12345678,
Addr: [16]byte{
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB,
0xCC, 0x00, 0x00, 0x00,
},
}),
sa: &SockaddrCANJ1939{
Ifindex: 12345678,
Name: 0xAAAAAAAAAAAAAAAA,
PGN: 0xBBBBBBBB,
Addr: 0xCC,
},
proto: makeProto(CAN_J1939),
},
{
name: "AF_MAX EAFNOSUPPORT",
rsa: &RawSockaddrAny{
Addr: RawSockaddr{
Family: AF_MAX,
},
},
err: EAFNOSUPPORT,
},
// TODO: expand to support other families.
}
realSocketProtocol := socketProtocol
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fd := int(0)
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 {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
if !reflect.DeepEqual(sa, tt.sa) {
t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
}
})
}
}
func TestSockaddrTIPC_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrTIPC
raw *RawSockaddrTIPC
err error
}{
{
name: "no fields set",
sa: &SockaddrTIPC{},
err: EINVAL,
},
{
name: "ID",
sa: &SockaddrTIPC{
Scope: 1,
Addr: &TIPCSocketAddr{
Ref: 1,
Node: 2,
},
},
raw: &RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SOCKET_ADDR,
Scope: 1,
Addr: (&TIPCSocketAddr{
Ref: 1,
Node: 2,
}).tipcAddr(),
},
},
{
name: "NameSeq",
sa: &SockaddrTIPC{
Scope: 2,
Addr: &TIPCServiceRange{
Type: 1,
Lower: 2,
Upper: 3,
},
},
raw: &RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SERVICE_RANGE,
Scope: 2,
Addr: (&TIPCServiceRange{
Type: 1,
Lower: 2,
Upper: 3,
}).tipcAddr(),
},
},
{
name: "Name",
sa: &SockaddrTIPC{
Scope: 3,
Addr: &TIPCServiceName{
Type: 1,
Instance: 2,
Domain: 3,
},
},
raw: &RawSockaddrTIPC{
Family: AF_TIPC,
Addrtype: TIPC_SERVICE_ADDR,
Scope: 3,
Addr: (&TIPCServiceName{
Type: 1,
Instance: 2,
Domain: 3,
}).tipcAddr(),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
// Must be 0 on error or a fixed size otherwise.
if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) {
t.Fatalf("unexpected Socklen: %d", l)
}
if out == nil {
// No pointer to cast, return early.
return
}
raw := (*RawSockaddrTIPC)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw)
}
})
}
}
func TestSockaddrL2TPIP_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrL2TPIP
raw *RawSockaddrL2TPIP
err error
}{
{
name: "L2TPIP",
sa: &SockaddrL2TPIP{
Addr: [4]byte{0xef, 0x10, 0x5b, 0xa2},
ConnId: 0x1234abcd,
},
raw: &RawSockaddrL2TPIP{
Family: AF_INET,
Addr: [4]byte{0xef, 0x10, 0x5b, 0xa2},
Conn_id: 0x1234abcd,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
// Must be 0 on error or a fixed size otherwise.
if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP) {
t.Fatalf("unexpected Socklen: %d", l)
}
if out != nil {
raw := (*RawSockaddrL2TPIP)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrL2TPIP:\n got: %#v\nwant: %#v", raw, tt.raw)
}
}
})
}
}
func TestSockaddrL2TPIP6_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrL2TPIP6
raw *RawSockaddrL2TPIP6
err error
}{
{
name: "L2TPIP6",
sa: &SockaddrL2TPIP6{
Addr: [16]byte{
0x20, 0x01, 0x0d, 0xb8,
0x85, 0xa3, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x2e,
0x03, 0x70, 0x73, 0x34,
},
ZoneId: 90210,
ConnId: 0x1234abcd,
},
raw: &RawSockaddrL2TPIP6{
Family: AF_INET6,
Addr: [16]byte{
0x20, 0x01, 0x0d, 0xb8,
0x85, 0xa3, 0x00, 0x00,
0x00, 0x00, 0x8a, 0x2e,
0x03, 0x70, 0x73, 0x34,
},
Scope_id: 90210,
Conn_id: 0x1234abcd,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
// Must be 0 on error or a fixed size otherwise.
if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP6) {
t.Fatalf("unexpected Socklen: %d", l)
}
if out != nil {
raw := (*RawSockaddrL2TPIP6)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrL2TPIP6:\n got: %#v\nwant: %#v", raw, tt.raw)
}
}
})
}
}
func TestSockaddrUnix_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrUnix
raw *RawSockaddrUnix
slen _Socklen
err error
}{
{
name: "unnamed",
sa: &SockaddrUnix{},
raw: &RawSockaddrUnix{
Family: AF_UNIX,
},
slen: 2, // family (uint16)
},
{
name: "abstract",
sa: &SockaddrUnix{
Name: "@",
},
raw: &RawSockaddrUnix{
Family: AF_UNIX,
},
slen: 3, // family (uint16) + NULL
},
{
name: "named",
sa: &SockaddrUnix{
Name: "gopher",
},
raw: &RawSockaddrUnix{
Family: AF_UNIX,
Path: [108]int8{'g', 'o', 'p', 'h', 'e', 'r'},
},
slen: _Socklen(3 + len("gopher")), // family (uint16) + len(gopher)
},
{
name: "named too long",
sa: &SockaddrUnix{
Name: strings.Repeat("A", 108),
},
err: EINVAL,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
if l != tt.slen {
t.Fatalf("unexpected Socklen: %d, want %d", l, tt.slen)
}
if out == nil {
// No pointer to cast, return early.
return
}
raw := (*RawSockaddrUnix)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrUnix:\n got: %#v\nwant: %#v", raw, tt.raw)
}
})
}
}
func TestSockaddrIUCV_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrIUCV
raw *RawSockaddrIUCV
err error
}{
{
name: "no fields set",
sa: &SockaddrIUCV{},
raw: &RawSockaddrIUCV{
Family: AF_IUCV,
Nodeid: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
User_id: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
Name: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
},
},
{
name: "both fields set",
sa: &SockaddrIUCV{
UserID: "USERID",
Name: "NAME",
},
raw: &RawSockaddrIUCV{
Family: AF_IUCV,
Nodeid: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
User_id: [8]int8{'U', 'S', 'E', 'R', 'I', 'D', ' ', ' '},
Name: [8]int8{'N', 'A', 'M', 'E', ' ', ' ', ' ', ' '},
},
},
{
name: "too long userid",
sa: &SockaddrIUCV{
UserID: "123456789",
},
err: EINVAL,
},
{
name: "too long name",
sa: &SockaddrIUCV{
Name: "123456789",
},
err: EINVAL,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
// Must be 0 on error or a fixed size otherwise.
if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrIUCV) {
t.Fatalf("unexpected Socklen: %d", l)
}
if out == nil {
// No pointer to cast, return early.
return
}
raw := (*RawSockaddrIUCV)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrIUCV:\n got: %#v\nwant: %#v", raw, tt.raw)
}
})
}
}
func TestSockaddrCAN_sockaddr(t *testing.T) {
tests := []struct {
name string
sa *SockaddrCAN
raw *RawSockaddrCAN
err error
}{
{
name: "with ids",
sa: &SockaddrCAN{
Ifindex: 12345678,
RxID: 0xAAAAAAAA,
TxID: 0xBBBBBBBB,
},
raw: &RawSockaddrCAN{
Family: AF_CAN,
Ifindex: 12345678,
Addr: [16]byte{
0xAA, 0xAA, 0xAA, 0xAA,
0xBB, 0xBB, 0xBB, 0xBB,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
},
},
},
{
name: "negative ifindex",
sa: &SockaddrCAN{
Ifindex: -1,
},
err: EINVAL,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, l, err := tt.sa.sockaddr()
if err != tt.err {
t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
}
// Must be 0 on error or a fixed size otherwise.
if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrCAN) {
t.Fatalf("unexpected Socklen: %d", l)
}
if out != nil {
raw := (*RawSockaddrCAN)(out)
if !reflect.DeepEqual(raw, tt.raw) {
t.Fatalf("unexpected RawSockaddrCAN:\n got: %#v\nwant: %#v", raw, tt.raw)
}
}
})
}
}
// These helpers explicitly copy the contents of in into out to produce
// the correct sockaddr structure, without relying on unsafe casting to
// a type of a larger size.
func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}
func sockaddrL2TPIPToAny(in RawSockaddrL2TPIP) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrL2TPIP]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}
func sockaddrL2TPIP6ToAny(in RawSockaddrL2TPIP6) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrL2TPIP6]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}
func sockaddrUnixToAny(in RawSockaddrUnix) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}
func sockaddrIUCVToAny(in RawSockaddrIUCV) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}
func sockaddrCANToAny(in RawSockaddrCAN) *RawSockaddrAny {
var out RawSockaddrAny
copy(
(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
(*(*[SizeofSockaddrCAN]byte)(unsafe.Pointer(&in)))[:],
)
return &out
}