Commit graph

9 commits

Author SHA1 Message Date
Ondřej Surý
28483b3b73
Drop in-domain NS without glue from the delegation set
Pull the dns_message_findname() lookups into cache_delegglue() and
cache_delegglue6() so each helper now owns its glue lookup and returns
the number of addresses cached.  cache_delegns() splits referrals into
two cases: in-domain (the NS name is below the delegation point) and
sibling/in-bailiwick.

An in-domain NS without glue is unresolvable by definition - the
resolver would have to ask the very server it's trying to find.  Log
"missing mandatory glue" at notice level and skip the deleg entirely
rather than leaving an unusable entry in the set.  A new
dns_delegset_freedeleg() undoes a fresh dns_delegset_allocdeleg() so
the rest of the delegation set is preserved.
2026-05-15 07:26:38 +02:00
Ondřej Surý
592f3cc671
Add DTRACE probes to dns_delegdb
Instrument the delegation cache (introduced to back both NS-based and
DELEG-based delegations) with 11 USDT probes in the libdns provider so
that hit rate, eviction pressure, and lookup latency can be measured
without recompiling or enabling logging.

The probes are:

- delegdb_lookup_start / delegdb_lookup_done wrap dns_delegdb_lookup()
  and pass the query name plus the result code.

- delegdb_insert_start / delegdb_insert_done wrap dns_delegset_insert().
  The early SHUTTINGDOWN return is funneled through the cleanup label
  so the done probe fires on every path.

- delegdb_cleanup_start / delegdb_cleanup_done bracket the SIEVE-based
  eviction triggered when the cache goes overmem, reporting the number
  of bytes requested and actually reclaimed.  An additional per-node
  delegdb_evict probe (guarded by _ENABLED() because it fires inside
  the loop) exposes which zones are being evicted.

- delegdb_create, delegdb_reuse, and delegdb_shutdown trace the per-view
  lifecycle across server reloads.

- delegdb_delete traces rndc flush-delegation paths, reporting whether
  a subtree or single name was removed.

Name arguments are stringified with dns_name_format() behind
LIBDNS_*_ENABLED() guards so that the hot lookup and insert paths remain
zero-cost when no consumer is attached.
2026-04-20 13:14:19 +02:00
Colin Vidal
1d10e4513f rename DNS_DBFIND_NOEXACT to DNS_DBFIND_ABOVE
The `DNS_DBFIND_NOEXACT` flag name is ambiguous, as it does not clearly
indicate the lookup behavior (e.g., sibling, child, or parent).

Rename it to `DNS_DBFIND_ABOVE` to better reflect that the lookup
targets a closer ancestor name.
2026-04-16 11:28:13 +02:00
Ondřej Surý
ec024735df Replace FIXME with rationale for not cleaning expired delegdb nodes
Expired delegation nodes are naturally replaced when the resolver
fetches fresh data, and any remaining stale nodes are reclaimed by
SIEVE eviction under memory pressure.
2026-04-16 11:28:13 +02:00
Colin Vidal
193e01ab20 Remove hiwater/lowater fields from delegdb
The delegdb does not directly use the hiwater and lowater values during
the cleaning flow, so these fields are no longer necessary.
2026-04-16 11:28:13 +02:00
Ondřej Surý
4d772cda3c Reclaim only what the new delegation needs
delegdb_cleanup() was overwriting the caller-supplied 'requested'
value with (hiwater - lowater), so every overmem cleanup tried to
free the full watermark band regardless of how much memory the new
delegation actually needed.  Drop the override so the caller's size
is used: we now walk the SIEVE only until we have reclaimed enough
room for the new node, leaving unrelated entries in place.
2026-04-16 11:28:13 +02:00
Ondřej Surý
876a896f0f Account transient delegsets against the caller's memory context
dns_delegset_fromnsrdataset() used isc_g_mctx for the transient
delegset it builds from a DNS NS rdataset.  That hides delegation
data in the global default context instead of accounting it against
the subsystem that owns it: a resolver fctx, a view, or a query
context.

Take an explicit mctx parameter so callers can direct the allocation
to the right place, and update the three call sites:
- lib/dns/view.c:1189 (dns_view_bestzonecut fallback) uses view->mctx
- lib/dns/resolver.c:7071 (resume_dslookup) uses fctx->mctx
- lib/ns/query.c:8672 (query_delegation_recurse) uses the client
  manager's mctx

Also tighten delegdb cleanup to run inside the same write transaction
as the insert: delegdb_node_prepare() now returns the size of the new
node, and delegdb_cleanup() takes the caller's open qp so that the
overmem reclamation and the insert share one commit instead of doing
two nested write transactions.
2026-04-16 11:28:13 +02:00
Ondřej Surý
9191dc7acb Fix delegation database NOEXACT lookup for top-level names
dns__deleg_lookup() with DNS_DBFIND_NOEXACT is supposed to return
the deepest proper ancestor of the lookup name.  It called
getparentnode() to step up from an exact match, but getparentnode()
only iterated while the chain length was >= 2.  When the chain
contained a single entry (the exact match itself with no ancestor
stored in the trie), the loop did not execute and left the caller
looking at the exact match.  The subsequent isactive() check then
returned success and the function reported the exact match as the
"deepest ancestor", violating NOEXACT semantics.

This was observable as the resolver picking the child-side
delegation for an at-parent type (e.g. a DS query for a TLD), then
sending the query to the child's own nameservers and recovering via
the "chase DS servers" path.

Have getparentnode() set '*node' to NULL when it cannot find an
active proper ancestor, and make dns__deleg_lookup() NULL-check
before returning, matching the canonical NOEXACT implementation in
dns_zt_find().  Update the deleg unit test to expect NOTFOUND for
the top-level-no-parent case.
2026-04-16 11:28:13 +02:00
Colin Vidal
1b5f757084 Introduce a delegation database
Add `dns_delegdb_t`, a qpmulti-based database enabling to lookup a
delegation set (`dns_delegset_t`) from a zonecut name (`dns_name_t`). A
delegation set object essentially contains an expiration time and a list
of delegation (`dns_deleg_t`). Finally, a delegation can be either:

- A list of IP addresses (`isc_netaddrlist_t`), for NS-based delegation
  providing glues or DELEG-based delegation using `server-ipv4=` or
  `server-ipv6=`;
- Or a list of nameserver names, for NS-based delegation without glues,
  or DELEG-based delegation using `server-name=`;
- Or a list of nameserver names, for DELEG-based delegation using
  `include-delegparam=`.

The delegation database API provides lookup by closest zonecut,
delegation and delegation set builders as well as insertion of those
newly built delegation set, dumping to a `FILE *`, conversion from an NS
rdataset to a delegation set, deletion of a specific zonecut or all the
sub-tree of a given zonecut.

A memory context is internally used inside the delegation database and
can be constraint to a maximum size. Once it gets close to its maximum
size and a new delegation set is inserted into the database, a
reclamation flow is run internally removing the least recently used
entries.

The delegation set and delegation objects are, once they been inserted
into the database, read-only object. Thus, the caller can use them
without concurrency or locking concerns, and must detached them once its
done with it.
2026-03-30 20:41:13 +02:00