Finalize profile merging, add profile metadata state handling, re-attribute connections after profile deletion
This commit is contained in:
@@ -2,13 +2,18 @@ package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portbase/config"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/modules"
|
||||
"github.com/safing/portbase/modules/subsystems"
|
||||
_ "github.com/safing/portmaster/core"
|
||||
"github.com/safing/portmaster/network"
|
||||
"github.com/safing/portmaster/profile"
|
||||
"github.com/safing/spn/access"
|
||||
"github.com/safing/spn/captain"
|
||||
)
|
||||
|
||||
var module *modules.Module
|
||||
@@ -25,12 +30,6 @@ func init() {
|
||||
)
|
||||
}
|
||||
|
||||
const (
|
||||
configChangeEvent = "config change"
|
||||
profileConfigChangeEvent = "profile config change"
|
||||
onSPNConnectEvent = "spn connect"
|
||||
)
|
||||
|
||||
func prep() error {
|
||||
network.SetDefaultFirewallHandler(verdictHandler)
|
||||
|
||||
@@ -38,8 +37,8 @@ func prep() error {
|
||||
// this will be triggered on spn enable/disable
|
||||
err := module.RegisterEventHook(
|
||||
"config",
|
||||
configChangeEvent,
|
||||
"reset connection verdicts",
|
||||
config.ChangeEvent,
|
||||
"reset connection verdicts after global config change",
|
||||
func(ctx context.Context, _ interface{}) error {
|
||||
resetAllConnectionVerdicts()
|
||||
return nil
|
||||
@@ -52,10 +51,20 @@ func prep() error {
|
||||
// Reset connections every time profile changes
|
||||
err = module.RegisterEventHook(
|
||||
"profiles",
|
||||
profileConfigChangeEvent,
|
||||
"reset connection verdicts",
|
||||
func(ctx context.Context, _ interface{}) error {
|
||||
resetAllConnectionVerdicts()
|
||||
profile.ConfigChangeEvent,
|
||||
"reset connection verdicts after profile config change",
|
||||
func(ctx context.Context, eventData interface{}) error {
|
||||
// Expected event data: scoped profile ID.
|
||||
profileID, ok := eventData.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("event data is not a string: %v", eventData)
|
||||
}
|
||||
profileSource, profileID, ok := strings.Cut(profileID, "/")
|
||||
if !ok {
|
||||
return fmt.Errorf("event data does not seem to be a scoped profile ID: %v", eventData)
|
||||
}
|
||||
|
||||
resetProfileConnectionVerdict(profileSource, profileID)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -67,8 +76,8 @@ func prep() error {
|
||||
// connect and disconnecting is triggered on config change event but connecting takеs more time
|
||||
err = module.RegisterEventHook(
|
||||
"captain",
|
||||
onSPNConnectEvent,
|
||||
"reset connection verdicts",
|
||||
captain.SPNConnectedEvent,
|
||||
"reset connection verdicts on SPN connect",
|
||||
func(ctx context.Context, _ interface{}) error {
|
||||
resetAllConnectionVerdicts()
|
||||
return nil
|
||||
@@ -83,7 +92,7 @@ func prep() error {
|
||||
err = module.RegisterEventHook(
|
||||
"access",
|
||||
access.AccountUpdateEvent,
|
||||
"update connection feature flags",
|
||||
"update connection feature flags after account update",
|
||||
func(ctx context.Context, _ interface{}) error {
|
||||
resetAllConnectionVerdicts()
|
||||
return nil
|
||||
@@ -93,6 +102,24 @@ func prep() error {
|
||||
log.Errorf("filter: failed to register event hook: %s", err)
|
||||
}
|
||||
|
||||
err = module.RegisterEventHook(
|
||||
"network",
|
||||
network.ConnectionReattributedEvent,
|
||||
"reset verdict of re-attributed connection",
|
||||
func(ctx context.Context, eventData interface{}) error {
|
||||
// Expected event data: connection ID.
|
||||
connID, ok := eventData.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("event data is not a string: %v", eventData)
|
||||
}
|
||||
resetSingleConnectionVerdict(connID)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("filter: failed to register event hook: %s", err)
|
||||
}
|
||||
|
||||
if err := registerConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,13 +43,55 @@ var (
|
||||
ownPID = os.Getpid()
|
||||
)
|
||||
|
||||
func resetAllConnectionVerdicts() {
|
||||
// Resetting will force all the connection to be evaluated by the firewall again
|
||||
// this will set new verdicts if configuration was update or spn has been disabled or enabled.
|
||||
log.Info("interception: re-evaluating all connections")
|
||||
|
||||
func resetSingleConnectionVerdict(connID string) {
|
||||
// Create tracing context.
|
||||
ctx, tracer := log.AddTracer(context.Background())
|
||||
defer tracer.Submit()
|
||||
|
||||
conn, ok := network.GetConnection(connID)
|
||||
if !ok {
|
||||
conn, ok = network.GetDNSConnection(connID)
|
||||
if !ok {
|
||||
tracer.Debugf("filter: could not find re-attributed connection %s for re-evaluation", connID)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resetConnectionVerdict(ctx, conn)
|
||||
}
|
||||
|
||||
func resetProfileConnectionVerdict(profileSource, profileID string) {
|
||||
// Create tracing context.
|
||||
ctx, tracer := log.AddTracer(context.Background())
|
||||
defer tracer.Submit()
|
||||
|
||||
// Resetting will force all the connection to be evaluated by the firewall again
|
||||
// this will set new verdicts if configuration was update or spn has been disabled or enabled.
|
||||
tracer.Infof("filter: re-evaluating connections of %s/%s", profileSource, profileID)
|
||||
|
||||
// Re-evaluate all connections.
|
||||
var changedVerdicts int
|
||||
for _, conn := range network.GetAllConnections() {
|
||||
// Check if connection is complete and attributed to the deleted profile.
|
||||
if conn.DataIsComplete() &&
|
||||
conn.ProcessContext.Profile == profileID &&
|
||||
conn.ProcessContext.Source == profileSource {
|
||||
if resetConnectionVerdict(ctx, conn) {
|
||||
changedVerdicts++
|
||||
}
|
||||
}
|
||||
}
|
||||
tracer.Infof("filter: changed verdict on %d connections", changedVerdicts)
|
||||
}
|
||||
|
||||
func resetAllConnectionVerdicts() {
|
||||
// Create tracing context.
|
||||
ctx, tracer := log.AddTracer(context.Background())
|
||||
defer tracer.Submit()
|
||||
|
||||
// Resetting will force all the connection to be evaluated by the firewall again
|
||||
// this will set new verdicts if configuration was update or spn has been disabled or enabled.
|
||||
tracer.Info("filter: re-evaluating all connections")
|
||||
|
||||
// Re-evaluate all connections.
|
||||
var changedVerdicts int
|
||||
@@ -59,54 +101,60 @@ func resetAllConnectionVerdicts() {
|
||||
continue
|
||||
}
|
||||
|
||||
func() {
|
||||
conn.Lock()
|
||||
defer conn.Unlock()
|
||||
|
||||
// Update feature flags.
|
||||
if err := conn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {
|
||||
tracer.Warningf("network: failed to update connection feature flags: %s", err)
|
||||
}
|
||||
|
||||
// Skip internal connections:
|
||||
// - Pre-authenticated connections from Portmaster
|
||||
// - Redirected DNS requests
|
||||
// - SPN Uplink to Home Hub
|
||||
if conn.Internal {
|
||||
tracer.Tracef("filter: skipping internal connection %s", conn)
|
||||
return
|
||||
}
|
||||
|
||||
tracer.Debugf("filter: re-evaluating verdict of %s", conn)
|
||||
previousVerdict := conn.Verdict.Firewall
|
||||
|
||||
// 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 {
|
||||
err := conn.TunnelContext.StopTunnel()
|
||||
if err != nil {
|
||||
tracer.Debugf("filter: failed to stopped unneeded tunnel: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
changedVerdicts++
|
||||
} else {
|
||||
tracer.Tracef("filter: verdict to connection %s unchanged at %s", conn, conn.VerdictVerb())
|
||||
}
|
||||
}()
|
||||
if resetConnectionVerdict(ctx, conn) {
|
||||
changedVerdicts++
|
||||
}
|
||||
}
|
||||
tracer.Infof("filter: changed verdict on %d connections", changedVerdicts)
|
||||
tracer.Submit()
|
||||
}
|
||||
|
||||
func resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verdictChanged bool) {
|
||||
tracer := log.Tracer(ctx)
|
||||
|
||||
conn.Lock()
|
||||
defer conn.Unlock()
|
||||
|
||||
// Update feature flags.
|
||||
if err := conn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {
|
||||
tracer.Warningf("filter: failed to update connection feature flags: %s", err)
|
||||
}
|
||||
|
||||
// Skip internal connections:
|
||||
// - Pre-authenticated connections from Portmaster
|
||||
// - Redirected DNS requests
|
||||
// - SPN Uplink to Home Hub
|
||||
if conn.Internal {
|
||||
// tracer.Tracef("filter: skipping internal connection %s", conn)
|
||||
return false
|
||||
}
|
||||
|
||||
tracer.Debugf("filter: re-evaluating verdict of %s", conn)
|
||||
previousVerdict := conn.Verdict.Firewall
|
||||
|
||||
// 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 {
|
||||
err := conn.TunnelContext.StopTunnel()
|
||||
if err != nil {
|
||||
tracer.Debugf("filter: failed to stopped unneeded tunnel: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
return true
|
||||
}
|
||||
|
||||
tracer.Tracef("filter: verdict to connection %s unchanged at %s", conn, conn.VerdictVerb())
|
||||
return false
|
||||
}
|
||||
|
||||
// SetNameserverIPMatcher sets a function that is used to match the internal
|
||||
|
||||
Reference in New Issue
Block a user