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