diff --git a/.circleci/config.yml b/.circleci/config.yml index 5b88a2eb..41fcae8d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -208,9 +208,11 @@ jobs: IMG=kindest/node:v1.30.0@sha256:047357ac0cfea04663786a612ba1eaba9702bef25227a794b52890dd8bcd692e sudo docker pull "${IMG}" sudo docker pull alpine:3.18 + sudo docker pull busybox:1 sudo kind create cluster sudo kind load docker-image alpine:3.18 + sudo kind load docker-image busybox:1 sudo kind export kubeconfig - restore_cache: @@ -252,6 +254,11 @@ jobs: command: | sudo bash testdata/run_test_k8s_filter_by_pod.sh + - run: + name: test k8s filter by pod name with multiple containers + command: | + sudo bash testdata/run_test_k8s_filter_by_pod_2.sh + workflows: e2e: jobs: diff --git a/bpf/bpf.go b/bpf/bpf.go index a9f7ddf0..f0caf4b2 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -36,16 +36,17 @@ type BPF struct { } type Options struct { - Pid uint32 - Comm [16]int8 + haveFilter uint8 + pids []uint32 + comm [16]int8 filterComm uint8 - FollowForks uint8 - PcapFilter string - mntnsId uint32 - pidnsId uint32 - netnsId uint32 + followForks uint8 + pcapFilter string + mntnsIds []uint32 + pidnsIds []uint32 + netnsIds []uint32 maxPayloadSize uint32 - KernelTypes *btf.Spec + kernelTypes *btf.Spec } func NewBPF() (*BPF, error) { @@ -75,47 +76,15 @@ func NewBPF() (*BPF, error) { return bf, nil } -func NewOptions(pid uint, comm string, followForks bool, pcapFilter string, - mntnsId uint32, pidnsId uint32, netnsId uint32, maxPayloadSize uint32) Options { - opts := Options{ - Pid: uint32(pid), - mntnsId: mntnsId, - pidnsId: pidnsId, - netnsId: netnsId, - maxPayloadSize: maxPayloadSize, - } - opts.Comm = [16]int8{} - if len(comm) > 0 { - for i, s := range comm { - if i == 15 { - break - } - opts.Comm[i] = int8(s) - } - opts.Comm[15] = '\x00' - opts.filterComm = 1 - } - opts.FollowForks = 0 - if followForks { - opts.FollowForks = 1 - } - opts.PcapFilter = strings.TrimSpace(pcapFilter) - - return opts -} - func (b *BPF) Load(opts Options) error { log.Infof("load with opts: %#v", opts) var err error config := BpfGconfigT{ - FilterPid: opts.Pid, - FilterComm: opts.Comm, + HaveFilter: opts.haveFilter, + FilterFollowForks: opts.followForks, + FilterComm: opts.comm, FilterCommEnable: opts.filterComm, - FilterFollowForks: opts.FollowForks, - FilterMntnsId: opts.mntnsId, - FilterNetnsId: opts.netnsId, - FilterPidnsId: opts.pidnsId, MaxPayloadSize: opts.maxPayloadSize, } if !b.isLegacyKernel { @@ -128,14 +97,14 @@ func (b *BPF) Load(opts Options) error { } } - if opts.PcapFilter != "" { + if opts.pcapFilter != "" { for _, progName := range []string{"tc_ingress", "tc_egress"} { prog, ok := b.spec.Programs[progName] if !ok { return fmt.Errorf("program %s not found", progName) } prog.Instructions, err = elibpcap.Inject( - opts.PcapFilter, + opts.pcapFilter, prog.Instructions, elibpcap.Options{ AtBpf2Bpf: "pcap_filter", @@ -155,7 +124,7 @@ func (b *BPF) Load(opts Options) error { objs := BpfObjectsForLegacyKernel{} if err = b.spec.LoadAndAssign(&objs, &ebpf.CollectionOptions{ Programs: ebpf.ProgramOptions{ - KernelTypes: opts.KernelTypes, + KernelTypes: opts.kernelTypes, LogLevel: ebpf.LogLevelInstruction, LogSize: logSzie, }, @@ -166,7 +135,7 @@ func (b *BPF) Load(opts Options) error { } else { err = b.spec.LoadAndAssign(b.objs, &ebpf.CollectionOptions{ Programs: ebpf.ProgramOptions{ - KernelTypes: opts.KernelTypes, + KernelTypes: opts.kernelTypes, LogLevel: ebpf.LogLevelInstruction, LogSize: logSzie, }, @@ -185,6 +154,9 @@ func (b *BPF) Load(opts Options) error { return fmt.Errorf(": %w", err) } } + if err := b.applyFilters(); err != nil { + return fmt.Errorf(": %w", err) + } return nil } @@ -375,8 +347,8 @@ func (b *BPF) AttachTcHooks(ifindex int, egress, ingress bool) error { return nil } -func (o Options) attachForks() bool { - return o.FollowForks == 1 +func (opts Options) attachForks() bool { + return opts.followForks == 1 } func attachTcHook(ifindex int, prog *ebpf.Program, ingress bool) (func(), error) { @@ -476,3 +448,131 @@ func htons(n uint16) uint16 { b := *(*[2]byte)(unsafe.Pointer(&n)) return binary.BigEndian.Uint16(b[:]) } + +func (b *BPF) applyFilters() error { + value := uint8(0) + opts := b.opts + + log.Infof("start to update FilterPidMap with %+v", opts.pids) + for _, pid := range opts.pids { + pid := pid + if err := b.objs.BpfMaps.FilterPidMap.Update(pid, value, ebpf.UpdateAny); err != nil { + return fmt.Errorf("update FilterPidMap: %w", err) + } + } + + log.Infof("start to update FilterPidnsMap with %+v", opts.pidnsIds) + for _, id := range opts.pidnsIds { + id := id + if err := b.objs.BpfMaps.FilterPidnsMap.Update(id, value, ebpf.UpdateAny); err != nil { + return fmt.Errorf("update FilterPidnsMap: %w", err) + } + } + + log.Infof("start to update FilterMntnsMap with %+v", opts.mntnsIds) + for _, id := range opts.mntnsIds { + id := id + if err := b.objs.BpfMaps.FilterMntnsMap.Update(id, value, ebpf.UpdateAny); err != nil { + return fmt.Errorf("update FilterMntnsMap: %w", err) + } + } + + log.Infof("start to update FilterNetnsMap with %+v", opts.netnsIds) + for _, id := range opts.netnsIds { + id := id + if err := b.objs.BpfMaps.FilterNetnsMap.Update(id, value, ebpf.UpdateAny); err != nil { + return fmt.Errorf("update FilterNetnsMap: %w", err) + } + } + + return nil +} + +func (opts *Options) WithPids(pids []uint) *Options { + for _, id := range pids { + if id == 0 { + continue + } + opts.pids = append(opts.pids, uint32(id)) + } + if len(opts.pids) > 0 { + opts.haveFilter = 1 + } + return opts +} + +func (opts *Options) WithComm(comm string) *Options { + opts.comm = [16]int8{} + if len(comm) > 0 { + opts.haveFilter = 1 + for i, s := range comm { + if i == 15 { + break + } + opts.comm[i] = int8(s) + } + opts.comm[15] = '\x00' + opts.filterComm = 1 + } + return opts +} + +func (opts *Options) WithFollowFork(v bool) *Options { + if v { + opts.followForks = 1 + } else { + opts.followForks = 0 + } + return opts +} + +func (opts *Options) WithPidNsIds(ids []uint32) *Options { + for _, id := range ids { + if id == 0 { + continue + } + opts.pidnsIds = append(opts.pidnsIds, id) + } + if len(opts.pidnsIds) > 0 { + opts.haveFilter = 1 + } + return opts +} +func (opts *Options) WithMntNsIds(ids []uint32) *Options { + for _, id := range ids { + if id == 0 { + continue + } + opts.mntnsIds = append(opts.mntnsIds, id) + } + if len(opts.mntnsIds) > 0 { + opts.haveFilter = 1 + } + return opts +} +func (opts *Options) WithNetNsIds(ids []uint32) *Options { + for _, id := range ids { + if id == 0 { + continue + } + opts.netnsIds = append(opts.netnsIds, id) + } + if len(opts.netnsIds) > 0 { + opts.haveFilter = 1 + } + return opts +} +func (opts *Options) WithPcapFilter(pcapFilter string) *Options { + opts.pcapFilter = strings.TrimSpace(pcapFilter) + return opts +} + +func (opts *Options) WithMaxPayloadSize(n uint32) *Options { + opts.maxPayloadSize = n + return opts +} + +func (opts *Options) WithKernelTypes(spec *btf.Spec) *Options { + opts.kernelTypes = spec + return opts +} diff --git a/bpf/bpf_arm64_bpfel.go b/bpf/bpf_arm64_bpfel.go index f09a85f3..249edbf6 100644 --- a/bpf/bpf_arm64_bpfel.go +++ b/bpf/bpf_arm64_bpfel.go @@ -31,14 +31,11 @@ type BpfFlowPidKeyT struct { } type BpfGconfigT struct { - FilterPid uint32 + HaveFilter uint8 FilterFollowForks uint8 FilterComm [16]int8 FilterCommEnable uint8 - _ [2]byte - FilterMntnsId uint32 - FilterNetnsId uint32 - FilterPidnsId uint32 + _ [1]byte MaxPayloadSize uint32 } @@ -137,7 +134,10 @@ type BpfMapSpecs struct { ExecEvents *ebpf.MapSpec `ebpf:"exec_events"` ExitEvents *ebpf.MapSpec `ebpf:"exit_events"` FilterByKernelCount *ebpf.MapSpec `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.MapSpec `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.MapSpec `ebpf:"filter_netns_map"` FilterPidMap *ebpf.MapSpec `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.MapSpec `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.MapSpec `ebpf:"flow_pid_map"` NatFlowMap *ebpf.MapSpec `ebpf:"nat_flow_map"` PacketEventStack *ebpf.MapSpec `ebpf:"packet_event_stack"` @@ -169,7 +169,10 @@ type BpfMaps struct { ExecEvents *ebpf.Map `ebpf:"exec_events"` ExitEvents *ebpf.Map `ebpf:"exit_events"` FilterByKernelCount *ebpf.Map `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.Map `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.Map `ebpf:"filter_netns_map"` FilterPidMap *ebpf.Map `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.Map `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.Map `ebpf:"flow_pid_map"` NatFlowMap *ebpf.Map `ebpf:"nat_flow_map"` PacketEventStack *ebpf.Map `ebpf:"packet_event_stack"` @@ -184,7 +187,10 @@ func (m *BpfMaps) Close() error { m.ExecEvents, m.ExitEvents, m.FilterByKernelCount, + m.FilterMntnsMap, + m.FilterNetnsMap, m.FilterPidMap, + m.FilterPidnsMap, m.FlowPidMap, m.NatFlowMap, m.PacketEventStack, diff --git a/bpf/bpf_arm64_bpfel.o b/bpf/bpf_arm64_bpfel.o index ace6fdb3..e8710fa7 100644 Binary files a/bpf/bpf_arm64_bpfel.o and b/bpf/bpf_arm64_bpfel.o differ diff --git a/bpf/bpf_legacy_arm64_bpfel.go b/bpf/bpf_legacy_arm64_bpfel.go index f81fd18c..ab9dc265 100644 --- a/bpf/bpf_legacy_arm64_bpfel.go +++ b/bpf/bpf_legacy_arm64_bpfel.go @@ -75,7 +75,10 @@ type bpf_legacyMapSpecs struct { ExecEvents *ebpf.MapSpec `ebpf:"exec_events"` ExitEvents *ebpf.MapSpec `ebpf:"exit_events"` FilterByKernelCount *ebpf.MapSpec `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.MapSpec `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.MapSpec `ebpf:"filter_netns_map"` FilterPidMap *ebpf.MapSpec `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.MapSpec `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.MapSpec `ebpf:"flow_pid_map"` NatFlowMap *ebpf.MapSpec `ebpf:"nat_flow_map"` PacketEventStack *ebpf.MapSpec `ebpf:"packet_event_stack"` @@ -107,7 +110,10 @@ type bpf_legacyMaps struct { ExecEvents *ebpf.Map `ebpf:"exec_events"` ExitEvents *ebpf.Map `ebpf:"exit_events"` FilterByKernelCount *ebpf.Map `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.Map `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.Map `ebpf:"filter_netns_map"` FilterPidMap *ebpf.Map `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.Map `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.Map `ebpf:"flow_pid_map"` NatFlowMap *ebpf.Map `ebpf:"nat_flow_map"` PacketEventStack *ebpf.Map `ebpf:"packet_event_stack"` @@ -122,7 +128,10 @@ func (m *bpf_legacyMaps) Close() error { m.ExecEvents, m.ExitEvents, m.FilterByKernelCount, + m.FilterMntnsMap, + m.FilterNetnsMap, m.FilterPidMap, + m.FilterPidnsMap, m.FlowPidMap, m.NatFlowMap, m.PacketEventStack, diff --git a/bpf/bpf_legacy_arm64_bpfel.o b/bpf/bpf_legacy_arm64_bpfel.o index 2c558566..0a933b41 100644 Binary files a/bpf/bpf_legacy_arm64_bpfel.o and b/bpf/bpf_legacy_arm64_bpfel.o differ diff --git a/bpf/bpf_legacy_x86_bpfel.go b/bpf/bpf_legacy_x86_bpfel.go index 743c752a..985e5572 100644 --- a/bpf/bpf_legacy_x86_bpfel.go +++ b/bpf/bpf_legacy_x86_bpfel.go @@ -75,7 +75,10 @@ type bpf_legacyMapSpecs struct { ExecEvents *ebpf.MapSpec `ebpf:"exec_events"` ExitEvents *ebpf.MapSpec `ebpf:"exit_events"` FilterByKernelCount *ebpf.MapSpec `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.MapSpec `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.MapSpec `ebpf:"filter_netns_map"` FilterPidMap *ebpf.MapSpec `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.MapSpec `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.MapSpec `ebpf:"flow_pid_map"` NatFlowMap *ebpf.MapSpec `ebpf:"nat_flow_map"` PacketEventStack *ebpf.MapSpec `ebpf:"packet_event_stack"` @@ -107,7 +110,10 @@ type bpf_legacyMaps struct { ExecEvents *ebpf.Map `ebpf:"exec_events"` ExitEvents *ebpf.Map `ebpf:"exit_events"` FilterByKernelCount *ebpf.Map `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.Map `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.Map `ebpf:"filter_netns_map"` FilterPidMap *ebpf.Map `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.Map `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.Map `ebpf:"flow_pid_map"` NatFlowMap *ebpf.Map `ebpf:"nat_flow_map"` PacketEventStack *ebpf.Map `ebpf:"packet_event_stack"` @@ -122,7 +128,10 @@ func (m *bpf_legacyMaps) Close() error { m.ExecEvents, m.ExitEvents, m.FilterByKernelCount, + m.FilterMntnsMap, + m.FilterNetnsMap, m.FilterPidMap, + m.FilterPidnsMap, m.FlowPidMap, m.NatFlowMap, m.PacketEventStack, diff --git a/bpf/bpf_legacy_x86_bpfel.o b/bpf/bpf_legacy_x86_bpfel.o index 6d440d6f..5d71e4df 100644 Binary files a/bpf/bpf_legacy_x86_bpfel.o and b/bpf/bpf_legacy_x86_bpfel.o differ diff --git a/bpf/bpf_x86_bpfel.go b/bpf/bpf_x86_bpfel.go index ef75d960..21baad3a 100644 --- a/bpf/bpf_x86_bpfel.go +++ b/bpf/bpf_x86_bpfel.go @@ -31,14 +31,11 @@ type BpfFlowPidKeyT struct { } type BpfGconfigT struct { - FilterPid uint32 + HaveFilter uint8 FilterFollowForks uint8 FilterComm [16]int8 FilterCommEnable uint8 - _ [2]byte - FilterMntnsId uint32 - FilterNetnsId uint32 - FilterPidnsId uint32 + _ [1]byte MaxPayloadSize uint32 } @@ -137,7 +134,10 @@ type BpfMapSpecs struct { ExecEvents *ebpf.MapSpec `ebpf:"exec_events"` ExitEvents *ebpf.MapSpec `ebpf:"exit_events"` FilterByKernelCount *ebpf.MapSpec `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.MapSpec `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.MapSpec `ebpf:"filter_netns_map"` FilterPidMap *ebpf.MapSpec `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.MapSpec `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.MapSpec `ebpf:"flow_pid_map"` NatFlowMap *ebpf.MapSpec `ebpf:"nat_flow_map"` PacketEventStack *ebpf.MapSpec `ebpf:"packet_event_stack"` @@ -169,7 +169,10 @@ type BpfMaps struct { ExecEvents *ebpf.Map `ebpf:"exec_events"` ExitEvents *ebpf.Map `ebpf:"exit_events"` FilterByKernelCount *ebpf.Map `ebpf:"filter_by_kernel_count"` + FilterMntnsMap *ebpf.Map `ebpf:"filter_mntns_map"` + FilterNetnsMap *ebpf.Map `ebpf:"filter_netns_map"` FilterPidMap *ebpf.Map `ebpf:"filter_pid_map"` + FilterPidnsMap *ebpf.Map `ebpf:"filter_pidns_map"` FlowPidMap *ebpf.Map `ebpf:"flow_pid_map"` NatFlowMap *ebpf.Map `ebpf:"nat_flow_map"` PacketEventStack *ebpf.Map `ebpf:"packet_event_stack"` @@ -184,7 +187,10 @@ func (m *BpfMaps) Close() error { m.ExecEvents, m.ExitEvents, m.FilterByKernelCount, + m.FilterMntnsMap, + m.FilterNetnsMap, m.FilterPidMap, + m.FilterPidnsMap, m.FlowPidMap, m.NatFlowMap, m.PacketEventStack, diff --git a/bpf/bpf_x86_bpfel.o b/bpf/bpf_x86_bpfel.o index 77db6f8d..f76313e1 100644 Binary files a/bpf/bpf_x86_bpfel.o and b/bpf/bpf_x86_bpfel.o differ diff --git a/bpf/ptcpdump.c b/bpf/ptcpdump.c index 0799bdb1..5ac7c42c 100644 --- a/bpf/ptcpdump.c +++ b/bpf/ptcpdump.c @@ -32,13 +32,10 @@ char _license[] SEC("license") = "Dual MIT/GPL"; struct gconfig_t { - u32 filter_pid; + u8 have_filter; u8 filter_follow_forks; char filter_comm[TASK_COMM_LEN]; u8 filter_comm_enable; - u32 filter_mntns_id; - u32 filter_netns_id; - u32 filter_pidns_id; u32 max_payload_size; }; @@ -129,6 +126,27 @@ struct { __type(value, struct gconfig_t); } config_map SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10); + __type(key, u32); + __type(value, u8); +} filter_mntns_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10); + __type(key, u32); + __type(value, u8); +} filter_pidns_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10); + __type(key, u32); + __type(value, u8); +} filter_netns_map SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); @@ -406,8 +424,35 @@ static __always_inline int str_cmp(const char *a, const volatile char *b, int le static __always_inline bool have_pid_filter_rules() { GET_CONFIG() - return g.filter_pid > 0 || g.filter_comm_enable == 1 || g.filter_mntns_id > 0 || g.filter_netns_id > 0 || - g.filter_pidns_id > 0; + return g.have_filter > 0; +} + +static __always_inline int filter_pid(u32 pid) { + if (bpf_map_lookup_elem(&filter_pid_map, &pid)) { + return 0; + } + return -1; +} + +static __always_inline int filter_mntns(u32 ns) { + if (bpf_map_lookup_elem(&filter_mntns_map, &ns)) { + return 0; + } + return -1; +} + +static __always_inline int filter_pidns(u32 ns) { + if (bpf_map_lookup_elem(&filter_pidns_map, &ns)) { + return 0; + } + return -1; +} + +static __always_inline int filter_netns(u32 ns) { + if (bpf_map_lookup_elem(&filter_netns_map, &ns)) { + return 0; + } + return -1; } static __always_inline int process_filter(struct task_struct *task) { @@ -418,7 +463,7 @@ static __always_inline int process_filter(struct task_struct *task) { } u32 pid = BPF_CORE_READ(task, tgid); - if (bpf_map_lookup_elem(&filter_pid_map, &pid)) { + if (filter_pid(pid) == 0) { // debug_log("match filter\n"); return 0; } @@ -429,22 +474,14 @@ static __always_inline int process_filter(struct task_struct *task) { #endif bool should_filter = false; - if (g.filter_pid > 0 && pid == g.filter_pid) { - // debug_log("filter_id\n"); + u32 mntns_id = BPF_CORE_READ(task, nsproxy, mnt_ns, ns.inum); + u32 netns_id = BPF_CORE_READ(task, nsproxy, net_ns, ns.inum); + u32 pidns_id = BPF_CORE_READ(task, nsproxy, pid_ns_for_children, ns.inum); + if ((filter_pidns(pidns_id) == 0) || (filter_mntns(mntns_id) == 0) || (filter_netns(netns_id) == 0)) { + // debug_log("%u %u %u\n", mntns_id, netns_id, pidns_id); should_filter = true; } - if (!should_filter) { - u32 mntns_id = BPF_CORE_READ(task, nsproxy, mnt_ns, ns.inum); - u32 netns_id = BPF_CORE_READ(task, nsproxy, net_ns, ns.inum); - u32 pidns_id = BPF_CORE_READ(task, nsproxy, pid_ns_for_children, ns.inum); - if ((mntns_id > 0 && mntns_id == g.filter_mntns_id) || (netns_id > 0 && netns_id == g.filter_netns_id) || - (pidns_id > 0 && pidns_id == g.filter_pidns_id)) { - // debug_log("%u %u %u\n", mntns_id, netns_id, pidns_id); - should_filter = true; - } - } - if (!should_filter) { if (g.filter_comm_enable == 1) { char comm[TASK_COMM_LEN]; @@ -466,43 +503,6 @@ static __always_inline int process_filter(struct task_struct *task) { return -1; } -// static __always_inline int process_meta_filter(struct process_meta_t *meta) { -// // no filter rules -// if (!have_pid_filter_rules()) { -// // debug_log("no filter\n"); -// return 0; -// } -// -// GET_CONFIG() -// -// // debug_log("meta->pid: %u, filter_id: %u\n", meta->pid, g.filter_pid); -// if (g.filter_pid > 0 && meta->pid == g.filter_pid) { -// // debug_log("filter_pid\n"); -// return 0; -// } -// if (g.filter_pid > 0 && g.filter_follow_forks == 1 && meta->ppid == g.filter_pid) { -// // debug_log("filter_pid by ppid\n"); -// return 0; -// } -// -// if ((meta->mntns_id > 0 && meta->mntns_id == g.filter_mntns_id) || -// (meta->netns_id > 0 && meta->netns_id == g.filter_netns_id) || -// (meta->pidns_id > 0 && meta->pidns_id == g.filter_pidns_id)) { -// // debug_log("%u %u %u\n", meta->mntns_id, meta->netns_id, meta->pidns_id); -// return 0; -// } -// -// if (g.filter_comm_enable == 1) { -// if (str_cmp(meta->comm, g.filter_comm, TASK_COMM_LEN) == 0) { -// return 0; -// } -// } -// -// // debug_log("meta_process not match, meta->pid: %u, filter_id: %u\n", meta->pid, g.filter_pid); -// -// return -1; -// } - static __always_inline int parent_process_filter(struct task_struct *current) { // no filter rules if (!have_pid_filter_rules()) { diff --git a/cmd/capture.go b/cmd/capture.go index 9c102c7d..25d193af 100644 --- a/cmd/capture.go +++ b/cmd/capture.go @@ -176,20 +176,26 @@ func getCurrentConnects(ctx context.Context, pcache *metadata.ProcessCache, opts ps := pcache.GetPidsByComm(opts.comm) pids = append(pids, ps...) } - if opts.pidnsId > 0 { + if len(opts.pidnsIds) > 0 { filterPid = true - ps := pcache.GetPidsByPidNsId(int64(opts.pidnsId)) - pids = append(pids, ps...) + for _, id := range opts.pidnsIds { + ps := pcache.GetPidsByPidNsId(int64(id)) + pids = append(pids, ps...) + } } - if opts.mntnsId > 0 { + if len(opts.mntnsIds) > 0 { filterPid = true - ps := pcache.GetPidsByPidNsId(int64(opts.mntnsId)) - pids = append(pids, ps...) + for _, id := range opts.mntnsIds { + ps := pcache.GetPidsByPidNsId(int64(id)) + pids = append(pids, ps...) + } } - if opts.netnsId > 0 { + if len(opts.netnsIds) > 0 { filterPid = true - ps := pcache.GetPidsByPidNsId(int64(opts.netnsId)) - pids = append(pids, ps...) + for _, id := range opts.netnsIds { + ps := pcache.GetPidsByPidNsId(int64(id)) + pids = append(pids, ps...) + } } pids = utils.GetUniqInts(pids) diff --git a/cmd/container.go b/cmd/container.go index 0e5bfa98..0894c937 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -62,13 +62,13 @@ func applyContainerFilter(ctx context.Context, opts *Options) (*metadata.Contain } log.Infof("filter by container %#v", container) if container.PidNamespace > 0 && container.PidNamespace != metadata.HostPidNs { - opts.pidnsId = uint32(container.PidNamespace) + opts.pidnsIds = append(opts.pidnsIds, uint32(container.PidNamespace)) } if container.MountNamespace > 0 && container.MountNamespace != metadata.HostMntNs { - opts.mntnsId = uint32(container.MountNamespace) + opts.mntnsIds = append(opts.mntnsIds, uint32(container.MountNamespace)) } if container.NetworkNamespace > 0 && container.NetworkNamespace != metadata.HostNetNs { - opts.netnsId = uint32(container.NetworkNamespace) + opts.netnsIds = append(opts.netnsIds, uint32(container.NetworkNamespace)) } opts.followForks = true } diff --git a/cmd/ebpf.go b/cmd/ebpf.go index 5f9a6e40..17cd8621 100644 --- a/cmd/ebpf.go +++ b/cmd/ebpf.go @@ -27,10 +27,18 @@ func attachHooks(btfSpec *btftype.Spec, currentConns []metadata.Connection, opts if err != nil { return nil, err } - bpfopts := bpf.NewOptions(opts.pid, opts.comm, opts.followForks, opts.pcapFilter, - opts.mntnsId, opts.pidnsId, opts.netnsId, opts.snapshotLength) - bpfopts.KernelTypes = btfSpec - if err := bf.Load(bpfopts); err != nil { + bpfopts := &bpf.Options{} + bpfopts = bpfopts.WithPids([]uint{opts.pid}). + WithComm(opts.comm). + WithFollowFork(opts.followForks). + WithPidNsIds(opts.pidnsIds). + WithMntNsIds(opts.mntnsIds). + WithNetNsIds(opts.netnsIds). + WithMaxPayloadSize(opts.snapshotLength). + WithPcapFilter(opts.pcapFilter). + WithKernelTypes(btfSpec) + + if err := bf.Load(*bpfopts); err != nil { return nil, err } diff --git a/cmd/options.go b/cmd/options.go index aaa1f536..5a4d6b6b 100644 --- a/cmd/options.go +++ b/cmd/options.go @@ -51,9 +51,9 @@ type Options struct { subProgArgs []string - mntnsId uint32 - netnsId uint32 - pidnsId uint32 + mntnsIds []uint32 + netnsIds []uint32 + pidnsIds []uint32 } func (o Options) filterByContainer() bool { diff --git a/testdata/run_e2e.sh b/testdata/run_e2e.sh index d9ae317f..62b8b812 100644 --- a/testdata/run_e2e.sh +++ b/testdata/run_e2e.sh @@ -4,7 +4,7 @@ set -ex function main() { rm -rf /tmp/ptcpdump_* | true - kubectl delet pod test-ptcpdump | true + kubectl delete pod test-ptcpdump | true bash testdata/test_default.sh ./ptcpdump bash testdata/test_base.sh ./ptcpdump diff --git a/testdata/run_test_k8s_filter_by_pod_2.sh b/testdata/run_test_k8s_filter_by_pod_2.sh new file mode 100644 index 00000000..1cc01280 --- /dev/null +++ b/testdata/run_test_k8s_filter_by_pod_2.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -ex + +sudo docker cp ./ptcpdump kind-control-plane:/ +sudo docker cp ./testdata/test_k8s_filter_2.yaml kind-control-plane:/ +sudo docker cp ./testdata/test_k8s_filter_by_pod_2.sh kind-control-plane:/ +sudo docker exec kind-control-plane sh -c 'bash /test_k8s_filter_by_pod_2.sh /ptcpdump /test_k8s_filter_2.yaml' diff --git a/testdata/test_k8s_filter_2.yaml b/testdata/test_k8s_filter_2.yaml new file mode 100644 index 00000000..6d549114 --- /dev/null +++ b/testdata/test_k8s_filter_2.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + run: test + name: test-ptcpdump +spec: + containers: + - args: + - sh + - '-c' + - 'sleep 20 && wget -T 10 8.8.8.8:53 || true' + image: busybox:1 + name: test1 + - args: + - sh + - '-c' + - 'sleep 20 && wget -T 10 1.1.1.1 || true' + image: alpine:3.18 + name: test2 + diff --git a/testdata/test_k8s_filter_by_pod_2.sh b/testdata/test_k8s_filter_by_pod_2.sh new file mode 100644 index 00000000..4a321daf --- /dev/null +++ b/testdata/test_k8s_filter_by_pod_2.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -ex + +CMD="$1" +TEST_YAML="$2" +FILE_PREFIX="/tmp/ptcpdump" +FNAME="${FILE_PREFIX}_k8s_filter_by_pod_2.pcapng" +LNAME="${FILE_PREFIX}_k8s_filter_by_pod_2.log" +RNAME="${FILE_PREFIX}_k8s_filter_by_pod_2.read.txt" + +function test_ptcpdump() { + + kubectl create ns test-ns || true + kubectl delete -f "${TEST_YAML}" || true + kubectl -n test-ns delete -f "${TEST_YAML}" || true + kubectl -n test-ns apply -f "${TEST_YAML}" + kubectl -n test-ns wait --for condition=Ready pod/test-ptcpdump + + timeout 120s ${CMD} -i any -c 20 --print -w "${FNAME}" --oneline -v \ + --pod-name "test-ptcpdump.test-ns" | tee "${LNAME}" + + wait + + cat "${LNAME}" + cat "${LNAME}" | grep "1.1.1.1.80.*Process (.*wget -T 10 1.1.1.1.*).* Container (.*alpine:3.18.*).* Pod (name test-ptcpdump, namespace test-ns" + cat "${LNAME}" | grep "8.8.8.8.53.*Process (.*wget -T 10 8.8.8.8.*).* Container (.*busybox:1.*).* Pod (name test-ptcpdump, namespace test-ns" +} + +function test_ptcpdump_read() { + EXPECT_NAME="${LNAME}.read.expect" + sed 's/ [a-zA-Z0-9_-]\+ \(In\|Out\) / /g' "${LNAME}" > "${EXPECT_NAME}" + timeout 30s ${CMD} --oneline -v -r "${FNAME}" > "${RNAME}" + diff "${EXPECT_NAME}" "${RNAME}" +} + +function main() { + rm "${LNAME}" || true + rm "${RNAME}" || true + test_ptcpdump + test_ptcpdump_read +} + +main