1
// Copyright 2022-2023 The Inspektor Gadget authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
27
"golang.org/x/sys/unix"
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"
35
func TestBindTracerCreate(t *testing.T) {
38
utilstest.RequireRoot(t)
40
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
42
t.Fatal("Returned tracer was nil")
46
func TestBindTracerStopIdempotent(t *testing.T) {
49
utilstest.RequireRoot(t)
51
tracer := createTracer(t, &tracer.Config{}, func(*types.Event) {})
53
// Check that a double stop doesn't cause issues
64
func TestBindTracer(t *testing.T) {
67
utilstest.RequireRoot(t)
69
const unprivilegedUID = int(1435)
70
const unprivilegedGID = int(6789)
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)
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{}
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 {
87
Event: eventtypes.Event{
88
Type: eventtypes.NORMAL,
90
Pid: uint32(info.Pid),
97
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
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),
107
generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0),
108
validateEvent: utilstest.ExpectNoEvent[types.Event, uint16],
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),
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 {
119
Event: eventtypes.Event{
120
Type: eventtypes.NORMAL,
122
Pid: uint32(info.Pid),
129
WithMountNsID: eventtypes.WithMountNsID{MountNsID: info.MountNsID},
134
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
135
return &tracer.Config{
136
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
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")
150
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
151
return &tracer.Config{
152
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
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")
166
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
167
return &tracer.Config{
168
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
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")
182
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
183
return &tracer.Config{
184
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
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")
198
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
199
return &tracer.Config{
200
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
203
generateEvent: func() (uint16, error) {
206
level: unix.SOL_SOCKET,
207
opt: unix.SO_BINDTOIFINDEX,
208
value: 1, // "lo" iface
212
return bindSocketWithOpts("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0, opts)
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))
219
utilstest.Equal(t, "lo", events[0].Interface, "Captured event has bad Interface")
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
229
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
239
"pid_filter_no_match": {
240
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
241
return &tracer.Config{
243
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
246
generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0),
247
validateEvent: utilstest.ExpectNoEvent[types.Event, uint16],
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},
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))
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},
270
generateEvent: bindSocketFn("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 5556),
271
validateEvent: utilstest.ExpectNoEvent[types.Event, uint16],
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},
280
generateEvent: func() (uint16, error) {
281
// Generate 5 events but only 4 should be captured
282
ports := []uint16{5555, 5556, 5557, 5558, 5559}
284
for _, port := range ports {
285
_, err = bindSocket("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, int(port))
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))
299
"ignore_errors_false": {
300
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
301
return &tracer.Config{
302
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
313
"ignore_errors_true": {
314
getTracerConfig: func(info *utilstest.RunnerInfo) *tracer.Config {
315
return &tracer.Config{
316
MountnsMap: utilstest.CreateMntNsFilterMap(t, info.MountNsID),
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))
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),
333
runnerConfig: &utilstest.RunnerConfig{
334
Uid: unprivilegedUID,
335
Gid: unprivilegedGID,
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")
343
utilstest.Equal(t, uint32(info.Uid), events[0].Uid,
346
utilstest.Equal(t, uint32(info.Gid), events[0].Gid,
353
t.Run(name, func(t *testing.T) {
356
events := []types.Event{}
357
eventCallback := func(event *types.Event) {
361
events = append(events, *event)
364
runner := utilstest.NewRunnerWithTest(t, test.runnerConfig)
366
createTracer(t, test.getTracerConfig(runner.Info), eventCallback)
370
utilstest.RunWithRunner(t, runner, func() error {
372
port, err = test.generateEvent()
376
// Give some time for the tracer to capture the events
377
time.Sleep(100 * time.Millisecond)
379
test.validateEvent(t, runner.Info, port, events)
384
func TestBindTracerOpts(t *testing.T) {
387
utilstest.RequireRoot(t)
389
type testDefinition struct {
394
for name, test := range map[string]testDefinition{
397
expectedOpts: ".....",
402
level: unix.SOL_SOCKET,
403
opt: unix.SO_REUSEPORT,
407
expectedOpts: "r....",
412
level: unix.SOL_SOCKET,
413
opt: unix.SO_REUSEADDR,
417
expectedOpts: ".R...",
422
level: unix.IPPROTO_IP,
423
opt: unix.IP_TRANSPARENT,
427
expectedOpts: "...T.",
429
"IP_BIND_ADDRESS_NO_PORT": {
432
level: unix.IPPROTO_IP,
433
opt: unix.IP_BIND_ADDRESS_NO_PORT,
437
expectedOpts: "..N..",
442
level: unix.IPPROTO_IP,
443
opt: unix.IP_FREEBIND,
447
expectedOpts: "....F",
449
"SO_REUSEPORT|SO_REUSEADDR": {
452
level: unix.SOL_SOCKET,
453
opt: unix.SO_REUSEPORT,
457
level: unix.SOL_SOCKET,
458
opt: unix.SO_REUSEADDR,
462
expectedOpts: "rR...",
464
"IP_TRANSPARENT|IP_BIND_ADDRESS_NO_PORT|IP_FREEBIND": {
467
level: unix.IPPROTO_IP,
468
opt: unix.IP_TRANSPARENT,
472
level: unix.IPPROTO_IP,
473
opt: unix.IP_BIND_ADDRESS_NO_PORT,
477
level: unix.IPPROTO_IP,
478
opt: unix.IP_FREEBIND,
482
expectedOpts: "..NTF",
487
t.Run(name, func(t *testing.T) {
490
events := []types.Event{}
491
eventCallback := func(event *types.Event) {
492
events = append(events, *event)
495
runner := utilstest.NewRunnerWithTest(t, nil)
497
tracerConfig := &tracer.Config{
498
MountnsMap: utilstest.CreateMntNsFilterMap(t, runner.Info.MountNsID),
501
createTracer(t, tracerConfig, eventCallback)
503
utilstest.RunWithRunner(t, runner, func() error {
504
_, err := bindSocketWithOpts("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0, test.opts)
508
// Give some time for the tracer to capture the events
509
time.Sleep(100 * time.Millisecond)
511
if len(events) != 1 {
512
t.Fatalf("Wrong number of events received %d, expected 1", len(events))
515
utilstest.Equal(t, test.expectedOpts, events[0].Options,
516
"Captured event has wrong options")
521
func TestBindTracerMultipleMntNsIDsFilter(t *testing.T) {
524
utilstest.RequireRoot(t)
526
events := []types.Event{}
527
eventCallback := func(event *types.Event) {
528
events = append(events, *event)
531
// struct with only fields we want to check on this test
532
type expectedEvent struct {
538
runners := make([]*utilstest.Runner, n)
539
expectedEvents := make([]expectedEvent, n)
540
mntNsIDs := make([]uint64, n)
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
548
// Filter events from all runners but last one
549
config := &tracer.Config{
550
MountnsMap: utilstest.CreateMntNsFilterMap(t, mntNsIDs[:n-1]...),
553
createTracer(t, config, eventCallback)
555
for i := 0; i < n; i++ {
556
utilstest.RunWithRunner(t, runners[i], func() error {
558
expectedEvents[i].port, err = bindSocket("127.0.0.1", unix.AF_INET, unix.SOCK_STREAM, 0)
563
// Give some time for the tracer to capture the events
564
time.Sleep(100 * time.Millisecond)
566
if len(events) != n-1 {
567
t.Fatalf("%d events were expected, %d found", n-1, len(events))
570
// Pop last event since it shouldn't have been captured
571
expectedEvents = expectedEvents[:n-1]
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
577
sort.Slice(events, func(i, j int) bool {
578
return events[i].WithMountNsID.MountNsID < events[j].WithMountNsID.MountNsID
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")
585
utilstest.Equal(t, expectedEvents[i].port, events[i].Port,
586
"Captured event has bad Port")
591
t *testing.T, config *tracer.Config, callback func(*types.Event),
595
tracer, err := tracer.NewTracer(config, nil, callback)
597
t.Fatalf("Error creating tracer: %s", err)
599
t.Cleanup(tracer.Stop)
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)
612
func bindSocket(ipStr string, domain, typ int, port int) (uint16, error) {
613
return bindSocketWithOpts(ipStr, domain, typ, port, nil)
616
func bindSocketWithOpts(ipStr string, domain, typ int, port int, opts []sockOpt) (uint16, error) {
617
fd, err := unix.Socket(domain, typ, 0)
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)
631
ip := net.ParseIP(ipStr)
634
sa4 := &unix.SockaddrInet4{Port: port}
635
copy(sa4.Addr[:], ip.To4())
637
} else if ip.To16() != nil {
638
sa6 := &unix.SockaddrInet6{Port: port}
639
copy(sa6.Addr[:], ip.To16())
642
return 0, fmt.Errorf("invalid IP address")
645
if err := unix.Bind(fd, sa); err != nil {
646
return 0, fmt.Errorf("Bind: %w", err)
649
sa2, err := unix.Getsockname(fd)
651
return 0, fmt.Errorf("Getsockname: %w", err)
655
return uint16(sa2.(*unix.SockaddrInet4).Port), nil
656
} else if ip.To16() != nil {
657
return uint16(sa2.(*unix.SockaddrInet6).Port), nil
659
return 0, fmt.Errorf("invalid IP address")
663
func bindSocketError() (uint16, error) {
664
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
670
if err := unix.Bind(fd, &unix.SockaddrInet4{}); err != nil {
671
return 0, fmt.Errorf("Bind: %w", err)
674
if err := unix.Bind(fd, &unix.SockaddrInet4{}); err == nil {
675
return 0, fmt.Errorf("Bind should have returned error")