mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Merge pull request #83 from safing/fix/netenv-resolver-interaction
Fix netenv resolver interaction
This commit is contained in:
commit
2426429237
4 changed files with 71 additions and 11 deletions
|
@ -106,12 +106,6 @@ func handleRequestAsWorker(w dns.ResponseWriter, query *dns.Msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) error { //nolint:gocognit // TODO
|
func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) error { //nolint:gocognit // TODO
|
||||||
// return with server failure if offline
|
|
||||||
if netenv.GetOnlineStatus() == netenv.StatusOffline {
|
|
||||||
returnServerFailure(w, query)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// only process first question, that's how everyone does it.
|
// only process first question, that's how everyone does it.
|
||||||
question := query.Question[0]
|
question := query.Question[0]
|
||||||
q := &resolver.Query{
|
q := &resolver.Query{
|
||||||
|
@ -119,6 +113,14 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er
|
||||||
QType: dns.Type(question.Qtype),
|
QType: dns.Type(question.Qtype),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return with server failure if offline
|
||||||
|
if netenv.GetOnlineStatus() == netenv.StatusOffline &&
|
||||||
|
!netenv.IsOnlineStatusTestDomain(q.FQDN) {
|
||||||
|
log.Tracer(ctx).Debugf("resolver: not resolving %s, device is offline", q.FQDN)
|
||||||
|
returnServerFailure(w, query)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// check class
|
// check class
|
||||||
if question.Qclass != dns.ClassINET {
|
if question.Qclass != dns.ClassINET {
|
||||||
// we only serve IN records, return nxdomain
|
// we only serve IN records, return nxdomain
|
||||||
|
|
|
@ -106,6 +106,8 @@ var (
|
||||||
|
|
||||||
captivePortalURL string
|
captivePortalURL string
|
||||||
captivePortalLock sync.Mutex
|
captivePortalLock sync.Mutex
|
||||||
|
|
||||||
|
waitForever = make(chan time.Time)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -200,12 +202,14 @@ func triggerOnlineStatusInvestigation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func monitorOnlineStatus(ctx context.Context) error {
|
func monitorOnlineStatus(ctx context.Context) error {
|
||||||
|
triggerOnlineStatusInvestigation()
|
||||||
for {
|
for {
|
||||||
// wait for trigger
|
// wait for trigger
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return nil
|
||||||
case <-onlineStatusInvestigationTrigger:
|
case <-onlineStatusInvestigationTrigger:
|
||||||
|
case <-getDynamicStatusTrigger():
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable waiting
|
// enable waiting
|
||||||
|
@ -221,6 +225,21 @@ func monitorOnlineStatus(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDynamicStatusTrigger() <-chan time.Time {
|
||||||
|
switch GetOnlineStatus() {
|
||||||
|
case StatusOffline:
|
||||||
|
return time.After(10 * time.Second)
|
||||||
|
case StatusLimited, StatusPortal:
|
||||||
|
return time.After(1 * time.Minute)
|
||||||
|
case StatusSemiOnline:
|
||||||
|
return time.After(5 * time.Minute)
|
||||||
|
case StatusOnline:
|
||||||
|
return waitForever
|
||||||
|
default: // unknown status
|
||||||
|
return time.After(5 * time.Minute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkOnlineStatus(ctx context.Context) {
|
func checkOnlineStatus(ctx context.Context) {
|
||||||
// TODO: implement more methods
|
// TODO: implement more methods
|
||||||
/*status, err := getConnectivityStateFromDbus()
|
/*status, err := getConnectivityStateFromDbus()
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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"
|
||||||
|
@ -24,6 +26,10 @@ var (
|
||||||
ErrLocalhost = errors.New("query for localhost")
|
ErrLocalhost = errors.New("query for localhost")
|
||||||
// ErrTimeout is returned when a query times out
|
// ErrTimeout is returned when a query times out
|
||||||
ErrTimeout = errors.New("query timed out")
|
ErrTimeout = errors.New("query timed out")
|
||||||
|
// ErrOffline is returned when no network connection is detected
|
||||||
|
ErrOffline = errors.New("device is offine")
|
||||||
|
// ErrFailure is returned when the type of failure is unclear
|
||||||
|
ErrFailure = errors.New("query failed")
|
||||||
|
|
||||||
// detailed errors
|
// detailed errors
|
||||||
|
|
||||||
|
@ -213,13 +219,24 @@ func deduplicateRequest(ctx context.Context, q *Query) (finishRequest func()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveAndCache(ctx context.Context, q *Query) (rrCache *RRCache, err error) {
|
func resolveAndCache(ctx context.Context, q *Query) (rrCache *RRCache, err error) { //nolint:gocognit
|
||||||
// get resolvers
|
// get resolvers
|
||||||
resolvers := GetResolversInScope(ctx, q)
|
resolvers := GetResolversInScope(ctx, q)
|
||||||
if len(resolvers) == 0 {
|
if len(resolvers) == 0 {
|
||||||
return nil, ErrNoCompliance
|
return nil, ErrNoCompliance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if we are online
|
||||||
|
if netenv.GetOnlineStatus() == netenv.StatusOffline {
|
||||||
|
if netenv.IsOnlineStatusTestDomain(q.FQDN) {
|
||||||
|
log.Tracer(ctx).Debugf("resolver: permitting online status test domain %s to resolve even though offline", q.FQDN)
|
||||||
|
} else {
|
||||||
|
log.Tracer(ctx).Debugf("resolver: not resolving %s, device is offline", q.FQDN)
|
||||||
|
// we are offline and this is not an online check query
|
||||||
|
return nil, ErrOffline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// start resolving
|
// start resolving
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
|
@ -246,6 +263,11 @@ resolveLoop:
|
||||||
case errors.Is(err, ErrBlocked):
|
case errors.Is(err, ErrBlocked):
|
||||||
// some resolvers might also block
|
// some resolvers might also block
|
||||||
return nil, err
|
return nil, err
|
||||||
|
case netenv.GetOnlineStatus() == netenv.StatusOffline &&
|
||||||
|
!netenv.IsOnlineStatusTestDomain(q.FQDN):
|
||||||
|
log.Tracer(ctx).Debugf("resolver: not resolving %s, device is offline", q.FQDN)
|
||||||
|
// we are offline and this is not an online check query
|
||||||
|
return nil, ErrOffline
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no error
|
// no error
|
||||||
|
|
|
@ -93,11 +93,9 @@ func (tr *TCPResolver) client(workerCtx context.Context) error { //nolint:gocogn
|
||||||
var cancelConnCtx func()
|
var cancelConnCtx func()
|
||||||
var recycleConn bool
|
var recycleConn bool
|
||||||
var shuttingDown bool
|
var shuttingDown bool
|
||||||
|
var failCnt int
|
||||||
var incoming = make(chan *dns.Msg, 100)
|
var incoming = make(chan *dns.Msg, 100)
|
||||||
|
|
||||||
// enable client restarting after crash
|
|
||||||
defer tr.clientStarted.UnSet()
|
|
||||||
|
|
||||||
connMgmt:
|
connMgmt:
|
||||||
for {
|
for {
|
||||||
// cleanup old connection
|
// cleanup old connection
|
||||||
|
@ -111,7 +109,7 @@ connMgmt:
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we are shutting down or failing
|
// check if we are shutting down or failing
|
||||||
if shuttingDown || tr.IsFailing() {
|
if shuttingDown || failCnt >= FailThreshold || tr.IsFailing() {
|
||||||
// reply to all waiting queries
|
// reply to all waiting queries
|
||||||
tr.Lock()
|
tr.Lock()
|
||||||
for id, inFlight := range tr.inFlightQueries {
|
for id, inFlight := range tr.inFlightQueries {
|
||||||
|
@ -181,7 +179,12 @@ connMgmt:
|
||||||
c, err := tr.dnsClient.Dial(tr.resolver.ServerAddress)
|
c, err := tr.dnsClient.Dial(tr.resolver.ServerAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tr.ReportFailure()
|
tr.ReportFailure()
|
||||||
|
failCnt++
|
||||||
|
if tr.IsFailing() {
|
||||||
|
shuttingDown = true
|
||||||
|
}
|
||||||
log.Debugf("resolver: failed to connect to %s (%s)", tr.resolver.Name, tr.resolver.ServerAddress)
|
log.Debugf("resolver: failed to connect to %s (%s)", tr.resolver.Name, tr.resolver.ServerAddress)
|
||||||
|
netenv.ReportFailedConnection()
|
||||||
continue connMgmt
|
continue connMgmt
|
||||||
}
|
}
|
||||||
tr.dnsConnection = c
|
tr.dnsConnection = c
|
||||||
|
@ -208,6 +211,10 @@ connMgmt:
|
||||||
if connClosing.SetToIf(false, true) {
|
if connClosing.SetToIf(false, true) {
|
||||||
cancelConnCtx()
|
cancelConnCtx()
|
||||||
tr.ReportFailure()
|
tr.ReportFailure()
|
||||||
|
failCnt++
|
||||||
|
if tr.IsFailing() {
|
||||||
|
shuttingDown = true
|
||||||
|
}
|
||||||
log.Warningf("resolver: read error from %s (%s): %s", tr.resolver.Name, tr.dnsConnection.RemoteAddr(), err)
|
log.Warningf("resolver: read error from %s (%s): %s", tr.resolver.Name, tr.dnsConnection.RemoteAddr(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -244,6 +251,10 @@ connMgmt:
|
||||||
if connClosing.SetToIf(false, true) {
|
if connClosing.SetToIf(false, true) {
|
||||||
cancelConnCtx()
|
cancelConnCtx()
|
||||||
tr.ReportFailure()
|
tr.ReportFailure()
|
||||||
|
failCnt++
|
||||||
|
if tr.IsFailing() {
|
||||||
|
shuttingDown = true
|
||||||
|
}
|
||||||
log.Warningf("resolver: write error to %s (%s): %s", tr.resolver.Name, tr.dnsConnection.RemoteAddr(), err)
|
log.Warningf("resolver: write error to %s (%s): %s", tr.resolver.Name, tr.dnsConnection.RemoteAddr(), err)
|
||||||
}
|
}
|
||||||
continue connMgmt
|
continue connMgmt
|
||||||
|
@ -263,6 +274,7 @@ connMgmt:
|
||||||
if ok {
|
if ok {
|
||||||
select {
|
select {
|
||||||
case inFlight.Response <- msg:
|
case inFlight.Response <- msg:
|
||||||
|
failCnt = 0 // reset fail counter
|
||||||
// responded!
|
// responded!
|
||||||
default:
|
default:
|
||||||
// save to cache, if enabled
|
// save to cache, if enabled
|
||||||
|
@ -351,6 +363,11 @@ func (tr *TCPResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {
|
||||||
return nil, ErrTimeout
|
return nil, ErrTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reply == nil {
|
||||||
|
// Resolver is shutting down, could be server failure or we are offline
|
||||||
|
return nil, ErrFailure
|
||||||
|
}
|
||||||
|
|
||||||
if tr.resolver.IsBlockedUpstream(reply) {
|
if tr.resolver.IsBlockedUpstream(reply) {
|
||||||
return nil, &BlockedUpstreamError{tr.resolver.GetName()}
|
return nil, &BlockedUpstreamError{tr.resolver.GetName()}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue