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 {
return err
}
nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 600)
nameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 300)
err = config.Register(&config.Option{
Name: "Ignore System/Network Servers",

View file

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

View file

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

View file

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

View file

@ -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.

View file

@ -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.

View file

@ -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,16 +182,27 @@ 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.
type BasicResolverConn struct {
sync.Mutex // for lastFail
sync.Mutex // Also used by inheriting structs.
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.
@ -198,20 +212,47 @@ func (brc *BasicResolverConn) ReportFailure() {
return
}
brc.Lock()
defer brc.Unlock()
brc.failLock.Lock()
defer brc.failLock.Unlock()
brc.fails++
if brc.fails > FailThreshold {
brc.failing.Set()
brc.failingUntil = time.Now().Add(time.Duration(nameserverRetryRate()) * time.Second)
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.
func (brc *BasicResolverConn) IsFailing() bool {
brc.Lock()
defer brc.Unlock()
// Check if not failing.
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)
}
// 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
}
}