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_MAX EAFNOSUPPORT",
161			rsa: &RawSockaddrAny{
162				Addr: RawSockaddr{
163					Family: AF_MAX,
164				},
165			},
166			err: EAFNOSUPPORT,
167		},
168		// TODO: expand to support other families.
169	}
170
171	for _, tt := range tests {
172		t.Run(tt.name, func(t *testing.T) {
173			fd := int(0)
174			var err error
175			if tt.skt.domain != 0 {
176				fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol)
177				// Some sockaddr types need specific kernel modules running: if these
178				// are not present we'll get EPROTONOSUPPORT back when trying to create
179				// the socket.  Skip the test in this situation.
180				if err == EPROTONOSUPPORT {
181					t.Skip("socket family/protocol not supported by kernel")
182				} else if err != nil {
183					t.Fatalf("socket(%v): %v", tt.skt, err)
184				}
185				defer Close(fd)
186			}
187			sa, err := anyToSockaddr(fd, tt.rsa)
188			if err != tt.err {
189				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
190			}
191
192			if !reflect.DeepEqual(sa, tt.sa) {
193				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
194			}
195		})
196	}
197}
198
199func TestSockaddrTIPC_sockaddr(t *testing.T) {
200	tests := []struct {
201		name string
202		sa   *SockaddrTIPC
203		raw  *RawSockaddrTIPC
204		err  error
205	}{
206		{
207			name: "no fields set",
208			sa:   &SockaddrTIPC{},
209			err:  EINVAL,
210		},
211		{
212			name: "ID",
213			sa: &SockaddrTIPC{
214				Scope: 1,
215				Addr: &TIPCSocketAddr{
216					Ref:  1,
217					Node: 2,
218				},
219			},
220			raw: &RawSockaddrTIPC{
221				Family:   AF_TIPC,
222				Addrtype: TIPC_SOCKET_ADDR,
223				Scope:    1,
224				Addr: (&TIPCSocketAddr{
225					Ref:  1,
226					Node: 2,
227				}).tipcAddr(),
228			},
229		},
230		{
231			name: "NameSeq",
232			sa: &SockaddrTIPC{
233				Scope: 2,
234				Addr: &TIPCServiceRange{
235					Type:  1,
236					Lower: 2,
237					Upper: 3,
238				},
239			},
240			raw: &RawSockaddrTIPC{
241				Family:   AF_TIPC,
242				Addrtype: TIPC_SERVICE_RANGE,
243				Scope:    2,
244				Addr: (&TIPCServiceRange{
245					Type:  1,
246					Lower: 2,
247					Upper: 3,
248				}).tipcAddr(),
249			},
250		},
251		{
252			name: "Name",
253			sa: &SockaddrTIPC{
254				Scope: 3,
255				Addr: &TIPCServiceName{
256					Type:     1,
257					Instance: 2,
258					Domain:   3,
259				},
260			},
261			raw: &RawSockaddrTIPC{
262				Family:   AF_TIPC,
263				Addrtype: TIPC_SERVICE_ADDR,
264				Scope:    3,
265				Addr: (&TIPCServiceName{
266					Type:     1,
267					Instance: 2,
268					Domain:   3,
269				}).tipcAddr(),
270			},
271		},
272	}
273
274	for _, tt := range tests {
275		t.Run(tt.name, func(t *testing.T) {
276			out, l, err := tt.sa.sockaddr()
277			if err != tt.err {
278				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
279			}
280
281			// Must be 0 on error or a fixed size otherwise.
282			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) {
283				t.Fatalf("unexpected Socklen: %d", l)
284			}
285			if out == nil {
286				// No pointer to cast, return early.
287				return
288			}
289
290			raw := (*RawSockaddrTIPC)(out)
291			if !reflect.DeepEqual(raw, tt.raw) {
292				t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw)
293			}
294		})
295	}
296}
297
298func TestSockaddrL2TPIP_sockaddr(t *testing.T) {
299	tests := []struct {
300		name string
301		sa   *SockaddrL2TPIP
302		raw  *RawSockaddrL2TPIP
303		err  error
304	}{
305		{
306			name: "L2TPIP",
307			sa: &SockaddrL2TPIP{
308				Addr:   [4]byte{0xef, 0x10, 0x5b, 0xa2},
309				ConnId: 0x1234abcd,
310			},
311			raw: &RawSockaddrL2TPIP{
312				Family:  AF_INET,
313				Addr:    [4]byte{0xef, 0x10, 0x5b, 0xa2},
314				Conn_id: 0x1234abcd,
315			},
316		},
317	}
318
319	for _, tt := range tests {
320		t.Run(tt.name, func(t *testing.T) {
321			out, l, err := tt.sa.sockaddr()
322			if err != tt.err {
323				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
324			}
325
326			// Must be 0 on error or a fixed size otherwise.
327			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP) {
328				t.Fatalf("unexpected Socklen: %d", l)
329			}
330
331			if out != nil {
332				raw := (*RawSockaddrL2TPIP)(out)
333				if !reflect.DeepEqual(raw, tt.raw) {
334					t.Fatalf("unexpected RawSockaddrL2TPIP:\n got: %#v\nwant: %#v", raw, tt.raw)
335				}
336			}
337		})
338	}
339}
340
341func TestSockaddrL2TPIP6_sockaddr(t *testing.T) {
342	tests := []struct {
343		name string
344		sa   *SockaddrL2TPIP6
345		raw  *RawSockaddrL2TPIP6
346		err  error
347	}{
348		{
349			name: "L2TPIP6",
350			sa: &SockaddrL2TPIP6{
351				Addr: [16]byte{
352					0x20, 0x01, 0x0d, 0xb8,
353					0x85, 0xa3, 0x00, 0x00,
354					0x00, 0x00, 0x8a, 0x2e,
355					0x03, 0x70, 0x73, 0x34,
356				},
357				ZoneId: 90210,
358				ConnId: 0x1234abcd,
359			},
360			raw: &RawSockaddrL2TPIP6{
361				Family: AF_INET6,
362				Addr: [16]byte{
363					0x20, 0x01, 0x0d, 0xb8,
364					0x85, 0xa3, 0x00, 0x00,
365					0x00, 0x00, 0x8a, 0x2e,
366					0x03, 0x70, 0x73, 0x34,
367				},
368				Scope_id: 90210,
369				Conn_id:  0x1234abcd,
370			},
371		},
372	}
373
374	for _, tt := range tests {
375		t.Run(tt.name, func(t *testing.T) {
376			out, l, err := tt.sa.sockaddr()
377			if err != tt.err {
378				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
379			}
380
381			// Must be 0 on error or a fixed size otherwise.
382			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrL2TPIP6) {
383				t.Fatalf("unexpected Socklen: %d", l)
384			}
385
386			if out != nil {
387				raw := (*RawSockaddrL2TPIP6)(out)
388				if !reflect.DeepEqual(raw, tt.raw) {
389					t.Fatalf("unexpected RawSockaddrL2TPIP6:\n got: %#v\nwant: %#v", raw, tt.raw)
390				}
391			}
392		})
393	}
394}
395
396func TestSockaddrUnix_sockaddr(t *testing.T) {
397	tests := []struct {
398		name string
399		sa   *SockaddrUnix
400		raw  *RawSockaddrUnix
401		slen _Socklen
402		err  error
403	}{
404		{
405			name: "unnamed",
406			sa:   &SockaddrUnix{},
407			raw: &RawSockaddrUnix{
408				Family: AF_UNIX,
409			},
410			slen: 2, // family (uint16)
411		},
412		{
413			name: "abstract",
414			sa: &SockaddrUnix{
415				Name: "@",
416			},
417			raw: &RawSockaddrUnix{
418				Family: AF_UNIX,
419			},
420			slen: 3, // family (uint16) + NULL
421		},
422		{
423			name: "named",
424			sa: &SockaddrUnix{
425				Name: "gopher",
426			},
427			raw: &RawSockaddrUnix{
428				Family: AF_UNIX,
429				Path:   [108]int8{'g', 'o', 'p', 'h', 'e', 'r'},
430			},
431			slen: _Socklen(3 + len("gopher")), // family (uint16) + len(gopher)
432		},
433		{
434			name: "named too long",
435			sa: &SockaddrUnix{
436				Name: strings.Repeat("A", 108),
437			},
438			err: EINVAL,
439		},
440	}
441
442	for _, tt := range tests {
443		t.Run(tt.name, func(t *testing.T) {
444			out, l, err := tt.sa.sockaddr()
445			if err != tt.err {
446				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
447			}
448
449			if l != tt.slen {
450				t.Fatalf("unexpected Socklen: %d, want %d", l, tt.slen)
451			}
452			if out == nil {
453				// No pointer to cast, return early.
454				return
455			}
456
457			raw := (*RawSockaddrUnix)(out)
458			if !reflect.DeepEqual(raw, tt.raw) {
459				t.Fatalf("unexpected RawSockaddrUnix:\n got: %#v\nwant: %#v", raw, tt.raw)
460			}
461		})
462	}
463}
464
465// These helpers explicitly copy the contents of in into out to produce
466// the correct sockaddr structure, without relying on unsafe casting to
467// a type of a larger size.
468func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny {
469	var out RawSockaddrAny
470	copy(
471		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
472		(*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:],
473	)
474	return &out
475}
476
477func sockaddrL2TPIPToAny(in RawSockaddrL2TPIP) *RawSockaddrAny {
478	var out RawSockaddrAny
479	copy(
480		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
481		(*(*[SizeofSockaddrL2TPIP]byte)(unsafe.Pointer(&in)))[:],
482	)
483	return &out
484}
485
486func sockaddrL2TPIP6ToAny(in RawSockaddrL2TPIP6) *RawSockaddrAny {
487	var out RawSockaddrAny
488	copy(
489		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
490		(*(*[SizeofSockaddrL2TPIP6]byte)(unsafe.Pointer(&in)))[:],
491	)
492	return &out
493}
494
495func sockaddrUnixToAny(in RawSockaddrUnix) *RawSockaddrAny {
496	var out RawSockaddrAny
497
498	// Explicitly copy the contents of in into out to produce the correct
499	// sockaddr structure, without relying on unsafe casting to a type of a
500	// larger size.
501	copy(
502		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
503		(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
504	)
505
506	return &out
507}
508