authority

package
v1.8.2 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache type.

func NewCache

func NewCache() *Cache

NewCache return new cache.

func (*Cache) Get

func (n *Cache) Get(key uint64) (*Delegation, error)

(*Cache).Get returns the delegation entry for a key or an error.

func (*Cache) Remove

func (n *Cache) Remove(key uint64)

(*Cache).Remove remove remove a cache.

func (*Cache) Set

func (n *Cache) Set(key uint64, dsSet []dns.RR, servers *Servers, ttl time.Duration)

(*Cache).Set stores a delegation entry that expires ttl from now.

The lease must honour the parent-granted TTL. The former one-hour lower clamp inflated a short referral TTL (e.g. a 4s delegation) into a one-hour lease, which let a withdrawn child zone be kept alive indefinitely from its own authoritative NS answer — the ghost-domain vulnerability (GHSA-mqfw-f48p-2vc8). Only the upper bound is clamped now; a non-positive TTL is not cached at all (caching an already-expired entry is pointless and a zero TTL means "do not cache").

func (*Cache) SetUntil added in v1.7.3

func (n *Cache) SetUntil(key uint64, dsSet []dns.RR, servers *Servers, expiresAt time.Time)

(*Cache).SetUntil stores a delegation with an ABSOLUTE expiry, capped at the 12h ceiling. Resolver writes use this so a parent-granted deadline — possibly inherited from a shorter-lived ancestor — is stored verbatim rather than reconstructed from time.Until(deadline): any delay (including a scheduler pause) between computing the remaining duration and Set's now.Add(ttl) would otherwise restart the lease.

func (*Cache) SetUntilIfAbsent added in v1.8.1

func (n *Cache) SetUntilIfAbsent(key uint64, dsSet []dns.RR, servers *Servers, expiresAt time.Time) *Delegation

(*Cache).SetUntilIfAbsent is SetUntil for provisional writers: it stores only when the key holds no live delegation — absent, or present but past its expiry. A live entry always wins, atomically: the absent case inserts under the segment write lock (AddIfAbsent), and the expired case replaces exactly the expired value it examined (CompareAndSwap), so a real lease published by a concurrent walk can never be displaced by the provisional one racing it.

It returns the delegation that is live under the key afterwards — the one it stored, or the one that beat it. Callers that go on to use the delegation must use the returned value and not their own inputs: servers, DS set and expiry belong to one entry, and pairing a winner's servers with a loser's DS chain would validate one delegation's answers against another's keys. A nil return means nothing is live (a past deadline is not stored).

type Delegation

type Delegation struct {
	Servers   *Servers
	DSSet     []dns.RR
	ExpiresAt time.Time
}

Delegation represents a cache entry holding the authoritative servers for a zone plus the DS RRset that proves the delegation.

ExpiresAt is a single immutable absolute expiry (monotonic clock retained). Storing the absolute deadline — rather than a duration re-anchored at insertion — is what lets a descendant delegation inherit an ancestor's shorter lease without a scheduler pause between "compute remaining" and "store" silently re-inflating it (GHSA-mqfw-f48p-2vc8, Phoenix downward-delegation variant).

type IPVersion

type IPVersion byte

IPVersion type.

const (
	// IPv4 mode.
	IPv4 IPVersion = 0x1

	// IPv6 mode.
	IPv6 IPVersion = 0x2
)

func (IPVersion) String

func (v IPVersion) String() string

type Server

type Server struct {
	Addr      string
	IPVersion IPVersion

	// UDPAddr is Addr pre-parsed as *net.UDPAddr so the upstream
	// exchange path can use net.DialUDP directly instead of going
	// through Dialer.DialContext's string-parsing + dialParallel
	// machinery. Nil only if Addr failed to parse — callers fall
	// back to the string path in that case.
	UDPAddr *net.UDPAddr
	// contains filtered or unexported fields
}

Server type.

func NewServer

func NewServer(addr string, ipVersion IPVersion) *Server

NewServer return a new server. addr is expected to be an "IP:port" pair — the IP is parsed once here so upstream exchanges can skip Go's DialContext address-resolution path.

Addr is stored in canonical netip form (lowercase, compressed, 4-in-6 unmapped). Every producer builds addr from an IP literal (glue A/AAAA String, configured roots), so the canonical form is what comparison sites and map keys already see; deriving it here keeps one string per server instead of the parse chain's residue.

func NewServerFromAddrPort added in v1.8.0

func NewServerFromAddrPort(ap netip.AddrPort) *Server

NewServerFromAddrPort builds a Server straight from a decoded address — the netip-native producer path (glue records, NS-address lookups) that never materializes an intermediate "IP:port" string. The IP family is derived from the address itself, and the canonical string is created exactly once here for the key/log surfaces that need it.

func Sort

func Sort(serversList []*Server) *Server

Sort ranks a delegation's addresses in place, fastest first. It runs on every cache miss, so it allocates nothing for the sets a resolver actually meets: the scores are read once into a small array and the pass over them is insertion, which is the cheapest thing for a handful of addresses and does not need a closure the way sort.Slice does.

It returns the server the second slot is spending on an exploration probe, or nil when that slot is an ordinary hedge. The caller has to treat the two differently: a hedge is a spare answer, worth nothing once the leader has answered, and cancelling it is right. A probe is worth only the measurement it brings back, and cancelling it brings none — which is what happens by default, every time, because the leader is by construction the fastest server in the list.

func (*Server) Answering added in v1.8.1

func (s *Server) Answering() bool

Answering reports whether the last completed exchange came back with an answer. Unmeasured servers report true: nothing has failed yet.

func (*Server) CanonicalAddr added in v1.8.0

func (a *Server) CanonicalAddr() (string, bool)

CanonicalAddr returns Addr together with whether it is already in the canonical spelling. A caller that keys on the endpoint can use the string as-is when this reports true, and must normalize it otherwise.

func (*Server) Observe added in v1.8.1

func (s *Server) Observe(d time.Duration)

Observe records a completed exchange: how long this server took to answer. The estimate is blended half and half with each new sample, so one bad sample is visible in the ranking immediately — which is what a resolver needs when an authority starts to degrade. A running average over every sample ever taken needed dozens of them to notice.

func (*Server) ObserveNoAnswer added in v1.8.1

func (s *Server) ObserveNoAnswer(d time.Duration)

ObserveNoAnswer records an exchange that came back with no answer — a timeout, a transport error, a refusal. The caller prices it, and prices it as a timeout; this only adds that the authority did not reply.

func (*Server) Score added in v1.8.1

func (s *Server) Score() time.Duration

Score is what the ranking sorts on, at this instant.

func (*Server) SmoothedRTT added in v1.8.1

func (s *Server) SmoothedRTT() time.Duration

SmoothedRTT is the measured latency, or zero when nothing has answered. The adaptive per-server timeout reads this rather than the ranking score: a timeout should follow how fast the server is, not how far the ranking has priced it down.

func (*Server) String

func (a *Server) String() string

type Servers

type Servers struct {
	sync.RWMutex
	// place atomic members at the start to fix alignment for ARM32
	ErrorCount uint32

	Zone string

	List  []*Server
	Hosts []string

	CheckingDisable bool
	Checked         bool
	// contains filtered or unexported fields
}

Servers type.

func (*Servers) Fingerprint

func (a *Servers) Fingerprint() uint64

Fingerprint returns a stable identifier for the current List.Addr set. Callers must not hold the Servers lock.

func (*Servers) InvalidateFingerprint

func (a *Servers) InvalidateFingerprint()

InvalidateFingerprint must be called whenever List is mutated. It has to run *before* the mutator releases the Servers write lock so readers can't observe the mutated List with a still-valid cached hash. A single atomic increment is cheap enough to keep inside the critical section.

Jump to

Keyboard shortcuts

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