diff --git a/firewall/interception.go b/firewall/interception.go index bc4395a7..e5be02dc 100644 --- a/firewall/interception.go +++ b/firewall/interception.go @@ -149,6 +149,10 @@ func resetAllConnectionVerdicts() { // Save if verdict changed. if conn.Verdict.Firewall != previousVerdict { + err := interception.UpdateVerdictOfConnection(conn) + if err != nil { + log.Debugf("filter: failed to delete connection verdict: %s", err) + } conn.Save() tracer.Infof("filter: verdict of connection %s changed from %s to %s", conn, previousVerdict.Verb(), conn.VerdictVerb()) changedVerdicts++ @@ -159,11 +163,6 @@ func resetAllConnectionVerdicts() { } tracer.Infof("filter: changed verdict on %d connections", changedVerdicts) tracer.Submit() - - err := interception.ResetVerdictOfAllConnections() - if err != nil { - log.Errorf("interception: failed to remove persistent verdicts: %s", err) - } } func interceptionStart() error { diff --git a/firewall/interception/interception_linux.go b/firewall/interception/interception_linux.go index 6fe38edf..f0f1d99f 100644 --- a/firewall/interception/interception_linux.go +++ b/firewall/interception/interception_linux.go @@ -2,6 +2,7 @@ package interception import ( "github.com/safing/portmaster/firewall/interception/nfq" + "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/packet" ) @@ -19,3 +20,7 @@ func stop() error { func ResetVerdictOfAllConnections() error { return nfq.DeleteAllMarkedConnection() } + +func UpdateVerdictOfConnection(conn *network.Connection) error { + return nfq.DeleteMarkedConnection(conn) +} diff --git a/firewall/interception/nfq/conntrack.go b/firewall/interception/nfq/conntrack.go index ac25728d..ce494792 100644 --- a/firewall/interception/nfq/conntrack.go +++ b/firewall/interception/nfq/conntrack.go @@ -4,20 +4,37 @@ package nfq import ( "encoding/binary" + "fmt" ct "github.com/florianl/go-conntrack" "github.com/safing/portbase/log" "github.com/safing/portmaster/netenv" + "github.com/safing/portmaster/network" ) -// DeleteAllMarkedConnection deletes all marked entries from the conntrack table. -func DeleteAllMarkedConnection() error { - nfct, err := ct.Open(&ct.Config{}) +var ( + nfct *ct.Nfct // Conntrack handler. NFCT: Network Filter Connection Tracking +) + +func InitNFCT() error { + var err error + nfct, err = ct.Open(&ct.Config{}) if err != nil { return err } - defer func() { _ = nfct.Close() }() + return nil +} + +func DeinitNFCT() { + _ = nfct.Close() +} + +// DeleteAllMarkedConnection deletes all marked entries from the conntrack table. +func DeleteAllMarkedConnection() error { + if nfct == nil { + return fmt.Errorf("nfq: nfct not initialized") + } // Delete all ipv4 marked connections deleted := deleteMarkedConnections(nfct, ct.IPv4) @@ -64,3 +81,35 @@ func deleteMarkedConnections(nfct *ct.Nfct, f ct.Family) (deleted int) { } return deleted } + +func DeleteMarkedConnection(conn *network.Connection) error { + if nfct == nil { + return fmt.Errorf("nfq: nfct not initialized") + } + + con := ct.Con{ + Origin: &ct.IPTuple{ + Src: &conn.LocalIP, + Dst: &conn.Entity.IP, + Proto: &ct.ProtoTuple{ + Number: &conn.Entity.Protocol, + SrcPort: &conn.LocalPort, + DstPort: &conn.Entity.Port, + }, + }, + } + connections, err := nfct.Get(ct.Conntrack, ct.IPv4, con) + if err != nil { + return fmt.Errorf("nfq: failed to find entry for connection %s: %s", conn.String(), err) + } + + if len(connections) > 1 { + log.Warningf("nfq: multiple entries found for single connection: %s -> %d", conn.String(), len(connections)) + } + + for _, connection := range connections { + nfct.Delete(ct.Conntrack, ct.IPv4, connection) + } + + return nil +} diff --git a/firewall/interception/nfqueue_linux.go b/firewall/interception/nfqueue_linux.go index 488cc7a4..54d7f91a 100644 --- a/firewall/interception/nfqueue_linux.go +++ b/firewall/interception/nfqueue_linux.go @@ -147,6 +147,11 @@ func activateNfqueueFirewall() error { } } + if err := nfq.InitNFCT(); err != nil { + return err + } + nfq.DeleteAllMarkedConnection() + return nil } @@ -166,6 +171,9 @@ func DeactivateNfqueueFirewall() error { } } + nfq.DeleteAllMarkedConnection() + nfq.DeinitNFCT() + return result.ErrorOrNil() }