diff --git a/resolver/resolve.go b/resolver/resolve.go index 67b95ec6..b917968a 100644 --- a/resolver/resolve.go +++ b/resolver/resolve.go @@ -215,9 +215,7 @@ func checkCache(ctx context.Context, q *Query) *RRCache { // Check if the cache will expire soon and start an async request. if rrCache.ExpiresSoon() { // Set flag that we are refreshing this entry. - rrCache.Lock() - rrCache.requestingNew = true - rrCache.Unlock() + rrCache.RequestingNew = true log.Tracer(ctx).Tracef( "resolver: cache for %s will expire in %s, refreshing async now", @@ -397,7 +395,7 @@ resolveLoop: // Check if we want to use an older cache instead. if oldCache != nil { - oldCache.isBackup = true + oldCache.IsBackup = true switch { case err != nil: diff --git a/resolver/resolver-mdns.go b/resolver/resolver-mdns.go index 21a91a87..166cebfb 100644 --- a/resolver/resolver-mdns.go +++ b/resolver/resolver-mdns.go @@ -196,9 +196,9 @@ func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { if saveFullRequest { // get from database rrCache, err = GetRRCache(question.Name, dns.Type(question.Qtype)) - // if we have no cached entry, or it has been updated less more than two seconds ago, or if it expired: + // if we have no cached entry, or it has been updated more than two seconds ago, or if it expired: // create new and do not append - if err != nil || rrCache.updated < time.Now().Add(-2*time.Second).Unix() || rrCache.TTL < time.Now().Unix() { + if err != nil || rrCache.Modified < time.Now().Add(-2*time.Second).Unix() || rrCache.Expired() { rrCache = &RRCache{ Domain: question.Name, Question: dns.Type(question.Qtype), diff --git a/resolver/rrcache.go b/resolver/rrcache.go index 5a277987..1eee7b4a 100644 --- a/resolver/rrcache.go +++ b/resolver/rrcache.go @@ -5,7 +5,6 @@ import ( "fmt" "math/rand" "net" - "sync" "time" "github.com/safing/portbase/log" @@ -15,31 +14,37 @@ import ( "github.com/miekg/dns" ) -// RRCache is used to cache DNS data +// RRCache is a single-use structure to hold a DNS response. +// Persistence is handled through NameRecords because of a limitation of the +// underlying dns library. //nolint:maligned // TODO type RRCache struct { - sync.Mutex + // Respnse Header + Domain string + Question dns.Type + RCode int - Domain string // constant - Question dns.Type // constant - RCode int // constant + // Response Content + Answer []dns.RR + Ns []dns.RR + Extra []dns.RR + TTL int64 - Answer []dns.RR // mutable (mixing, non-standard formats) - Ns []dns.RR // constant - Extra []dns.RR // constant - TTL int64 // constant + // Source Information + Server string + ServerScope int8 + ServerInfo string - Server string // constant - ServerScope int8 // constant - ServerInfo string // constant + // Metadata about the request and handling + ServedFromCache bool + RequestingNew bool + IsBackup bool + Filtered bool + FilteredEntries []string - servedFromCache bool // mutable - requestingNew bool // mutable - isBackup bool // mutable - Filtered bool // mutable - FilteredEntries []string // mutable - - updated int64 // mutable + // Modified holds when this entry was last changed, ie. saved to database. + // This field is only populated when the entry comes from the cache. + Modified int64 } // ID returns the ID of the RRCache consisting of the domain and question type. @@ -59,9 +64,6 @@ func (rrCache *RRCache) ExpiresSoon() bool { // Clean sets all TTLs to 17 and sets cache expiry with specified minimum. func (rrCache *RRCache) Clean(minExpires uint32) { - rrCache.Lock() - defer rrCache.Unlock() - var lowestTTL uint32 = 0xFFFFFFFF var header *dns.RR_Header @@ -200,7 +202,8 @@ func GetRRCache(domain string, question dns.Type) (*RRCache, error) { rrCache.Server = nameRecord.Server rrCache.ServerScope = nameRecord.ServerScope rrCache.ServerInfo = nameRecord.ServerInfo - rrCache.servedFromCache = true + rrCache.ServedFromCache = true + rrCache.Modified = nameRecord.Meta().Modified return rrCache, nil } @@ -217,26 +220,16 @@ func parseRR(section []dns.RR, entry string) []dns.RR { return section } -// ServedFromCache marks the RRCache as served from cache. -func (rrCache *RRCache) ServedFromCache() bool { - return rrCache.servedFromCache -} - -// RequestingNew informs that it has expired and new RRs are being fetched. -func (rrCache *RRCache) RequestingNew() bool { - return rrCache.requestingNew -} - // Flags formats ServedFromCache and RequestingNew to a condensed, flag-like format. func (rrCache *RRCache) Flags() string { var s string - if rrCache.servedFromCache { + if rrCache.ServedFromCache { s += "C" } - if rrCache.requestingNew { + if rrCache.RequestingNew { s += "R" } - if rrCache.isBackup { + if rrCache.IsBackup { s += "B" } if rrCache.Filtered { @@ -255,21 +248,22 @@ func (rrCache *RRCache) ShallowCopy() *RRCache { Domain: rrCache.Domain, Question: rrCache.Question, RCode: rrCache.RCode, - Answer: rrCache.Answer, - Ns: rrCache.Ns, - Extra: rrCache.Extra, - TTL: rrCache.TTL, + + Answer: rrCache.Answer, + Ns: rrCache.Ns, + Extra: rrCache.Extra, + TTL: rrCache.TTL, Server: rrCache.Server, ServerScope: rrCache.ServerScope, ServerInfo: rrCache.ServerInfo, - updated: rrCache.updated, - servedFromCache: rrCache.servedFromCache, - requestingNew: rrCache.requestingNew, - isBackup: rrCache.isBackup, + ServedFromCache: rrCache.ServedFromCache, + RequestingNew: rrCache.RequestingNew, + IsBackup: rrCache.IsBackup, Filtered: rrCache.Filtered, FilteredEntries: rrCache.FilteredEntries, + Modified: rrCache.Modified, } } @@ -308,7 +302,7 @@ func (rrCache *RRCache) ReplyWithDNS(ctx context.Context, request *dns.Msg) *dns // GetExtraRRs returns a slice of RRs with additional informational records. func (rrCache *RRCache) GetExtraRRs(ctx context.Context, query *dns.Msg) (extra []dns.RR) { // Add cache status and source of data. - if rrCache.servedFromCache { + if rrCache.ServedFromCache { extra = addExtra(ctx, extra, "served from cache, resolved by "+rrCache.ServerInfo) } else { extra = addExtra(ctx, extra, "freshly resolved by "+rrCache.ServerInfo) @@ -320,10 +314,10 @@ func (rrCache *RRCache) GetExtraRRs(ctx context.Context, query *dns.Msg) (extra } else { extra = addExtra(ctx, extra, fmt.Sprintf("record valid for %s", time.Until(time.Unix(rrCache.TTL, 0)).Round(time.Second))) } - if rrCache.requestingNew { + if rrCache.RequestingNew { extra = addExtra(ctx, extra, "async request to refresh the cache has been started") } - if rrCache.isBackup { + if rrCache.IsBackup { extra = addExtra(ctx, extra, "this record is served because a fresh request failed") }