Show compatibility notification when all global resolvers fail
This commit is contained in:
@@ -4,11 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portbase/modules"
|
"github.com/safing/portbase/modules"
|
||||||
|
"github.com/safing/portbase/notifications"
|
||||||
"github.com/safing/portmaster/intel"
|
"github.com/safing/portmaster/intel"
|
||||||
|
"github.com/tevino/abool"
|
||||||
|
|
||||||
// module dependencies
|
// module dependencies
|
||||||
_ "github.com/safing/portmaster/core/base"
|
_ "github.com/safing/portmaster/core/base"
|
||||||
@@ -105,3 +108,50 @@ func getLocalAddr(network string) net.Addr {
|
|||||||
}
|
}
|
||||||
return nil
|
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"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portmaster/netenv"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/safing/portbase/database"
|
"github.com/safing/portbase/database"
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portmaster/compat"
|
||||||
|
"github.com/safing/portmaster/netenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -313,13 +313,13 @@ retry:
|
|||||||
|
|
||||||
func resolveAndCache(ctx context.Context, q *Query, oldCache *RRCache) (rrCache *RRCache, err error) { //nolint:gocognit,gocyclo
|
func resolveAndCache(ctx context.Context, q *Query, oldCache *RRCache) (rrCache *RRCache, err error) { //nolint:gocognit,gocyclo
|
||||||
// get resolvers
|
// get resolvers
|
||||||
resolvers, tryAll := GetResolversInScope(ctx, q)
|
resolvers, primarySource, tryAll := GetResolversInScope(ctx, q)
|
||||||
if len(resolvers) == 0 {
|
if len(resolvers) == 0 {
|
||||||
return nil, ErrNoCompliance
|
return nil, ErrNoCompliance
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we are online
|
// check if we are online
|
||||||
if netenv.GetOnlineStatus() == netenv.StatusOffline {
|
if primarySource != ServerSourceEnv && netenv.GetOnlineStatus() == netenv.StatusOffline {
|
||||||
if !netenv.IsConnectivityDomain(q.FQDN) {
|
if !netenv.IsConnectivityDomain(q.FQDN) {
|
||||||
// we are offline and this is not an online check query
|
// we are offline and this is not an online check query
|
||||||
return oldCache, ErrOffline
|
return oldCache, ErrOffline
|
||||||
@@ -391,6 +391,10 @@ resolveLoop:
|
|||||||
|
|
||||||
// Report a successful connection.
|
// Report a successful connection.
|
||||||
resolver.Conn.ResetFailure()
|
resolver.Conn.ResetFailure()
|
||||||
|
// Reset failing resolvers notification, if querying in global scope.
|
||||||
|
if primarySource == ServerSourceConfigured {
|
||||||
|
resetFailingResolversNotification()
|
||||||
|
}
|
||||||
|
|
||||||
break resolveLoop
|
break resolveLoop
|
||||||
}
|
}
|
||||||
@@ -401,6 +405,13 @@ resolveLoop:
|
|||||||
// tried all resolvers, possibly twice
|
// tried all resolvers, possibly twice
|
||||||
if i > 1 {
|
if i > 1 {
|
||||||
err = fmt.Errorf("all %d query-compliant resolvers failed, last error: %s", len(resolvers), err)
|
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 */ {
|
} else if rrCache == nil /* defensive */ {
|
||||||
err = ErrNotFound
|
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.
|
// 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()
|
resolversLock.RLock()
|
||||||
defer resolversLock.RUnlock()
|
defer resolversLock.RUnlock()
|
||||||
|
|
||||||
// Internal use domains
|
// Internal use domains
|
||||||
if domainInScope(q.dotPrefixedFQDN, internalSpecialUseDomains) {
|
if domainInScope(q.dotPrefixedFQDN, internalSpecialUseDomains) {
|
||||||
return envResolvers, false
|
return envResolvers, ServerSourceEnv, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special connectivity domains
|
// Special connectivity domains
|
||||||
if netenv.IsConnectivityDomain(q.FQDN) && len(systemResolvers) > 0 {
|
if netenv.IsConnectivityDomain(q.FQDN) && len(systemResolvers) > 0 {
|
||||||
// Do not do compliance checks for connectivity domains.
|
// Do not do compliance checks for connectivity domains.
|
||||||
selected = append(selected, systemResolvers...) // dhcp assigned resolvers
|
selected = append(selected, systemResolvers...) // dhcp assigned resolvers
|
||||||
return selected, false
|
return selected, ServerSourceOperatingSystem, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prioritize search scopes
|
// 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, mDNSResolvers)
|
||||||
selected = addResolvers(ctx, q, selected, localResolvers)
|
selected = addResolvers(ctx, q, selected, localResolvers)
|
||||||
selected = addResolvers(ctx, q, selected, systemResolvers)
|
selected = addResolvers(ctx, q, selected, systemResolvers)
|
||||||
return selected, true
|
return selected, ServerSourceMDNS, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special use domains
|
// Special use domains
|
||||||
@@ -145,12 +145,12 @@ func GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, t
|
|||||||
domainInScope(q.dotPrefixedFQDN, specialServiceDomains) {
|
domainInScope(q.dotPrefixedFQDN, specialServiceDomains) {
|
||||||
selected = addResolvers(ctx, q, selected, localResolvers)
|
selected = addResolvers(ctx, q, selected, localResolvers)
|
||||||
selected = addResolvers(ctx, q, selected, systemResolvers)
|
selected = addResolvers(ctx, q, selected, systemResolvers)
|
||||||
return selected, true
|
return selected, "special", true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global domains
|
// Global domains
|
||||||
selected = addResolvers(ctx, q, selected, globalResolvers)
|
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 {
|
func addResolvers(ctx context.Context, q *Query, selected []*Resolver, addResolvers []*Resolver) []*Resolver {
|
||||||
|
|||||||
Reference in New Issue
Block a user