From e5b54f0a6b472014ba0dad20a8778933bf959dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20I=C3=B1iguez=20Goia?= Date: Sat, 29 May 2021 00:16:18 +0200 Subject: [PATCH] eBPF: ignore netlink errors if there're no connections When enabling the eBPF monitor method we dump the active connections, but in some cases there're no active connections, and because of this we're failing enabling this monitor method. If there're no connections established, netlink returns 0 entries. It's not clear if it's an indication of error in some cases or the expected result. Either way: - fail only if we're unable to load the eBPF module. - dump TCP IPv6 connections only if IPv6 is enabled in the syste,- --- daemon/netlink/socket_linux.go | 2 +- daemon/procmon/ebpf/ebpf.go | 30 +++++++++++---------- daemon/procmon/ebpf/monitor.go | 49 ++++++++++++++++++---------------- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/daemon/netlink/socket_linux.go b/daemon/netlink/socket_linux.go index 694fcdbe2d..b5ed5dea6c 100644 --- a/daemon/netlink/socket_linux.go +++ b/daemon/netlink/socket_linux.go @@ -223,7 +223,7 @@ func netlinkRequest(sockReq *SocketRequest, family uint8, proto uint8, srcPort, return nil, err } if len(msgs) == 0 { - return nil, errors.New("Warning, no message nor error from netlink") + return nil, errors.New("Warning, no message nor error from netlink, or no connections found") } var sock []*Socket for n, m := range msgs { diff --git a/daemon/procmon/ebpf/ebpf.go b/daemon/procmon/ebpf/ebpf.go index 0d8292a284..122885f026 100644 --- a/daemon/procmon/ebpf/ebpf.go +++ b/daemon/procmon/ebpf/ebpf.go @@ -8,6 +8,7 @@ import ( "syscall" "unsafe" + "github.com/evilsocket/opensnitch/daemon/core" "github.com/evilsocket/opensnitch/daemon/log" daemonNetlink "github.com/evilsocket/opensnitch/daemon/netlink" "github.com/evilsocket/opensnitch/daemon/procmon" @@ -123,8 +124,7 @@ func Start() error { // save already established connections socketListTCP, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET), uint8(syscall.IPPROTO_TCP)) if err != nil { - log.Error("eBPF could not dump TCP sockets via netlink: %v", err) - return err + log.Debug("eBPF could not dump TCP sockets via netlink: %v", err) } for _, sock := range socketListTCP { inode := int((*sock).INode) @@ -135,18 +135,20 @@ func Start() error { alreadyEstablished.Unlock() } - socketListTCPv6, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET6), uint8(syscall.IPPROTO_TCP)) - if err != nil { - log.Error("eBPF could not dump TCPv6 sockets via netlink: %v", err) - return err - } - for _, sock := range socketListTCPv6 { - inode := int((*sock).INode) - pid := procmon.GetPIDFromINode(inode, fmt.Sprint(inode, - (*sock).ID.Source, (*sock).ID.SourcePort, (*sock).ID.Destination, (*sock).ID.DestinationPort)) - alreadyEstablished.Lock() - alreadyEstablished.TCPv6[sock] = pid - alreadyEstablished.Unlock() + if core.IPv6Enabled { + socketListTCPv6, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET6), uint8(syscall.IPPROTO_TCP)) + if err != nil { + log.Debug("eBPF could not dump TCPv6 sockets via netlink: %v", err) + } else { + for _, sock := range socketListTCPv6 { + inode := int((*sock).INode) + pid := procmon.GetPIDFromINode(inode, fmt.Sprint(inode, + (*sock).ID.Source, (*sock).ID.SourcePort, (*sock).ID.Destination, (*sock).ID.DestinationPort)) + alreadyEstablished.Lock() + alreadyEstablished.TCPv6[sock] = pid + alreadyEstablished.Unlock() + } + } } go monitorMaps() diff --git a/daemon/procmon/ebpf/monitor.go b/daemon/procmon/ebpf/monitor.go index 224667bdce..6f7fb7e998 100644 --- a/daemon/procmon/ebpf/monitor.go +++ b/daemon/procmon/ebpf/monitor.go @@ -5,6 +5,7 @@ import ( "time" "unsafe" + "github.com/evilsocket/opensnitch/daemon/core" "github.com/evilsocket/opensnitch/daemon/log" daemonNetlink "github.com/evilsocket/opensnitch/daemon/netlink" elf "github.com/iovisor/gobpf/elf" @@ -70,7 +71,7 @@ func monitorAlreadyEstablished() { } socketListTCP, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET), uint8(syscall.IPPROTO_TCP)) if err != nil { - log.Error("eBPF error in dumping TCP sockets via netlink") + log.Debug("eBPF error in dumping TCP sockets via netlink") continue } alreadyEstablished.Lock() @@ -94,31 +95,33 @@ func monitorAlreadyEstablished() { } alreadyEstablished.Unlock() - socketListTCPv6, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET6), uint8(syscall.IPPROTO_TCP)) - if err != nil { - log.Error("eBPF error in dumping TCPv6 sockets via netlink") - continue - } - alreadyEstablished.Lock() - for aesock := range alreadyEstablished.TCPv6 { - found := false - for _, sock := range socketListTCPv6 { - if (*aesock).INode == (*sock).INode && - //inodes are unique enough, so the matches below will never have to be checked - (*aesock).ID.SourcePort == (*sock).ID.SourcePort && - (*aesock).ID.Source.Equal((*sock).ID.Source) && - (*aesock).ID.Destination.Equal((*sock).ID.Destination) && - (*aesock).ID.DestinationPort == (*sock).ID.DestinationPort && - (*aesock).UID == (*sock).UID { - found = true - break - } + if core.IPv6Enabled { + socketListTCPv6, err := daemonNetlink.SocketsDump(uint8(syscall.AF_INET6), uint8(syscall.IPPROTO_TCP)) + if err != nil { + log.Debug("eBPF error in dumping TCPv6 sockets via netlink: %s", err) + continue } - if !found { - delete(alreadyEstablished.TCPv6, aesock) + alreadyEstablished.Lock() + for aesock := range alreadyEstablished.TCPv6 { + found := false + for _, sock := range socketListTCPv6 { + if (*aesock).INode == (*sock).INode && + //inodes are unique enough, so the matches below will never have to be checked + (*aesock).ID.SourcePort == (*sock).ID.SourcePort && + (*aesock).ID.Source.Equal((*sock).ID.Source) && + (*aesock).ID.Destination.Equal((*sock).ID.Destination) && + (*aesock).ID.DestinationPort == (*sock).ID.DestinationPort && + (*aesock).UID == (*sock).UID { + found = true + break + } + } + if !found { + delete(alreadyEstablished.TCPv6, aesock) + } } + alreadyEstablished.Unlock() } - alreadyEstablished.Unlock() } }