github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/bind/tracer/tracer_test.go (about) 1 // Copyright 2022-2023 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux 16 // +build linux 17 18 package tracer_test 19 20 import ( 21 "fmt" 22 "net" 23 "sort" 24 "testing" 25 "time" 26 27 "golang.org/x/sys/unix" 28 29 utilstest "github.com/inspektor-gadget/inspektor-gadget/internal/test" 30 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/bind/tracer" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/bind/types" 32 eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 33 ) 34 35 func TestBindTracerCreate(t *testing.T) { 36 t.Parallel() 37 38 utilstest.RequireRoot(t) 39 40 tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {}) 41 if tracer == nil { 42 t.Fatal("Returned tracer was nil") 43 } 44 } 45 46 func TestBindTracerStopIdempotent(t *testing.T) { 47 t.Parallel() 48 49 utilstest.RequireRoot(t) 50 51 tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {}) 52 53 // Check that a double stop doesn't cause issues 54 tracer.Stop() 55 tracer.Stop() 56 } 57 58 type sockOpt struct { 59 level int 60 opt int 61 value int 62 } 63 64 func TestBindTracer(t *testing.T) { 65 t.Parallel() 66 67 utilstest.RequireRoot(t) 68 69 const unprivilegedUID = int(1435) 70 const unprivilegedGID = int(6789) 71 72 type testDefinition struct { 73 getTracerConfig func(info *utilstest.RunnerInfo) *tracer.Config 74 runnerConfig *utilstest.RunnerConfig 75 generateEvent func() (uint16, error) 76 validateEvent func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) 77 } 78 79 for name, test := range map[string]testDefinition{ 80 "captures_all_events_with_no_filters_configured": { 81 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 82 return &tracer.Config{} 83 }, 84 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 85 validateEvent: utilstest.ExpectAtLeastOneEvent(func(info *utilstest.RunnerInfo, port uint16) *types.Event { 86 return &types.Event{ 87 Event: eventtypes.Event{ 88 Type: eventtypes.NORMAL, 89 }, 90 Pid: uint32(info.Pid), 91 Comm: info.Comm, 92 Protocol: "TCP", 93 Addr: "127.0.0.1", 94 Port: port, 95 Options: ".....", 96 Interface: "", 97 WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID}, 98 } 99 }), 100 }, 101 "captures_no_events_with_no_matching_filter": { 102 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 103 return &tracer.Config{ 104 MountnsMap: utilstest.CreateMntNsFilterMap(t, 0), 105 } 106 }, 107 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 108 validateEvent: utilstest.ExpectNoEvent[types.Event, uint16], 109 }, 110 "captures_events_with_matching_filter": { 111 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 112 return &tracer.Config{ 113 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 114 } 115 }, 116 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 117 validateEvent: utilstest.ExpectOneEvent(func(info *utilstest.RunnerInfo, port uint16) *types.Event { 118 return &types.Event{ 119 Event: eventtypes.Event{ 120 Type: eventtypes.NORMAL, 121 }, 122 Pid: uint32(info.Pid), 123 Comm: info.Comm, 124 Protocol: "TCP", 125 Addr: "127.0.0.1", 126 Port: port, 127 Options: ".....", 128 Interface: "", 129 WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID}, 130 } 131 }), 132 }, 133 "tcp4": { 134 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 135 return &tracer.Config{ 136 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 137 } 138 }, 139 generateEvent: bindSocketFn("127.0.0.2", unix.AF_INET, unix.SOCK_STREAM, 0), 140 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 141 if len(events) != 1 { 142 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 143 } 144 145 utilstest.Equal(t, "127.0.0.2", events[0].Addr, "Captured event has bad Addr") 146 utilstest.Equal(t, "TCP", events[0].Protocol, "Captured event has bad Protocol") 147 }, 148 }, 149 "tcp6": { 150 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 151 return &tracer.Config{ 152 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 153 } 154 }, 155 generateEvent: bindSocketFn("::", unix.AF_INET6, unix.SOCK_STREAM, 0), 156 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 157 if len(events) != 1 { 158 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 159 } 160 161 utilstest.Equal(t, "::", events[0].Addr, "Captured event has bad Addr") 162 utilstest.Equal(t, "TCP", events[0].Protocol, "Captured event has bad Protocol") 163 }, 164 }, 165 "udp4": { 166 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 167 return &tracer.Config{ 168 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 169 } 170 }, 171 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_DGRAM, 0), 172 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 173 if len(events) != 1 { 174 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 175 } 176 177 utilstest.Equal(t, "127.0.0.1", events[0].Addr, "Captured event has bad Addr") 178 utilstest.Equal(t, "UDP", events[0].Protocol, "Captured event has bad Protocol") 179 }, 180 }, 181 "udp6": { 182 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 183 return &tracer.Config{ 184 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 185 } 186 }, 187 generateEvent: bindSocketFn("::", unix.AF_INET6, unix.SOCK_DGRAM, 0), 188 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 189 if len(events) != 1 { 190 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 191 } 192 193 utilstest.Equal(t, "::", events[0].Addr, "Captured event has bad Addr") 194 utilstest.Equal(t, "UDP", events[0].Protocol, "Captured event has bad Protocol") 195 }, 196 }, 197 "interface": { 198 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 199 return &tracer.Config{ 200 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 201 } 202 }, 203 generateEvent: func() (uint16, error) { 204 opts := []sockOpt{ 205 { 206 level: unix.SOL_SOCKET, 207 opt: unix.SO_BINDTOIFINDEX, 208 value: 1, // "lo" iface 209 }, 210 } 211 212 return bindSocketWithOpts("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0, opts) 213 }, 214 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 215 if len(events) != 1 { 216 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 217 } 218 219 utilstest.Equal(t, "lo", events[0].Interface, "Captured event has bad Interface") 220 }, 221 }, 222 "pid_filter_match": { 223 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 224 return &tracer.Config{ 225 TargetPid: int32(info.Pid), 226 // It's difficult to only test the PID filter since other 227 // test events are generated from the same PID on this 228 // test suite 229 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 230 } 231 }, 232 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 233 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 234 if len(events) != 1 { 235 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 236 } 237 }, 238 }, 239 "pid_filter_no_match": { 240 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 241 return &tracer.Config{ 242 TargetPid: int32(1), 243 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 244 } 245 }, 246 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 247 validateEvent: utilstest.ExpectNoEvent[types.Event, uint16], 248 }, 249 "target_ports_filter_match": { 250 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 251 return &tracer.Config{ 252 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 253 TargetPorts: []uint16{5555}, 254 } 255 }, 256 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 5555), 257 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 258 if len(events) != 1 { 259 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 260 } 261 }, 262 }, 263 "target_ports_filter_no_match": { 264 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 265 return &tracer.Config{ 266 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 267 TargetPorts: []uint16{5555}, 268 } 269 }, 270 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 5556), 271 validateEvent: utilstest.ExpectNoEvent[types.Event, uint16], 272 }, 273 "target_ports_filter_multiple_ports": { 274 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 275 return &tracer.Config{ 276 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 277 TargetPorts: []uint16{5555, 5556, 5557, 5558}, 278 } 279 }, 280 generateEvent: func() (uint16, error) { 281 // Generate 5 events but only 4 should be captured 282 ports := []uint16{5555, 5556, 5557, 5558, 5559} 283 var err error 284 for _, port := range ports { 285 _, err = bindSocket("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, int(port)) 286 if err != nil { 287 return 0, err 288 } 289 } 290 291 return 0, nil 292 }, 293 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 294 if len(events) != 4 { 295 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 296 } 297 }, 298 }, 299 "ignore_errors_false": { 300 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 301 return &tracer.Config{ 302 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 303 IgnoreErrors: false, 304 } 305 }, 306 generateEvent: bindSocketError, 307 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 308 if len(events) != 2 { 309 t.Fatalf("Wrong number of events received %d, expected 2", len(events)) 310 } 311 }, 312 }, 313 "ignore_errors_true": { 314 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 315 return &tracer.Config{ 316 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 317 IgnoreErrors: true, 318 } 319 }, 320 generateEvent: bindSocketError, 321 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, port uint16, events []types.Event) { 322 if len(events) != 1 { 323 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 324 } 325 }, 326 }, 327 "event_has_UID_and_GID_of_user_generating_event": { 328 getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config { 329 return &tracer.Config{ 330 MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID), 331 } 332 }, 333 runnerConfig: &utilstest.RunnerConfig{ 334 Uid: unprivilegedUID, 335 Gid: unprivilegedGID, 336 }, 337 generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0), 338 validateEvent: func(t *testing.T, info *utilstest.RunnerInfo, _ uint16, events []types.Event) { 339 if len(events) != 1 { 340 t.Fatalf("One event expected") 341 } 342 343 utilstest.Equal(t, uint32(info.Uid), events[0].Uid, 344 "Event has bad UID") 345 346 utilstest.Equal(t, uint32(info.Gid), events[0].Gid, 347 "Event has bad GID") 348 }, 349 }, 350 } { 351 test := test 352 353 t.Run(name, func(t *testing.T) { 354 t.Parallel() 355 356 events := []types.Event{} 357 eventCallback := func(event *types.Event) { 358 // normalize 359 event.Timestamp = 0 360 361 events = append(events, *event) 362 } 363 364 runner := utilstest.NewRunnerWithTest(t, test.runnerConfig) 365 366 createTracer(t, test.getTracerConfig(runner.Info), eventCallback) 367 368 var port uint16 369 370 utilstest.RunWithRunner(t, runner, func() error { 371 var err error 372 port, err = test.generateEvent() 373 return err 374 }) 375 376 // Give some time for the tracer to capture the events 377 time.Sleep(100 * time.Millisecond) 378 379 test.validateEvent(t, runner.Info, port, events) 380 }) 381 } 382 } 383 384 func TestBindTracerOpts(t *testing.T) { 385 t.Parallel() 386 387 utilstest.RequireRoot(t) 388 389 type testDefinition struct { 390 opts []sockOpt 391 expectedOpts string 392 } 393 394 for name, test := range map[string]testDefinition{ 395 "no_options": { 396 opts: nil, 397 expectedOpts: ".....", 398 }, 399 "SO_REUSEPORT": { 400 opts: []sockOpt{ 401 { 402 level: unix.SOL_SOCKET, 403 opt: unix.SO_REUSEPORT, 404 value: 1, 405 }, 406 }, 407 expectedOpts: "r....", 408 }, 409 "SO_REUSEADDR": { 410 opts: []sockOpt{ 411 { 412 level: unix.SOL_SOCKET, 413 opt: unix.SO_REUSEADDR, 414 value: 1, 415 }, 416 }, 417 expectedOpts: ".R...", 418 }, 419 "IP_TRANSPARENT": { 420 opts: []sockOpt{ 421 { 422 level: unix.IPPROTO_IP, 423 opt: unix.IP_TRANSPARENT, 424 value: 1, 425 }, 426 }, 427 expectedOpts: "...T.", 428 }, 429 "IP_BIND_ADDRESS_NO_PORT": { 430 opts: []sockOpt{ 431 { 432 level: unix.IPPROTO_IP, 433 opt: unix.IP_BIND_ADDRESS_NO_PORT, 434 value: 1, 435 }, 436 }, 437 expectedOpts: "..N..", 438 }, 439 "IP_FREEBIND": { 440 opts: []sockOpt{ 441 { 442 level: unix.IPPROTO_IP, 443 opt: unix.IP_FREEBIND, 444 value: 1, 445 }, 446 }, 447 expectedOpts: "....F", 448 }, 449 "SO_REUSEPORT|SO_REUSEADDR": { 450 opts: []sockOpt{ 451 { 452 level: unix.SOL_SOCKET, 453 opt: unix.SO_REUSEPORT, 454 value: 1, 455 }, 456 { 457 level: unix.SOL_SOCKET, 458 opt: unix.SO_REUSEADDR, 459 value: 1, 460 }, 461 }, 462 expectedOpts: "rR...", 463 }, 464 "IP_TRANSPARENT|IP_BIND_ADDRESS_NO_PORT|IP_FREEBIND": { 465 opts: []sockOpt{ 466 { 467 level: unix.IPPROTO_IP, 468 opt: unix.IP_TRANSPARENT, 469 value: 1, 470 }, 471 { 472 level: unix.IPPROTO_IP, 473 opt: unix.IP_BIND_ADDRESS_NO_PORT, 474 value: 1, 475 }, 476 { 477 level: unix.IPPROTO_IP, 478 opt: unix.IP_FREEBIND, 479 value: 1, 480 }, 481 }, 482 expectedOpts: "..NTF", 483 }, 484 } { 485 test := test 486 487 t.Run(name, func(t *testing.T) { 488 t.Parallel() 489 490 events := []types.Event{} 491 eventCallback := func(event *types.Event) { 492 events = append(events, *event) 493 } 494 495 runner := utilstest.NewRunnerWithTest(t, nil) 496 497 tracerConfig := &tracer.Config{ 498 MountnsMap: utilstest.CreateMntNsFilterMap(t, runner.Info.MountNsID), 499 } 500 501 createTracer(t, tracerConfig, eventCallback) 502 503 utilstest.RunWithRunner(t, runner, func() error { 504 _, err := bindSocketWithOpts("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0, test.opts) 505 return err 506 }) 507 508 // Give some time for the tracer to capture the events 509 time.Sleep(100 * time.Millisecond) 510 511 if len(events) != 1 { 512 t.Fatalf("Wrong number of events received %d, expected 1", len(events)) 513 } 514 515 utilstest.Equal(t, test.expectedOpts, events[0].Options, 516 "Captured event has wrong options") 517 }) 518 } 519 } 520 521 func TestBindTracerMultipleMntNsIDsFilter(t *testing.T) { 522 t.Parallel() 523 524 utilstest.RequireRoot(t) 525 526 events := []types.Event{} 527 eventCallback := func(event *types.Event) { 528 events = append(events, *event) 529 } 530 531 // struct with only fields we want to check on this test 532 type expectedEvent struct { 533 mntNsID uint64 534 port uint16 535 } 536 537 const n int = 5 538 runners := make([]*utilstest.Runner, n) 539 expectedEvents := make([]expectedEvent, n) 540 mntNsIDs := make([]uint64, n) 541 542 for i := 0; i < n; i++ { 543 runners[i] = utilstest.NewRunnerWithTest(t, nil) 544 mntNsIDs[i] = runners[i].Info.MountNsID 545 expectedEvents[i].mntNsID = runners[i].Info.MountNsID 546 } 547 548 // Filter events from all runners but last one 549 config := &tracer.Config{ 550 MountnsMap: utilstest.CreateMntNsFilterMap(t, mntNsIDs[:n-1]...), 551 } 552 553 createTracer(t, config, eventCallback) 554 555 for i := 0; i < n; i++ { 556 utilstest.RunWithRunner(t, runners[i], func() error { 557 var err error 558 expectedEvents[i].port, err = bindSocket("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0) 559 return err 560 }) 561 } 562 563 // Give some time for the tracer to capture the events 564 time.Sleep(100 * time.Millisecond) 565 566 if len(events) != n-1 { 567 t.Fatalf("%d events were expected, %d found", n-1, len(events)) 568 } 569 570 // Pop last event since it shouldn't have been captured 571 expectedEvents = expectedEvents[:n-1] 572 573 // Order of events is not guaranteed, then we need to sort before comparing 574 sort.Slice(expectedEvents, func(i, j int) bool { 575 return expectedEvents[i].mntNsID < expectedEvents[j].mntNsID 576 }) 577 sort.Slice(events, func(i, j int) bool { 578 return events[i].WithMountNsID.MountNsID < events[j].WithMountNsID.MountNsID 579 }) 580 581 for i := 0; i < n-1; i++ { 582 utilstest.Equal(t, expectedEvents[i].mntNsID, events[i].WithMountNsID.MountNsID, 583 "Captured event has bad MountNsID") 584 585 utilstest.Equal(t, expectedEvents[i].port, events[i].Port, 586 "Captured event has bad Port") 587 } 588 } 589 590 func createTracer( 591 t *testing.T, config *tracer.Config, callback func(*types.Event), 592 ) *tracer.Tracer { 593 t.Helper() 594 595 tracer, err := tracer.NewTracer(config, nil, callback) 596 if err != nil { 597 t.Fatalf("Error creating tracer: %s", err) 598 } 599 t.Cleanup(tracer.Stop) 600 601 return tracer 602 } 603 604 // bindSocketFn returns a function that creates a socket, binds it and 605 // returns the port the socket was bound to. 606 func bindSocketFn(ipStr string, domain, typ int, port int) func() (uint16, error) { 607 return func() (uint16, error) { 608 return bindSocket(ipStr, domain, typ, port) 609 } 610 } 611 612 func bindSocket(ipStr string, domain, typ int, port int) (uint16, error) { 613 return bindSocketWithOpts(ipStr, domain, typ, port, nil) 614 } 615 616 func bindSocketWithOpts(ipStr string, domain, typ int, port int, opts []sockOpt) (uint16, error) { 617 fd, err := unix.Socket(domain, typ, 0) 618 if err != nil { 619 return 0, err 620 } 621 defer unix.Close(fd) 622 623 for _, opt := range opts { 624 if err := unix.SetsockoptInt(fd, opt.level, opt.opt, opt.value); err != nil { 625 return 0, fmt.Errorf("SetsockoptInt: %w", err) 626 } 627 } 628 629 var sa unix.Sockaddr 630 631 ip := net.ParseIP(ipStr) 632 633 if ip.To4() != nil { 634 sa4 := &unix.SockaddrInet4{Port: port} 635 copy(sa4.Addr[:], ip.To4()) 636 sa = sa4 637 } else if ip.To16() != nil { 638 sa6 := &unix.SockaddrInet6{Port: port} 639 copy(sa6.Addr[:], ip.To16()) 640 sa = sa6 641 } else { 642 return 0, fmt.Errorf("invalid IP address") 643 } 644 645 if err := unix.Bind(fd, sa); err != nil { 646 return 0, fmt.Errorf("Bind: %w", err) 647 } 648 649 sa2, err := unix.Getsockname(fd) 650 if err != nil { 651 return 0, fmt.Errorf("Getsockname: %w", err) 652 } 653 654 if ip.To4() != nil { 655 return uint16(sa2.(*unix.SockaddrInet4).Port), nil 656 } else if ip.To16() != nil { 657 return uint16(sa2.(*unix.SockaddrInet6).Port), nil 658 } else { 659 return 0, fmt.Errorf("invalid IP address") 660 } 661 } 662 663 func bindSocketError() (uint16, error) { 664 fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) 665 if err != nil { 666 return 0, err 667 } 668 defer unix.Close(fd) 669 670 if err := unix.Bind(fd, &unix.SockaddrInet4{}); err != nil { 671 return 0, fmt.Errorf("Bind: %w", err) 672 } 673 674 if err := unix.Bind(fd, &unix.SockaddrInet4{}); err == nil { 675 return 0, fmt.Errorf("Bind should have returned error") 676 } 677 678 return 0, nil 679 }