1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build linux
6
7package unix
8
9import (
10	"reflect"
11	"testing"
12	"unsafe"
13)
14
15// as per socket(2)
16type SocketSpec struct {
17	domain   int
18	typ      int
19	protocol int
20}
21
22func Test_anyToSockaddr(t *testing.T) {
23	tests := []struct {
24		name string
25		rsa  *RawSockaddrAny
26		sa   Sockaddr
27		err  error
28		skt  SocketSpec
29	}{
30		{
31			name: "AF_TIPC bad addrtype",
32			rsa: &RawSockaddrAny{
33				Addr: RawSockaddr{
34					Family: AF_TIPC,
35				},
36			},
37			err: EINVAL,
38		},
39		{
40			name: "AF_TIPC NameSeq",
41			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
42				Family:   AF_TIPC,
43				Addrtype: TIPC_SERVICE_RANGE,
44				Scope:    1,
45				Addr: (&TIPCServiceRange{
46					Type:  1,
47					Lower: 2,
48					Upper: 3,
49				}).tipcAddr(),
50			}),
51			sa: &SockaddrTIPC{
52				Scope: 1,
53				Addr: &TIPCServiceRange{
54					Type:  1,
55					Lower: 2,
56					Upper: 3,
57				},
58			},
59		},
60		{
61			name: "AF_TIPC Name",
62			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
63				Family:   AF_TIPC,
64				Addrtype: TIPC_SERVICE_ADDR,
65				Scope:    2,
66				Addr: (&TIPCServiceName{
67					Type:     1,
68					Instance: 2,
69					Domain:   3,
70				}).tipcAddr(),
71			}),
72			sa: &SockaddrTIPC{
73				Scope: 2,
74				Addr: &TIPCServiceName{
75					Type:     1,
76					Instance: 2,
77					Domain:   3,
78				},
79			},
80		},
81		{
82			name: "AF_TIPC ID",
83			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
84				Family:   AF_TIPC,
85				Addrtype: TIPC_SOCKET_ADDR,
86				Scope:    3,
87				Addr: (&TIPCSocketAddr{
88					Ref:  1,
89					Node: 2,
90				}).tipcAddr(),
91			}),
92			sa: &SockaddrTIPC{
93				Scope: 3,
94				Addr: &TIPCSocketAddr{
95					Ref:  1,
96					Node: 2,
97				},
98			},
99		},
100		{
101			name: "AF_INET IPPROTO_L2TP",
102			rsa: sockaddrL2TPIPToAny(RawSockaddrL2TPIP{
103				Family:  AF_INET,
104				Addr:    [4]byte{0xef, 0x10, 0x5b, 0xa2},
105				Conn_id: 0x1234abcd,
106			}),
107			sa: &SockaddrL2TPIP{
108				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
109				ConnId: 0x1234abcd,
110			},
111			skt: SocketSpec{domain: AF_INET, typ: SOCK_DGRAM, protocol: IPPROTO_L2TP},
112		},
113		{
114			name: "AF_INET6 IPPROTO_L2TP",
115			rsa: sockaddrL2TPIP6ToAny(RawSockaddrL2TPIP6{
116				Family:   AF_INET6,
117				Flowinfo: 42,
118				Addr: [16]byte{
119					0x20, 0x01, 0x0d, 0xb8,
120					0x85, 0xa3, 0x00, 0x00,
121					0x00, 0x00, 0x8a, 0x2e,
122					0x03, 0x70, 0x73, 0x34,
123				},
124				Scope_id: 90210,
125				Conn_id:  0x1234abcd,
126			}),
127			sa: &SockaddrL2TPIP6{
128				Addr: [16]byte{
129					0x20, 0x01, 0x0d, 0xb8,
130					0x85, 0xa3, 0x00, 0x00,
131					0x00, 0x00, 0x8a, 0x2e,
132					0x03, 0x70, 0x73, 0x34,
133				},
134				ZoneId: 90210,
135				ConnId: 0x1234abcd,
136			},
137			skt: SocketSpec{domain: AF_INET6, typ: SOCK_DGRAM, protocol: IPPROTO_L2TP},
138		},
139		{
140			name: "AF_MAX EAFNOSUPPORT",
141			rsa: &RawSockaddrAny{
142				Addr: RawSockaddr{
143					Family: AF_MAX,
144				},
145			},
146			err: EAFNOSUPPORT,
147		},
148		// TODO: expand to support other families.
149	}
150
151	for _, tt := range tests {
152		t.Run(tt.name, func(t *testing.T) {
153			fd := int(0)
154			var err error
155			if tt.skt.domain != 0 {
156				fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol)
157				// Some sockaddr types need specific kernel modules running: if these
158				// are not present we'll get EPROTONOSUPPORT back when trying to create
159				// the socket.  Skip the test in this situation.
160				if err == EPROTONOSUPPORT {
161					t.Skip("socket family/protocol not supported by kernel")
162				} else if err != nil {
163					t.Fatalf("socket(%v): %v", tt.skt, err)
164				}
165				defer Close(fd)
166			}
167			sa, err := anyToSockaddr(fd, tt.rsa)
168			if err != tt.err {
169				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
170			}
171
172			if !reflect.DeepEqual(sa, tt.sa) {
173				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
174			}
175		})
176	}
177}
178
179func TestSockaddrTIPC_sockaddr(t *testing.T) {
180	tests := []struct {
181		name string
182		sa   *SockaddrTIPC
183		raw  *RawSockaddrTIPC
184		err  error
185	}{
186		{
187			name: "no fields set",
188			sa:   &SockaddrTIPC{},
189			err:  EINVAL,
190		},
191		{
192			name: "ID",
193			sa: &SockaddrTIPC{
194				Scope: 1,
195				Addr: &TIPCSocketAddr{
196					Ref:  1,
197					Node: 2,
198				},
199			},
200			raw: &RawSockaddrTIPC{
201				Family:   AF_TIPC,
202				Addrtype: TIPC_SOCKET_ADDR,
203				Scope:    1,
204				Addr: (&TIPCSocketAddr{
205					Ref:  1,
206					Node: 2,
207				}).tipcAddr(),
208			},
209		},
210		{
211			name: "NameSeq",
212			sa: &SockaddrTIPC{
213				Scope: 2,
214				Addr: &TIPCServiceRange{
215					Type:  1,
216					Lower: 2,
217					Upper: 3,
218				},
219			},
220			raw: &RawSockaddrTIPC{
221				Family:   AF_TIPC,
222				Addrtype: TIPC_SERVICE_RANGE,
223				Scope:    2,
224				Addr: (&TIPCServiceRange{
225					Type:  1,
226					Lower: 2,
227					Upper: 3,
228				}).tipcAddr(),
229			},
230		},
231		{
232			name: "Name",
233			sa: &SockaddrTIPC{
234				Scope: 3,
235				Addr: &TIPCServiceName{
236					Type:     1,
237					Instance: 2,
238					Domain:   3,
239				},
240			},
241			raw: &RawSockaddrTIPC{
242				Family:   AF_TIPC,
243				Addrtype: TIPC_SERVICE_ADDR,
244				Scope:    3,
245				Addr: (&TIPCServiceName{
246					Type:     1,
247					Instance: 2,
248					Domain:   3,
249				}).tipcAddr(),
250			},
251		},
252	}
253
254	for _, tt := range tests {
255		t.Run(tt.name, func(t *testing.T) {
256			out, l, err := tt.sa.sockaddr()
257			if err != tt.err {
258				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
259			}
260
261			// Must be 0 on error or a fixed size otherwise.
262			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) {
263				t.Fatalf("unexpected Socklen: %d", l)
264			}
265			if out == nil {
266				// No pointer to cast, return early.
267				return
268			}
269
270			raw := (*RawSockaddrTIPC)(out)
271			if !reflect.DeepEqual(raw, tt.raw) {
272				t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw)
273			}
274		})
275	}
276}
277
278func TestSockaddrL2TPIP_sockaddr(t *testing.T) {
279	tests := []struct {
280		name string
281		sa   *SockaddrL2TPIP
282		raw  *RawSockaddrL2TPIP
283		err  error
284	}{
285		{
286			name: "L2TPIP",
287			sa: &SockaddrL2TPIP{
288				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
289				ConnId: 0x1234abcd,
290			},
291			raw: &RawSockaddrL2TPIP{
292				Family:  AF_INET,
293				Addr:    [4]byte{0xef, 0x10, 0x5b, 0xa2},
294				Conn_id: 0x1234abcd,
295			},
296		},
297	}
298
299	for _, tt := range tests {
300		t.Run(tt.name, func(t *testing.T) {
301			out, l, err := tt.sa.sockaddr()
302			if err != tt.err {
303				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
304			}
305
306			// Must be 0 on error or a fixed size otherwise.
307			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP) {
308				t.Fatalf("unexpected Socklen: %d", l)
309			}
310
311			if out != nil {
312				raw := (*RawSockaddrL2TPIP)(out)
313				if !reflect.DeepEqual(raw, tt.raw) {
314					t.Fatalf("unexpected RawSockaddrL2TPIP:\n got: %#v\nwant: %#v", raw, tt.raw)
315				}
316			}
317		})
318	}
319}
320
321func TestSockaddrL2TPIP6_sockaddr(t *testing.T) {
322	tests := []struct {
323		name string
324		sa   *SockaddrL2TPIP6
325		raw  *RawSockaddrL2TPIP6
326		err  error
327	}{
328		{
329			name: "L2TPIP6",
330			sa: &SockaddrL2TPIP6{
331				Addr: [16]byte{
332					0x20, 0x01, 0x0d, 0xb8,
333					0x85, 0xa3, 0x00, 0x00,
334					0x00, 0x00, 0x8a, 0x2e,
335					0x03, 0x70, 0x73, 0x34,
336				},
337				ZoneId: 90210,
338				ConnId: 0x1234abcd,
339			},
340			raw: &RawSockaddrL2TPIP6{
341				Family: AF_INET6,
342				Addr: [16]byte{
343					0x20, 0x01, 0x0d, 0xb8,
344					0x85, 0xa3, 0x00, 0x00,
345					0x00, 0x00, 0x8a, 0x2e,
346					0x03, 0x70, 0x73, 0x34,
347				},
348				Scope_id: 90210,
349				Conn_id:  0x1234abcd,
350			},
351		},
352	}
353
354	for _, tt := range tests {
355		t.Run(tt.name, func(t *testing.T) {
356			out, l, err := tt.sa.sockaddr()
357			if err != tt.err {
358				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
359			}
360
361			// Must be 0 on error or a fixed size otherwise.
362			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP6) {
363				t.Fatalf("unexpected Socklen: %d", l)
364			}
365
366			if out != nil {
367				raw := (*RawSockaddrL2TPIP6)(out)
368				if !reflect.DeepEqual(raw, tt.raw) {
369					t.Fatalf("unexpected RawSockaddrL2TPIP6:\n got: %#v\nwant: %#v", raw, tt.raw)
370				}
371			}
372		})
373	}
374}
375
376// These helpers explicitly copy the contents of in into out to produce
377// the correct sockaddr structure, without relying on unsafe casting to
378// a type of a larger size.
379func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny {
380	var out RawSockaddrAny
381	copy(
382		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
383		(*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:],
384	)
385	return &out
386}
387
388func sockaddrL2TPIPToAny(in RawSockaddrL2TPIP) *RawSockaddrAny {
389	var out RawSockaddrAny
390	copy(
391		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
392		(*(*[SizeofSockaddrL2TPIP]byte)(unsafe.Pointer(&in)))[:],
393	)
394	return &out
395}
396
397func sockaddrL2TPIP6ToAny(in RawSockaddrL2TPIP6) *RawSockaddrAny {
398	var out RawSockaddrAny
399	copy(
400		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
401		(*(*[SizeofSockaddrL2TPIP6]byte)(unsafe.Pointer(&in)))[:],
402	)
403	return &out
404}
405