mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-02 07:07:33 -04:00
unix: implement L2TPIP socket address on Linux
Add 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. Fixes golang/go#37787 Change-Id: I16ae1e24dcced4ccc6ce6a79a90a5a2f6a560967 GitHub-Last-Rev: ca554ad1b6d3a5e55c70f05cf0e542968fa2418c GitHub-Pull-Request: golang/sys#60 Reviewed-on: https://go-review.googlesource.com/c/sys/+/223157 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
committed by
Ian Lance Taylor
parent
5c8b2ff675
commit
9a0dfc3c55
@@ -12,12 +12,20 @@ import (
|
||||
"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",
|
||||
@@ -89,6 +97,45 @@ func Test_anyToSockaddr(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
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{
|
||||
@@ -103,8 +150,21 @@ func Test_anyToSockaddr(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// TODO: parameterize fd (and its setup) when needed.
|
||||
sa, err := anyToSockaddr(0, tt.rsa)
|
||||
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)
|
||||
}
|
||||
@@ -215,16 +275,130 @@ func TestSockaddrTIPC_sockaddr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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)))[:],
|
||||
(*(*[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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user