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  }