Commit graph

10216 commits

Author SHA1 Message Date
Aram Sargsyan
357331f886 Revert NTA flush on expire
Flushing the name when NTA expires causes problems for the ongoing
resolving process. Do not flush the name from the cache. Instead,
the resolver should do the flushing (this is planned to be merged
next).
2026-03-30 18:27:35 +00:00
Ondřej Surý
6ba57a1f0f
Count temporal problems with DNSSEC validation as attempts
After KeyTrap, the temporal DNSSEC were originally hard errors that
caused validation failures even if the records had another valid
signature.  This has been changed and the RRSIGs outside of the
inception and expiration time are not counted as hard errors.  However,
these errors are not even counted as validation attempts, so excessive
number of expired RRSIGs would cause some non-cryptograhic extra work
for the validator.  This has been fixed and the temporal errors are
correctly counted as validation attempts.
2026-03-30 11:16:13 +02:00
Mark Andrews
f2fd54f4b2 Allow the dns_rdata_in_apl structure to be walked twice
The offset value should be set prior to calculating the length.
2026-03-27 12:00:22 +00:00
Aram Sargsyan
35b8af229e Allow empty APL records
Allow empty APL records because RFC 3123 (Section 4) says "zero or
more items". This fixes processing of a catalog zone ACL (which is
based on APL records) when the zone contains an empty APL record or
when a zone update arrives which creates an empty APL record.
2026-03-27 12:36:50 +11:00
Alessio Podda
ed0ecb62e4 Add low contention stats counter
In the current statistics counter implementation, the statistics are
backed by an array of counters, which are updated via atomic operations.
This leads to contention, especially on high core count
machines.

This commit introduces a new isc_statsmulti_t counter that keeps a
separate array per thread. These counters are then aggregated only when
statistics are queried, shifting work off the critical path.

These changes lead to a ~2% improvement in perflab.
2026-03-26 10:19:25 +01:00
Mark Andrews
ed15b6cb26 Add switch to disable cookie checking in delv
This adds the switch +[no]cookie to delv to control the sending of
DNS COOKIE options when sending requests.  The default is to send
DNS COOKIE options.
2026-03-26 11:18:26 +11:00
Michał Kępień
b0fc0e31c5 Merge tag 'v9.21.20' 2026-03-25 14:23:41 +00:00
Ondřej Surý
da8e1c956a
Fix cache flush ordering on NTA expiry
dns_view_flushnode() was called in the delete_expired() async
callback, which runs after the query that detected the NTA expiry.
This created a race: the query would proceed with stale cached data
from the NTA period before the flush had a chance to run, resulting
in transient SERVFAIL with EDE 22 (No Reachable Authority).

Move dns_view_flushnode() into dns_ntatable_covered() so the cache
is flushed synchronously when the expiry is detected, before the
query continues.

Also simplify the expiry comparison in delete_expired() to a direct
pointer comparison (nta == pval) instead of comparing expiry
timestamps.
2026-03-20 14:35:11 +01:00
Ondřej Surý
4d15494b94 Fix non-atomic read-modify-write on entry->srtt in adjustsrtt()
The SRTT update loaded the old value, computed a new one, and stored it
back as separate operations.  Two concurrent callers could each read the
same old value and one update would be silently lost.

Use a CAS loop for the read-modify-write on entry->srtt.  For the aging
path, also CAS on entry->lastage to prevent multiple threads from aging
the same entry in the same second.
2026-03-20 02:06:21 +01:00
Ondřej Surý
a2bd833909 Fix data race on fctx->vresult in validated()
Move the write to fctx->vresult after LOCK(&fctx->lock).  The field was
being set before acquiring the lock, but dns_resolver_logfetch() reads
it under the same lock from another thread.
2026-03-20 00:56:19 +01:00
Ondřej Surý
44bb3cd2a7 Fix data race on nta->expiry
Use CMM_LOAD_SHARED/CMM_STORE_SHARED for nta->expiry, which is
written from the NTA's owning loop but read from any loop (validator,
rndc status, rndc nta -dump).

Also dispatch delete_expired to the NTA's owning loop rather than
the caller's loop.
2026-03-19 01:44:37 +01:00
Ondřej Surý
fae6c6eead Refactor NTA to use RCU instead of rwlock
Replace the ntatable rwlock with RCU read-side critical sections.
The QP multi trie already provides its own concurrency control for
reads and writes, making the rwlock redundant. NTA fields like
expiry are only accessed from the NTA's own event loop thread, so
no additional synchronization is needed.

The table shutdown is now deferred via call_rcu to ensure all
read-side critical sections have completed before iterating and
shutting down individual NTAs.
2026-03-19 01:44:37 +01:00
Aram Sargsyan
1899a3318c
Flush the node when NTA expires
When NTA expires the name's node should be flushed from the view's
cache as it's done when the NTA is manually removed using a rndc
command.
2026-03-19 00:12:59 +01:00
Aram Sargsyan
48d7401f0d Take 'env' reference before async calling perform_reopen()
The 'env' pointer is passed to an async function without taking
a reference first, which can potentially cause a use-after-free
error. Take a reference, then detach in the async function.
2026-03-18 16:10:07 +00:00
Aram Sargsyan
4ac3a6520e Convert dns_dtenv_t reference counting to standard macors
Use standard reference counting macros for dns_dtenv_t instead of
custom attach/detach functions.
2026-03-18 16:10:07 +00:00
Ondřej Surý
7f8b972a3d
Remove NZF support, make LMDB required for new zone storage
Drop the NZF (New Zone File) fallback for persisting runtime zone
configurations, making LMDB (NZD) the only storage backend. This
removes all #ifdef HAVE_LMDB conditionals, the meson 'lmdb' option,
and the NZF-related functions. LMDB is now a mandatory build
dependency.

The named-nzd2nzf tool is now always built.
2026-03-18 11:02:33 +01:00
Ondřej Surý
5b1750f15f Fix missing mutex destroy and ede invalidate on fctx_create() error paths
The error cleanup in fctx_create() was missing isc_mutex_destroy() and
dns_ede_invalidate() calls. When error paths (cleanup_nameservers,
cleanup_fcount, cleanup_qmessage, cleanup_adb) were taken after the
mutex and edectx were initialized, the fctx memory was freed without
properly destroying these resources first.
2026-03-17 16:05:11 +01:00
Ondřej Surý
96a22451d7 Fix rwlock type mismatch in delete_ds() error path
The lock is acquired for reading but the error path from
dns_rdata_fromstruct() incorrectly unlocks it as a write lock.
2026-03-17 16:05:11 +01:00
Matthijs Mekking
bc1d177cc2 Fast fail a validator deadlock
We return DNS_R_NOVALIDSIG if we detected a deadlock. Then in
'validate_async_done()', this result value is used to check if we
need to fall back to insecure. As part of that we create a new fetch
but that fails because of the detected deadlock. This results in a loop
of deadlock detected, fallback to insecure, deadlock detected, ...

Add a new result value, ISC_R_DEADLOCK, and return this instead when
we have detected a deadlock. This will be treated as a generic error,
as there is no special handling for this result value.
2026-03-16 16:46:51 +00:00
Ondřej Surý
6e286beaa6 Cleanup weird syntax defining struct dns_ixfr
The struct dns_ixfr was defined as part of struct dns_xfrin, probably
because at some point it was an anonymous struct and then it was changed
to named struct with typedef at the top.  Move the definition from
struct dns_xfrin into and fold into the typedef ... dns_ixfr_t.
2026-03-16 12:17:06 +01:00
Ondřej Surý
f4b4f030c4 Cleanup the duplicate logic and comments around add into NSEC tree
After merging the NORMAL, NSEC and NSEC3 tree into single QP tree, there
were some comments still speaking about auxiliary NSEC tree.  These were
cleaned up and the logic when we pass the qp tree (write transaction) to
qpzone_addrdataset_inner() was changed to be more obvious that this is
needed only when we are adding NSEC records.
2026-03-16 12:17:06 +01:00
Ondřej Surý
e57245ee81
Fix use-after-free in xfrin_recv_done
Move the LIBDNS_XFRIN_RECV_DONE probe execution before dns_xfrin_detach
in xfrin_recv_done.

Previously, dns_xfrin_detach was called before the trace probe, which
could free the xfr object.  Because the accessed member xfr->info is an
embedded array, the expression evaluates via pointer arithmetic rather
than a direct memory dereference.  Although this prevents a reliable
crash in practice, it technically remains a use-after-free issue.
Reorder the statements to ensure the transfer context is fully valid
when the probe executes.
2026-03-16 11:06:06 +01:00
Ondřej Surý
63d3c1f58a
Simplify checkds_create() to return void
Since memory allocation never fails in BIND 9, checkds_create() cannot
fail.  Change it to return void and use designated initializers,
removing error handling at all call sites.
2026-03-14 13:58:26 +01:00
Ondřej Surý
d7e1013741
Fix cb_args memory leak in ns_query() error path
Initialize cb_args to NULL and free it in the cleanup path so it
is not leaked when the function fails after allocation.
2026-03-14 13:48:08 +01:00
Ondřej Surý
1505cb1c24
Fix TSIG key and transport leaks in zone_notify() error paths
Two 'goto next' paths in zone_notify() skipped detaching the TSIG
key and transport, leaking them on TLS configuration failure and
when the destination address is disabled.
2026-03-14 13:48:08 +01:00
Ondřej Surý
80fae7a4b7
Fix memory leak in ixfr_commit() error path
The 'data' allocation was not freed when reaching the cleanup
label with an error result.
2026-03-14 13:48:08 +01:00
Ondřej Surý
d0165070c7
Fix memory context leak in dns_client_resolve() error path
Use isc_mem_putanddetach() instead of isc_mem_put() to properly
detach the attached memory context stored in resarg->mctx.
2026-03-14 13:47:48 +01:00
Aram Sargsyan
4df5b9ac32
Fix a bug in rpz.c:del_name()
When the dns_qp_getname() call returns an error the del_name() function
just returns without cleaning up the trasnaction.

Instead of returning, jump to a new label 'done:' similar to the code
written in the add_nm() function.
2026-03-14 13:01:55 +01:00
Ondřej Surý
5cd17c8adc
Fix memory leak in dns_catz_options_setdefault() for zonedir
When defaults->zonedir is set, opts->zonedir is unconditionally
overwritten without freeing the previous value. This leaks memory
on every catalog zone update when zonedir defaults are configured.

Free the existing opts->zonedir before replacing it.
2026-03-14 07:57:00 +01:00
Ondřej Surý
e7c550730a
Dispatch async work jobs from the correct loop
Refactor dns_loadctx_t and dns_dumpctx_t to use standard
ISC_REFCOUNT_DECL and ISC_REFCOUNT_IMPL macros, retiring the
redundant manual attach and detach implementations.

Introduce dns_loadctx_enqueue() and dns_dumpctx_enqueue() to
ensure compliance with the new strict loop affinity in
isc_work_enqueue(). If the current loop does not match the
target loop, the enqueue operation is safely bounced to the
correct thread via isc_async_run().
2026-03-14 06:32:54 +01:00
Aram Sargsyan
172f5496ba
Fix a bug in dns_tkey_processquery()
The 'keyname' variable could be used in the add_rdata_to_list()
call without being initialized. Make sure that 'keyname' is non-NULL
for all the cases that do not jump to the 'cleanup:' label.
2026-03-13 13:38:07 +01:00
Ondřej Surý
a854a5c83d
Fix memory leak in QPcache addnoqname/addclosest mechanism
The attacker that controls DNSSEC-signed zone can trigger a memory leak
in the addnoqname() and/or addclosest() by creating more than
max-records-per-type RRSIG for any NSEC records.  The memory leaks have
been fixed.
2026-03-13 13:18:48 +01:00
Matthijs Mekking
6ca67f65cd
Check RRset trust in validate_neg_rrset()
In many places we only create a validator if the RRset has too low
trust (the RRset is pending validation, or could not be validated
before). This check was missing prior to validating negative response
data.
2026-03-13 13:03:33 +01:00
Matthijs Mekking
d4c7c83a70
Combine validator_log and marksecure
When we mark RRsets as secure, we most of the time also log a debug
message. Combine this the same way as 'markanswer()' does.
2026-03-13 13:03:33 +01:00
Matthijs Mekking
0ec08c2120
Don't verify already trusted rdatasets
If we already marked an rdataset as secure (or it has even stronger
trust), there is no need to cryptographically verify it again.
2026-03-13 13:03:33 +01:00
Matthijs Mekking
988040a5e0
Check iterations in isdelegation()
When looking up an NSEC3 as part of an insecurity proof, check the
number of iterations. If this is too high, treat the answer as insecure
by marking the answer with trust level "answer", indicating that they
did not validate, but could be cached as insecure.
2026-03-13 13:03:33 +01:00
Mark Andrews
cfa21d1e8b Set length in dns_rdata_in_dhcid structure
tostruct_in_dhcid was not setting the length field in the
dns_rdata_in_dhcid structure.
2026-03-12 14:08:32 +11:00
Ondřej Surý
2da669490c Fix resquery reference imbalance on TCP connect failure
In fctx_query(), resquery_ref(query) is called before
dns_dispatch_connect() in anticipation of the resquery_connected()
callback consuming the reference.

When dns_dispatch_connect() fails synchronously on TCP (e.g. from
dns_transport_get_tlsctx() failing in tcp_dispatch_connect()), the
connect callback is never scheduled, so the extra reference is never
consumed.  The error path then tears down the query via manual cleanup
(isc_mem_put) without going through the refcount destructor, leaving
the reference imbalanced.

Fix by dropping the extra reference on the error path, just after
dns_dispatch_done() which cleans up the dispatch entry.
2026-03-10 17:58:43 +01:00
Ondřej Surý
0d28e1bed2 Fix copy-paste typos in dns_dispatchmgr comments
The v6ports and nv6ports fields are documented as "available ports
for IPv4" instead of "IPv6".
2026-03-10 17:58:43 +01:00
Alessio Podda
547c280002 Replace lock keyfile hashmap with lock pool
Kasp used a lock per zone origin in order to prevent concurrent access
to keyfiles. This lead to substantial memory consumption in the case of
authoritative servers with many small zones, as lots of locks need to be
allocated.

Since the number of keyfile locks taken cannot exceed the number of
helper threads, it makes more sense to use a lock pool of fixed size
keyed by the hash of the origin name, leading to memory savings.
2026-03-06 12:31:24 +01:00
Mark Andrews
05c69f4103 Fix setting retire in dns_keymgr_key_init
The wrong variable was passed to dst_key_gettime when attempting
to set retire.
2026-03-05 10:14:45 +00:00
Ondřej Surý
c1ba80169c
Introduce max-delegation-servers configuration option
Make the maximum number of processed delegation nameservers configurable
via the new 'max-delegation-servers' option (default: 13), replacing the
hardcoded NS_PROCESSING_LIMIT (20).

The default is reduced to 13 to precisely match the maximum number of
root servers that can fit into a classic 512-byte UDP payload.  This
provides a natural, historically sound cap that mitigates resource
exhaustion and amplification attacks from artificially inflated or
misconfigured delegations.

The configuration option is strictly bounded between 1 and 100 to ensure
resolver stability.
2026-03-04 16:13:49 +01:00
Michal Nowak
239464f276
Use clang-format-22 to update formatting 2026-03-04 10:56:41 +01:00
Aram Sargsyan
e41fbea843 Replace the outgoing queries RTT histogram code with isc_histomulti
The granularity of the simple histogram with fixed number of ranges
sometimes isn't good enough. As there's a need to implement a new
histogram statistics for the incoming query times (RTT), it was decided
to also update the existing RTT statistics of the outgoing queries
so that they look similar and use common code.

Remove the old histogram code from the resolver and from the statistics
channel. Reimplement the outgoing queries RTT histogram using the
isc_histomulti module, and prepare the necessary base for implementing
the incoming queries RTT histogram. The statistics channel will be
updated to expose the new histograms in an upcoming commit.
2026-02-26 14:00:10 +00:00
Ondřej Surý
3c33e7d937
Implement Fisher-Yates shuffle for nameserver selection
Replace the two-pass "random start index and wrap around" logic in
fctx_getaddresses_nameservers() with a statistically sound Fisher-Yates
shuffle.

The previous implementation picked a random starting node and did two
passes over the linked list to find query candidates.  The new logic
extracts the available nameservers into a bounded, stack-allocated array
of dns_rdata_t structures.

This array is then randomized in-place using a Fisher-Yates shuffle.
Finally, the shuffled array is traversed sequentially to launch fetches
until the dynamic quota (fctx->pending_running >= fetches_allowed) is
reached.

This guarantees a fair random distribution for outbound queries while
properly respecting dynamic query limits, entirely within O(1) memory
and without the overhead of linked-list pointer shuffling or multiple
dataset traversals.
2026-02-26 06:57:53 +01:00
Matthijs Mekking
5bd6322739 Fix log level bug in keystore
A debug message that logs a PKCS#11 object has been generated was
erroneously logged at error level. This has been fixed.
2026-02-25 11:34:07 +01:00
Mark Andrews
b78052119a Remove determinist selection of nameserver
When selecting nameserver addresses to be looked up we where
always selecting them in dnssec name order from the start of
the nameserver rrset.  This could lead to resolution failure
despite there being address that could be resolved for the
other names.  Use a random starting point when selecting which
names to lookup.
2026-02-25 09:27:03 +01:00
Ondřej Surý
46cfac0825
Remove purged adb names and entries from SIEVE list immediately
Both `expire_name()` and `expire_entry()` use the isc_async mechanism to
remove names and entries from the SIEVE-LRU lists on the matching
isc_loop.

Under heavy load when the cleaning mechanism didn't have the chance to
kick in yet, this delay could lead to double-counting the purged names
and entries when purging the SIEVE-LRU lists during an overmem
condition.  This would result in insufficient memory being cleaned up,
causing the ADB to never recover from the overmem condition and leading
to an OOM crash of `named`.

This patch resolves the issue by bypassing the async queue and executing
the removal synchronously if the target loop matches the current
isc_loop().
2026-02-25 07:26:38 +01:00
Ondřej Surý
8ab4827a0c Importing invalid SKR file might overflow the stack buffer
If an invalid SKR file is imported, reading the time from the token
buffer might overflow the buffer on the local stack.  This has been
fixed by removing the intermediate buffer and parsing the lexer token
directly.
2026-02-24 19:44:57 +01:00
Mark Andrews
f030bc6756
Remove invalid REQUIRE in NSEC3 fromstruct method
The NSEC3 fromstruct method only worked for hash type 1
when it should work for all hash types.
2026-02-24 14:58:18 +01:00