github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/pkg/ebpftracer/tracer_test.go (about) 1 package ebpftracer_test 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "log/slog" 8 "os" 9 "testing" 10 "time" 11 12 castaipb "github.com/castai/kvisor/api/v1/runtime" 13 "github.com/castai/kvisor/pkg/cgroup" 14 "github.com/castai/kvisor/pkg/containers" 15 "github.com/castai/kvisor/pkg/ebpftracer" 16 "github.com/castai/kvisor/pkg/ebpftracer/events" 17 "github.com/castai/kvisor/pkg/ebpftracer/signature" 18 "github.com/castai/kvisor/pkg/ebpftracer/types" 19 "github.com/castai/kvisor/pkg/logging" 20 "github.com/castai/kvisor/pkg/proc" 21 "github.com/davecgh/go-spew/spew" 22 ) 23 24 func TestTracer(t *testing.T) { 25 if testing.Short() { 26 t.Skip() 27 } 28 29 ctx := context.Background() 30 31 log := logging.New(&logging.Config{ 32 Level: slog.LevelDebug, 33 }) 34 35 procHandle := proc.New() 36 pidNS, err := procHandle.GetCurrentPIDNSID() 37 if err != nil { 38 t.Fatal(err) 39 } 40 41 tr := ebpftracer.New(log, ebpftracer.Config{ 42 //BTFPath: fmt.Sprintf("./testdata/5.10.0-0.deb10.24-cloud-%s.btf", runtime.GOARCH), 43 EventsPerCPUBuffer: os.Getpagesize() * 64, 44 EventsOutputChanSize: 10000, 45 DefaultCgroupsVersion: "V2", 46 DebugEnabled: true, 47 AllowAnyEvent: true, 48 ContainerClient: &ebpftracer.MockContainerClient{ 49 ContainerGetter: func(ctx context.Context, cgroupID uint64) (*containers.Container, error) { 50 dummyContainerID := fmt.Sprint(cgroupID) 51 return &containers.Container{ 52 ID: dummyContainerID, 53 Name: "dummy-container", 54 CgroupID: cgroupID, 55 PodNamespace: "default", 56 PodUID: dummyContainerID, 57 PodName: "dummy-container-" + dummyContainerID, 58 Cgroup: &cgroup.Cgroup{ 59 Id: cgroupID, 60 Version: cgroup.V2, 61 ContainerRuntime: cgroup.ContainerdRuntime, 62 ContainerID: dummyContainerID, 63 Path: "", 64 }, 65 PIDs: []uint32{}, 66 }, nil 67 }, 68 }, 69 CgroupClient: &ebpftracer.MockCgroupClient{}, 70 MountNamespacePIDStore: getInitializedMountNamespacePIDStore(procHandle), 71 HomePIDNS: pidNS, 72 NetflowSampleSubmitIntervalSeconds: 1, 73 }) 74 defer tr.Close() 75 76 if err := tr.Load(); err != nil { 77 t.Fatalf("load: %v", err) 78 } 79 80 errc := make(chan error, 1) 81 go func() { 82 errc <- tr.Run(ctx) 83 }() 84 85 signatures, err := signature.DefaultSignatures(log, signature.DefaultSignatureConfig{ 86 TTYDetectedSignatureEnabled: true, 87 SOCKS5DetectedSignatureEnabled: true, 88 }) 89 if err != nil { 90 t.Fatalf("error while configuring signatures: %v", err) 91 } 92 93 signatureEngine := signature.NewEngine(signatures, log, signature.SignatureEngineConfig{ 94 InputChanSize: 100, 95 OutputChanSize: 100, 96 }) 97 sigerr := make(chan error, 1) 98 go func() { 99 sigerr <- signatureEngine.Run(ctx) 100 }() 101 102 policy := &ebpftracer.Policy{ 103 Events: []*ebpftracer.EventPolicy{ 104 {ID: events.NetFlowBase}, 105 //{ID: events.SecuritySocketConnect}, 106 //{ID: events.SockSetState}, 107 //{ID: events.NetPacketDNSBase}, 108 }, 109 } 110 111 if err := tr.ApplyPolicy(policy); err != nil { 112 t.Fatalf("apply policy: %v", err) 113 } 114 115 //go printSyscallStatsLoop(ctx, tr, log) 116 117 for { 118 select { 119 case <-ctx.Done(): 120 return 121 case err := <-sigerr: 122 t.Fatal(err) 123 case s := <-signatureEngine.Events(): 124 printSignatureEvent(s) 125 case e := <-tr.Events(): 126 printEvent(tr, e) 127 case e := <-tr.NetflowEvents(): 128 printEvent(tr, e) 129 case err := <-errc: 130 if err != nil { 131 t.Fatal(err) 132 } 133 } 134 } 135 } 136 137 func printEvent(tr *ebpftracer.Tracer, e *types.Event) { 138 eventName := tr.GetEventName(e.Context.EventID) 139 fmt.Printf( 140 "ts=%d cgroup=%d, pid=%d, proc=%s, event=%s, args=%+v", 141 e.Context.Ts, 142 e.Context.CgroupID, 143 e.Context.HostPid, 144 string(bytes.TrimRight(e.Context.Comm[:], "\x00")), 145 eventName, 146 e.Args, 147 ) 148 if e.Context.EventID == events.NetFlowBase { 149 fmt.Printf(" ret=%d direction=%s, type=%s, initiator=%v", e.Context.Retval, e.Context.GetFlowDirection(), e.Context.GetNetflowType(), e.Context.IsSourceInitiator()) 150 } 151 fmt.Print("\n") 152 } 153 154 func printSignatureEvent(e *castaipb.Event) { 155 fmt.Printf( 156 "cgroup=%d, pid=%d, proc=%s, event=%s,args=%+v", 157 e.CgroupId, 158 e.HostPid, 159 e.ProcessName, 160 e.EventType, 161 e.Data, 162 ) 163 fmt.Print("\n") 164 } 165 166 func getInitializedMountNamespacePIDStore(procHandler *proc.Proc) *types.PIDsPerNamespace { 167 mountNamespacePIDStore, err := types.NewPIDsPerNamespaceCache(2048, 5) 168 if err != nil { 169 panic(err) 170 } 171 172 processes, err := procHandler.LoadMountNSOldestProcesses() 173 if err != nil { 174 panic(err) 175 } 176 177 for ns, pid := range processes { 178 mountNamespacePIDStore.ForceAddToBucket(ns, pid) 179 } 180 181 return mountNamespacePIDStore 182 } 183 184 func printSyscallStatsLoop(ctx context.Context, tr *ebpftracer.Tracer, log *logging.Logger) { 185 for { 186 select { 187 case <-ctx.Done(): 188 return 189 case <-time.After(5 * time.Second): 190 stats, err := tr.ReadSyscallStats() 191 if err != nil { 192 log.Errorf("reading syscall stats: %v", err) 193 continue 194 } 195 spew.Dump(stats) 196 } 197 } 198 }