Skip to content

Commit

Permalink
Resolver implementation based on information /proc/net/(tcp[6]|udp) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
iluxa authored Dec 2, 2024
1 parent 306c8a0 commit 63c24ca
Show file tree
Hide file tree
Showing 13 changed files with 911 additions and 32 deletions.
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

0 comments on commit 63c24ca

Please sign in to comment.