mirror of
https://github.com/golang/sys.git
synced 2026-02-09 04:06:04 +03:00
unix: implement L2TPIP socket address on Linux
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.
This commit is contained in:
@@ -205,6 +205,8 @@ union sockaddr_all {
|
||||
struct sockaddr_ll s5;
|
||||
struct sockaddr_nl s6;
|
||||
struct sockaddr_pppox s7;
|
||||
struct sockaddr_l2tpip s8;
|
||||
struct sockaddr_l2tpip6 s9;
|
||||
};
|
||||
|
||||
struct sockaddr_any {
|
||||
@@ -509,6 +511,10 @@ type RawSockaddrPPPoX [C.sizeof_struct_sockaddr_pppox]byte
|
||||
|
||||
type RawSockaddrTIPC C.struct_sockaddr_tipc
|
||||
|
||||
type RawSockaddrL2TPIP C.struct_sockaddr_l2tpip
|
||||
|
||||
type RawSockaddrL2TPIP6 C.struct_sockaddr_l2tpip6
|
||||
|
||||
type RawSockaddr C.struct_sockaddr
|
||||
|
||||
type RawSockaddrAny C.struct_sockaddr_any
|
||||
@@ -561,6 +567,8 @@ const (
|
||||
SizeofSockaddrXDP = C.sizeof_struct_sockaddr_xdp
|
||||
SizeofSockaddrPPPoX = C.sizeof_struct_sockaddr_pppox
|
||||
SizeofSockaddrTIPC = C.sizeof_struct_sockaddr_tipc
|
||||
SizeofSockaddrL2TPIP = C.sizeof_struct_sockaddr_l2tpip
|
||||
SizeofSockaddrL2TPIP6 = C.sizeof_struct_sockaddr_l2tpip6
|
||||
SizeofLinger = C.sizeof_struct_linger
|
||||
SizeofIovec = C.sizeof_struct_iovec
|
||||
SizeofIPMreq = C.sizeof_struct_ip_mreq
|
||||
|
||||
@@ -280,6 +280,11 @@ struct ltchars {
|
||||
// for the tipc_subscr timeout __u32 field.
|
||||
#undef TIPC_WAIT_FOREVER
|
||||
#define TIPC_WAIT_FOREVER 0xffffffff
|
||||
|
||||
// Copied from linux/l2tp.h
|
||||
// Including linux/l2tp.h here causes conflicts between linux/in.h
|
||||
// and netinet/in.h included via net/route.h above.
|
||||
#define IPPROTO_L2TP 115
|
||||
'
|
||||
|
||||
includes_NetBSD='
|
||||
|
||||
@@ -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,18 @@ 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)
|
||||
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)
|
||||
}
|
||||
@@ -215,16 +272,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
|
||||
}
|
||||
|
||||
@@ -839,6 +839,43 @@ func (sa *SockaddrTIPC) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrTIPC, nil
|
||||
}
|
||||
|
||||
// SockaddrL2TPIP implements the Sockaddr interface for IPPROTO_L2TP/AF_INET sockets.
|
||||
type SockaddrL2TPIP struct {
|
||||
Addr [4]byte
|
||||
ConnId uint32
|
||||
raw RawSockaddrL2TPIP
|
||||
}
|
||||
|
||||
func (sa *SockaddrL2TPIP) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
|
||||
sa.raw.Family = AF_INET
|
||||
sa.raw.Conn_id = sa.ConnId
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP, nil
|
||||
}
|
||||
|
||||
// SockaddrL2TPIP6 implements the Sockaddr interface for IPPROTO_L2TP/AF_INET6 sockets.
|
||||
type SockaddrL2TPIP6 struct {
|
||||
Addr [16]byte
|
||||
ZoneId uint32
|
||||
ConnId uint32
|
||||
raw RawSockaddrL2TPIP6
|
||||
}
|
||||
|
||||
func (sa *SockaddrL2TPIP6) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
|
||||
sa.raw.Family = AF_INET6
|
||||
sa.raw.Conn_id = sa.ConnId
|
||||
sa.raw.Scope_id = sa.ZoneId
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP6, nil
|
||||
}
|
||||
|
||||
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
||||
switch rsa.Addr.Family {
|
||||
case AF_NETLINK:
|
||||
@@ -889,25 +926,58 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet4)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch proto {
|
||||
case IPPROTO_L2TP:
|
||||
pp := (*RawSockaddrL2TPIP)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrL2TPIP)
|
||||
sa.ConnId = pp.Conn_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
default:
|
||||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet4)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case AF_INET6:
|
||||
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet6)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch proto {
|
||||
case IPPROTO_L2TP:
|
||||
pp := (*RawSockaddrL2TPIP6)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrL2TPIP6)
|
||||
sa.ConnId = pp.Conn_id
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
default:
|
||||
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet6)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case AF_VSOCK:
|
||||
pp := (*RawSockaddrVM)(unsafe.Pointer(rsa))
|
||||
|
||||
@@ -890,6 +890,7 @@ const (
|
||||
IPPROTO_IP = 0x0
|
||||
IPPROTO_IPIP = 0x4
|
||||
IPPROTO_IPV6 = 0x29
|
||||
IPPROTO_L2TP = 0x73
|
||||
IPPROTO_MH = 0x87
|
||||
IPPROTO_MPLS = 0x89
|
||||
IPPROTO_MTP = 0x5c
|
||||
|
||||
@@ -243,6 +243,23 @@ type RawSockaddrTIPC struct {
|
||||
Addr [12]byte
|
||||
}
|
||||
|
||||
type RawSockaddrL2TPIP struct {
|
||||
Family uint16
|
||||
Unused uint16
|
||||
Addr [4]byte /* in_addr */
|
||||
Conn_id uint32
|
||||
_ [4]uint8
|
||||
}
|
||||
|
||||
type RawSockaddrL2TPIP6 struct {
|
||||
Family uint16
|
||||
Unused uint16
|
||||
Flowinfo uint32
|
||||
Addr [16]byte /* in6_addr */
|
||||
Scope_id uint32
|
||||
Conn_id uint32
|
||||
}
|
||||
|
||||
type _Socklen uint32
|
||||
|
||||
type Linger struct {
|
||||
@@ -353,6 +370,8 @@ const (
|
||||
SizeofSockaddrXDP = 0x10
|
||||
SizeofSockaddrPPPoX = 0x1e
|
||||
SizeofSockaddrTIPC = 0x10
|
||||
SizeofSockaddrL2TPIP = 0x10
|
||||
SizeofSockaddrL2TPIP6 = 0x20
|
||||
SizeofLinger = 0x8
|
||||
SizeofIPMreq = 0x8
|
||||
SizeofIPMreqn = 0xc
|
||||
|
||||
Reference in New Issue
Block a user