dnssec

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: 28 Imported by: 0

Documentation

Overview

Package dnssec implements pure DNSSEC verification primitives: RRSIG/DS validation, NSEC and NSEC3 denial-of-existence proofs, and the EDE-coded sentinel errors they return. None of the functions here hold resolver state; they take the records they need to validate as inputs and return a pass/fail result. The recursive resolver wraps them with the chain-of-trust orchestration (DS lookups, key fetches, trust-anchor management).

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoDNSKEY = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSKEYMissing,
		Message: "No DNSKEY records found in response",
	}
	ErrMissingKSK = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSKEYMissing,
		Message: "No KSK DNSKEY matches DS records from parent",
	}
	ErrFailedToConvertKSK = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "Unable to validate DNSKEY against parent DS record",
	}
	ErrMismatchingDS = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "DNSKEY does not match DS record from parent zone",
	}
	ErrNoSignatures = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeRRSIGsMissing,
		Message: "Response is missing required RRSIG records",
	}
	ErrMissingDNSKEY = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSKEYMissing,
		Message: "No DNSKEY found to validate RRSIG",
	}
	ErrInvalidSignaturePeriod = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeSignatureExpired,
		Message: "RRSIG validity period check failed",
	}
	ErrMissingSigned = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "RRsets covered by RRSIG are missing",
	}
	ErrDSRecords = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "Parent has DS records but zone appears unsigned",
	}
	ErrTrustAnchorsUnavailable = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeOther,
		Message: "Trust anchors unavailable — refusing to validate",
	}
)

DNSKEY-side validation errors.

View Source
var (
	ErrNSECTypeExists = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "NSEC record indicates queried type exists",
	}
	ErrNSECMissingCoverage = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeNSECMissing,
		Message: "Incomplete NSEC proof for name non-existence",
	}
	ErrNSECBadDelegation = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "Invalid NSEC type bitmap for delegation",
	}
	ErrNSECNSMissing = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "NSEC missing NS bit at delegation point",
	}
	ErrNSECOptOut = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "NSEC3 opt-out validation failed",
	}
	ErrWildcardNoDenial = &dnsutil.EDEError{
		Code:    dns.ExtendedErrorCodeDNSBogus,
		Message: "Wildcard-expanded answer lacks NSEC/NSEC3 proof of no closer match",
	}
)

NSEC / NSEC3 denial-of-existence errors.

Functions

func AggressiveNSEC3Usable added in v1.7.4

func AggressiveNSEC3Usable(n *dns.NSEC3) bool

AggressiveNSEC3Usable is a cheap, record-local preflight for an NSEC3 candidate. It does not validate the owner name, signer zone, class, salt, or tuple homogeneity; EvaluateAggressiveNSEC3 performs those set-level checks before using a record.

func CanonicalWireRR added in v1.8.2

func CanonicalWireRR(r dns.RR) (wire []byte, rdataOff int, err error)

CanonicalWireRR returns one record's canonical on-the-wire form as RFC 4034 §6.2 defines it for zone-content digests (RFC 8976): the owner and the RDATA names §6.2 lists are lowercased, the record packs without compression, and the record's own TTL is retained — the original-TTL substitution belongs to signature computation, not to a digest of the zone as published. rdataOff is where the RDATA begins in wire, so a caller ordering records per §6.3 can compare RDATA without re-walking the owner labels.

func DNSKEYMissingForZone

func DNSKEYMissingForZone(zone string) *dnsutil.EDEError

DNSKEYMissingForZone returns a DNSKEY-missing error tagged with zone.

func DNSKEYToDSWithWork added in v1.7.4

func DNSKEYToDSWithWork(key *dns.DNSKEY, digestType uint8, work DSDigestWork) (*dns.DS, error)

DNSKEYToDSWithWork computes one DNSKEY digest under the same accounting and concurrency gate used by VerifyDSWithWork. It is used when the resolver materializes DS records from configured trust anchors.

func EnsureNSEC3HashMemo added in v1.7.4

func EnsureNSEC3HashMemo(ctx context.Context) context.Context

EnsureNSEC3HashMemo attaches one bounded memo to ctx unless the request tree already carries one. Cache and resolver entrypoints both call this helper, which keeps cache-less pipelines safe and makes nested Queryer pipelines inherit the same digest results. The memo state is request-lifetime, so a pin on the deadline carrier is preferred over deriving a value context; a foreign context (detached enrichment, tests) falls back to a value node.

func InheritNSEC3HashMemos added in v1.7.4

func InheritNSEC3HashMemos(ctx, parent context.Context) context.Context

InheritNSEC3HashMemos copies only the opaque request-tree memo state from parent into ctx. Detached-but-retained resolver enrichment uses this instead of inheriting the full parent context, which would also leak cancellation, response metadata, and unrelated request values into background work.

func IsCryptoWaitError added in v1.7.4

func IsCryptoWaitError(err error) bool

IsCryptoWaitError reports whether err followed an observed wait for a resolver-wide crypto slot.

func IsSupportedDNSKEYAlgorithm

func IsSupportedDNSKEYAlgorithm(alg uint8) bool

IsSupportedDNSKEYAlgorithm reports whether miekg/dns' RRSIG.Verify can process signatures of the given algorithm without returning ErrAlg. DS records advertising unsupported DNSKEY algorithms are unusable — DNSKEY.ToDS will still hash them, but later RRSIG verification would fail. Per RFC 6840 §5.2 such DS entries must be disregarded so an unsupported-only DS RRset is treated as insecure rather than bogus.

The list intentionally matches miekg/dns' switch in RRSIG.Verify exactly. RSAMD5 (deprecated by RFC 8624) is *not* accepted there, so classifying it as supported would let an RSAMD5 DS RRset appear usable and then bogus out on verification instead of downgrading to insecure.

func IsSupportedDS

func IsSupportedDS(ds *dns.DS) bool

IsSupportedDS reports whether a DS record is usable for validation: both its digest type and the DNSKEY algorithm it advertises must be something this validator can verify.

func IsSupportedDSDigest

func IsSupportedDSDigest(t uint8) bool

IsSupportedDSDigest reports whether the given DS digest type is implemented locally. RFC 6840 §5.2 requires validators to ignore DS records that use unknown or unimplemented digest algorithms. Only the three digest types miekg/dns' DNSKEY.ToDS actually computes are treated as supported here — anything else (GOST94, future digest types, unknown values) is skipped.

func IsWorkError added in v1.7.4

func IsWorkError(err error) bool

IsWorkError reports whether err originated from a DNSSEC work governor.

func KeyTag added in v1.8.0

func KeyTag(key *dns.DNSKEY) uint16

KeyTag returns the RFC 4034 Appendix B key tag of a DNSKEY, agreeing with dns.DNSKEY.KeyTag on every input that one can answer for.

The tag is a checksum over the record's RDATA, and the library computes it by packing that RDATA into a fixed buffer and summing it. The buffer itself stays on the stack; what does not is the key material, decoded in full so that it can be summed and dropped — one allocation the size of the key, per key, for a number sixteen bits wide.

Nothing about the sum needs the octets to exist all at once, so this decodes a few hundred at a time into a stack buffer and accumulates as it goes.

An encoding the chunked decode cannot read the same way a single decode would is handed to the library rather than guessed at, so the two agree on every input the library can answer for.

RSAMD5 is derived here rather than delegated, because the library's derivation of it crashes; see rsamd5KeyTag.

func SignatureExpiredForRRset

func SignatureExpiredForRRset(rrtype, zone string) *dnsutil.EDEError

SignatureExpiredForRRset returns a signature-expired error tagged with the RR type and zone.

func UniqueRRSIGs added in v1.8.2

func UniqueRRSIGs(signatures []*dns.RRSIG) []*dns.RRSIG

UniqueRRSIGs returns signatures with exact duplicates removed, in a deterministic order. Identity spans every field a verification depends on — owner, class, covered type, algorithm, labels, original TTL, validity window, key tag, signer and the signature bytes — so two records that differ anywhere that matters are kept apart. A caller deduplicating on less can discard a sound signature as a copy of an unsound one that merely resembles it.

func ValidateSigner

func ValidateSigner(signer, qname string) error

ValidateSigner checks that the signer claimed by an RRSIG is a plausible zone apex for qname — either qname itself or a proper ancestor. The check must run before the DS-chain lookup because RRSIG.SignerName is unauthenticated RDATA until a key verifies the signature: without it, an on-path attacker can rewrite SignerName to an unsigned sibling or descendant, then rely on findDS() returning an empty set to silently skip verifyDNSSEC() and downgrade a signed response to "insecure" instead of bogus.

func VerifyDS

func VerifyDS(keyMap map[uint16][]*dns.DNSKEY, parentDSSet []dns.RR) (bool, error)

VerifyDS looks for a DS record in parentDSSet that authenticates one of the KSKs in keyMap. It returns (unsupportedOnly, err):

  • (false, nil) — at least one supported DS matched a KSK.
  • (false, err) — at least one supported DS was present but none matched; the zone is bogus (not "insecure").
  • (true, err) — every DS in the RRset uses an unsupported digest type. Per RFC 6840 §5.2 validators MUST ignore such records, and if none remain the caller must treat the zone as insecure.

keyMap groups DNSKEYs by key tag because RFC 4034 Appendix B.1 does not guarantee key-tag uniqueness: a colliding tag could otherwise mask the KSK that actually authenticates the DS.

func VerifyDSWithWork added in v1.7.4

func VerifyDSWithWork(
	keyMap map[uint16][]*dns.DNSKEY,
	parentDSSet []dns.RR,
	work DSDigestWork,
) (bool, error)

VerifyDSWithWork is VerifyDS with request-tree digest work accounting. Cheap DS/DNSKEY compatibility checks and duplicate removal happen before a digest slot is consumed.

func VerifyDelegation

func VerifyDelegation(delegation string, nsec []dns.RR) error

VerifyDelegation verifies an insecure-delegation claim using NSEC3. The delegation is authenticated either by an exact-match NSEC3 with NS set (and DS / SOA cleared) or, for opt-out spans, by an NSEC3 covering the next closer name with the Opt-Out bit set.

func VerifyDelegationForZoneWithWork added in v1.7.4

func VerifyDelegationForZoneWithWork(
	delegation string,
	signer string,
	nsec []dns.RR,
	work NSEC3Work,
) error

VerifyDelegationForZoneWithWork binds an insecure-delegation proof to the parent signer before evaluating exact-match or Opt-Out semantics.

func VerifyDelegationNSEC

func VerifyDelegationNSEC(delegation string, nsecSet []dns.RR) error

VerifyDelegationNSEC verifies an insecure-delegation claim using NSEC records (RFC 4035 §5.2). It must find an NSEC whose owner equals the delegation name and whose type bitmap contains NS but neither DS nor SOA. Anything looser would let a malicious parent strip the DS from a signed child and have the resolver treat the child as insecure.

func VerifyDelegationWithWork added in v1.7.4

func VerifyDelegationWithWork(delegation string, nsec []dns.RR, work NSEC3Work) error

VerifyDelegationWithWork is VerifyDelegation with request-tree work accounting and the resolver-wide crypto semaphore enabled.

func VerifyNODATA

func VerifyNODATA(msg *dns.Msg, nsec []dns.RR) error

VerifyNODATA verifies a NODATA proof using NSEC3 records (RFC 5155 §8.5–§8.7), including the DS-specific opt-out branch.

func VerifyNODATAForZoneWithWork added in v1.7.4

func VerifyNODATAForZoneWithWork(
	msg *dns.Msg,
	nsec []dns.RR,
	signer string,
	work NSEC3Work,
) (secure bool, err error)

VerifyNODATAForZoneWithWork is the signer-bound form of VerifyNODATAWithWork. secure follows RFC 5155 §9.2: an Opt-Out next-closer proof is accepted only with AD cleared.

func VerifyNODATANSEC

func VerifyNODATANSEC(msg *dns.Msg, nsecSet []dns.RR) error

VerifyNODATANSEC verifies NODATA using NSEC records (RFC 4035 §3.1.3.1).

func VerifyNODATAWithWork added in v1.7.4

func VerifyNODATAWithWork(msg *dns.Msg, nsec []dns.RR, work NSEC3Work) error

VerifyNODATAWithWork is VerifyNODATA with request-tree work accounting and the resolver-wide crypto semaphore enabled.

func VerifyNSEC

func VerifyNSEC(q dns.Question, nsecSet []dns.RR) (typeMatch bool)

VerifyNSEC reports whether any NSEC in nsecSet has q.Qtype set in its type bitmap. This is a cheap structural check used as a pre-filter before the full denial-of-existence proofs in VerifyNODATANSEC / VerifyNameErrorNSEC. A true result alone does not authenticate anything.

func VerifyNameError

func VerifyNameError(msg *dns.Msg, nsec []dns.RR) error

VerifyNameError verifies an NXDOMAIN proof using NSEC3 records (RFC 5155 §8.4): closest encloser exists, an NSEC3 covers the next closer name, and an NSEC3 covers the wildcard at the closest encloser.

func VerifyNameErrorForZoneWithWork added in v1.7.4

func VerifyNameErrorForZoneWithWork(
	msg *dns.Msg,
	nsec []dns.RR,
	signer string,
	work NSEC3Work,
) (secure bool, err error)

VerifyNameErrorForZoneWithWork validates an NSEC3 NXDOMAIN proof against the exact RRSIG signer zone. secure is false only when a required covering interval has Opt-Out set; the response remains usable as insecure data but MUST NOT carry AD or seed shared aggressive denial state.

func VerifyNameErrorNSEC

func VerifyNameErrorNSEC(msg *dns.Msg, nsecSet []dns.RR) error

VerifyNameErrorNSEC verifies NXDOMAIN using NSEC records (RFC 4035 §3.1.3.2). The proof requires two NSEC records: one that covers QNAME (proving QNAME does not exist) and one that covers the wildcard at the closest encloser of QNAME (proving no wildcard match could synthesize the answer). Accepting wildcard coverage from an arbitrary ancestor lets a mismatched proof pass, so the wildcard is derived from the covering NSEC's owner/next labels, not from any ancestor of QNAME.

func VerifyNameErrorWithWork added in v1.7.4

func VerifyNameErrorWithWork(msg *dns.Msg, nsec []dns.RR, work NSEC3Work) error

VerifyNameErrorWithWork is VerifyNameError with request-tree work accounting and the resolver-wide crypto semaphore enabled.

func VerifyRRSIG

func VerifyRRSIG(signer string, keys map[uint16][]*dns.DNSKEY, msg *dns.Msg) (bool, error)

VerifyRRSIG validates that every in-zone RRset in msg is covered by at least one RRSIG that successfully verifies against the supplied DNSKEYs.

The signer zone is supplied by the caller (verifyDNSSEC / verifyRootKeys) and represents the zone whose keys should authenticate this response. RRsets whose owner name is not in that zone — for example, target records appended via DNAME synthesis — are validated by their own recursion and are skipped here. An unsigned RRset inside the zone is rejected; a signature that fails (missing key, bad exponent, verify error, expired) only causes the RRset to fail if no sibling signature succeeds.

func VerifyRRSIGWithWork added in v1.7.4

func VerifyRRSIGWithWork(
	signer string,
	keys map[uint16][]*dns.DNSKEY,
	msg *dns.Msg,
	work SignatureWork,
) (bool, error)

VerifyRRSIGWithWork is VerifyRRSIG with request-tree signature work accounting. Structural rejection, duplicate removal, and deterministic candidate ordering all happen before a public-key operation consumes work.

func VerifyWildcardAnswer added in v1.7.3

func VerifyWildcardAnswer(resp *dns.Msg) error

VerifyWildcardAnswer enforces the RFC 4035 §5.3.4 / RFC 5155 §8.8 requirement for positive answers synthesized from a wildcard.

An RRSIG whose Labels field is smaller than the label count of the RRset owner name signals that the RRset was expanded from a wildcard (*.<closest-encloser>). miekg's RRSIG.Verify accepts such a signature against any owner name deeper than the wildcard because it canonicalises the owner back to "*.<closest-encloser>" before hashing. On its own that lets an attacker replay a zone's legitimately-signed wildcard RRSIG over a concrete name that actually exists and hand it back with AD=1 — a forged-but-"authenticated" answer. RFC 4035 closes this by additionally requiring proof that the owner name has no closer match than the wildcard, i.e. that the "next closer" name does not exist.

For every wildcard-expanded RRSIG in the Answer section this checks that the Authority section carries an NSEC or NSEC3 covering the next closer name. Those denial records live in the same response and have already been cryptographically validated by VerifyRRSIG (they belong to the signer zone and carry their own RRSIGs), so only their semantic coverage is checked here. An attacker cannot satisfy the check by replaying a genuine signed NSEC/NSEC3: no such record covers a name that exists.

Callers must invoke this only after VerifyRRSIG has returned true for resp; a false or error result means the answer must be treated as bogus.

func VerifyWildcardAnswerForZoneWithWork added in v1.7.4

func VerifyWildcardAnswerForZoneWithWork(
	resp *dns.Msg,
	signer string,
	work NSEC3Work,
) (secure bool, err error)

VerifyWildcardAnswerForZoneWithWork binds NSEC3 witnesses to signer and reports whether every denial interval is fully authenticated. An Opt-Out next-closer interval validates only an insecure answer and therefore returns secure=false without turning the response into SERVFAIL.

func VerifyWildcardAnswerWithWork added in v1.7.4

func VerifyWildcardAnswerWithWork(resp *dns.Msg, work NSEC3Work) error

VerifyWildcardAnswerWithWork is VerifyWildcardAnswer with request-tree accounting for every NSEC3 hash operation.

Types

type AggressiveNSECSet added in v1.8.0

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

AggressiveNSECSet is a prepared NSEC collection whose set-level invariants — class homogeneity, signer containment, interval conflicts — were checked once at construction. Those checks are static properties of the stored set; re-running them per query rebuilt the entry slice on every negative answer, which was the resolver's single largest allocator under NXDOMAIN-heavy load.

func NewAggressiveNSECSet added in v1.8.0

func NewAggressiveNSECSet(prepared []PreparedNSEC, zone string) (*AggressiveNSECSet, error)

NewAggressiveNSECSet validates prepared as one aggressive-answer set for zone. The checks are exactly EvaluateAggressiveNSECPrepared's set-level checks — a set rejected here would be rejected on every evaluation.

type AggressiveNegativeResult added in v1.7.4

type AggressiveNegativeResult struct {
	Rcode int
	Proof []dns.RR
}

AggressiveNegativeResult is a DNSSEC proof that can synthesize either an NXDOMAIN response or a NOERROR/NODATA response. Proof contains only the input NSEC or NSEC3 records needed for that conclusion; callers add the independently validated SOA and matching RRSIG RRsets when constructing the wire response.

func EvaluateAggressiveNSEC added in v1.7.4

func EvaluateAggressiveNSEC(
	q dns.Question,
	zone string,
	records []dns.RR,
) (AggressiveNegativeResult, error)

EvaluateAggressiveNSEC evaluates DNSSEC-validated NSEC records for aggressive negative caching as described by RFC 8198. The caller remains responsible for establishing the records' cryptographic provenance and lifetime. Any incomplete, inconsistent, or inapplicable proof returns an error so the caller can fall back to ordinary resolution.

func EvaluateAggressiveNSEC3 added in v1.7.4

func EvaluateAggressiveNSEC3(
	q dns.Question,
	zone string,
	records []dns.RR,
	work NSEC3Work,
) (AggressiveNegativeResult, error)

EvaluateAggressiveNSEC3 evaluates one homogeneous set of DNSSEC-validated NSEC3 records for aggressive negative caching. It implements the non-Opt-Out RFC 5155 closest-encloser, name-error, exact NODATA, and wildcard NODATA paths. The DS Opt-Out NODATA branch is deliberately not synthesized: an Opt-Out covering record always causes a fail-closed fallback.

func EvaluateAggressiveNSECPrepared added in v1.8.0

func EvaluateAggressiveNSECPrepared(
	q dns.Question,
	zone string,
	prepared []PreparedNSEC,
) (AggressiveNegativeResult, error)

EvaluateAggressiveNSECPrepared is EvaluateAggressiveNSEC over records canonicalized ahead of time by PrepareAggressiveNSEC. It applies the same set-level validation and reaches the same verdict; only the per-record canonicalization is already paid for.

func EvaluateAggressiveNSECSet added in v1.8.0

func EvaluateAggressiveNSECSet(
	q dns.Question,
	set *AggressiveNSECSet,
) (AggressiveNegativeResult, error)

EvaluateAggressiveNSECSet is EvaluateAggressiveNSECPrepared over a pre-validated set: per query only the question is canonicalized and classified; the entry table is used as stored.

type CryptoLimiter added in v1.7.4

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

CryptoLimiter bounds expensive DNSSEC work across all request trees handled by one Resolver. Per-tree budgets prevent asymmetric amplification; this resolver-level gate prevents many individually-bounded requests from running unbounded crypto concurrently.

func NewCryptoLimiter added in v1.7.4

func NewCryptoLimiter(maxConcurrent uint32) *CryptoLimiter

NewCryptoLimiter constructs a fixed-size crypto semaphore.

func (*CryptoLimiter) Acquire added in v1.7.4

func (l *CryptoLimiter) Acquire(ctx context.Context) (func(), error)

Acquire waits for one crypto slot or for ctx cancellation. The returned release function must be called exactly once after the operation completes.

func (*CryptoLimiter) Capacity added in v1.7.4

func (l *CryptoLimiter) Capacity() uint32

Capacity reports the configured resolver-wide concurrency ceiling.

func (*CryptoLimiter) TryAcquire added in v1.7.4

func (l *CryptoLimiter) TryAcquire() (func(), bool)

TryAcquire reserves one crypto slot without waiting. Optional work uses this path so a saturated resolver always gives required validation priority.

type DSDigestWork added in v1.7.4

type DSDigestWork interface {
	CheckDNSKEYCandidate(used uint32) error
	BeginDSDigest() (release func(), err error)
}

DSDigestWork is the resolver-owned work contract used immediately before a DNSKEY digest operation.

type NSEC3HashMemo added in v1.7.4

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

NSEC3HashMemo deduplicates identical RFC 5155 hashes across all validation and aggressive-cache operations in one request tree. Entries include the complete (algorithm, iterations, salt, canonical owner) preimage, so salt rotation and parallel parameter chains cannot share a digest.

The memo is concurrency-safe because resolver fan-out can validate sibling branches in parallel. A caller that loses the first-computation race waits for that exact digest instead of consuming another work unit and crypto slot.

func NSEC3HashMemoFromContext added in v1.7.4

func NSEC3HashMemoFromContext(ctx context.Context) *NSEC3HashMemo

NSEC3HashMemoFromContext returns the request tree's memo, if installed.

func NSEC3HashMemoFromContextScope added in v1.7.4

func NSEC3HashMemoFromContextScope(
	ctx context.Context,
	scope NSEC3HashMemoScope,
) *NSEC3HashMemo

NSEC3HashMemoFromContextScope returns one request-tree memo compartment.

func NewNSEC3HashMemo added in v1.7.4

func NewNSEC3HashMemo() *NSEC3HashMemo

NewNSEC3HashMemo returns an independently bounded memo. Optional work paths use private memos so they cannot pre-populate the required-validation memo and thereby bypass request-tree work accounting.

func (*NSEC3HashMemo) TryReserveWork added in v1.7.4

func (m *NSEC3HashMemo) TryReserveWork(limit uint32) bool

TryReserveWork atomically consumes one unit from a request-scoped optional hash allowance. Required validation continues to use the recursion ledger; optional resolver and cache scopes call this on their private memos so constructing another work adapter cannot reset the per-tree ceiling.

func (*NSEC3HashMemo) WorkUsed added in v1.7.4

func (m *NSEC3HashMemo) WorkUsed() uint32

WorkUsed reports optional hash work reserved through TryReserveWork.

type NSEC3HashMemoAccess added in v1.7.4

type NSEC3HashMemoAccess struct {
	Read  *NSEC3HashMemo
	Write *NSEC3HashMemo
}

NSEC3HashMemoAccess keeps required and optional accounting directional. Read may expose hashes already paid for by required validation. Write is the memo populated by this work class. Required work uses the same memo for both; optional resolver work reads the required memo but writes privately; optional cache work reads and writes only its private memo.

type NSEC3HashMemoProvider added in v1.7.4

type NSEC3HashMemoProvider interface {
	NSEC3HashMemos() NSEC3HashMemoAccess
}

NSEC3HashMemoProvider is an optional extension to NSEC3Work. Production work governors implement it; focused callers that provide only accounting retain the original behavior.

type NSEC3HashMemoScope added in v1.7.4

type NSEC3HashMemoScope uint8

NSEC3HashMemoScope selects one directional request-tree compartment. Required validation owns the shared compartment. Resolver-side optional classification may read that compartment but writes only ResolverOptional; cache-side optional synthesis is isolated entirely in CacheOptional.

const (
	NSEC3HashMemoScopeRequired NSEC3HashMemoScope = iota
	NSEC3HashMemoScopeResolverOptional
	NSEC3HashMemoScopeCacheOptional
)

type NSEC3Work added in v1.7.4

type NSEC3Work interface {
	BeginNSEC3Hash() (release func(), err error)
}

NSEC3Work is the resolver-owned work contract used immediately before each hash-backed NSEC3 Match or Cover operation.

type PreparedNSEC added in v1.8.0

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

PreparedNSEC is an NSEC record whose owner and next-domain names are already in canonical form.

Canonicalizing a name allocates, and it is a pure function of the record, so a caller holding NSEC records across many queries — a denial-proof cache is why this exists — can pay for it once when the record is admitted instead of on every evaluation. The canonical form is immutable once built and may be shared by concurrent evaluations.

func PrepareAggressiveNSEC added in v1.8.0

func PrepareAggressiveNSEC(rr *dns.NSEC) (PreparedNSEC, error)

PrepareAggressiveNSEC canonicalizes rr's names for later evaluation. The result keeps rr itself, which the evaluator hands back in its proof, so the caller must not mutate the record afterwards.

type SignatureWork added in v1.7.4

type SignatureWork interface {
	CheckDNSKEYCandidate(used uint32) error
	CheckRRsetSignature(used uint32) error
	BeginSignature() (release func(), err error)
}

SignatureWork is the resolver-owned work contract used immediately before an RRSIG public-key operation. Cheap structural checks and candidate deduplication happen before these methods are reached.

type WorkError added in v1.7.4

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

WorkError marks an error returned by the resolver-owned work governor. It preserves the original error for errors.Is/errors.As while letting DNSSEC candidate loops distinguish a terminal budget/semaphore failure from an ordinary bad signature that may have a valid sibling.

func (*WorkError) Error added in v1.7.4

func (e *WorkError) Error() string

func (*WorkError) Unwrap added in v1.7.4

func (e *WorkError) Unwrap() error

Jump to

Keyboard shortcuts

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