Skip to content

Commit

Permalink
force to reestablish non-local connections on start
Browse files Browse the repository at this point in the history
When we start to intercept connections, we flush out the conntrack
table, to force already established connections reconnect again so we
can intercept them, and let the user choose if allow or deny them.

Since we no longer use conntrack states to intercept TCP connections, we
now close existing connections, leaving to the applications reestablish
them again.
Local connections are excluded, because it may cause problems with some
local servers.

Both options interfere with the established connections, so you may
experience ocasional network interruptions when enabling the
interception for the first time.

Discussion: #995
  • Loading branch information
gustavo-iniguez-goya committed Jul 24, 2023
1 parent d1598fd commit 26b8415
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
2 changes: 1 addition & 1 deletion daemon/firewall/nftables/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (n *Nft) AreRulesLoaded() bool {
}
}
}
// we expect to have exactly 3 rules (2 queue and dns). If there're less or more, then we
// we expect to have exactly 3 rules (2 queue and 1 dns). If there're less or more, then we
// need to reload them.
if nRules != 3 {
log.Warning("nfables filter rules not loaded: %d", nRules)
Expand Down
9 changes: 8 additions & 1 deletion daemon/firewall/nftables/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
"github.com/evilsocket/opensnitch/daemon/log"
daemonNetlink "github.com/evilsocket/opensnitch/daemon/netlink"
"github.com/google/nftables"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
Expand Down Expand Up @@ -180,8 +181,14 @@ func (n *Nft) QueueConnections(enable bool, logError bool) (error, error) {
// flush conntrack as soon as netfilter rule is set. This ensures that already-established
// connections will go to netfilter queue.
if err := netlink.ConntrackTableFlush(netlink.ConntrackTable); err != nil {
log.Error("nftables, error in ConntrackTableFlush %s", err)
log.Error("nftables, error flushing ConntrackTable %s", err)
}
if err := netlink.ConntrackTableFlush(netlink.ConntrackExpectTable); err != nil {
log.Error("nftables, error flusing ConntrackExpectTable %s", err)
}

// Force established connections to reestablish again.
daemonNetlink.KillAllSockets()
}

return nil, nil
Expand Down
48 changes: 47 additions & 1 deletion daemon/netlink/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"syscall"

"github.com/evilsocket/opensnitch/daemon/log"
"golang.org/x/sys/unix"
)

// GetSocketInfo asks the kernel via netlink for a given connection.
Expand Down Expand Up @@ -151,13 +152,58 @@ func KillSocket(proto string, srcIP net.IP, srcPort uint, dstIP net.IP, dstPort

if sockList, err := SocketGet(family, ipproto, uint16(srcPort), uint16(dstPort), srcIP, dstIP); err == nil {
for _, s := range sockList {
if err := socketKill(family, ipproto, s.ID); err != nil {
if err := SocketKill(family, ipproto, s.ID); err != nil {
log.Debug("Unable to kill socket: %d, %d, %v", srcPort, dstPort, err)
}
}
}
}

// KillSockets kills all sockets given a family and a protocol.
// Be careful if you don't exclude local sockets, many local servers may misbehave,
// entering in an infinite loop.
func KillSockets(fam, proto uint8, excludeLocal bool) error {
sockListTCP, err := SocketsDump(fam, proto)
if err != nil {
return fmt.Errorf("eBPF could not dump TCP (%d/%d) sockets via netlink: %v", fam, proto, err)
}

for _, sock := range sockListTCP {
if excludeLocal && (sock.ID.Destination.IsPrivate() ||
sock.ID.Source.IsUnspecified() ||
sock.ID.Destination.IsUnspecified()) {
continue
}
log.Error("KILLINGIT: %+v", sock.ID)
if err := SocketKill(fam, proto, sock.ID); err != nil {
log.Error("ERRORERRORERROR KILLING: %s", err)
}
}

return nil
}

// KillAllSockets kills the sockets for the given families and protocols.
func KillAllSockets() {
type opts struct {
fam uint8
proto uint8
}
optList := []opts{
// add families and protos as wish
{unix.AF_INET, uint8(syscall.IPPROTO_TCP)},
{unix.AF_INET6, uint8(syscall.IPPROTO_TCP)},
{unix.AF_INET, uint8(syscall.IPPROTO_UDP)},
{unix.AF_INET6, uint8(syscall.IPPROTO_UDP)},
{unix.AF_INET, uint8(syscall.IPPROTO_SCTP)},
{unix.AF_INET6, uint8(syscall.IPPROTO_SCTP)},
}
for _, opt := range optList {
KillSockets(opt.fam, opt.proto, true)
}

}

// SocketsAreEqual compares 2 different sockets to see if they match.
func SocketsAreEqual(aSocket, bSocket *Socket) bool {
return ((*aSocket).INode == (*bSocket).INode &&
Expand Down
2 changes: 1 addition & 1 deletion daemon/netlink/socket_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func (s *Socket) deserialize(b []byte) error {
}

// SocketKill kills a connection
func socketKill(family, proto uint8, sockID SocketID) error {
func SocketKill(family, proto uint8, sockID SocketID) error {

sockReq := &SocketRequest{
Family: family,
Expand Down

0 comments on commit 26b8415

Please # to comment.