cache

package module
v0.0.0-...-279a53c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: BSD-2-Clause Imports: 13 Imported by: 0

Documentation

Overview

* Copyright (c) 2024 Johan Stenstam, johani@johani.org

* Copyright (c) 2024 Johan Stenstam, johani@johani.org

* Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se

* Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se

* Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se

* Copyright (c) 2024 Johan Stenstam, johani@johani.org

Index

Constants

View Source
const CompiledInRootHints = `` /* 2432-byte string literal not displayed */

CompiledInRootHints contains the default root hints compiled into the binary. This is used when no root-hints configuration file is specified. The format is a standard DNS zone file with NS records for the root zone and A/AAAA glue records for root nameservers.

Current IANA root servers (as of 2024)

Variables

View Source
var CacheContextToString = map[CacheContext]string{
	ContextAnswer:     "answer",
	ContextHint:       "hint",
	ContextPriming:    "priming",
	ContextReferral:   "referral",
	ContextNXDOMAIN:   "NXDOMAIN (negative response type 3)",
	ContextNoErrNoAns: "NOERROR, NODATA (negative response type 0)",
	ContextGlue:       "glue",
	ContextFailure:    "failure",
}
View Source
var DnskeyCache = NewDnskeyCache()

This is still global, but also present in the RRsetCacheT struct

View Source
var ValidationStateToString = map[ValidationState]string{
	ValidationStateNone:          "none",
	ValidationStateInsecure:      "insecure",
	ValidationStateSecure:        "secure",
	ValidationStateBogus:         "bogus",
	ValidationStateIndeterminate: "indeterminate",
}

Functions

func GetMinTTL

func GetMinTTL(rrs []dns.RR) time.Duration

func ValidateDNSKEYRRsetSignature

func ValidateDNSKEYRRsetSignature(rrset *core.RRset, keyid uint16, signerName string, dnskey *dns.DNSKEY, verbose bool) (bool, *dns.RRSIG)

ValidateDNSKEYRRsetSignature validates a DNSKEY RRset signature using a provided DNSKEY. It finds the RRSIG(DNSKEY) signed by the specified key, verifies the signature, checks time validity, and caps TTLs to signature expiration if necessary. Returns true if validation succeeds, false otherwise. Also returns the RRSIG if found. signature's expiration; it does not modify any caches.

func ValidateDNSKEYRRsetUsingDS

func ValidateDNSKEYRRsetUsingDS(rrset *core.RRset, ds *dns.DS, signerName string, verbose bool) (bool, *dns.DNSKEY)

ValidateDNSKEYRRsetUsingDS validates a DNSKEY RRset using a DS record. It finds the DNSKEY in the RRset that matches the DS (by keytag, SEP bit, and digest), then validates the RRset signature using that DNSKEY. Returns true if validation succeeds, false otherwise. Also returns the candidate DNSKEY if found. The function may modify the TTLs of RRs in rrset (capping them to signature expiration) but does not modify any caches.

func WithinValidityPeriod

func WithinValidityPeriod(inc, exp uint32, t time.Time) bool

Types

type AddressBackoff

type AddressBackoff struct {
	NextTry      time.Time // When this address can be tried again
	FailureCount uint8     // Number of consecutive failures (1 = first failure, 2+ = second+ failure)
	LastError    string    // Last error message (stored when debug mode is enabled)
}

AddressBackoff tracks backoff state for a single server address. Used to avoid repeatedly querying addresses that don't respond or have routing issues.

type AuthServer

type AuthServer struct {
	Name             string
	Addrs            []string
	Alpn             []string // {"do53", "doq", "dot", "doh"}
	Transports       []core.Transport
	PrefTransport    core.Transport           // "doq" | "dot" | "doh" | "do53"
	TransportWeights map[core.Transport]uint8 // percentage per transport (sum <= 100). Remainder -> do53
	// Optional config-only field for stubs: colon-separated transport weights, e.g. "doq:30,dot:70"
	// When provided in config, this overrides Alpn for building Transports/PrefTransport/TransportWeights.
	TransportSignal string                  `yaml:"transport" mapstructure:"transport"`
	ConnMode        ConnMode                `yaml:"connmode" mapstructure:"connmode"`
	TLSARecords     map[string]*CachedRRset // keyed by owner (_port._proto.name.), validated RRsets only

	TransportCounters map[core.Transport]uint64 // total queries attempted per transport
	Src               string                    // "answer", "glue", "hint", "priming", "stub", ...
	Expire            time.Time
	Debug             bool // If true, store error messages in AddressBackoff.LastError
	// Backoff tracking (guarded by mu)
	AddressBackoffs map[string]*AddressBackoff // keyed by address string (e.g., "1.2.3.4:53" or "[2001:db8::1]:53")
	// contains filtered or unexported fields
}

func NewAuthServer

func NewAuthServer(name string) *AuthServer

NewAuthServer creates a new AuthServer instance with default values. The name parameter is required and identifies the nameserver. All other fields are initialized with safe defaults:

  • Alpn: ["do53"]
  • Transports: [TransportDo53]
  • PrefTransport: TransportDo53
  • Src: "unknown"
  • ConnMode: ConnModeLegacy
  • Other fields: nil or zero values

func (*AuthServer) AddAddr

func (as *AuthServer) AddAddr(addr string)

AddAddr adds an address if it doesn't already exist. Thread-safe.

func (*AuthServer) AddAlpn

func (as *AuthServer) AddAlpn(alpn string)

AddAlpn adds an ALPN value if it doesn't already exist. Thread-safe.

func (*AuthServer) AddTransport

func (as *AuthServer) AddTransport(t core.Transport)

AddTransport adds a transport if it doesn't already exist. Thread-safe.

func (*AuthServer) AllAddressesInBackoff

func (as *AuthServer) AllAddressesInBackoff() bool

AllAddressesInBackoff returns true if all addresses for this server are currently in backoff. Thread-safe: acquires mu lock once for the entire operation.

func (*AuthServer) ConnectionMode

func (as *AuthServer) ConnectionMode() ConnMode

func (*AuthServer) ForceSetSrc

func (as *AuthServer) ForceSetSrc(src string)

ForceSetSrc sets the source string unconditionally. Thread-safe.

func (*AuthServer) GetAddrs

func (as *AuthServer) GetAddrs() []string

GetAddrs returns a copy of the addresses slice. Thread-safe.

func (*AuthServer) GetAlpn

func (as *AuthServer) GetAlpn() []string

GetAlpn returns a copy of the ALPN slice. Thread-safe.

func (*AuthServer) GetAvailableAddresses

func (as *AuthServer) GetAvailableAddresses() []string

GetAvailableAddresses returns a list of addresses that are currently available (not in backoff). Thread-safe: acquires mu lock once for the entire operation.

func (*AuthServer) GetDebug

func (as *AuthServer) GetDebug() bool

GetDebug returns the debug flag. Thread-safe.

func (*AuthServer) GetExpire

func (as *AuthServer) GetExpire() time.Time

GetExpire returns the expiration time. Thread-safe.

func (*AuthServer) GetPrefTransport

func (as *AuthServer) GetPrefTransport() core.Transport

GetPrefTransport returns the preferred transport. Thread-safe.

func (*AuthServer) GetSrc

func (as *AuthServer) GetSrc() string

GetSrc returns the source string. Thread-safe.

func (*AuthServer) GetTransportWeights

func (as *AuthServer) GetTransportWeights() map[core.Transport]uint8

GetTransportWeights returns a copy of the transport weights map. Thread-safe.

func (*AuthServer) GetTransports

func (as *AuthServer) GetTransports() []core.Transport

GetTransports returns a copy of the transports slice. Thread-safe.

func (*AuthServer) IncrementTransportCounter

func (as *AuthServer) IncrementTransportCounter(t core.Transport)

func (*AuthServer) IsAddressAvailable

func (as *AuthServer) IsAddressAvailable(addr string) bool

IsAddressAvailable returns true if the given address is not in backoff or backoff has expired. Thread-safe: acquires mu lock.

func (*AuthServer) MergeTransportWeights

func (as *AuthServer) MergeTransportWeights(weights map[core.Transport]uint8)

MergeTransportWeights merges the provided weights into the existing map. Thread-safe.

func (*AuthServer) PromoteConnMode

func (as *AuthServer) PromoteConnMode(target ConnMode)

func (*AuthServer) PromoteDebug

func (as *AuthServer) PromoteDebug()

PromoteDebug sets debug to true if not already set. Thread-safe.

func (*AuthServer) RecordAddressFailure

func (as *AuthServer) RecordAddressFailure(addr string, err error)

RecordAddressFailure records a failure for the given address and sets appropriate backoff. The error parameter is analyzed to determine backoff duration:

  • Routing errors ("no route to host"): 1 hour immediately
  • Timeout errors: 2 minutes
  • Other errors: 2 minutes for first failure, 1 hour for subsequent failures

If as.Debug is true, the error message is stored in LastError for debugging purposes. Thread-safe: acquires mu lock.

func (*AuthServer) RecordAddressFailureForRcode

func (as *AuthServer) RecordAddressFailureForRcode(addr string, rcode uint8)

RecordAddressFailureForRcode records a failure for the given address based on a DNS response code. Thread-safe: acquires mu lock.

func (*AuthServer) RecordAddressSuccess

func (as *AuthServer) RecordAddressSuccess(addr string)

RecordAddressSuccess clears any backoff for the given address. Thread-safe: acquires mu lock.

func (*AuthServer) SetAddrs

func (as *AuthServer) SetAddrs(addrs []string)

SetAddrs sets the addresses slice. Thread-safe.

func (*AuthServer) SetAlpn

func (as *AuthServer) SetAlpn(alpn []string)

SetAlpn sets the ALPN slice. Thread-safe.

func (*AuthServer) SetDebug

func (as *AuthServer) SetDebug(debug bool)

SetDebug sets the debug flag. Thread-safe.

func (*AuthServer) SetExpire

func (as *AuthServer) SetExpire(expire time.Time)

SetExpire sets the expiration time. Thread-safe.

func (*AuthServer) SetPrefTransport

func (as *AuthServer) SetPrefTransport(t core.Transport)

SetPrefTransport sets the preferred transport. Thread-safe.

func (*AuthServer) SetSrc

func (as *AuthServer) SetSrc(src string)

SetSrc sets the source string if it's more specific than the current value. Thread-safe.

func (*AuthServer) SetTransportWeight

func (as *AuthServer) SetTransportWeight(t core.Transport, weight uint8)

SetTransportWeight sets a single transport weight. Thread-safe.

func (*AuthServer) SetTransportWeights

func (as *AuthServer) SetTransportWeights(weights map[core.Transport]uint8)

SetTransportWeights replaces the entire transport weights map. Thread-safe.

func (*AuthServer) SetTransports

func (as *AuthServer) SetTransports(transports []core.Transport)

SetTransports sets the transports slice. Thread-safe.

func (*AuthServer) SnapshotAddressBackoffs

func (as *AuthServer) SnapshotAddressBackoffs(now time.Time) map[string]*AddressBackoff

SnapshotAddressBackoffs returns a copy of the address backoff map. Only includes addresses that are currently in backoff (NextTry > now).

func (*AuthServer) SnapshotCounters

func (as *AuthServer) SnapshotCounters() map[core.Transport]uint64

SnapshotCounters returns a copy of the per-transport counters.

func (*AuthServer) SnapshotTLSARecords

func (as *AuthServer) SnapshotTLSARecords() map[string]*CachedRRset

func (*AuthServer) SnapshotTransportCounters

func (as *AuthServer) SnapshotTransportCounters() map[core.Transport]uint64

SnapshotTransportCounters returns a thread-safe copy of the transport counters.

type CacheContext

type CacheContext uint8
const (
	ContextAnswer CacheContext = iota + 1
	ContextHint
	ContextPriming
	ContextReferral
	ContextNXDOMAIN
	ContextNoErrNoAns
	ContextGlue    // from additional section
	ContextFailure // some sort of general failure that we cannot sort out
)

type CachedDnskeyRRset

type CachedDnskeyRRset struct {
	Name  string
	Keyid uint16
	State ValidationState
	// Trusted     bool
	TrustAnchor bool
	Dnskey      dns.DNSKEY  // just this key
	RRset       *core.RRset // complete RRset
	Expiration  time.Time
}

type CachedRRset

type CachedRRset struct {
	Name         string
	RRtype       uint16
	Rcode        uint8
	RRset        *core.RRset
	NegAuthority []*core.RRset
	Ttl          uint32
	Context      CacheContext
	// OBE Validated    bool
	// OBE Bogus        bool
	State      ValidationState
	Expiration time.Time
	EDECode    uint16
	EDEText    string
	Transport  core.Transport // Transport used to receive this data (for privacy tracking)
}

type ConnMode

type ConnMode uint8
const (
	ConnModeLegacy ConnMode = iota
	ConnModeOpportunistic
	ConnModeValidated
	ConnModeStrict
)

func ParseConnMode

func ParseConnMode(s string) (ConnMode, bool)

func (ConnMode) String

func (m ConnMode) String() string

type DnskeyCacheT

type DnskeyCacheT struct {
	Map *core.ConcurrentMap[string, CachedDnskeyRRset]
}

type TAStore map[string]map[uint16]TrustAnchor

func NewDnskeyCache

func NewDnskeyCache() *DnskeyCacheT

NewDnskeyCache creates and returns a new DnskeyCacheT with its map initialized. The returned cache has Map set to a fresh concurrent map for storing CachedDnskeyRRset entries.

func (*DnskeyCacheT) Get

func (dkc *DnskeyCacheT) Get(zonename string, keyid uint16) *CachedDnskeyRRset

func (*DnskeyCacheT) Set

func (dkc *DnskeyCacheT) Set(zonename string, keyid uint16, cdr *CachedDnskeyRRset)

type ParentZoneFinder

type ParentZoneFinder func(name string) (string, error)

ParentZoneFinder finds the authoritative zone for a given domain name. It should check the cache first and only query if necessary. Returns the zone name and an error if not found.

type RRsetCacheT

type RRsetCacheT struct {
	RRsets        *core.ConcurrentMap[string, CachedRRset]
	Servers       *core.ConcurrentMap[string, []string]
	ServerMap     *core.ConcurrentMap[string, map[string]*AuthServer] // map[zone]map[nsname]*AuthServer
	AuthServerMap *core.ConcurrentMap[string, *AuthServer]            // Global map: nsname -> *AuthServer (ensures single instance per nameserver)
	ZoneMap       *core.ConcurrentMap[string, *Zone]                  // map[zone]*Zone
	DnskeyCache   *DnskeyCacheT
	DNSClient     map[core.Transport]*core.DNSClient
	//Options                map[ImrOption]string
	Primed    bool
	Logger    *log.Logger
	LineWidth int
	Verbose   bool
	Debug     bool
	Quiet     bool // if true, suppress informational logging (useful for CLI tools)
	// contains filtered or unexported fields
}

func NewRRsetCache

func NewRRsetCache(lg *log.Logger, verbose, debug bool) *RRsetCacheT

NewRRsetCache creates and initializes an RRsetCacheT with per-transport DNS clients and empty concurrent maps.

The returned cache has ready-to-use concurrent maps for RRsets, Servers, ServerMap, AuthServerMap, ZoneMap and a reference to the global DnskeyCache, along with per-transport DNS clients (Do53, DoT, DoH, DoQ) using standard ports. The provided logger is used for cache logging; the verbose and debug flags enable their respective logging modes.

func (*RRsetCacheT) AddServers

func (rrcache *RRsetCacheT) AddServers(zone string, sm map[string]*AuthServer) error

func (*RRsetCacheT) AddStub

func (rrcache *RRsetCacheT) AddStub(zone string, servers []AuthServer) error

A stub is a static mapping from a zone name to a list of addresses (later probably AuthServers)

func (*RRsetCacheT) ClearNSRevalidation

func (rrcache *RRsetCacheT) ClearNSRevalidation(zone string)

func (*RRsetCacheT) ClearTLSAQuery

func (rrcache *RRsetCacheT) ClearTLSAQuery(owner string)

func (*RRsetCacheT) ClearTransportQuery

func (rrcache *RRsetCacheT) ClearTransportQuery(owner string)

func (*RRsetCacheT) FindClosestKnownZone

func (rrcache *RRsetCacheT) FindClosestKnownZone(qname string) (string, map[string]*AuthServer, error)

func (*RRsetCacheT) FlushAll

func (rrcache *RRsetCacheT) FlushAll() int

FlushAll removes all cached data except root zone priming data (NS for ".", root server A/AAAA records). Returns the number of RRsets removed.

func (*RRsetCacheT) FlushDomain

func (rrcache *RRsetCacheT) FlushDomain(domain string, keepStructural bool) (int, error)

FlushDomain removes cached RRsets at or below the provided domain. When keepStructural is true, NS/DS/DNSKEY RRsets and the address records for their nameservers are preserved.

func (*RRsetCacheT) Get

func (rrcache *RRsetCacheT) Get(qname string, qtype uint16) *CachedRRset

func (*RRsetCacheT) GetOrCreateAuthServer

func (rrcache *RRsetCacheT) GetOrCreateAuthServer(nsname string) *AuthServer

GetOrCreateAuthServer returns an existing AuthServer instance for the given nameserver name, or creates a new one if it doesn't exist. This ensures there is only one AuthServer instance per nameserver name across all zones. Uses O(1) map lookup instead of iterating through zones.

func (*RRsetCacheT) IsPrimed

func (rrcache *RRsetCacheT) IsPrimed() bool

func (*RRsetCacheT) MarkNSRevalidation

func (rrcache *RRsetCacheT) MarkNSRevalidation(zone string) bool

func (*RRsetCacheT) MarkRRsetBogus

func (rrcache *RRsetCacheT) MarkRRsetBogus(qname string, qtype uint16, rrset *core.RRset, dnssecOK bool) (uint16, string)

func (*RRsetCacheT) MarkTLSAQuery

func (rrcache *RRsetCacheT) MarkTLSAQuery(owner string) bool

func (*RRsetCacheT) MarkTransportQuery

func (rrcache *RRsetCacheT) MarkTransportQuery(owner string) bool

func (*RRsetCacheT) PrimeWithHints

func (rrcache *RRsetCacheT) PrimeWithHints(hintsfile string, fetcher RRsetFetcher) error

func (*RRsetCacheT) Set

func (rrcache *RRsetCacheT) Set(qname string, qtype uint16, crrset *CachedRRset)

func (*RRsetCacheT) SetPrimed

func (rrcache *RRsetCacheT) SetPrimed(primed bool)

func (*RRsetCacheT) StoreTLSAForServer

func (rrcache *RRsetCacheT) StoreTLSAForServer(base, owner string, rrset *core.RRset, vstate ValidationState)

func (*RRsetCacheT) ValidateDNSKEYs

func (rrcache *RRsetCacheT) ValidateDNSKEYs(ctx context.Context, rrset *core.RRset, fetcher RRsetFetcher) (ValidationState, error)

ValidateDNSKEYs validates a DNSKEY RRset using DS from the parent and the specific KSK named in the RRSIG. Steps: 1) Identify signer (apex) and key tag from an RRSIG covering DNSKEY. 2) Find the matching DNSKEY in the RRset (should be KSK). 3) Ensure a validated DS RRset for this apex exists in the cache. 4) Match the DNSKEY against any DS digest present. 5) Verify the DNSKEY RRset RRSIG with the matched DNSKEY and time window.

func (*RRsetCacheT) ValidateNegativeResponse

func (rrcache *RRsetCacheT) ValidateNegativeResponse(ctx context.Context, qname string, qtype uint16, rcode uint8,
	negAuthority []*core.RRset, fetcher RRsetFetcher) (ValidationState, uint8, error)

func (*RRsetCacheT) ValidateRRset

func (rrcache *RRsetCacheT) ValidateRRset(ctx context.Context, rrset *core.RRset, fetcher RRsetFetcher) (ValidationState, error)

ValidateRRset attempts to validate the provided RRset using DNSKEYs present in the DnskeyCache. If a required signer key is missing, it will query for the signer's DNSKEY via the recursive engine and retry using keys from the cache. Only keys marked as ValidateionStateSecure are accepted for successful validation. Returns ValidationStateSecure if at least one signature validates and is time-valid.

func (*RRsetCacheT) ValidateRRsetWithParentZone

func (rrcache *RRsetCacheT) ValidateRRsetWithParentZone(ctx context.Context, rrset *core.RRset, fetcher RRsetFetcher, parentZoneFinder ParentZoneFinder) (ValidationState, error)

ValidateRRsetWithParentZone validates an RRset, optionally using a ParentZoneFinder to find the authoritative zone. If parentZoneFinder is nil, it falls back to checking ZoneMap by walking up the domain name. If the RRset is already cached with a validation state, that state is returned without re-validating.

type RRsetFetcher

type RRsetFetcher func(ctx context.Context, qname string, qtype uint16, servers map[string]*AuthServer) (*core.RRset, error)

RRsetFetcher is a function type for fetching RRsets by querying authoritative servers. It takes a context, query name, query type, and a map of authoritative servers, and returns the fetched RRset or an error.

type ValidationState

type ValidationState uint8
const (
	ValidationStateNone ValidationState = iota + 1
	ValidationStateInsecure
	ValidationStateSecure
	ValidationStateBogus
	ValidationStateIndeterminate
)

type Zone

type Zone struct {
	ZoneName string
	State    ValidationState
	// Zone-specific address backoffs: map[address]*AddressBackoff
	// Tracks per-zone, per-address failures (e.g., REFUSED for this zone from this address)
	AddressBackoffs map[string]*AddressBackoff
	// contains filtered or unexported fields
}

func (*Zone) GetState

func (z *Zone) GetState() ValidationState

GetState returns the current validation state of the zone. Thread-safe: acquires mu lock.

func (*Zone) IsZoneAddressAvailable

func (z *Zone) IsZoneAddressAvailable(addr string) bool

IsZoneAddressAvailable returns true if the given address is not in zone-specific backoff or backoff has expired. Thread-safe: acquires mu lock.

func (*Zone) RecordZoneAddressFailureForRcode

func (z *Zone) RecordZoneAddressFailureForRcode(addr string, rcode uint8, debug bool)

RecordZoneAddressFailureForRcode records a zone-specific failure for the given address based on a DNS response code. REFUSED/NOTAUTH/NOTIMP responses (lame delegations) get 1 hour backoff immediately as they're unlikely to resolve soon. Thread-safe: acquires mu lock.

func (*Zone) RecordZoneAddressSuccess

func (z *Zone) RecordZoneAddressSuccess(addr string)

RecordZoneAddressSuccess clears any zone-specific backoff for the given address. Thread-safe: acquires mu lock.

func (*Zone) SetState

func (z *Zone) SetState(state ValidationState)

SetState sets the validation state of the zone. Thread-safe: acquires mu lock.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL