From 18617fc6170273ffe20f92e245d1a6978a48d44f Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 29 Mar 2021 17:12:47 +0200 Subject: [PATCH] Improve resolver unfailing --- resolver/config.go | 2 +- resolver/resolve.go | 4 ++++ resolver/resolver-env.go | 2 ++ resolver/resolver-mdns.go | 2 ++ resolver/resolver-plain.go | 4 +++- resolver/resolver-tcp.go | 4 +++- resolver/resolver.go | 37 +++++++++++++++++++++++++++++++++++++ 7 files changed, 52 insertions(+), 3 deletions(-) diff --git a/resolver/config.go b/resolver/config.go index 9985f72e..f8d24cdf 100644 --- a/resolver/config.go +++ b/resolver/config.go @@ -174,7 +174,7 @@ The format is: "protocol://ip:port?parameter=value¶meter=value" if err != nil { return err } - nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 600) + nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 300) err = config.Register(&config.Option{ Name: "Ignore System/Network Servers", diff --git a/resolver/resolve.go b/resolver/resolve.go index 31ceeb74..8bfb959a 100644 --- a/resolver/resolve.go +++ b/resolver/resolve.go @@ -377,6 +377,10 @@ resolveLoop: if rrCache.RCode != dns.RcodeSuccess && tryAll { continue } + + // Report a successful connection. + resolver.Conn.ResetFailure() + break resolveLoop } } diff --git a/resolver/resolver-env.go b/resolver/resolver-env.go index 30786063..d3d809ef 100644 --- a/resolver/resolver-env.go +++ b/resolver/resolver-env.go @@ -124,3 +124,5 @@ func (er *envResolverConn) ReportFailure() {} func (er *envResolverConn) IsFailing() bool { return false } + +func (er *envResolverConn) ResetFailure() {} diff --git a/resolver/resolver-mdns.go b/resolver/resolver-mdns.go index cd28eb5f..88549176 100644 --- a/resolver/resolver-mdns.go +++ b/resolver/resolver-mdns.go @@ -54,6 +54,8 @@ func (mrc *mDNSResolverConn) IsFailing() bool { return false } +func (mrc *mDNSResolverConn) ResetFailure() {} + type savedQuestion struct { question dns.Question expires time.Time diff --git a/resolver/resolver-plain.go b/resolver/resolver-plain.go index 01862a7e..024c079b 100644 --- a/resolver/resolver-plain.go +++ b/resolver/resolver-plain.go @@ -24,11 +24,13 @@ type PlainResolver struct { // NewPlainResolver returns a new TPCResolver. func NewPlainResolver(resolver *Resolver) *PlainResolver { - return &PlainResolver{ + newResolver := &PlainResolver{ BasicResolverConn: BasicResolverConn{ resolver: resolver, }, } + newResolver.BasicResolverConn.init() + return newResolver } // Query executes the given query against the resolver. diff --git a/resolver/resolver-tcp.go b/resolver/resolver-tcp.go index 49680516..63a0c6ef 100644 --- a/resolver/resolver-tcp.go +++ b/resolver/resolver-tcp.go @@ -62,7 +62,7 @@ func (ifq *InFlightQuery) MakeCacheRecord(reply *dns.Msg) *RRCache { // NewTCPResolver returns a new TPCResolver. func NewTCPResolver(resolver *Resolver) *TCPResolver { var instanceID uint32 - return &TCPResolver{ + newResolver := &TCPResolver{ BasicResolverConn: BasicResolverConn{ resolver: resolver, }, @@ -79,6 +79,8 @@ func NewTCPResolver(resolver *Resolver) *TCPResolver { queries: make(chan *dns.Msg, 1000), inFlightQueries: make(map[uint16]*InFlightQuery), } + newResolver.BasicResolverConn.init() + return newResolver } // UseTLS enabled TLS for the TCPResolver. TLS settings must be correctly configured in the Resolver. diff --git a/resolver/resolver.go b/resolver/resolver.go index 8b523148..ec56eb4e 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -8,6 +8,9 @@ import ( "time" "github.com/miekg/dns" + "github.com/tevino/abool" + + "github.com/safing/portbase/utils" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/netutils" ) @@ -179,6 +182,7 @@ type ResolverConn interface { //nolint:go-lint // TODO Query(ctx context.Context, q *Query) (*RRCache, error) ReportFailure() IsFailing() bool + ResetFailure() } // BasicResolverConn implements ResolverConn for standard dns clients. @@ -187,8 +191,18 @@ type BasicResolverConn struct { resolver *Resolver + failing *abool.AtomicBool failingUntil time.Time fails int + failLock sync.Mutex + + networkChangedFlag *utils.Flag +} + +// init initializes the basic resolver connection. +func (brc *BasicResolverConn) init() { + brc.failing = abool.New() + brc.networkChangedFlag = netenv.GetNetworkChangedFlag() } // ReportFailure reports that an error occurred with this resolver. @@ -203,6 +217,7 @@ func (brc *BasicResolverConn) ReportFailure() { brc.fails++ if brc.fails > FailThreshold { + brc.failing.Set() brc.failingUntil = time.Now().Add(time.Duration(nameserverRetryRate()) * time.Second) brc.fails = 0 } @@ -210,8 +225,30 @@ func (brc *BasicResolverConn) ReportFailure() { // IsFailing returns if this resolver is currently failing. func (brc *BasicResolverConn) IsFailing() bool { + // Check if not failing. + if !brc.failing.IsSet() { + return false + } + brc.Lock() defer brc.Unlock() + // Reset failure status if the network changed since the last query. + if brc.networkChangedFlag.IsSet() { + brc.networkChangedFlag.Refresh() + brc.ResetFailure() + return false + } + + // Check if we are still return time.Now().Before(brc.failingUntil) } + +// ResetFailure resets the failure status. +func (brc *BasicResolverConn) ResetFailure() { + if brc.failing.SetToIf(true, false) { + brc.Lock() + defer brc.Unlock() + brc.fails = 0 + } +}