mirror of
https://github.com/golang/sys.git
synced 2026-02-09 12:16:04 +03:00
Adds constants and types to support IP-encapsulated L2TP/RFC3931 tunnels on Linux systems. The L2TP subsystem for IP encapsulated tunnels hooks into the inet kernel code using a specific IP protocol value. In order to handle this, anyToSockaddr now has to query the socket protocol type using GetsockoptInt for the AF_INET and AF_INET6 address families. Although this change is reasonably simple, unit tests have been added to validate handling of the new types.
402 lines
8.2 KiB
Go
402 lines
8.2 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"
|
|
"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_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)
|
|
if err != nil {
|
|
t.Fatalf("socket(%v): %v", tt.skt, err)
|
|
}
|
|
defer func() {
|
|
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)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|