Show compatibility notification when all global resolvers fail

This commit is contained in:
Daniel
2021-11-17 14:12:19 +01:00
parent 68710dd284
commit 8d753808e1
3 changed files with 71 additions and 10 deletions

View File

@@ -4,11 +4,14 @@ import (
"context"
"net"
"strings"
"sync"
"time"
"github.com/safing/portbase/log"
"github.com/safing/portbase/modules"
"github.com/safing/portbase/notifications"
"github.com/safing/portmaster/intel"
"github.com/tevino/abool"
// module dependencies
_ "github.com/safing/portmaster/core/base"
@@ -105,3 +108,50 @@ func getLocalAddr(network string) net.Addr {
}
return nil
}
var (
failingResolverNotification *notifications.Notification
failingResolverNotificationSet = abool.New()
failingResolverNotificationLock sync.Mutex
)
func notifyAboutFailingResolvers(err error) {
failingResolverNotificationLock.Lock()
defer failingResolverNotificationLock.Unlock()
failingResolverNotificationSet.Set()
// Check if already set.
if failingResolverNotification != nil {
return
}
// Create new notification.
n := &notifications.Notification{
EventID: "resolver:all-configured-resolvers-failed",
Type: notifications.Error,
Title: "Detected DNS Compatibility Issue",
Message: "Portmaster detected that something is interfering with its Secure DNS resolver. This could be a firewall or another secure DNS resolver software. Please check if you are running incompatible [software](https://docs.safing.io/portmaster/install/status/software-compatibility). Otherwise, please report the issue via [GitHub](https://github.com/safing/portmaster/issues) or send a mail to [support@safing.io](mailto:support@safing.io) so we can help you out.",
ShowOnSystem: true,
}
notifications.Notify(n)
failingResolverNotification = n
n.AttachToModule(module)
// Report the raw error as module error.
module.NewErrorMessage("resolving", err).Report()
}
func resetFailingResolversNotification() {
if failingResolverNotificationSet.IsNotSet() {
return
}
failingResolverNotificationLock.Lock()
defer failingResolverNotificationLock.Unlock()
if failingResolverNotification != nil {
failingResolverNotification.Delete()
failingResolverNotification = nil
}
}

View File

@@ -7,12 +7,12 @@ import (
"sync"
"time"
"github.com/safing/portmaster/netenv"
"github.com/miekg/dns"
"github.com/safing/portbase/database"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/compat"
"github.com/safing/portmaster/netenv"
)
var (
@@ -313,13 +313,13 @@ retry:
func resolveAndCache(ctx context.Context, q *Query, oldCache *RRCache) (rrCache *RRCache, err error) { //nolint:gocognit,gocyclo
// get resolvers
resolvers, tryAll := GetResolversInScope(ctx, q)
resolvers, primarySource, tryAll := GetResolversInScope(ctx, q)
if len(resolvers) == 0 {
return nil, ErrNoCompliance
}
// check if we are online
if netenv.GetOnlineStatus() == netenv.StatusOffline {
if primarySource != ServerSourceEnv && netenv.GetOnlineStatus() == netenv.StatusOffline {
if !netenv.IsConnectivityDomain(q.FQDN) {
// we are offline and this is not an online check query
return oldCache, ErrOffline
@@ -391,6 +391,10 @@ resolveLoop:
// Report a successful connection.
resolver.Conn.ResetFailure()
// Reset failing resolvers notification, if querying in global scope.
if primarySource == ServerSourceConfigured {
resetFailingResolversNotification()
}
break resolveLoop
}
@@ -401,6 +405,13 @@ resolveLoop:
// tried all resolvers, possibly twice
if i > 1 {
err = fmt.Errorf("all %d query-compliant resolvers failed, last error: %s", len(resolvers), err)
if primarySource == ServerSourceConfigured &&
netenv.Online() && compat.SelfCheckIsFailing() {
notifyAboutFailingResolvers(err)
} else {
resetFailingResolversNotification()
}
}
} else if rrCache == nil /* defensive */ {
err = ErrNotFound

View File

@@ -109,20 +109,20 @@ func domainInScope(dotPrefixedFQDN string, scopeList []string) bool {
}
// GetResolversInScope returns all resolvers that are in scope the resolve the given query and options.
func GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, tryAll bool) { //nolint:gocognit // TODO
func GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, primarySource string, tryAll bool) { //nolint:gocognit // TODO
resolversLock.RLock()
defer resolversLock.RUnlock()
// Internal use domains
if domainInScope(q.dotPrefixedFQDN, internalSpecialUseDomains) {
return envResolvers, false
return envResolvers, ServerSourceEnv, false
}
// Special connectivity domains
if netenv.IsConnectivityDomain(q.FQDN) && len(systemResolvers) > 0 {
// Do not do compliance checks for connectivity domains.
selected = append(selected, systemResolvers...) // dhcp assigned resolvers
return selected, false
return selected, ServerSourceOperatingSystem, false
}
// Prioritize search scopes
@@ -137,7 +137,7 @@ func GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, t
selected = addResolvers(ctx, q, selected, mDNSResolvers)
selected = addResolvers(ctx, q, selected, localResolvers)
selected = addResolvers(ctx, q, selected, systemResolvers)
return selected, true
return selected, ServerSourceMDNS, true
}
// Special use domains
@@ -145,12 +145,12 @@ func GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, t
domainInScope(q.dotPrefixedFQDN, specialServiceDomains) {
selected = addResolvers(ctx, q, selected, localResolvers)
selected = addResolvers(ctx, q, selected, systemResolvers)
return selected, true
return selected, "special", true
}
// Global domains
selected = addResolvers(ctx, q, selected, globalResolvers)
return selected, false
return selected, ServerSourceConfigured, false
}
func addResolvers(ctx context.Context, q *Query, selected []*Resolver, addResolvers []*Resolver) []*Resolver {