diff --git a/firewall/filter.go b/firewall/filter.go index 58a24737..390ef3f3 100644 --- a/firewall/filter.go +++ b/firewall/filter.go @@ -2,9 +2,11 @@ package firewall import ( "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/intel/filterlists" "github.com/safing/spn/captain" ) @@ -12,10 +14,13 @@ var ( filterModule *modules.Module filterEnabled config.BoolOption tunnelEnabled config.BoolOption + + unbreakFilterListIDs = []string{"UNBREAK"} + resolvedUnbreakFilterListIDs []string ) func init() { - filterModule = modules.Register("filter", filterPrep, nil, nil, "core", "intel") + filterModule = modules.Register("filter", filterPrep, filterStart, nil, "core", "intel") subsystems.Register( "filter", "Privacy Filter", @@ -47,3 +52,14 @@ func filterPrep() (err error) { tunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false) return nil } + +func filterStart() error { + // TODO: Re-resolve IDs when filterlist index changes. + resolvedIDs, err := filterlists.ResolveListIDs(unbreakFilterListIDs) + if err != nil { + log.Warningf("filter: failed to resolve unbreak filter list IDs: %s", err) + } else { + resolvedUnbreakFilterListIDs = resolvedIDs + } + return nil +} diff --git a/firewall/master.go b/firewall/master.go index e50617d0..1de7f194 100644 --- a/firewall/master.go +++ b/firewall/master.go @@ -432,6 +432,16 @@ func checkFilterLists(ctx context.Context, conn *network.Connection, p *profile. result, reason := p.MatchFilterLists(ctx, conn.Entity) switch result { case endpoints.Denied: + // If the connection matches a filter list, check if the "unbreak" list matches too and abort blocking. + for _, blockedListID := range conn.Entity.BlockedByLists { + for _, unbreakListID := range resolvedUnbreakFilterListIDs { + if blockedListID == unbreakListID { + log.Tracer(ctx).Debugf("filter: unbreak filter %s matched, ignoring other filter list matches", unbreakListID) + return false + } + } + } + // Otherwise, continue with blocking. conn.DenyWithContext(reason.String(), profile.CfgOptionFilterListsKey, reason.Context()) return true case endpoints.NoMatch: