Skip to content

Commit

Permalink
eBPF: ignore netlink errors if there're no connections
Browse files Browse the repository at this point in the history
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,-
  • Loading branch information
gustavo-iniguez-goya committed May 28, 2021
1 parent 1db03b5 commit e5b54f0
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 38 deletions.
2 changes: 1 addition & 1 deletion daemon/netlink/socket_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
30 changes: 16 additions & 14 deletions daemon/procmon/ebpf/ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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()
Expand Down
49 changes: 26 additions & 23 deletions daemon/procmon/ebpf/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()
Expand All @@ -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()
}
}

Expand Down

0 comments on commit e5b54f0

Please sign in to comment.