Merge pull request #279 from safing/fix/resolver-unfailing

Improve resolver unfailing
This commit is contained in:
Daniel 2021-04-03 16:07:52 +02:00 committed by GitHub
commit 909c7a031c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 8 deletions

View file

@ -174,7 +174,7 @@ The format is: "protocol://ip:port?parameter=value&parameter=value"
if err != nil { if err != nil {
return err return err
} }
nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 600) nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 300)
err = config.Register(&config.Option{ err = config.Register(&config.Option{
Name: "Ignore System/Network Servers", Name: "Ignore System/Network Servers",

View file

@ -377,6 +377,10 @@ resolveLoop:
if rrCache.RCode != dns.RcodeSuccess && tryAll { if rrCache.RCode != dns.RcodeSuccess && tryAll {
continue continue
} }
// Report a successful connection.
resolver.Conn.ResetFailure()
break resolveLoop break resolveLoop
} }
} }

View file

@ -124,3 +124,5 @@ func (er *envResolverConn) ReportFailure() {}
func (er *envResolverConn) IsFailing() bool { func (er *envResolverConn) IsFailing() bool {
return false return false
} }
func (er *envResolverConn) ResetFailure() {}

View file

@ -54,6 +54,8 @@ func (mrc *mDNSResolverConn) IsFailing() bool {
return false return false
} }
func (mrc *mDNSResolverConn) ResetFailure() {}
type savedQuestion struct { type savedQuestion struct {
question dns.Question question dns.Question
expires time.Time expires time.Time

View file

@ -24,11 +24,13 @@ type PlainResolver struct {
// NewPlainResolver returns a new TPCResolver. // NewPlainResolver returns a new TPCResolver.
func NewPlainResolver(resolver *Resolver) *PlainResolver { func NewPlainResolver(resolver *Resolver) *PlainResolver {
return &PlainResolver{ newResolver := &PlainResolver{
BasicResolverConn: BasicResolverConn{ BasicResolverConn: BasicResolverConn{
resolver: resolver, resolver: resolver,
}, },
} }
newResolver.BasicResolverConn.init()
return newResolver
} }
// Query executes the given query against the resolver. // Query executes the given query against the resolver.

View file

@ -62,7 +62,7 @@ func (ifq *InFlightQuery) MakeCacheRecord(reply *dns.Msg) *RRCache {
// NewTCPResolver returns a new TPCResolver. // NewTCPResolver returns a new TPCResolver.
func NewTCPResolver(resolver *Resolver) *TCPResolver { func NewTCPResolver(resolver *Resolver) *TCPResolver {
var instanceID uint32 var instanceID uint32
return &TCPResolver{ newResolver := &TCPResolver{
BasicResolverConn: BasicResolverConn{ BasicResolverConn: BasicResolverConn{
resolver: resolver, resolver: resolver,
}, },
@ -79,6 +79,8 @@ func NewTCPResolver(resolver *Resolver) *TCPResolver {
queries: make(chan *dns.Msg, 1000), queries: make(chan *dns.Msg, 1000),
inFlightQueries: make(map[uint16]*InFlightQuery), 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. // UseTLS enabled TLS for the TCPResolver. TLS settings must be correctly configured in the Resolver.

View file

@ -8,6 +8,9 @@ import (
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/tevino/abool"
"github.com/safing/portbase/utils"
"github.com/safing/portmaster/netenv" "github.com/safing/portmaster/netenv"
"github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/network/netutils"
) )
@ -179,16 +182,27 @@ type ResolverConn interface { //nolint:go-lint // TODO
Query(ctx context.Context, q *Query) (*RRCache, error) Query(ctx context.Context, q *Query) (*RRCache, error)
ReportFailure() ReportFailure()
IsFailing() bool IsFailing() bool
ResetFailure()
} }
// BasicResolverConn implements ResolverConn for standard dns clients. // BasicResolverConn implements ResolverConn for standard dns clients.
type BasicResolverConn struct { type BasicResolverConn struct {
sync.Mutex // for lastFail sync.Mutex // Also used by inheriting structs.
resolver *Resolver resolver *Resolver
failing *abool.AtomicBool
failingUntil time.Time failingUntil time.Time
fails int 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. // ReportFailure reports that an error occurred with this resolver.
@ -198,20 +212,47 @@ func (brc *BasicResolverConn) ReportFailure() {
return return
} }
brc.Lock() brc.failLock.Lock()
defer brc.Unlock() defer brc.failLock.Unlock()
brc.fails++ brc.fails++
if brc.fails > FailThreshold { if brc.fails > FailThreshold {
brc.failing.Set()
brc.failingUntil = time.Now().Add(time.Duration(nameserverRetryRate()) * time.Second) brc.failingUntil = time.Now().Add(time.Duration(nameserverRetryRate()) * time.Second)
brc.fails = 0 brc.fails = 0
// Refresh the network changed flag in order to only regard changes after
// the fail.
brc.networkChangedFlag.Refresh()
} }
} }
// IsFailing returns if this resolver is currently failing. // IsFailing returns if this resolver is currently failing.
func (brc *BasicResolverConn) IsFailing() bool { func (brc *BasicResolverConn) IsFailing() bool {
brc.Lock() // Check if not failing.
defer brc.Unlock() if !brc.failing.IsSet() {
return false
}
brc.failLock.Lock()
defer brc.failLock.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) return time.Now().Before(brc.failingUntil)
} }
// ResetFailure resets the failure status.
func (brc *BasicResolverConn) ResetFailure() {
if brc.failing.SetToIf(true, false) {
brc.failLock.Lock()
defer brc.failLock.Unlock()
brc.fails = 0
}
}