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