diff --git a/firewall/dns.go b/firewall/dns.go index 5c3542f12..498d3a52d 100644 --- a/firewall/dns.go +++ b/firewall/dns.go @@ -177,6 +177,15 @@ 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 diff --git a/firewall/master.go b/firewall/master.go index 627dfe911..4f7292999 100644 --- a/firewall/master.go +++ b/firewall/master.go @@ -31,7 +31,9 @@ type deciderFn func(context.Context, *network.Connection, *profile.LayeredProfil var defaultDeciders = []deciderFn{ checkPortmasterConnection, - checkSelfCommunication, + // TODO: This is currently very slow. + // Find a way to improve performance using the eBPF data. + // checkSelfCommunication, checkIfBroadcastReply, checkConnectionType, checkConnectionScope, @@ -619,6 +621,11 @@ matchLoop: } func checkCustomFilterList(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool { + // Check if any custom list is loaded at all. + if !customlists.IsLoaded() { + return false + } + // block if the domain name appears in the custom filter list (check for subdomains if enabled) if conn.Entity.Domain != "" { if ok, match := customlists.LookupDomain(conn.Entity.Domain, p.FilterSubDomains()); ok { diff --git a/intel/customlists/lists.go b/intel/customlists/lists.go index e0f14fdd8..c13a8cd52 100644 --- a/intel/customlists/lists.go +++ b/intel/customlists/lists.go @@ -36,6 +36,25 @@ func initFilterLists() { domainsFilterList = make(map[string]struct{}) } +// IsLoaded returns whether a custom filter list is loaded. +func IsLoaded() bool { + filterListLock.RLock() + defer filterListLock.RUnlock() + + switch { + case len(domainsFilterList) > 0: + return true + case len(ipAddressesFilterList) > 0: + return true + case len(countryCodesFilterList) > 0: + return true + case len(autonomousSystemsFilterList) > 0: + return true + default: + return false + } +} + func parseFile(filePath string) error { // Reset all maps, previous (if any) settings will be lost. for key := range countryCodesFilterList { diff --git a/netquery/manager.go b/netquery/manager.go index 19a79ab1b..8749f4824 100644 --- a/netquery/manager.go +++ b/netquery/manager.go @@ -127,7 +127,7 @@ func (mng *Manager) HandleFeed(ctx context.Context, feed <-chan *network.Connect // Save to netquery database. // Do not include internal connections in history. - if err := mng.store.Save(ctx, *model, conn.HistoryEnabled && !conn.Internal); err != nil { + if err := mng.store.Save(ctx, *model, conn.HistoryEnabled); err != nil { log.Errorf("netquery: failed to save connection %s in sqlite database: %s", conn.ID, err) return } diff --git a/network/clean.go b/network/clean.go index cd17f3926..1a690757b 100644 --- a/network/clean.go +++ b/network/clean.go @@ -81,6 +81,11 @@ func cleanConnections() (activePIDs map[int]struct{}) { // Step 2: mark as ended if !exists { conn.Ended = nowUnix + + // Stop the firewall handler, in case one is running. + conn.StopFirewallHandler() + + // Save to database. conn.Save() } @@ -93,8 +98,6 @@ func cleanConnections() (activePIDs map[int]struct{}) { // DEBUG: // log.Tracef("network.clean: deleted %s (ended at %s)", conn.DatabaseKey(), time.Unix(conn.Ended, 0)) - // Stop the firewall handler, in case one is running. - conn.StopFirewallHandler() // Remove connection from state. conn.delete() } diff --git a/network/connection.go b/network/connection.go index 10d5d5865..fd2cc35c1 100644 --- a/network/connection.go +++ b/network/connection.go @@ -578,8 +578,8 @@ func (conn *Connection) SetLocalIP(ip net.IP) { conn.LocalIPScope = netutils.GetIPScope(ip) } -// UpdateFeatures checks which connection related features may be used and sets -// the flags accordingly. +// UpdateFeatures checks which connection related features may and should be +// used and sets the flags accordingly. // The caller must hold a lock on the connection. func (conn *Connection) UpdateFeatures() error { // Get user. @@ -591,7 +591,15 @@ func (conn *Connection) UpdateFeatures() error { // Check if history may be used and if it is enabled for this application. conn.HistoryEnabled = false - if user.MayUse(account.FeatureHistory) { + switch { + case conn.Internal: + // Do not record internal connections, as they are of low interest in the history. + // TODO: Should we create a setting for this? + case conn.Entity.IPScope.IsLocalhost(): + // Do not record localhost-only connections, as they are very low interest in the history. + // TODO: Should we create a setting for this? + case user.MayUse(account.FeatureHistory): + // Check if history may be used and is enabled. lProfile := conn.Process().Profile() if lProfile != nil { conn.HistoryEnabled = lProfile.EnableHistory() diff --git a/profile/config.go b/profile/config.go index 761102ca9..45be8ce3e 100644 --- a/profile/config.go +++ b/profile/config.go @@ -196,7 +196,7 @@ func registerConfiguration() error { //nolint:maintidx err := config.Register(&config.Option{ Name: "Default Network Action", Key: CfgOptionDefaultActionKey, - Description: `The default network action is applied when nothing else allows or blocks an outgoing connection. Incoming connections are always blocked by default.`, + Description: `The default network action is applied when nothing else allows or blocks a connection. This affects both outgoing and incoming connections. This setting is the weakest of all and is commonly overruled by Force Block settings or Rules.`, OptType: config.OptTypeString, DefaultValue: DefaultActionPermitValue, Annotations: config.Annotations{ @@ -252,9 +252,11 @@ func registerConfiguration() error { //nolint:maintidx // Enable History err = config.Register(&config.Option{ - Name: "Enable Network History", - Key: CfgOptionEnableHistoryKey, - Description: "Save connections in a database (on disk) in order to view and search them later. Changes might take a couple minutes to apply to all connections.", + Name: "Enable Network History", + Key: CfgOptionEnableHistoryKey, + Description: `Save connections in a database (on disk) in order to view and search them later. Changes might take a couple minutes to apply to all connections. + +In order to reduce noise optimize performance, internal and device-only (localhost) connections are not saved to history.`, OptType: config.OptTypeBool, ReleaseLevel: config.ReleaseLevelStable, ExpertiseLevel: config.ExpertiseLevelUser, diff --git a/profile/special.go b/profile/special.go index 106d294fb..1cc9c0a31 100644 --- a/profile/special.go +++ b/profile/special.go @@ -175,8 +175,12 @@ func createSpecialProfile(profileID string, path string) *Profile { // attributed to a connection of a regular process. Otherwise, users // would see two connection prompts for the same domain. CfgOptionDefaultActionKey: DefaultActionPermitValue, - // Explicitly allow incoming connections. - CfgOptionBlockInboundKey: status.SecurityLevelOff, + // Disable force blockers. + CfgOptionBlockScopeInternetKey: status.SecurityLevelOff, + CfgOptionBlockScopeLANKey: status.SecurityLevelOff, + CfgOptionBlockScopeLocalKey: status.SecurityLevelOff, + CfgOptionBlockP2PKey: status.SecurityLevelOff, + CfgOptionBlockInboundKey: status.SecurityLevelOff, // Explicitly allow localhost and answers to multicast protocols that // are commonly used by system resolvers. // TODO: When the Portmaster gains the ability to attribute multicast @@ -233,7 +237,12 @@ func createSpecialProfile(profileID string, path string) *Profile { Source: SourceLocal, PresentationPath: path, Config: map[string]interface{}{ - CfgOptionDefaultActionKey: DefaultActionBlockValue, + CfgOptionDefaultActionKey: DefaultActionBlockValue, + CfgOptionBlockScopeInternetKey: status.SecurityLevelOff, + CfgOptionBlockScopeLANKey: status.SecurityLevelOff, + CfgOptionBlockScopeLocalKey: status.SecurityLevelOff, + CfgOptionBlockP2PKey: status.SecurityLevelOff, + CfgOptionBlockInboundKey: status.SecurityLevelsAll, CfgOptionEndpointsKey: []string{ "+ Localhost", "+ .safing.io", @@ -248,7 +257,12 @@ func createSpecialProfile(profileID string, path string) *Profile { Source: SourceLocal, PresentationPath: path, Config: map[string]interface{}{ - CfgOptionDefaultActionKey: DefaultActionBlockValue, + CfgOptionDefaultActionKey: DefaultActionBlockValue, + CfgOptionBlockScopeInternetKey: status.SecurityLevelOff, + CfgOptionBlockScopeLANKey: status.SecurityLevelOff, + CfgOptionBlockScopeLocalKey: status.SecurityLevelOff, + CfgOptionBlockP2PKey: status.SecurityLevelOff, + CfgOptionBlockInboundKey: status.SecurityLevelsAll, CfgOptionEndpointsKey: []string{ "+ Localhost", }, @@ -281,11 +295,11 @@ func specialProfileNeedsReset(profile *Profile) bool { switch profile.ID { case SystemResolverProfileID: - return canBeUpgraded(profile, "21.10.2022") + return canBeUpgraded(profile, "12.8.2023") // FIXME: set one day after stable release date. case PortmasterProfileID: - return canBeUpgraded(profile, "21.10.2022") + return canBeUpgraded(profile, "12.8.2023") // FIXME: set one day after stable release date. case PortmasterAppProfileID: - return canBeUpgraded(profile, "8.9.2021") + return canBeUpgraded(profile, "12.8.2023") // FIXME: set one day after stable release date. default: // Not a special profile or no upgrade available yet. return false