Fix tests and linters
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Supported upstream block detections
|
||||
// Supported upstream block detections.
|
||||
const (
|
||||
BlockDetectionRefused = "refused"
|
||||
BlockDetectionZeroIP = "zeroip"
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/safing/portmaster/status"
|
||||
)
|
||||
|
||||
// Configuration Keys
|
||||
// Configuration Keys.
|
||||
var (
|
||||
defaultNameServers = []string{
|
||||
// Collection of default DNS Servers
|
||||
|
||||
@@ -14,21 +14,19 @@ const (
|
||||
IPInfoProfileScopeGlobal = "global"
|
||||
)
|
||||
|
||||
var (
|
||||
ipInfoDatabase = database.NewInterface(&database.Options{
|
||||
Local: true,
|
||||
Internal: true,
|
||||
var ipInfoDatabase = database.NewInterface(&database.Options{
|
||||
Local: true,
|
||||
Internal: true,
|
||||
|
||||
// Cache entries because new/updated entries will often be queries soon
|
||||
// after inserted.
|
||||
CacheSize: 256,
|
||||
// Cache entries because new/updated entries will often be queries soon
|
||||
// after inserted.
|
||||
CacheSize: 256,
|
||||
|
||||
// We only use the cache database here, so we can delay and batch all our
|
||||
// writes. Also, no one else accesses these records, so we are fine using
|
||||
// this.
|
||||
DelayCachedWrites: "cache",
|
||||
})
|
||||
)
|
||||
// We only use the cache database here, so we can delay and batch all our
|
||||
// writes. Also, no one else accesses these records, so we are fine using
|
||||
// this.
|
||||
DelayCachedWrites: "cache",
|
||||
})
|
||||
|
||||
// ResolvedDomain holds a Domain name and a list of
|
||||
// CNAMES that have been resolved.
|
||||
@@ -54,7 +52,7 @@ type ResolvedDomain struct {
|
||||
}
|
||||
|
||||
// String returns a string representation of ResolvedDomain including
|
||||
// the CNAME chain. It implements fmt.Stringer
|
||||
// the CNAME chain. It implements fmt.Stringer.
|
||||
func (resolved *ResolvedDomain) String() string {
|
||||
ret := resolved.Domain
|
||||
cnames := ""
|
||||
@@ -67,7 +65,7 @@ func (resolved *ResolvedDomain) String() string {
|
||||
}
|
||||
|
||||
// ResolvedDomains is a helper type for operating on a slice
|
||||
// of ResolvedDomain
|
||||
// of ResolvedDomain.
|
||||
type ResolvedDomains []ResolvedDomain
|
||||
|
||||
// String returns a string representation of all domains joined
|
||||
@@ -141,21 +139,21 @@ func GetIPInfo(profileID, ip string) (*IPInfo, error) {
|
||||
// unwrap
|
||||
if r.IsWrapped() {
|
||||
// only allocate a new struct, if we need it
|
||||
new := &IPInfo{}
|
||||
err = record.Unwrap(r, new)
|
||||
newInfo := &IPInfo{}
|
||||
err = record.Unwrap(r, newInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new, nil
|
||||
return newInfo, nil
|
||||
}
|
||||
|
||||
// or adjust type
|
||||
new, ok := r.(*IPInfo)
|
||||
newInfo, ok := r.(*IPInfo)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("record not of type *IPInfo, but %T", r)
|
||||
}
|
||||
return new, nil
|
||||
return newInfo, nil
|
||||
}
|
||||
|
||||
// Save saves the IPInfo record to the database.
|
||||
@@ -187,7 +185,7 @@ func (info *IPInfo) Save() error {
|
||||
return ipInfoDatabase.Put(info)
|
||||
}
|
||||
|
||||
// FmtDomains returns a string consisting of the domains that have seen to use this IP, joined by " or "
|
||||
// String returns a string consisting of the domains that have seen to use this IP.
|
||||
func (info *IPInfo) String() string {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
)
|
||||
|
||||
func TestIPInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
example := ResolvedDomain{
|
||||
Domain: "example.com.",
|
||||
}
|
||||
|
||||
@@ -8,20 +8,19 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/tevino/abool"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/modules"
|
||||
"github.com/safing/portbase/notifications"
|
||||
"github.com/safing/portbase/utils/debug"
|
||||
"github.com/safing/portmaster/intel"
|
||||
"github.com/tevino/abool"
|
||||
|
||||
// module dependencies
|
||||
// Dependency.
|
||||
_ "github.com/safing/portmaster/core/base"
|
||||
"github.com/safing/portmaster/intel"
|
||||
)
|
||||
|
||||
var (
|
||||
module *modules.Module
|
||||
)
|
||||
var module *modules.Module
|
||||
|
||||
func init() {
|
||||
module = modules.Register("resolver", prep, start, nil, "base", "netenv")
|
||||
@@ -93,9 +92,7 @@ func start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
localAddrFactory func(network string) net.Addr
|
||||
)
|
||||
var localAddrFactory func(network string) net.Addr
|
||||
|
||||
// SetLocalAddrFactory supplies the intel package with a function to get permitted local addresses for connections.
|
||||
func SetLocalAddrFactory(laf func(network string) net.Addr) {
|
||||
|
||||
@@ -6,9 +6,7 @@ import (
|
||||
"github.com/safing/portmaster/core/pmtesting"
|
||||
)
|
||||
|
||||
var (
|
||||
domainFeed = make(chan string)
|
||||
)
|
||||
var domainFeed = make(chan string)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
pmtesting.TestMain(m, module)
|
||||
@@ -28,106 +26,104 @@ func feedDomains() {
|
||||
|
||||
// Data
|
||||
|
||||
var (
|
||||
testDomains = []string{
|
||||
"facebook.com.",
|
||||
"google.com.",
|
||||
"youtube.com.",
|
||||
"twitter.com.",
|
||||
"instagram.com.",
|
||||
"linkedin.com.",
|
||||
"microsoft.com.",
|
||||
"apple.com.",
|
||||
"wikipedia.org.",
|
||||
"plus.google.com.",
|
||||
"en.wikipedia.org.",
|
||||
"googletagmanager.com.",
|
||||
"youtu.be.",
|
||||
"adobe.com.",
|
||||
"vimeo.com.",
|
||||
"pinterest.com.",
|
||||
"itunes.apple.com.",
|
||||
"play.google.com.",
|
||||
"maps.google.com.",
|
||||
"goo.gl.",
|
||||
"wordpress.com.",
|
||||
"blogspot.com.",
|
||||
"bit.ly.",
|
||||
"github.com.",
|
||||
"player.vimeo.com.",
|
||||
"amazon.com.",
|
||||
"wordpress.org.",
|
||||
"docs.google.com.",
|
||||
"yahoo.com.",
|
||||
"mozilla.org.",
|
||||
"tumblr.com.",
|
||||
"godaddy.com.",
|
||||
"flickr.com.",
|
||||
"parked-content.godaddy.com.",
|
||||
"drive.google.com.",
|
||||
"support.google.com.",
|
||||
"apache.org.",
|
||||
"gravatar.com.",
|
||||
"europa.eu.",
|
||||
"qq.com.",
|
||||
"w3.org.",
|
||||
"nytimes.com.",
|
||||
"reddit.com.",
|
||||
"macromedia.com.",
|
||||
"get.adobe.com.",
|
||||
"soundcloud.com.",
|
||||
"sourceforge.net.",
|
||||
"sites.google.com.",
|
||||
"nih.gov.",
|
||||
"amazonaws.com.",
|
||||
"t.co.",
|
||||
"support.microsoft.com.",
|
||||
"forbes.com.",
|
||||
"theguardian.com.",
|
||||
"cnn.com.",
|
||||
"github.io.",
|
||||
"bbc.co.uk.",
|
||||
"dropbox.com.",
|
||||
"whatsapp.com.",
|
||||
"medium.com.",
|
||||
"creativecommons.org.",
|
||||
"www.ncbi.nlm.nih.gov.",
|
||||
"httpd.apache.org.",
|
||||
"archive.org.",
|
||||
"ec.europa.eu.",
|
||||
"php.net.",
|
||||
"apps.apple.com.",
|
||||
"weebly.com.",
|
||||
"support.apple.com.",
|
||||
"weibo.com.",
|
||||
"wixsite.com.",
|
||||
"issuu.com.",
|
||||
"who.int.",
|
||||
"paypal.com.",
|
||||
"m.facebook.com.",
|
||||
"oracle.com.",
|
||||
"msn.com.",
|
||||
"gnu.org.",
|
||||
"tinyurl.com.",
|
||||
"reuters.com.",
|
||||
"l.facebook.com.",
|
||||
"cloudflare.com.",
|
||||
"wsj.com.",
|
||||
"washingtonpost.com.",
|
||||
"domainmarket.com.",
|
||||
"imdb.com.",
|
||||
"bbc.com.",
|
||||
"bing.com.",
|
||||
"accounts.google.com.",
|
||||
"vk.com.",
|
||||
"api.whatsapp.com.",
|
||||
"opera.com.",
|
||||
"cdc.gov.",
|
||||
"slideshare.net.",
|
||||
"wpa.qq.com.",
|
||||
"harvard.edu.",
|
||||
"mit.edu.",
|
||||
"code.google.com.",
|
||||
"wikimedia.org.",
|
||||
}
|
||||
)
|
||||
var testDomains = []string{
|
||||
"facebook.com.",
|
||||
"google.com.",
|
||||
"youtube.com.",
|
||||
"twitter.com.",
|
||||
"instagram.com.",
|
||||
"linkedin.com.",
|
||||
"microsoft.com.",
|
||||
"apple.com.",
|
||||
"wikipedia.org.",
|
||||
"plus.google.com.",
|
||||
"en.wikipedia.org.",
|
||||
"googletagmanager.com.",
|
||||
"youtu.be.",
|
||||
"adobe.com.",
|
||||
"vimeo.com.",
|
||||
"pinterest.com.",
|
||||
"itunes.apple.com.",
|
||||
"play.google.com.",
|
||||
"maps.google.com.",
|
||||
"goo.gl.",
|
||||
"wordpress.com.",
|
||||
"blogspot.com.",
|
||||
"bit.ly.",
|
||||
"github.com.",
|
||||
"player.vimeo.com.",
|
||||
"amazon.com.",
|
||||
"wordpress.org.",
|
||||
"docs.google.com.",
|
||||
"yahoo.com.",
|
||||
"mozilla.org.",
|
||||
"tumblr.com.",
|
||||
"godaddy.com.",
|
||||
"flickr.com.",
|
||||
"parked-content.godaddy.com.",
|
||||
"drive.google.com.",
|
||||
"support.google.com.",
|
||||
"apache.org.",
|
||||
"gravatar.com.",
|
||||
"europa.eu.",
|
||||
"qq.com.",
|
||||
"w3.org.",
|
||||
"nytimes.com.",
|
||||
"reddit.com.",
|
||||
"macromedia.com.",
|
||||
"get.adobe.com.",
|
||||
"soundcloud.com.",
|
||||
"sourceforge.net.",
|
||||
"sites.google.com.",
|
||||
"nih.gov.",
|
||||
"amazonaws.com.",
|
||||
"t.co.",
|
||||
"support.microsoft.com.",
|
||||
"forbes.com.",
|
||||
"theguardian.com.",
|
||||
"cnn.com.",
|
||||
"github.io.",
|
||||
"bbc.co.uk.",
|
||||
"dropbox.com.",
|
||||
"whatsapp.com.",
|
||||
"medium.com.",
|
||||
"creativecommons.org.",
|
||||
"www.ncbi.nlm.nih.gov.",
|
||||
"httpd.apache.org.",
|
||||
"archive.org.",
|
||||
"ec.europa.eu.",
|
||||
"php.net.",
|
||||
"apps.apple.com.",
|
||||
"weebly.com.",
|
||||
"support.apple.com.",
|
||||
"weibo.com.",
|
||||
"wixsite.com.",
|
||||
"issuu.com.",
|
||||
"who.int.",
|
||||
"paypal.com.",
|
||||
"m.facebook.com.",
|
||||
"oracle.com.",
|
||||
"msn.com.",
|
||||
"gnu.org.",
|
||||
"tinyurl.com.",
|
||||
"reuters.com.",
|
||||
"l.facebook.com.",
|
||||
"cloudflare.com.",
|
||||
"wsj.com.",
|
||||
"washingtonpost.com.",
|
||||
"domainmarket.com.",
|
||||
"imdb.com.",
|
||||
"bbc.com.",
|
||||
"bing.com.",
|
||||
"accounts.google.com.",
|
||||
"vk.com.",
|
||||
"api.whatsapp.com.",
|
||||
"opera.com.",
|
||||
"cdc.gov.",
|
||||
"slideshare.net.",
|
||||
"wpa.qq.com.",
|
||||
"harvard.edu.",
|
||||
"mit.edu.",
|
||||
"code.google.com.",
|
||||
"wikimedia.org.",
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
@@ -81,30 +80,30 @@ func GetNameRecord(domain, question string) (*NameRecord, error) {
|
||||
// Unwrap record if it's wrapped.
|
||||
if r.IsWrapped() {
|
||||
// only allocate a new struct, if we need it
|
||||
new := &NameRecord{}
|
||||
err = record.Unwrap(r, new)
|
||||
newNR := &NameRecord{}
|
||||
err = record.Unwrap(r, newNR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check if the record is valid.
|
||||
if !new.IsValid() {
|
||||
if !newNR.IsValid() {
|
||||
return nil, errors.New("record is invalid (outdated format)")
|
||||
}
|
||||
|
||||
return new, nil
|
||||
return newNR, nil
|
||||
}
|
||||
|
||||
// Or just adjust the type.
|
||||
new, ok := r.(*NameRecord)
|
||||
newNR, ok := r.(*NameRecord)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("record not of type *NameRecord, but %T", r)
|
||||
}
|
||||
// Check if the record is valid.
|
||||
if !new.IsValid() {
|
||||
if !newNR.IsValid() {
|
||||
return nil, errors.New("record is invalid (outdated format)")
|
||||
}
|
||||
|
||||
return new, nil
|
||||
return newNR, nil
|
||||
}
|
||||
|
||||
// ResetCachedRecord deletes a NameRecord from the cache database.
|
||||
@@ -118,16 +117,16 @@ func ResetCachedRecord(domain, question string) error {
|
||||
}
|
||||
|
||||
// Save saves the NameRecord to the database.
|
||||
func (rec *NameRecord) Save() error {
|
||||
if rec.Domain == "" || rec.Question == "" {
|
||||
func (nameRecord *NameRecord) Save() error {
|
||||
if nameRecord.Domain == "" || nameRecord.Question == "" {
|
||||
return errors.New("could not save NameRecord, missing Domain and/or Question")
|
||||
}
|
||||
|
||||
rec.SetKey(makeNameRecordKey(rec.Domain, rec.Question))
|
||||
rec.UpdateMeta()
|
||||
rec.Meta().SetAbsoluteExpiry(rec.Expires + databaseOvertime)
|
||||
nameRecord.SetKey(makeNameRecordKey(nameRecord.Domain, nameRecord.Question))
|
||||
nameRecord.UpdateMeta()
|
||||
nameRecord.Meta().SetAbsoluteExpiry(nameRecord.Expires + databaseOvertime)
|
||||
|
||||
return recordDatabase.PutNew(rec)
|
||||
return recordDatabase.PutNew(nameRecord)
|
||||
}
|
||||
|
||||
// clearNameCache clears all dns caches from the database.
|
||||
@@ -144,18 +143,3 @@ func clearNameCache(ar *api.Request) (msg string, err error) {
|
||||
log.Debugf("resolver: cleared %d entries from dns cache", n)
|
||||
return fmt.Sprintf("cleared %d dns cache entries", n), nil
|
||||
}
|
||||
|
||||
// DEPRECATED: remove in v0.7
|
||||
func clearNameCacheEventHandler(ctx context.Context, _ interface{}) error {
|
||||
log.Debugf("resolver: dns cache clearing started...")
|
||||
|
||||
recordDatabase.FlushCache()
|
||||
recordDatabase.ClearCache()
|
||||
n, err := recordDatabase.Purge(ctx, query.New(nameRecordsKeyPrefix))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("resolver: cleared %d entries from dns cache", n)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package resolver
|
||||
import "testing"
|
||||
|
||||
func TestNameRecordStorage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testDomain := "Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com."
|
||||
testQuestion := "A"
|
||||
|
||||
|
||||
@@ -14,35 +14,36 @@ import (
|
||||
"github.com/safing/portmaster/netenv"
|
||||
)
|
||||
|
||||
// Errors.
|
||||
var (
|
||||
// basic errors
|
||||
// Basic Errors.
|
||||
|
||||
// ErrNotFound is a basic error that will match all "not found" errors
|
||||
// ErrNotFound is a basic error that will match all "not found" errors.
|
||||
ErrNotFound = errors.New("record could not be found")
|
||||
// ErrBlocked is basic error that will match all "blocked" errors
|
||||
// ErrBlocked is basic error that will match all "blocked" errors.
|
||||
ErrBlocked = errors.New("query was blocked")
|
||||
// ErrLocalhost is returned to *.localhost queries
|
||||
// ErrLocalhost is returned to *.localhost queries.
|
||||
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")
|
||||
// ErrOffline is returned when no network connection is detected
|
||||
// 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 is returned when the type of failure is unclear.
|
||||
ErrFailure = errors.New("query failed")
|
||||
// ErrContinue is returned when the resolver has no answer, and the next resolver should be asked
|
||||
// ErrContinue is returned when the resolver has no answer, and the next resolver should be asked.
|
||||
ErrContinue = errors.New("resolver has no answer")
|
||||
// ErrShuttingDown is returned when the resolver is shutting down.
|
||||
ErrShuttingDown = errors.New("resolver is shutting down")
|
||||
|
||||
// detailed errors
|
||||
// Detailed Errors.
|
||||
|
||||
// ErrTestDomainsDisabled wraps ErrBlocked
|
||||
// ErrTestDomainsDisabled wraps ErrBlocked.
|
||||
ErrTestDomainsDisabled = fmt.Errorf("%w: test domains disabled", ErrBlocked)
|
||||
// ErrSpecialDomainsDisabled wraps ErrBlocked
|
||||
// ErrSpecialDomainsDisabled wraps ErrBlocked.
|
||||
ErrSpecialDomainsDisabled = fmt.Errorf("%w: special domains disabled", ErrBlocked)
|
||||
// ErrInvalid wraps ErrNotFound
|
||||
// ErrInvalid wraps ErrNotFound.
|
||||
ErrInvalid = fmt.Errorf("%w: invalid request", ErrNotFound)
|
||||
// ErrNoCompliance wraps ErrBlocked and is returned when no resolvers were able to comply with the current settings
|
||||
// ErrNoCompliance wraps ErrBlocked and is returned when no resolvers were able to comply with the current settings.
|
||||
ErrNoCompliance = fmt.Errorf("%w: no compliant resolvers for this query", ErrBlocked)
|
||||
)
|
||||
|
||||
@@ -74,7 +75,7 @@ func (blocked *BlockedUpstreamError) Error() string {
|
||||
return fmt.Sprintf("%s by upstream DNS resolver %s", ErrBlocked, blocked.ResolverName)
|
||||
}
|
||||
|
||||
// Unwrap implements errors.Unwrapper
|
||||
// Unwrap implements errors.Unwrapper.
|
||||
func (blocked *BlockedUpstreamError) Unwrap() error {
|
||||
return ErrBlocked
|
||||
}
|
||||
@@ -166,10 +167,9 @@ func checkCache(ctx context.Context, q *Query) *RRCache {
|
||||
|
||||
// Get data from cache.
|
||||
rrCache, err := GetRRCache(q.FQDN, q.QType)
|
||||
|
||||
// Return if entry is not in cache.
|
||||
if err != nil {
|
||||
if err != database.ErrNotFound {
|
||||
if !errors.Is(err, database.ErrNotFound) {
|
||||
log.Tracer(ctx).Warningf("resolver: getting RRCache %s%s from database failed: %s", q.FQDN, q.QType.String(), err)
|
||||
}
|
||||
return nil
|
||||
@@ -403,7 +403,7 @@ resolveLoop:
|
||||
if err != nil {
|
||||
// tried all resolvers, possibly twice
|
||||
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: %w", len(resolvers), err)
|
||||
|
||||
if primarySource == ServerSourceConfigured &&
|
||||
netenv.Online() && CompatSelfCheckIsFailing() {
|
||||
|
||||
@@ -7,12 +7,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/netenv"
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
// InternalSpecialUseDomain is the domain scope used for internal services.
|
||||
InternalSpecialUseDomain = "portmaster.home.arpa."
|
||||
|
||||
routerDomain = "router.local." + InternalSpecialUseDomain
|
||||
@@ -91,8 +93,7 @@ func (er *envResolverConn) Query(ctx context.Context, q *Query) (*RRCache, error
|
||||
}
|
||||
|
||||
// Check for suffix matches.
|
||||
switch {
|
||||
case strings.HasSuffix(q.FQDN, CompatDNSCheckInternalDomainScope):
|
||||
if strings.HasSuffix(q.FQDN, CompatDNSCheckInternalDomainScope) {
|
||||
subdomain := strings.TrimSuffix(q.FQDN, CompatDNSCheckInternalDomainScope)
|
||||
respondWith := CompatSubmitDNSCheckDomain(subdomain)
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
)
|
||||
|
||||
// DNS Classes
|
||||
// DNS Classes.
|
||||
const (
|
||||
DNSClassMulticast = dns.ClassINET | 1<<15
|
||||
)
|
||||
@@ -85,7 +86,9 @@ func listenToMDNS(ctx context.Context) error {
|
||||
module.StartServiceWorker("mdns udp4 multicast listener", 0, func(ctx context.Context) error {
|
||||
return listenForDNSPackets(ctx, multicast4Conn, messages)
|
||||
})
|
||||
defer multicast4Conn.Close()
|
||||
defer func() {
|
||||
_ = multicast4Conn.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
multicast6Conn, err = net.ListenMulticastUDP("udp6", nil, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353})
|
||||
@@ -96,7 +99,9 @@ func listenToMDNS(ctx context.Context) error {
|
||||
module.StartServiceWorker("mdns udp6 multicast listener", 0, func(ctx context.Context) error {
|
||||
return listenForDNSPackets(ctx, multicast6Conn, messages)
|
||||
})
|
||||
defer multicast6Conn.Close()
|
||||
defer func() {
|
||||
_ = multicast6Conn.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
unicast4Conn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
@@ -107,7 +112,9 @@ func listenToMDNS(ctx context.Context) error {
|
||||
module.StartServiceWorker("mdns udp4 unicast listener", 0, func(ctx context.Context) error {
|
||||
return listenForDNSPackets(ctx, unicast4Conn, messages)
|
||||
})
|
||||
defer unicast4Conn.Close()
|
||||
defer func() {
|
||||
_ = unicast4Conn.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
unicast6Conn, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
|
||||
@@ -118,7 +125,9 @@ func listenToMDNS(ctx context.Context) error {
|
||||
module.StartServiceWorker("mdns udp6 unicast listener", 0, func(ctx context.Context) error {
|
||||
return listenForDNSPackets(ctx, unicast6Conn, messages)
|
||||
})
|
||||
defer unicast6Conn.Close()
|
||||
defer func() {
|
||||
_ = unicast6Conn.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
// start message handler
|
||||
@@ -131,8 +140,7 @@ func listenToMDNS(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo,gocognit // TODO
|
||||
func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error {
|
||||
func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { //nolint:maintidx // TODO: Improve.
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -319,7 +327,6 @@ func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error {
|
||||
|
||||
cleanSavedQuestions()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func listenForDNSPackets(ctx context.Context, conn *net.UDPConn, messages chan *dns.Msg) error {
|
||||
@@ -377,30 +384,30 @@ func queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) {
|
||||
// pack qeury
|
||||
buf, err := dnsQuery.Pack()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to pack query: %s", err)
|
||||
return nil, fmt.Errorf("failed to pack query: %w", err)
|
||||
}
|
||||
|
||||
// send queries
|
||||
if unicast4Conn != nil && uint16(q.QType) != dns.TypeAAAA {
|
||||
err = unicast4Conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to configure query (set timout): %s", err)
|
||||
return nil, fmt.Errorf("failed to configure query (set timout): %w", err)
|
||||
}
|
||||
|
||||
_, err = unicast4Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 251), Port: 5353})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send query: %s", err)
|
||||
return nil, fmt.Errorf("failed to send query: %w", err)
|
||||
}
|
||||
}
|
||||
if unicast6Conn != nil && uint16(q.QType) != dns.TypeA {
|
||||
err = unicast6Conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to configure query (set timout): %s", err)
|
||||
return nil, fmt.Errorf("failed to configure query (set timout): %w", err)
|
||||
}
|
||||
|
||||
_, err = unicast6Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send query: %s", err)
|
||||
return nil, fmt.Errorf("failed to send query: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +420,7 @@ func queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) {
|
||||
case <-time.After(1 * time.Second):
|
||||
// check cache again
|
||||
rrCache, err := GetRRCache(q.FQDN, q.QType)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
return rrCache, nil
|
||||
}
|
||||
case <-ctx.Done():
|
||||
|
||||
@@ -2,10 +2,12 @@ package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/netenv"
|
||||
)
|
||||
@@ -65,7 +67,8 @@ func (pr *PlainResolver) Query(ctx context.Context, q *Query) (*RRCache, error)
|
||||
// error handling
|
||||
if err != nil {
|
||||
// Hint network environment at failed connection if err is not a timeout.
|
||||
if nErr, ok := err.(net.Error); ok && !nErr.Timeout() {
|
||||
var nErr net.Error
|
||||
if errors.As(err, &nErr) && !nErr.Timeout() {
|
||||
netenv.ReportFailedConnection()
|
||||
}
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/tevino/abool"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/netenv"
|
||||
"github.com/tevino/abool"
|
||||
)
|
||||
|
||||
const (
|
||||
tcpConnectionEstablishmentTimeout = 3 * time.Second
|
||||
tcpWriteTimeout = 2 * time.Second
|
||||
heartbeatTimeout = 5 * time.Second
|
||||
ignoreQueriesAfter = 5 * time.Minute
|
||||
)
|
||||
|
||||
// TCPResolver is a resolver using just a single tcp connection with pipelining.
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
)
|
||||
|
||||
// DNS Resolver Attributes
|
||||
// DNS Resolver Attributes.
|
||||
const (
|
||||
ServerTypeDNS = "dns"
|
||||
ServerTypeTCP = "tcp"
|
||||
@@ -30,10 +30,8 @@ const (
|
||||
ServerSourceEnv = "env"
|
||||
)
|
||||
|
||||
var (
|
||||
// FailThreshold is amount of errors a resolvers must experience in order to be regarded as failed.
|
||||
FailThreshold = 20
|
||||
)
|
||||
// FailThreshold is amount of errors a resolvers must experience in order to be regarded as failed.
|
||||
var FailThreshold = 20
|
||||
|
||||
// Resolver holds information about an active resolver.
|
||||
type Resolver struct {
|
||||
@@ -73,7 +71,7 @@ type Resolver struct {
|
||||
// ResolverInfo is a subset of resolver attributes that is attached to answers
|
||||
// from that server in order to use it later for decision making. It must not
|
||||
// be changed by anyone after creation and initialization is complete.
|
||||
type ResolverInfo struct {
|
||||
type ResolverInfo struct { //nolint:golint,maligned // TODO
|
||||
// Name describes the name given to the resolver. The name is configured in the config URL using the name parameter.
|
||||
Name string
|
||||
|
||||
@@ -178,7 +176,7 @@ func (resolver *Resolver) String() string {
|
||||
}
|
||||
|
||||
// ResolverConn is an interface to implement different types of query backends.
|
||||
type ResolverConn interface { //nolint:go-lint // TODO
|
||||
type ResolverConn interface { //nolint:golint // TODO
|
||||
Query(ctx context.Context, q *Query) (*RRCache, error)
|
||||
ReportFailure()
|
||||
IsFailing() bool
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -27,10 +27,12 @@ func init() {
|
||||
}
|
||||
|
||||
func startQuery(t *testing.T, wg *sync.WaitGroup, rc ResolverConn, q *Query) {
|
||||
t.Helper()
|
||||
|
||||
start := time.Now()
|
||||
_, err := rc.Query(silencingTraceCtx, q)
|
||||
if err != nil {
|
||||
t.Logf("client failed: %s", err) //nolint:staticcheck
|
||||
t.Logf("client failed: %s", err)
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
@@ -39,6 +41,8 @@ func startQuery(t *testing.T, wg *sync.WaitGroup, rc ResolverConn, q *Query) {
|
||||
}
|
||||
|
||||
func TestSingleResolving(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// skip if short - this test depends on the Internet and might fail randomly
|
||||
if testing.Short() {
|
||||
t.Skip()
|
||||
@@ -48,7 +52,6 @@ func TestSingleResolving(t *testing.T) {
|
||||
|
||||
// create separate resolver for this test
|
||||
resolver, _, err := createResolver(testResolver, "config")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -59,7 +62,7 @@ func TestSingleResolving(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(100)
|
||||
for i := 0; i < 100; i++ {
|
||||
startQuery(t, wg, resolver.Conn, &Query{ //nolint:staticcheck
|
||||
startQuery(t, wg, resolver.Conn, &Query{
|
||||
FQDN: <-domainFeed,
|
||||
QType: dns.Type(dns.TypeA),
|
||||
})
|
||||
@@ -70,6 +73,8 @@ func TestSingleResolving(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBulkResolving(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// skip if short - this test depends on the Internet and might fail randomly
|
||||
if testing.Short() {
|
||||
t.Skip()
|
||||
@@ -79,7 +84,6 @@ func TestBulkResolving(t *testing.T) {
|
||||
|
||||
// create separate resolver for this test
|
||||
resolver, _, err := createResolver(testResolver, "config")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -90,7 +94,7 @@ func TestBulkResolving(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(100)
|
||||
for i := 0; i < 100; i++ {
|
||||
go startQuery(t, wg, resolver.Conn, &Query{ //nolint:staticcheck
|
||||
go startQuery(t, wg, resolver.Conn, &Query{
|
||||
FQDN: <-domainFeed,
|
||||
QType: dns.Type(dns.TypeA),
|
||||
})
|
||||
|
||||
@@ -138,7 +138,7 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) {
|
||||
return nil, false, fmt.Errorf("invalid value for upstream block detection (blockedif=)")
|
||||
}
|
||||
|
||||
new := &Resolver{
|
||||
newResolver := &Resolver{
|
||||
ConfigURL: resolverURL,
|
||||
Info: &ResolverInfo{
|
||||
Name: query.Get("name"),
|
||||
@@ -153,8 +153,8 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) {
|
||||
UpstreamBlockDetection: blockType,
|
||||
}
|
||||
|
||||
new.Conn = resolverConnFactory(new)
|
||||
return new, false, nil
|
||||
newResolver.Conn = resolverConnFactory(newResolver)
|
||||
return newResolver, false, nil
|
||||
}
|
||||
|
||||
func configureSearchDomains(resolver *Resolver, searches []string) {
|
||||
|
||||
@@ -3,8 +3,11 @@ package resolver
|
||||
import "testing"
|
||||
|
||||
func TestCheckResolverSearchScope(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
test := func(t *testing.T, domain string, expectedResult bool) {
|
||||
t.Helper()
|
||||
|
||||
if checkSearchScope(domain) != expectedResult {
|
||||
if expectedResult {
|
||||
t.Errorf("domain %s failed scope test", domain)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
)
|
||||
|
||||
func testReverse(t *testing.T, ip, result, expectedErr string) {
|
||||
t.Helper()
|
||||
|
||||
ctx, tracer := log.AddTracer(context.Background())
|
||||
defer tracer.Submit()
|
||||
|
||||
@@ -26,6 +28,8 @@ func testReverse(t *testing.T, ip, result, expectedErr string) {
|
||||
}
|
||||
|
||||
func TestResolveIPAndValidate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testReverse(t, "198.41.0.4", "a.root-servers.net.", "")
|
||||
// testReverse(t, "9.9.9.9", "dns.quad9.net.", "") // started resolving to dns9.quad9.net.
|
||||
// testReverse(t, "2620:fe::fe", "dns.quad9.net.", "") // fails sometimes for some (external) reason
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/nameserver/nsutil"
|
||||
"github.com/safing/portmaster/netenv"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// RRCache is a single-use structure to hold a DNS response.
|
||||
@@ -127,7 +127,7 @@ func (rrCache *RRCache) ExportAllARecords() (ips []net.IP) {
|
||||
|
||||
// ToNameRecord converts the RRCache to a NameRecord for cleaner persistence.
|
||||
func (rrCache *RRCache) ToNameRecord() *NameRecord {
|
||||
new := &NameRecord{
|
||||
newRecord := &NameRecord{
|
||||
Domain: rrCache.Domain,
|
||||
Question: rrCache.Question.String(),
|
||||
RCode: rrCache.RCode,
|
||||
@@ -136,11 +136,11 @@ func (rrCache *RRCache) ToNameRecord() *NameRecord {
|
||||
}
|
||||
|
||||
// Serialize RR entries to strings.
|
||||
new.Answer = toNameRecordSection(rrCache.Answer)
|
||||
new.Ns = toNameRecordSection(rrCache.Ns)
|
||||
new.Extra = toNameRecordSection(rrCache.Extra)
|
||||
newRecord.Answer = toNameRecordSection(rrCache.Answer)
|
||||
newRecord.Ns = toNameRecordSection(rrCache.Ns)
|
||||
newRecord.Extra = toNameRecordSection(rrCache.Extra)
|
||||
|
||||
return new
|
||||
return newRecord
|
||||
}
|
||||
|
||||
func toNameRecordSection(rrSection []dns.RR) []string {
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
)
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testDomain := "Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com."
|
||||
testQuestion := "A"
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portmaster/netenv"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portmaster/netenv"
|
||||
)
|
||||
|
||||
// Domain Scopes
|
||||
// Domain Scopes.
|
||||
var (
|
||||
// Localhost Domain
|
||||
// Handling: Respond with 127.0.0.1 and ::1 to A and AAAA queries, respectively.
|
||||
// RFC6761
|
||||
// See RFC6761.
|
||||
localhostDomain = ".localhost."
|
||||
|
||||
// Invalid Domain
|
||||
// Handling: Always respond with NXDOMAIN.
|
||||
// RFC6761
|
||||
// See RFC6761.
|
||||
invalidDomain = ".invalid."
|
||||
|
||||
// Internal Special-Use Domain
|
||||
@@ -31,7 +31,7 @@ var (
|
||||
|
||||
// Multicast DNS
|
||||
// Handling: Send to nameservers with matching search scope, then MDNS
|
||||
// RFC6762
|
||||
// See RFC6762.
|
||||
multicastDomains = []string{
|
||||
".local.",
|
||||
".254.169.in-addr.arpa.",
|
||||
@@ -89,7 +89,7 @@ var (
|
||||
}
|
||||
|
||||
// Special-Service Domain Names
|
||||
// Handling: Send to nameservers with matching search scope, then local and system assigned nameservers
|
||||
// Handling: Send to nameservers with matching search scope, then local and system assigned nameservers.
|
||||
specialServiceDomains = []string{
|
||||
// RFC7686: Tor Hidden Services
|
||||
".onion.",
|
||||
|
||||
Reference in New Issue
Block a user