Show compatibility notification when all global resolvers fail
This commit is contained in:
@@ -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 := ¬ifications.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user