From 4ffc6e53b70cfa206c99b1dda56e22fe2544e44f Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 Dec 2023 11:00:14 +0100 Subject: [PATCH] Remove connection prompts when applicable settings are changed by user --- firewall/packet_handler.go | 16 ++++++++++++---- firewall/prompt.go | 10 +++++++++- network/connection.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/firewall/packet_handler.go b/firewall/packet_handler.go index 5b092495..093df319 100644 --- a/firewall/packet_handler.go +++ b/firewall/packet_handler.go @@ -111,6 +111,9 @@ func resetAllConnectionVerdicts() { func resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verdictChanged bool) { tracer := log.Tracer(ctx) + // Remove any active prompt as we settings are being re-evaluated. + conn.RemovePrompt() + conn.Lock() defer conn.Unlock() @@ -144,12 +147,17 @@ func resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verd // Save if verdict changed. if conn.Verdict.Firewall != previousVerdict { - err := interception.UpdateVerdictOfConnection(conn) - if err != nil { - log.Debugf("filter: failed to update connection verdict: %s", err) - } conn.Save() tracer.Infof("filter: verdict of connection %s changed from %s to %s", conn, previousVerdict.Verb(), conn.VerdictVerb()) + + // Update verdict in OS integration, if an IP connection. + if conn.Type == network.IPConnection { + err := interception.UpdateVerdictOfConnection(conn) + if err != nil { + log.Debugf("filter: failed to update connection verdict: %s", err) + } + } + return true } diff --git a/firewall/prompt.go b/firewall/prompt.go index e3582ba0..0b2b4ef7 100644 --- a/firewall/prompt.go +++ b/firewall/prompt.go @@ -54,6 +54,9 @@ func prompt(ctx context.Context, conn *network.Connection) { return } + // Add prompt to connection. + conn.SetPrompt(n) + // Get decision timeout and make sure it does not exceed the ask timeout. timeout := decisionTimeout if timeout > askTimeout() { @@ -65,8 +68,13 @@ func prompt(ctx context.Context, conn *network.Connection) { case promptResponse := <-n.Response(): switch promptResponse { case allowDomainAll, allowDomainDistinct, allowIP, allowServingIP: + // Accept conn.Accept("allowed via prompt", profile.CfgOptionEndpointsKey) - default: // deny + case "": + // Dismissed + conn.Deny("prompting canceled, waiting for new decision", profile.CfgOptionDefaultActionKey) + default: + // Deny conn.Deny("blocked via prompt", profile.CfgOptionEndpointsKey) } diff --git a/network/connection.go b/network/connection.go index 55fc6a3d..6954b0f1 100644 --- a/network/connection.go +++ b/network/connection.go @@ -12,6 +12,7 @@ import ( "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" + "github.com/safing/portbase/notifications" "github.com/safing/portmaster/intel" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/netutils" @@ -187,6 +188,13 @@ type Connection struct { //nolint:maligned // TODO: fix alignment // BytesSent holds the observed sent bytes of the connection. BytesSent uint64 + // prompt holds the active prompt for this connection, if there is one. + prompt *notifications.Notification + // promptLock locks the prompt separately from the connection. + // This allows goroutines to dismiss the notification, while another goroutine + // is waiting for the prompt and holding a lock on the connection. + promptLock sync.Mutex + // pkgQueue is used to serialize packet handling for a single // connection and is served by the connections packetHandler. pktQueue chan packet.Packet @@ -1030,6 +1038,28 @@ func (conn *Connection) SetInspectorData(newInspectorData map[uint8]interface{}) conn.inspectorData = newInspectorData } +// SetPrompt sets the given prompt on the connection. +// If there already is a prompt set, the previous prompt notification is deleted. +func (conn *Connection) SetPrompt(prompt *notifications.Notification) { + conn.promptLock.Lock() + defer conn.promptLock.Unlock() + + if conn.prompt != nil { + conn.prompt.Delete() + } + conn.prompt = prompt +} + +// RemovePrompt removes the prompt on the connection. +func (conn *Connection) RemovePrompt() { + conn.promptLock.Lock() + defer conn.promptLock.Unlock() + + if conn.prompt != nil { + conn.prompt.Delete() + } +} + // String returns a string representation of conn. func (conn *Connection) String() string { switch {