Files
sys/unix/syscall_internal_linux_test.go
Christian Svensson 3ff754bf58 unix: add AF_IUCV and SockaddrIUCV
On z series machines the IUCV address family is used to communicate
between parts of the machine and other VMs that may be running.

This adds support for addressing these services using AF_IUCV.

Fixes golang/go#40826

Change-Id: I3aba3beb5cb98d9c548d7abc874ca86fb25c8a52
GitHub-Last-Rev: b964d186b4
GitHub-Pull-Request: golang/sys#76
Reviewed-on: https://go-review.googlesource.com/c/sys/+/248777
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
2020-08-17 08:59:35 +00:00

529 lines
11 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"
)
// 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_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,
},
skt: SocketSpec{domain: AF_INET, typ: SOCK_DGRAM, protocol: 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,
},
skt: SocketSpec{domain: AF_INET6, typ: SOCK_DGRAM, protocol: 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_MAX EAFNOSUPPORT",
rsa: &RawSockaddrAny{
Addr: RawSockaddr{
Family: AF_MAX,
},
},
err: EAFNOSUPPORT,
},
// TODO: expand to support other families.
}
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)
}
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)
}
})
}
}
// 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
// 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.
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
}