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