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).
The prescan and main update loops in DNS UPDATE processing both used the
same counter to index the maxbytype[] quota array. The prescan loop
always incremented the counter, but the main loop had 14 continue paths
that skipped the increment. This allowed an authenticated DDNS client to
craft an UPDATE message with padding records (e.g. CNAME+A pairs that
trigger CNAME-conflict skips) to shift the counter and read wrong quota
entries, bypassing per-type record limits entirely.
Fix by incrementing the counter unconditionally at the start of each
iteration in the main loop.
Since it is impossible to increase an isc_statsmulti counter and
retrieve the new counter atomically, and we need the output of
recursclients in order to compute ns_highwater_recursive, we change the
recursclients counter to an isc_stats one.
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.
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.
The "nsec3-delegation" test was added in a release branch, before commit
67aca1f8c6 introduced the current system
test naming convention. Rename the test to comply with that convention.
Unlike new transports with a new dependency DNS-over-QUIC support will
be added incrementally due to the non-trivial amound of plumbing
required by libngtcp2. This will require non-functional QUIC code in the
main branch that won't be exposed for non-development builds.
Therefore, libngtcp2 is linked as an optional dependency only on
explicitly enabled development builds and cannot be required. This will
be changed with a `doq` meson build option once the server-side
functionality is complete for consumption.
Commit `604d8f0b967563b0ba9dcd4f09559fdd9e21dfbe` introduced during 9.19
development cycle a check to ensure the resolver never attempts to
lookup more than 20 NS names. This limit was introduced by
`3a44097fd6c6c260765b628cd1d2c9cb7efb0b2a` as part of the CVE-2022-2795.
However, this test relies on the fact that, at the time, the NS names
were processed in a specific order in the nameserver, as this snip from
the log (from a build on `604d8f0` branch) running the test illustrates:
```
24-Mar-2026 21:19:46.346 dispatch 0x7fdaa722d200: success, length == 19956, addr = 0x7fdaa0a7c102
24-Mar-2026 21:19:46.346 dispatch 0x7fdaa722d200: got valid DNS message header, /QR 1, id 14328
24-Mar-2026 21:19:46.346 dispatch 0x7fdaa722d200: search for response in bucket 7213: success
24-Mar-2026 21:19:46.354 received packet from 10.53.0.3#5300
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14328
;; flags: qr aa; QUESTION: 1, ANSWER: 0, AUTHORITY: 999, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
; COOKIE: baf16b0241efc700
;; QUESTION SECTION:
;large-referral.example.net. IN A
;; AUTHORITY SECTION:
;large-referral.example.net. 300 IN NS ns1.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns2.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns3.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns4.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns5.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns6.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns7.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns8.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns9.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns10.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns11.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns12.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns13.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns14.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns15.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns16.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns17.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns18.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns19.fake.redirect.com.
;large-referral.example.net. 300 IN NS ns20.fake.redirect.com.
```
This is not true anymore, as the NS are in a random order. Moreover,
commit `3c33e7d9370006b1599e3d99c0d5fa6a6dad7979` introduced the
randomization of the selection of the NS names to lookup, which make the
test potentially unreliable, as it now doesn't mean anything to check
the nameserver does not query `ns21.fake.redirect.com.`, as it could be
the first one, or in any position form the randomized list.
Another test has been added in commit
`c67b52684f11652b07afaa75a917f6f0355dbca6` which test both the
randomization of the NS name to be looked up, as well as the upper bound
limit of NS name lookup to be done.
For all those reasons, this specific legacy check is now removed.
The -C option, introduced in BIND 9.7, caused a backward-compatible
key to be generated, using private key format version 1.2, omitting the
creation date and other timing metadata. This made it possible to
generate keys that could be loaded by older versions of BIND.
Those older versions having reached end of life many years ago, the
option can now be removed, along with the "dnssec-settime -f" option,
which caused old-style keys to be upgraded.
previously, rpz_rrset_find() behaved differently depending on whether
a cache lookup returned DNS_R_DELEGATION or ISC_R_NOTFOUND. the former
indicates the presence of a cached NS rrset, and the latter indicates
that the cache is cold or that all NS rrsets above the query name have
expired. both results indicate that the caller should recurse, but
rpz_rrset_find() only recursed in the case of DNS_R_DELEGATION.
the nsip-wait-recurse and nsdname-wait-recurse test cases in the
rpzrecurse system test were dependent on this misbehavior. the test
server was configured with a lame delegation, so that recursion always
failed, but once the lame delegation was expired due to a zero TTL, the
cache returned ISC_R_NOTFOUND, which caused the recursion not to be
attempted. the test seemed to be observing a delay before recursion
succeeded, but it was actually observing a delay before recursion was
skipped. fixing this bug caused the test to fail.
the test server has now been reconfigured so that recursion succeeds
after a delay, instead of failing. now we're able to test that
we're waiting for the successful completion of recursion.
Race rndc reconfig (toggling between allow-update and update-policy)
against a stream of DNS UPDATEs for 5 seconds and verify that named
does not crash.
Before the fix, the race between send_update() and update_action()
reading the SSU table independently could trigger an assertion
failure (INSIST) when the zone's update policy changed between the
two reads.
All system tests previously using a hyphen have been renamed to use
underscore instead. A couple of symlinks were corrected and one path in
`nsec3-answer` adjusted accordingly.
Change the convention for system test directory names to always use an
underscore rather than a hyphen. Names using underscore are valid python
package names and can be used with standard `import` facilities in
python, which allows easier code reuse.
The temporary directories for test execution and their convenience
symlinks have been switched to using hyphens rather than underscores to
keep the pytest collection, filtering and .gitignore working as
expected.
Move all LMDB-based new zone database functions from server.c into
nzd.c to reduce the size of server.c and isolate the NZD/LMDB
interface. Rename load_nzf() to nzd_load_nzf() to match the nzd_
namespace.
Now that NZF write support is gone, remove the unused nzfwriter_t
typedef and nzfwriter parameter from delete_zoneconf(). Remove the
bool locked parameter and simplify the locking in do_modzone() and
rmzone() to unconditional lock/unlock pairs.
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.
If we are modifiying the zone, the zone must have been added before.
Don't overwrite this value on modifications.
Also it feels cleaner to pass added=false to configure_zone() in
do_modzone().
Some code paths try to lock an already locked view->newzone.lock.
For example, do_modzone() aqcuires the lock and then calls
delete_zoneconf(), that wants to acquire the same lock.
Add a parameter to delete_zoneconf() that informs the function if the
lock has already been acquired.
A few port validation checks use >= UINT16_MAX instead of > UINT16_MAX,
incorrectly rejecting port 65535 as out of range. Port 65535 is a valid
TCP/UDP port number. Other port checks in the same file already use the
correct > comparison.
The asynchronous SIG(0) handling improperly used srcaddr, and dstaddr
from the caller's stack and didn't attach to aclenv. This could
possibly lead to ACL bypass as an invalid srcaddr could be matched or
possible assertion failure if the ACL environment would change between
the initial call and the SIG(0) processing due to the server
reconfiguration. This has been fixed.
This adds a system test to verify that asynchronous SIG(0)
validation correctly retains the ACL environment and network
addresses of the caller, preventing unauthorized ACL bypass
when evaluating match-clients and match-destinations.
This new test sends two signed TKEY queries, one in delegation
mode and one in an unrecognized mode to check that named
correctly processes them.
Co-authored-by: Nicki Křížek <nicki@isc.org>
When a validating resolver processes a delegation from a DNSSEC-signed
zone which uses too many NSEC3 iterations, it should cease the attempt
to validate due to an NSEC3 iteration limit being exceeded and fall back
to insecure.
These tests rely on somewhat precise timing, as they test that answers
arrive in a particular latency bucket within the statschannel stats.
These tests are affected by various timing and network issues on our
FreeBSD CI runners and the results are very unstable. Skip these on
FreeBSD entirely.
Some dns message modifications like TSIG happen only after .to_wire() is
called on the message. To ensure there isn't a discrepancy between what
has been logged and what has been sent, log the query after
dns.query.udp() is executed (which calls .to_wire() on the message).
Co-Authored-By: Štěpán Balážik <stepan@isc.org>
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.
Add a resolver instance "ns4" in the statschannel test and a "ans5"
instance which adds latency to the queries delegeated to it from the
resolver.
Make queries which add latency, and compare the expected values to
the values received from the statistics channel.
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.
Introduce a new system test (nsprocessinglimit) to verify that the
resolver strictly respects outgoing network fetch quotas when presented
with heavily delegated, unresponsive zones.
This test acts as a regression check for the recent Fisher-Yates nameserver
selection refactor. It sets up an authoritative server delegating a zone
to 23 distinct nameservers (all pointing to unresponsive loopback IPs).
Using dnstap, the test forces a resolution failure and verifies that:
1. The resolver successfully traverses the zone delegation path.
2. The resolver caps the outgoing network queries to the delegated
nameservers exactly at the processing limit (20 fetches), ensuring
array boundaries and dynamic fetch quotas are strictly enforced without
crashing or hanging.
Add randomizens system test which ensures that NS are randomly selected.
The test relies of the fact that `getaddresses_allowed()` logic won't
allow to query more than 3 NS at the top-level. The `example.` zone has
4 NS and the 3 formers are lame. As a result, if the resolved doesn't
randomize the NS selection, it will only quiery the 3 formers, which
won't give an answer, and fails. With randomization enabled, there is a
chance that the resolver queries the fourth NS, and gets the result.
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.
Adds a static system test that fails to load an NSEC3 record with an
invalid next part length. Additionally, introduces a dynamic test using
a crafted authoritative DNS proxy to inject invalid NSEC3 records on the
fly to test runtime behavior.
NSEC3 hashes are required to fit within a single DNS label. Since there
are 5 bits per label byte without pad characters, the maximum hash size
is floor(63*5/8) (39 bytes).
This patch enforces this maximum length for unknown algorithms, while
strictly enforcing the exact expected digest length for known algorithms
like SHA-1.