Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolver implementation based on information /proc/net/(tcp[6]|udp) #119

Merged
merged 6 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 61 additions & 6 deletions bpf/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ void BPF_KPROBE(tcp_connect) {

long err;
__u64 cgroup_id = compat_get_current_cgroup_id(NULL);
if (!should_target_cgroup(cgroup_id)) {
return;
}
__u64 id = tracer_get_current_pid_tgid();

struct sock* sk = (struct sock*)PT_REGS_PARM1(ctx);
Expand Down Expand Up @@ -49,6 +46,9 @@ void BPF_KPROBE(tcp_connect) {
return;
}

__u64 key = (__u64)sk;
bpf_map_update_elem(&tcp_connect_context, &key, &ev.pid, BPF_ANY);

bpf_probe_read_kernel_str(&ev.comm, 16, task->comm);

ev.port_dst = bpf_ntohs(ev.port_dst);
Expand Down Expand Up @@ -99,6 +99,9 @@ void BPF_KRETPROBE(syscall__accept4_ret) {
return;
}

__u64 key = (__u64)sk;
bpf_map_update_elem(&tcp_accept_context, &key, &ev.pid, BPF_ANY);

bpf_probe_read_kernel_str(&ev.comm, 16, task->comm);

ev.port_src = bpf_ntohs(ev.port_src);
Expand All @@ -113,9 +116,6 @@ void BPF_KRETPROBE(do_accept) {
return;

__u64 cgroup_id = compat_get_current_cgroup_id(NULL);
if (!should_target_cgroup(cgroup_id)) {
return;
}
struct file* f = (struct file*)PT_REGS_RC(ctx);
if (!f)
return;
Expand All @@ -141,6 +141,61 @@ int trace_cgroup_connect4(struct bpf_sock_addr* ctx) {
return 1;
}

SEC("kprobe/tcp_close")
void BPF_KPROBE(tcp_close) {
if (capture_disabled())
return;

long err;
__u64 cgroup_id = compat_get_current_cgroup_id(NULL);
__u64 id = tracer_get_current_pid_tgid();

struct sock* sk = (struct sock*)PT_REGS_PARM1(ctx);

short unsigned int family;
err = bpf_probe_read(&family, sizeof(family), (void*)&sk->__sk_common.skc_family);
if (err != 0) {
log_error(ctx, LOG_ERROR_READING_SOCKET_FAMILY, id, err, 0l);
return;
}

if (family != AF_INET) {
return;
}

__u16 event = 0;

__u64 key = (__u64)sk;
if (bpf_map_lookup_elem(&tcp_accept_context, &key)) {
event = SYSCALL_EVENT_ID_CLOSE_ACCEPT;
bpf_map_delete_elem(&tcp_accept_context, &key);
} else if (bpf_map_lookup_elem(&tcp_connect_context, &key)) {
event = SYSCALL_EVENT_ID_CLOSE_CONNECT;
bpf_map_delete_elem(&tcp_connect_context, &key);
} else {
return;
}

struct task_struct* task = (struct task_struct*)bpf_get_current_task();
struct syscall_event ev = {
.event_id = event,
.cgroup_id = cgroup_id,
.pid = get_task_pid(task),
.parent_pid = get_task_pid(get_parent_task(task)),
.host_pid = BPF_CORE_READ(task, tgid),
.host_parent_pid = get_parent_task_pid(task),
};

if (read_addrs_ports(ctx, (struct sock*)PT_REGS_PARM1(ctx), &ev.ip_src, &ev.port_src, &ev.ip_dst, &ev.port_dst)) {
return;
}

bpf_probe_read_kernel_str(&ev.comm, 16, task->comm);

ev.port_dst = bpf_ntohs(ev.port_dst);
bpf_perf_event_output(ctx, &syscall_events, BPF_F_CURRENT_CPU, &ev, sizeof(struct syscall_event));
}

static __always_inline int read_addrs_ports(struct pt_regs* ctx, struct sock* sk, __be32* saddr, __be16* sport, __be32* daddr, __be16* dport) {
long err;
__u64 id = tracer_get_current_pid_tgid();
Expand Down
2 changes: 2 additions & 0 deletions bpf/include/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ BPF_LRU_HASH(accept_context, __u64, struct accept_data);

#define SYSCALL_EVENT_ID_CONNECT 0
#define SYSCALL_EVENT_ID_ACCEPT 1
#define SYSCALL_EVENT_ID_CLOSE_CONNECT 2
#define SYSCALL_EVENT_ID_CLOSE_ACCEPT 3

struct syscall_event {
char comm[16];
Expand Down
3 changes: 3 additions & 0 deletions bpf/include/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,7 @@ BPF_LRU_HASH(go_kernel_read_context, __u64, __u32);
BPF_LRU_HASH(go_user_kernel_write_context, __u64, struct address_info);
BPF_LRU_HASH(go_user_kernel_read_context, __u64, struct address_info);

BPF_LRU_HASH(tcp_connect_context, __u64, __u32);
BPF_LRU_HASH(tcp_accept_context, __u64, __u32);

#endif /* __MAPS__ */
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ require (
github.com/hashicorp/golang-lru v0.5.4
github.com/hashicorp/golang-lru/v2 v2.0.2
github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9
github.com/kubeshark/api v1.1.31
github.com/kubeshark/gopacket v1.1.30
github.com/kubeshark/tracerproto v1.0.3-0.20240730073449-de3a99a3719c
github.com/kubeshark/utils v0.0.0-20240912210808-416dca610f11
github.com/moby/moby v25.0.4+incompatible
github.com/moby/sys/mount v0.3.4
github.com/moby/sys/mountinfo v0.7.2
github.com/prometheus/procfs v0.15.1
github.com/rs/zerolog v1.32.0
github.com/vishvananda/netlink v1.2.1-beta.2
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848
golang.org/x/sys v0.20.0
k8s.io/api v0.28.3
Expand Down Expand Up @@ -74,12 +77,10 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.3.0 // indirect
Expand Down
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubeshark/api v1.1.31 h1:stOsatiJ8C3SKLIStAwykc/dybHlyy9fYyH8b9tIv1c=
github.com/kubeshark/api v1.1.31/go.mod h1:+Ua35OiwreWiUYfqJz0Aswn3UmsLctLUQh3tvxagQz4=
github.com/kubeshark/gopacket v1.1.30 h1:Dz6eo7b6+NdVCrgiyKxlGEVTm0L6PwgbVvSomsuwIyU=
github.com/kubeshark/gopacket v1.1.30/go.mod h1:Qo8/i/tdT74CCT7/pjO0L55Pktv5dQfj7M/Arv8MKm8=
github.com/kubeshark/tracerproto v1.0.0/go.mod h1:+efDYkwXxwakmHRpxHVEekyXNtg/aFx0uSo/I0lGV9k=
Expand Down Expand Up @@ -172,6 +174,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
Expand Down Expand Up @@ -237,8 +241,8 @@ golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
3 changes: 1 addition & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ func main() {
}
}()

misc.InitDataDir()

run()
}

Expand Down Expand Up @@ -143,6 +141,7 @@ func run() {
if clusterMode {
misc.SetDataDir(fmt.Sprintf("/app/data/%s", nodeName))
}
misc.InitDataDir()

err = createTracer()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cgroup/cgroup_finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var (
)

// Borrowed from https://github.com/aquasecurity/tracee/blob/main/pkg/containers/containers.go
func getContainerIdByCgroupPath(cgroupPath string) (id string, runtime RuntimeId) {
func GetContainerIdByCgroupPath(cgroupPath string) (id string, runtime RuntimeId) {
cgroupParts := strings.Split(cgroupPath, "/")

for i := len(cgroupParts) - 1; i >= 0; i = i - 1 {
Expand Down
25 changes: 13 additions & 12 deletions pkg/cgroup/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type CgroupInfo struct {
type CgroupsController interface {
EbpfCapturePossible() bool
AddCgroupPath(cgroupPath string) (cgroupID uint64, containerID string, ok bool)
PopulateSocketsInodes(inodeMap *ebpf.Map) error
PopulateSocketsInodes(isCgroupV2 bool, inodeMap *ebpf.Map) error
DelCgroupID(cgroupID uint64)
GetContainerID(cgroupID uint64) (containerID string)
GetCgroupsV2(containerId string) []CgroupInfo
Expand Down Expand Up @@ -58,7 +58,7 @@ func (e *CgroupsControllerImpl) EbpfCapturePossible() bool {
func (e *CgroupsControllerImpl) AddCgroupPath(cgroupPath string) (cgroupID uint64, containerID string, ok bool) {
var err error

containerID, _ = getContainerIdByCgroupPath(cgroupPath)
containerID, _ = GetContainerIdByCgroupPath(cgroupPath)
if containerID == "" {
log.Debug().Str("path", cgroupPath).Msg("Can not get container id")
return
Expand Down Expand Up @@ -123,7 +123,7 @@ func (e *CgroupsControllerImpl) GetCgroupsV2(containerID string) (info []CgroupI
}

func (e *CgroupsControllerImpl) GetExistingCgroupsByCgroupPath(cgroupPath string) (info []CgroupInfo) {
containerID, _ := getContainerIdByCgroupPath(cgroupPath)
containerID, _ := GetContainerIdByCgroupPath(cgroupPath)
if containerID == "" {
return
}
Expand All @@ -136,7 +136,7 @@ func (e *CgroupsControllerImpl) GetCgroupV2MountPoint() string {
return e.cgroup.mountpoint
}

func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error {
func (e *CgroupsControllerImpl) PopulateSocketsInodes(isCgroupV2 bool, inodeMap *ebpf.Map) error {
getContId := func(pid string) string {
path := filepath.Join(e.procfs, pid, "cgroup")
file, err := os.Open(path)
Expand All @@ -148,22 +148,22 @@ func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if !strings.Contains(line, ":cpuset:") {
if !isCgroupV2 && !strings.Contains(line, ":cpuset:") {
continue
}
items := strings.Split(line, ":")
cgroupPath := items[len(items)-1]
containerID, _ := getContainerIdByCgroupPath(cgroupPath)
containerID, _ := GetContainerIdByCgroupPath(cgroupPath)
return containerID
}

return ""
}

extractInode := func(socketId string, cgroups []CgroupInfo) {
extractInode := func(isCgroupsV2 bool, socketId string, cgroups []CgroupInfo) {
if inode, err := strconv.ParseUint(socketId, 10, 64); err == nil {
for _, cgroup := range cgroups {
if !strings.Contains(cgroup.CgroupPath, "/sys/fs/cgroup/cpuset") {
if !isCgroupsV2 && !strings.Contains(cgroup.CgroupPath, "/sys/fs/cgroup/cpuset") {
continue
}
if err := inodeMap.Update(inode, cgroup.CgroupID, ebpf.UpdateNoExist); err != nil {
Expand All @@ -174,7 +174,8 @@ func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error
log.Error().Err(err).Str("Cgroup Path", cgroup.CgroupPath).Uint64("Cgroup ID", cgroup.CgroupID).Uint64("inode", inode).Msg("Lookup inodemap failed")
}
if cgroup.CgroupID != cgroupExist {
log.Error().Err(err).Str("Cgroup Path", cgroup.CgroupPath).Uint64("Cgroup ID", cgroup.CgroupID).Uint64("inode", inode).Uint64("Cgroup ID exists", cgroupExist).Msg("Update inodemap failed")
// having one of IDs in inodemap must be enough
log.Debug().Err(err).Str("Cgroup Path", cgroup.CgroupPath).Uint64("Cgroup ID", cgroup.CgroupID).Uint64("inode", inode).Uint64("Cgroup ID exists", cgroupExist).Msg("Update inodemap failed")
}
}
} else {
Expand All @@ -184,7 +185,7 @@ func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error
}
}

findProcessSockets := func(prefix string, files []os.DirEntry, cgroups []CgroupInfo) {
findProcessSockets := func(isCgroupsV2 bool, prefix string, files []os.DirEntry, cgroups []CgroupInfo) {
for _, file := range files {
link, err := os.Readlink(filepath.Join(prefix, file.Name()))
if err != nil {
Expand All @@ -193,7 +194,7 @@ func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error
}
match := socketRegex.FindStringSubmatch(link)
if match != nil {
extractInode(match[1], cgroups)
extractInode(isCgroupsV2, match[1], cgroups)
}
}

Expand Down Expand Up @@ -230,7 +231,7 @@ func (e *CgroupsControllerImpl) PopulateSocketsInodes(inodeMap *ebpf.Map) error
continue
}

findProcessSockets(fdPath, files, cgroups)
findProcessSockets(isCgroupV2, fdPath, files, cgroups)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/discoverer/discoverer.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (e *InternalEventsDiscovererImpl) scanExistingCgroups(isCgroupsV2 bool) {
_ = filepath.WalkDir("/sys/fs/cgroup", walk)

// scan all existing pids to find out all opened inodes of sockets
if err := e.cgroupsController.PopulateSocketsInodes(e.bpfObjects.BpfObjs.Inodemap); err != nil {
if err := e.cgroupsController.PopulateSocketsInodes(isCgroupsV2, e.bpfObjects.BpfObjs.Inodemap); err != nil {
log.Error().Err(err).Msg("Populate sockets inodes failed")
}
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/hooks/syscall/tcp_kprobe_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type tcpKprobeHooks struct {
accept link.Link
acceptRet link.Link
accept4 link.Link
tcpClose link.Link
}

func (s *tcpKprobeHooks) installTcpKprobeHooks(bpfObjects *bpf.TracerObjects) error {
Expand Down Expand Up @@ -44,6 +45,11 @@ func (s *tcpKprobeHooks) installTcpKprobeHooks(bpfObjects *bpf.TracerObjects) er
log.Warn().Err(err).Msg("do_accept can not be attached. Probably system is running on incomatible kernel")
}

s.tcpClose, err = link.Kprobe("tcp_close", bpfObjects.TcpClose, nil)
if err != nil {
return errors.Wrap(err, 0)
}

return nil
}

Expand Down Expand Up @@ -80,5 +86,11 @@ func (s *tcpKprobeHooks) close() []error {
}
}

if s.tcpClose != nil {
if err := s.tcpClose.Close(); err != nil {
returnValue = append(returnValue, err)
}
}

return returnValue
}
12 changes: 6 additions & 6 deletions pkg/poller/syscall/tracer_syscall_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,18 @@ func (t *SyscallEventsTracer) pollEvents() {
var evName string
if ev.EventId == 0 {
evName = "connect"
}
if ev.EventId == 1 {
} else if ev.EventId == 1 {
evName = "accept"
} else if ev.EventId == 2 {
evName = "close connect"
} else if ev.EventId == 3 {
evName = "close accept"
}

var e events.SyscallEvent
e.SyscallEventMessage = ev
contID := t.cgroupController.GetContainerID(ev.CgroupID)
e.ContainerID = string(contID)

log.Debug().Msg(fmt.Sprintf("Syscall event %v: %v:%v->%v:%v command: %v host pid: %v host ppid: %v pid: %v ppid: %v cgroup id: %v container id: %v",
log.Debug().Msg(fmt.Sprintf("Syscall event %v: %v:%v->%v:%v command: %v host pid: %v host ppid: %v pid: %v ppid: %v cgroup id: %v",
evName,
toIP(e.IpSrc),
toPort(e.PortSrc),
Expand All @@ -110,7 +111,6 @@ func (t *SyscallEventsTracer) pollEvents() {
e.Pid,
e.ParentPid,
e.CgroupID,
e.ContainerID,
))

t.eventSocket.WriteObject(e)
Expand Down
Loading
Loading