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//go:build linux
6// +build linux
7
8package unix
9
10import (
11	"reflect"
12	"strings"
13	"testing"
14	"unsafe"
15)
16
17func makeProto(proto int) *int {
18	return &proto
19}
20
21func Test_anyToSockaddr(t *testing.T) {
22	tests := []struct {
23		name  string
24		rsa   *RawSockaddrAny
25		sa    Sockaddr
26		err   error
27		proto *int
28	}{
29		{
30			name: "AF_TIPC bad addrtype",
31			rsa: &RawSockaddrAny{
32				Addr: RawSockaddr{
33					Family: AF_TIPC,
34				},
35			},
36			err: EINVAL,
37		},
38		{
39			name: "AF_TIPC NameSeq",
40			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
41				Family:   AF_TIPC,
42				Addrtype: TIPC_SERVICE_RANGE,
43				Scope:    1,
44				Addr: (&TIPCServiceRange{
45					Type:  1,
46					Lower: 2,
47					Upper: 3,
48				}).tipcAddr(),
49			}),
50			sa: &SockaddrTIPC{
51				Scope: 1,
52				Addr: &TIPCServiceRange{
53					Type:  1,
54					Lower: 2,
55					Upper: 3,
56				},
57			},
58		},
59		{
60			name: "AF_TIPC Name",
61			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
62				Family:   AF_TIPC,
63				Addrtype: TIPC_SERVICE_ADDR,
64				Scope:    2,
65				Addr: (&TIPCServiceName{
66					Type:     1,
67					Instance: 2,
68					Domain:   3,
69				}).tipcAddr(),
70			}),
71			sa: &SockaddrTIPC{
72				Scope: 2,
73				Addr: &TIPCServiceName{
74					Type:     1,
75					Instance: 2,
76					Domain:   3,
77				},
78			},
79		},
80		{
81			name: "AF_TIPC ID",
82			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
83				Family:   AF_TIPC,
84				Addrtype: TIPC_SOCKET_ADDR,
85				Scope:    3,
86				Addr: (&TIPCSocketAddr{
87					Ref:  1,
88					Node: 2,
89				}).tipcAddr(),
90			}),
91			sa: &SockaddrTIPC{
92				Scope: 3,
93				Addr: &TIPCSocketAddr{
94					Ref:  1,
95					Node: 2,
96				},
97			},
98		},
99		{
100			name: "AF_INET IPPROTO_L2TP",
101			rsa: sockaddrL2TPIPToAny(RawSockaddrL2TPIP{
102				Family:  AF_INET,
103				Addr:    [4]byte{0xef, 0x10, 0x5b, 0xa2},
104				Conn_id: 0x1234abcd,
105			}),
106			sa: &SockaddrL2TPIP{
107				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
108				ConnId: 0x1234abcd,
109			},
110			proto: makeProto(IPPROTO_L2TP),
111		},
112		{
113			name: "AF_INET6 IPPROTO_L2TP",
114			rsa: sockaddrL2TPIP6ToAny(RawSockaddrL2TPIP6{
115				Family:   AF_INET6,
116				Flowinfo: 42,
117				Addr: [16]byte{
118					0x20, 0x01, 0x0d, 0xb8,
119					0x85, 0xa3, 0x00, 0x00,
120					0x00, 0x00, 0x8a, 0x2e,
121					0x03, 0x70, 0x73, 0x34,
122				},
123				Scope_id: 90210,
124				Conn_id:  0x1234abcd,
125			}),
126			sa: &SockaddrL2TPIP6{
127				Addr: [16]byte{
128					0x20, 0x01, 0x0d, 0xb8,
129					0x85, 0xa3, 0x00, 0x00,
130					0x00, 0x00, 0x8a, 0x2e,
131					0x03, 0x70, 0x73, 0x34,
132				},
133				ZoneId: 90210,
134				ConnId: 0x1234abcd,
135			},
136			proto: makeProto(IPPROTO_L2TP),
137		},
138		{
139			name: "AF_UNIX unnamed/abstract",
140			rsa: sockaddrUnixToAny(RawSockaddrUnix{
141				Family: AF_UNIX,
142			}),
143			sa: &SockaddrUnix{
144				Name: "@",
145			},
146		},
147		{
148			name: "AF_UNIX named",
149			rsa: sockaddrUnixToAny(RawSockaddrUnix{
150				Family: AF_UNIX,
151				Path:   [108]int8{'g', 'o', 'p', 'h', 'e', 'r'},
152			}),
153			sa: &SockaddrUnix{
154				Name: "gopher",
155			},
156		},
157		{
158			name: "AF_IUCV",
159			rsa: sockaddrIUCVToAny(RawSockaddrIUCV{
160				Family:  AF_IUCV,
161				User_id: [8]int8{'*', 'M', 'S', 'G', ' ', ' ', ' ', ' '},
162				Name:    [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
163			}),
164			sa: &SockaddrIUCV{
165				UserID: "*MSG    ",
166				Name:   "        ",
167			},
168		},
169		{
170			name: "AF_CAN CAN_RAW",
171			rsa: sockaddrCANToAny(RawSockaddrCAN{
172				Family:  AF_CAN,
173				Ifindex: 12345678,
174				Addr: [16]byte{
175					0xAA, 0xAA, 0xAA, 0xAA,
176					0xBB, 0xBB, 0xBB, 0xBB,
177					0x0, 0x0, 0x0, 0x0,
178					0x0, 0x0, 0x0, 0x0,
179				},
180			}),
181			sa: &SockaddrCAN{
182				Ifindex: 12345678,
183				RxID:    0xAAAAAAAA,
184				TxID:    0xBBBBBBBB,
185			},
186			proto: makeProto(CAN_RAW),
187		},
188		{
189			name: "AF_CAN CAN_J1939",
190			rsa: sockaddrCANToAny(RawSockaddrCAN{
191				Family:  AF_CAN,
192				Ifindex: 12345678,
193				Addr: [16]byte{
194					0xAA, 0xAA, 0xAA, 0xAA,
195					0xAA, 0xAA, 0xAA, 0xAA,
196					0xBB, 0xBB, 0xBB, 0xBB,
197					0xCC, 0x00, 0x00, 0x00,
198				},
199			}),
200			sa: &SockaddrCANJ1939{
201				Ifindex: 12345678,
202				Name:    0xAAAAAAAAAAAAAAAA,
203				PGN:     0xBBBBBBBB,
204				Addr:    0xCC,
205			},
206			proto: makeProto(CAN_J1939),
207		},
208		{
209			name: "AF_MAX EAFNOSUPPORT",
210			rsa: &RawSockaddrAny{
211				Addr: RawSockaddr{
212					Family: AF_MAX,
213				},
214			},
215			err: EAFNOSUPPORT,
216		},
217		// TODO: expand to support other families.
218	}
219
220	realSocketProtocol := socketProtocol
221
222	for _, tt := range tests {
223		t.Run(tt.name, func(t *testing.T) {
224			fd := int(0)
225			if tt.proto != nil {
226				socketProtocol = func(fd int) (int, error) { return *tt.proto, nil }
227			} else {
228				socketProtocol = realSocketProtocol
229			}
230			sa, err := anyToSockaddr(fd, tt.rsa)
231			if err != tt.err {
232				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
233			}
234
235			if !reflect.DeepEqual(sa, tt.sa) {
236				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
237			}
238		})
239	}
240}
241
242func TestSockaddrTIPC_sockaddr(t *testing.T) {
243	tests := []struct {
244		name string
245		sa   *SockaddrTIPC
246		raw  *RawSockaddrTIPC
247		err  error
248	}{
249		{
250			name: "no fields set",
251			sa:   &SockaddrTIPC{},
252			err:  EINVAL,
253		},
254		{
255			name: "ID",
256			sa: &SockaddrTIPC{
257				Scope: 1,
258				Addr: &TIPCSocketAddr{
259					Ref:  1,
260					Node: 2,
261				},
262			},
263			raw: &RawSockaddrTIPC{
264				Family:   AF_TIPC,
265				Addrtype: TIPC_SOCKET_ADDR,
266				Scope:    1,
267				Addr: (&TIPCSocketAddr{
268					Ref:  1,
269					Node: 2,
270				}).tipcAddr(),
271			},
272		},
273		{
274			name: "NameSeq",
275			sa: &SockaddrTIPC{
276				Scope: 2,
277				Addr: &TIPCServiceRange{
278					Type:  1,
279					Lower: 2,
280					Upper: 3,
281				},
282			},
283			raw: &RawSockaddrTIPC{
284				Family:   AF_TIPC,
285				Addrtype: TIPC_SERVICE_RANGE,
286				Scope:    2,
287				Addr: (&TIPCServiceRange{
288					Type:  1,
289					Lower: 2,
290					Upper: 3,
291				}).tipcAddr(),
292			},
293		},
294		{
295			name: "Name",
296			sa: &SockaddrTIPC{
297				Scope: 3,
298				Addr: &TIPCServiceName{
299					Type:     1,
300					Instance: 2,
301					Domain:   3,
302				},
303			},
304			raw: &RawSockaddrTIPC{
305				Family:   AF_TIPC,
306				Addrtype: TIPC_SERVICE_ADDR,
307				Scope:    3,
308				Addr: (&TIPCServiceName{
309					Type:     1,
310					Instance: 2,
311					Domain:   3,
312				}).tipcAddr(),
313			},
314		},
315	}
316
317	for _, tt := range tests {
318		t.Run(tt.name, func(t *testing.T) {
319			out, l, err := tt.sa.sockaddr()
320			if err != tt.err {
321				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
322			}
323
324			// Must be 0 on error or a fixed size otherwise.
325			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) {
326				t.Fatalf("unexpected Socklen: %d", l)
327			}
328			if out == nil {
329				// No pointer to cast, return early.
330				return
331			}
332
333			raw := (*RawSockaddrTIPC)(out)
334			if !reflect.DeepEqual(raw, tt.raw) {
335				t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw)
336			}
337		})
338	}
339}
340
341func TestSockaddrL2TPIP_sockaddr(t *testing.T) {
342	tests := []struct {
343		name string
344		sa   *SockaddrL2TPIP
345		raw  *RawSockaddrL2TPIP
346		err  error
347	}{
348		{
349			name: "L2TPIP",
350			sa: &SockaddrL2TPIP{
351				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
352				ConnId: 0x1234abcd,
353			},
354			raw: &RawSockaddrL2TPIP{
355				Family:  AF_INET,
356				Addr:    [4]byte{0xef, 0x10, 0x5b, 0xa2},
357				Conn_id: 0x1234abcd,
358			},
359		},
360	}
361
362	for _, tt := range tests {
363		t.Run(tt.name, func(t *testing.T) {
364			out, l, err := tt.sa.sockaddr()
365			if err != tt.err {
366				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
367			}
368
369			// Must be 0 on error or a fixed size otherwise.
370			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP) {
371				t.Fatalf("unexpected Socklen: %d", l)
372			}
373
374			if out != nil {
375				raw := (*RawSockaddrL2TPIP)(out)
376				if !reflect.DeepEqual(raw, tt.raw) {
377					t.Fatalf("unexpected RawSockaddrL2TPIP:\n got: %#v\nwant: %#v", raw, tt.raw)
378				}
379			}
380		})
381	}
382}
383
384func TestSockaddrL2TPIP6_sockaddr(t *testing.T) {
385	tests := []struct {
386		name string
387		sa   *SockaddrL2TPIP6
388		raw  *RawSockaddrL2TPIP6
389		err  error
390	}{
391		{
392			name: "L2TPIP6",
393			sa: &SockaddrL2TPIP6{
394				Addr: [16]byte{
395					0x20, 0x01, 0x0d, 0xb8,
396					0x85, 0xa3, 0x00, 0x00,
397					0x00, 0x00, 0x8a, 0x2e,
398					0x03, 0x70, 0x73, 0x34,
399				},
400				ZoneId: 90210,
401				ConnId: 0x1234abcd,
402			},
403			raw: &RawSockaddrL2TPIP6{
404				Family: AF_INET6,
405				Addr: [16]byte{
406					0x20, 0x01, 0x0d, 0xb8,
407					0x85, 0xa3, 0x00, 0x00,
408					0x00, 0x00, 0x8a, 0x2e,
409					0x03, 0x70, 0x73, 0x34,
410				},
411				Scope_id: 90210,
412				Conn_id:  0x1234abcd,
413			},
414		},
415	}
416
417	for _, tt := range tests {
418		t.Run(tt.name, func(t *testing.T) {
419			out, l, err := tt.sa.sockaddr()
420			if err != tt.err {
421				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
422			}
423
424			// Must be 0 on error or a fixed size otherwise.
425			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP6) {
426				t.Fatalf("unexpected Socklen: %d", l)
427			}
428
429			if out != nil {
430				raw := (*RawSockaddrL2TPIP6)(out)
431				if !reflect.DeepEqual(raw, tt.raw) {
432					t.Fatalf("unexpected RawSockaddrL2TPIP6:\n got: %#v\nwant: %#v", raw, tt.raw)
433				}
434			}
435		})
436	}
437}
438
439func TestSockaddrUnix_sockaddr(t *testing.T) {
440	tests := []struct {
441		name string
442		sa   *SockaddrUnix
443		raw  *RawSockaddrUnix
444		slen _Socklen
445		err  error
446	}{
447		{
448			name: "unnamed",
449			sa:   &SockaddrUnix{},
450			raw: &RawSockaddrUnix{
451				Family: AF_UNIX,
452			},
453			slen: 2, // family (uint16)
454		},
455		{
456			name: "abstract",
457			sa: &SockaddrUnix{
458				Name: "@",
459			},
460			raw: &RawSockaddrUnix{
461				Family: AF_UNIX,
462			},
463			slen: 3, // family (uint16) + NULL
464		},
465		{
466			name: "named",
467			sa: &SockaddrUnix{
468				Name: "gopher",
469			},
470			raw: &RawSockaddrUnix{
471				Family: AF_UNIX,
472				Path:   [108]int8{'g', 'o', 'p', 'h', 'e', 'r'},
473			},
474			slen: _Socklen(3 + len("gopher")), // family (uint16) + len(gopher)
475		},
476		{
477			name: "named too long",
478			sa: &SockaddrUnix{
479				Name: strings.Repeat("A", 108),
480			},
481			err: EINVAL,
482		},
483	}
484
485	for _, tt := range tests {
486		t.Run(tt.name, func(t *testing.T) {
487			out, l, err := tt.sa.sockaddr()
488			if err != tt.err {
489				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
490			}
491
492			if l != tt.slen {
493				t.Fatalf("unexpected Socklen: %d, want %d", l, tt.slen)
494			}
495			if out == nil {
496				// No pointer to cast, return early.
497				return
498			}
499
500			raw := (*RawSockaddrUnix)(out)
501			if !reflect.DeepEqual(raw, tt.raw) {
502				t.Fatalf("unexpected RawSockaddrUnix:\n got: %#v\nwant: %#v", raw, tt.raw)
503			}
504		})
505	}
506}
507
508func TestSockaddrIUCV_sockaddr(t *testing.T) {
509	tests := []struct {
510		name string
511		sa   *SockaddrIUCV
512		raw  *RawSockaddrIUCV
513		err  error
514	}{
515		{
516			name: "no fields set",
517			sa:   &SockaddrIUCV{},
518			raw: &RawSockaddrIUCV{
519				Family:  AF_IUCV,
520				Nodeid:  [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
521				User_id: [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
522				Name:    [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
523			},
524		},
525		{
526			name: "both fields set",
527			sa: &SockaddrIUCV{
528				UserID: "USERID",
529				Name:   "NAME",
530			},
531			raw: &RawSockaddrIUCV{
532				Family:  AF_IUCV,
533				Nodeid:  [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
534				User_id: [8]int8{'U', 'S', 'E', 'R', 'I', 'D', ' ', ' '},
535				Name:    [8]int8{'N', 'A', 'M', 'E', ' ', ' ', ' ', ' '},
536			},
537		},
538		{
539			name: "too long userid",
540			sa: &SockaddrIUCV{
541				UserID: "123456789",
542			},
543			err: EINVAL,
544		},
545		{
546			name: "too long name",
547			sa: &SockaddrIUCV{
548				Name: "123456789",
549			},
550			err: EINVAL,
551		},
552	}
553
554	for _, tt := range tests {
555		t.Run(tt.name, func(t *testing.T) {
556			out, l, err := tt.sa.sockaddr()
557			if err != tt.err {
558				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
559			}
560
561			// Must be 0 on error or a fixed size otherwise.
562			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrIUCV) {
563				t.Fatalf("unexpected Socklen: %d", l)
564			}
565			if out == nil {
566				// No pointer to cast, return early.
567				return
568			}
569
570			raw := (*RawSockaddrIUCV)(out)
571			if !reflect.DeepEqual(raw, tt.raw) {
572				t.Fatalf("unexpected RawSockaddrIUCV:\n got: %#v\nwant: %#v", raw, tt.raw)
573			}
574		})
575	}
576}
577
578func TestSockaddrCAN_sockaddr(t *testing.T) {
579	tests := []struct {
580		name string
581		sa   *SockaddrCAN
582		raw  *RawSockaddrCAN
583		err  error
584	}{
585		{
586			name: "with ids",
587			sa: &SockaddrCAN{
588				Ifindex: 12345678,
589				RxID:    0xAAAAAAAA,
590				TxID:    0xBBBBBBBB,
591			},
592			raw: &RawSockaddrCAN{
593				Family:  AF_CAN,
594				Ifindex: 12345678,
595				Addr: [16]byte{
596					0xAA, 0xAA, 0xAA, 0xAA,
597					0xBB, 0xBB, 0xBB, 0xBB,
598					0x0, 0x0, 0x0, 0x0,
599					0x0, 0x0, 0x0, 0x0,
600				},
601			},
602		},
603		{
604			name: "negative ifindex",
605			sa: &SockaddrCAN{
606				Ifindex: -1,
607			},
608			err: EINVAL,
609		},
610	}
611
612	for _, tt := range tests {
613		t.Run(tt.name, func(t *testing.T) {
614			out, l, err := tt.sa.sockaddr()
615			if err != tt.err {
616				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
617			}
618
619			// Must be 0 on error or a fixed size otherwise.
620			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrCAN) {
621				t.Fatalf("unexpected Socklen: %d", l)
622			}
623
624			if out != nil {
625				raw := (*RawSockaddrCAN)(out)
626				if !reflect.DeepEqual(raw, tt.raw) {
627					t.Fatalf("unexpected RawSockaddrCAN:\n got: %#v\nwant: %#v", raw, tt.raw)
628				}
629			}
630		})
631	}
632}
633
634// These helpers explicitly copy the contents of in into out to produce
635// the correct sockaddr structure, without relying on unsafe casting to
636// a type of a larger size.
637func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny {
638	var out RawSockaddrAny
639	copy(
640		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
641		(*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:],
642	)
643	return &out
644}
645
646func sockaddrL2TPIPToAny(in RawSockaddrL2TPIP) *RawSockaddrAny {
647	var out RawSockaddrAny
648	copy(
649		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
650		(*(*[SizeofSockaddrL2TPIP]byte)(unsafe.Pointer(&in)))[:],
651	)
652	return &out
653}
654
655func sockaddrL2TPIP6ToAny(in RawSockaddrL2TPIP6) *RawSockaddrAny {
656	var out RawSockaddrAny
657	copy(
658		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
659		(*(*[SizeofSockaddrL2TPIP6]byte)(unsafe.Pointer(&in)))[:],
660	)
661	return &out
662}
663
664func sockaddrUnixToAny(in RawSockaddrUnix) *RawSockaddrAny {
665	var out RawSockaddrAny
666	copy(
667		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
668		(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
669	)
670	return &out
671}
672
673func sockaddrIUCVToAny(in RawSockaddrIUCV) *RawSockaddrAny {
674	var out RawSockaddrAny
675	copy(
676		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
677		(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
678	)
679	return &out
680}
681
682func sockaddrCANToAny(in RawSockaddrCAN) *RawSockaddrAny {
683	var out RawSockaddrAny
684	copy(
685		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
686		(*(*[SizeofSockaddrCAN]byte)(unsafe.Pointer(&in)))[:],
687	)
688	return &out
689}
690