120 lines
3.5 KiB
Go
120 lines
3.5 KiB
Go
package resolver
|
|
|
|
type ResolvePlanningInput struct {
|
|
Domains []string
|
|
Now int
|
|
TTL int
|
|
PrecheckDue bool
|
|
PrecheckMaxDomains int
|
|
StaleKeepSec int
|
|
NegTTLNX int
|
|
NegTTLTimeout int
|
|
NegTTLTemporary int
|
|
NegTTLOther int
|
|
}
|
|
|
|
type ResolvePlanningResult struct {
|
|
Fresh map[string][]string
|
|
ToResolve []string
|
|
CacheNegativeHits int
|
|
QuarantineHits int
|
|
StaleHits int
|
|
PrecheckScheduled int
|
|
}
|
|
|
|
func BuildResolvePlanning(
|
|
in ResolvePlanningInput,
|
|
domainCache *DomainCacheState,
|
|
cacheSourceForHost func(string) DomainCacheSource,
|
|
logf func(string, ...any),
|
|
) ResolvePlanningResult {
|
|
result := ResolvePlanningResult{
|
|
Fresh: map[string][]string{},
|
|
}
|
|
if domainCache == nil {
|
|
result.ToResolve = append(result.ToResolve, in.Domains...)
|
|
return result
|
|
}
|
|
|
|
resolveSource := cacheSourceForHost
|
|
if resolveSource == nil {
|
|
resolveSource = func(string) DomainCacheSource { return DomainCacheSourceDirect }
|
|
}
|
|
|
|
for _, d := range in.Domains {
|
|
source := resolveSource(d)
|
|
if ips, ok := domainCache.Get(d, source, in.Now, in.TTL); ok {
|
|
result.Fresh[d] = ips
|
|
if logf != nil {
|
|
logf("cache hit[%s]: %s -> %v", source, d, ips)
|
|
}
|
|
continue
|
|
}
|
|
// Quarantine has priority over negative TTL cache so 24h quarantine
|
|
// is not silently overridden by shorter negative cache windows.
|
|
if state, age, ok := domainCache.GetQuarantine(d, source, in.Now); ok {
|
|
kind, hasKind := domainCache.GetLastErrorKind(d, source)
|
|
timeoutKind := hasKind && kind == DNSErrorTimeout
|
|
if in.PrecheckDue && result.PrecheckScheduled < in.PrecheckMaxDomains {
|
|
// Timeout-based quarantine is rechecked in background batch and should
|
|
// not flood trace with per-domain debug lines.
|
|
if timeoutKind {
|
|
result.QuarantineHits++
|
|
if in.StaleKeepSec > 0 {
|
|
if staleIPs, staleAge, ok := domainCache.GetStale(d, source, in.Now, in.StaleKeepSec); ok {
|
|
result.StaleHits++
|
|
result.Fresh[d] = staleIPs
|
|
if logf != nil {
|
|
logf("cache stale-keep (quarantine)[age=%ds]: %s -> %v", staleAge, d, staleIPs)
|
|
}
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
result.PrecheckScheduled++
|
|
result.ToResolve = append(result.ToResolve, d)
|
|
if logf != nil {
|
|
logf("precheck schedule[quarantine/%s age=%ds]: %s (%s)", state, age, d, source)
|
|
}
|
|
continue
|
|
}
|
|
result.QuarantineHits++
|
|
if logf != nil {
|
|
logf("cache quarantine hit[%s age=%ds]: %s (%s)", state, age, d, source)
|
|
}
|
|
if in.StaleKeepSec > 0 {
|
|
if staleIPs, staleAge, ok := domainCache.GetStale(d, source, in.Now, in.StaleKeepSec); ok {
|
|
result.StaleHits++
|
|
result.Fresh[d] = staleIPs
|
|
if logf != nil {
|
|
logf("cache stale-keep (quarantine)[age=%ds]: %s -> %v", staleAge, d, staleIPs)
|
|
}
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if kind, age, ok := domainCache.GetNegative(d, source, in.Now, in.NegTTLNX, in.NegTTLTimeout, in.NegTTLTemporary, in.NegTTLOther); ok {
|
|
if in.PrecheckDue && result.PrecheckScheduled < in.PrecheckMaxDomains {
|
|
if kind == DNSErrorTimeout {
|
|
result.CacheNegativeHits++
|
|
continue
|
|
}
|
|
result.PrecheckScheduled++
|
|
result.ToResolve = append(result.ToResolve, d)
|
|
if logf != nil {
|
|
logf("precheck schedule[negative/%s age=%ds]: %s (%s)", kind, age, d, source)
|
|
}
|
|
continue
|
|
}
|
|
result.CacheNegativeHits++
|
|
if logf != nil {
|
|
logf("cache neg hit[%s/%s age=%ds]: %s", source, kind, age, d)
|
|
}
|
|
continue
|
|
}
|
|
result.ToResolve = append(result.ToResolve, d)
|
|
}
|
|
|
|
return result
|
|
}
|