Revamped verdict handling
This commit is contained in:
@@ -177,15 +177,6 @@ func FilterResolvedDNS(
|
||||
return rrCache
|
||||
}
|
||||
|
||||
// Finalize verdict.
|
||||
defer func() {
|
||||
// Reset from previous filtering.
|
||||
conn.Verdict.Active = network.VerdictUndecided
|
||||
conn.Verdict.Worst = network.VerdictUndecided
|
||||
// Update all values again.
|
||||
finalizeVerdict(conn)
|
||||
}()
|
||||
|
||||
// special grant for connectivity domains
|
||||
if checkConnectivityDomain(ctx, conn, layeredProfile, nil) {
|
||||
// returns true if check triggered
|
||||
@@ -197,7 +188,7 @@ func FilterResolvedDNS(
|
||||
|
||||
// Filter dns records and return if the query is blocked.
|
||||
rrCache = filterDNSResponse(ctx, conn, layeredProfile, rrCache, sysResolver)
|
||||
if conn.Verdict.Active == network.VerdictBlock {
|
||||
if conn.Verdict == network.VerdictBlock {
|
||||
return rrCache
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func RunInspectors(conn *network.Connection, pkt packet.Packet) (network.Verdict
|
||||
}
|
||||
|
||||
// check if the active verdict is already past the inspection criteria.
|
||||
if conn.Verdict.Active > inspectVerdicts[key] {
|
||||
if conn.Verdict > inspectVerdicts[key] {
|
||||
activeInspectors[key] = true
|
||||
continue
|
||||
}
|
||||
@@ -86,11 +86,11 @@ func RunInspectors(conn *network.Connection, pkt packet.Packet) (network.Verdict
|
||||
continueInspection = true
|
||||
case BLOCK_CONN:
|
||||
conn.SetVerdict(network.VerdictBlock, "", "", nil)
|
||||
verdict = conn.Verdict.Active
|
||||
verdict = conn.Verdict
|
||||
activeInspectors[key] = true
|
||||
case DROP_CONN:
|
||||
conn.SetVerdict(network.VerdictDrop, "", "", nil)
|
||||
verdict = conn.Verdict.Active
|
||||
verdict = conn.Verdict
|
||||
activeInspectors[key] = true
|
||||
case STOP_INSPECTING:
|
||||
activeInspectors[key] = true
|
||||
|
||||
@@ -254,7 +254,7 @@ func UpdateVerdict(conn *network.Connection) error {
|
||||
localPort: conn.LocalPort,
|
||||
remoteIP: ipAddressToArray(conn.Entity.IP, isIpv6 == 1),
|
||||
remotePort: conn.Entity.Port,
|
||||
verdict: uint8(conn.Verdict.Active),
|
||||
verdict: uint8(conn.Verdict),
|
||||
}
|
||||
|
||||
// Make driver request
|
||||
|
||||
@@ -103,7 +103,7 @@ func decideOnConnection(ctx context.Context, conn *network.Connection, pkt packe
|
||||
case profile.DefaultActionAsk:
|
||||
// Only prompt if there has not been a decision already.
|
||||
// This prevents prompts from being created when re-evaluating connections.
|
||||
if conn.Verdict.Firewall == network.VerdictUndecided {
|
||||
if conn.Verdict == network.VerdictUndecided {
|
||||
prompt(ctx, conn)
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/safing/portmaster/network"
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
"github.com/safing/portmaster/network/packet"
|
||||
"github.com/safing/portmaster/network/reference"
|
||||
"github.com/safing/portmaster/process"
|
||||
"github.com/safing/spn/access"
|
||||
)
|
||||
@@ -132,13 +131,13 @@ func resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verd
|
||||
}
|
||||
|
||||
tracer.Debugf("filter: re-evaluating verdict of %s", conn)
|
||||
previousVerdict := conn.Verdict.Firewall
|
||||
previousVerdict := conn.Verdict
|
||||
|
||||
// Apply privacy filter and check tunneling.
|
||||
FilterConnection(ctx, conn, nil, true, true)
|
||||
|
||||
// Stop existing SPN tunnel if not needed anymore.
|
||||
if conn.Verdict.Active != network.VerdictRerouteToTunnel && conn.TunnelContext != nil {
|
||||
if conn.Verdict != network.VerdictRerouteToTunnel && conn.TunnelContext != nil {
|
||||
err := conn.TunnelContext.StopTunnel()
|
||||
if err != nil {
|
||||
tracer.Debugf("filter: failed to stopped unneeded tunnel: %s", err)
|
||||
@@ -146,7 +145,11 @@ func resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verd
|
||||
}
|
||||
|
||||
// Save if verdict changed.
|
||||
if conn.Verdict.Firewall != previousVerdict {
|
||||
if conn.Verdict != 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())
|
||||
|
||||
@@ -368,16 +371,17 @@ func fastTrackHandler(conn *network.Connection, pkt packet.Packet) {
|
||||
fastTrackedVerdict, permanent := fastTrackedPermit(conn, pkt)
|
||||
if fastTrackedVerdict != network.VerdictUndecided {
|
||||
// Set verdict on connection.
|
||||
conn.Verdict.Active = fastTrackedVerdict
|
||||
conn.Verdict.Firewall = fastTrackedVerdict
|
||||
conn.Verdict = fastTrackedVerdict
|
||||
|
||||
// Apply verdict to (real) packet.
|
||||
if !pkt.InfoOnly() {
|
||||
issueVerdict(conn, pkt, fastTrackedVerdict, permanent)
|
||||
}
|
||||
|
||||
// Stop handler if permanent.
|
||||
if permanent {
|
||||
conn.SetVerdict(fastTrackedVerdict, "fast-tracked", "", nil)
|
||||
conn.Verdict.Worst = fastTrackedVerdict
|
||||
|
||||
// Do not finalize verdict, as we are missing necessary data.
|
||||
conn.StopFirewallHandler()
|
||||
}
|
||||
@@ -447,7 +451,7 @@ func filterHandler(conn *network.Connection, pkt packet.Packet) {
|
||||
|
||||
// End directly, as no other processing is necessary.
|
||||
conn.StopFirewallHandler()
|
||||
finalizeVerdict(conn)
|
||||
|
||||
issueVerdict(conn, pkt, 0, true)
|
||||
return
|
||||
}
|
||||
@@ -504,19 +508,17 @@ func FilterConnection(ctx context.Context, conn *network.Connection, pkt packet.
|
||||
checkTunneling(ctx, conn)
|
||||
}
|
||||
|
||||
// Handle verdict records and transitions.
|
||||
finalizeVerdict(conn)
|
||||
|
||||
// Request tunneling if no tunnel is set and connection should be tunneled.
|
||||
if conn.Verdict.Active == network.VerdictRerouteToTunnel &&
|
||||
if conn.Verdict == network.VerdictRerouteToTunnel &&
|
||||
conn.TunnelContext == nil {
|
||||
err := requestTunneling(ctx, conn)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
conn.ConnectionEstablished = true
|
||||
} else {
|
||||
// Set connection to failed, but keep tunneling data.
|
||||
// The tunneling data makes connection easy to recognize as a failed SPN
|
||||
// connection and the data will help with debugging and displaying in the UI.
|
||||
conn.Failed(fmt.Sprintf("failed to request tunneling: %s", err), "")
|
||||
finalizeVerdict(conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,8 +565,8 @@ func issueVerdict(conn *network.Connection, pkt packet.Packet, verdict network.V
|
||||
}
|
||||
|
||||
// do not allow to circumvent decision: e.g. to ACCEPT packets from a DROP-ed connection
|
||||
if verdict < conn.Verdict.Active {
|
||||
verdict = conn.Verdict.Active
|
||||
if verdict < conn.Verdict {
|
||||
verdict = conn.Verdict
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -622,53 +624,6 @@ var verdictRating = []network.Verdict{
|
||||
network.VerdictUndecided,
|
||||
}
|
||||
|
||||
func finalizeVerdict(conn *network.Connection) {
|
||||
// Update worst verdict at the end.
|
||||
defer func() {
|
||||
for _, worstVerdict := range verdictRating {
|
||||
if conn.Verdict.Firewall == worstVerdict {
|
||||
conn.Verdict.Worst = worstVerdict
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Check for non-applicable verdicts.
|
||||
// The earlier and clearer we do this, the better.
|
||||
switch conn.Verdict.Firewall { //nolint:exhaustive
|
||||
case network.VerdictUndecided, network.VerdictUndeterminable, network.VerdictFailed:
|
||||
if conn.Inbound {
|
||||
conn.Verdict.Active = network.VerdictDrop
|
||||
} else {
|
||||
conn.Verdict.Active = network.VerdictBlock
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Apply firewall verdict to active verdict.
|
||||
switch {
|
||||
case conn.Verdict.Active == network.VerdictUndecided:
|
||||
// Apply first verdict without change.
|
||||
conn.Verdict.Active = conn.Verdict.Firewall
|
||||
|
||||
case conn.Verdict.Worst == network.VerdictBlock ||
|
||||
conn.Verdict.Worst == network.VerdictDrop ||
|
||||
conn.Verdict.Worst == network.VerdictFailed ||
|
||||
conn.Verdict.Worst == network.VerdictUndeterminable:
|
||||
// Always allow to change verdict from any real initial/worst non-allowed state.
|
||||
// Note: This check needs to happen before updating the Worst verdict.
|
||||
conn.Verdict.Active = conn.Verdict.Firewall
|
||||
|
||||
case reference.IsPacketProtocol(conn.Entity.Protocol):
|
||||
// For known packet protocols, apply firewall verdict unchanged.
|
||||
conn.Verdict.Active = conn.Verdict.Firewall
|
||||
|
||||
case conn.Verdict.Active != conn.Verdict.Firewall:
|
||||
// For all other protocols (most notably, stream protocols), always block after the first change.
|
||||
// Block in both directions, as there is a live connection, which we want to actively kill.
|
||||
conn.Verdict.Active = network.VerdictBlock
|
||||
}
|
||||
}
|
||||
|
||||
// func tunnelHandler(pkt packet.Packet) {
|
||||
// tunnelInfo := GetTunnelInfo(pkt.Info().Dst)
|
||||
// if tunnelInfo == nil {
|
||||
|
||||
@@ -31,7 +31,7 @@ func checkTunneling(ctx context.Context, conn *network.Connection) {
|
||||
case conn.Inbound:
|
||||
// Can't tunnel incoming connections.
|
||||
return
|
||||
case conn.Verdict.Firewall != network.VerdictAccept:
|
||||
case conn.Verdict != network.VerdictAccept:
|
||||
// Connection will be blocked.
|
||||
return
|
||||
case conn.IPProtocol != packet.TCP && conn.IPProtocol != packet.UDP:
|
||||
|
||||
Reference in New Issue
Block a user