Commit graph

13086 commits

Author SHA1 Message Date
Ondřej Surý
205cd3509f Cover exact-name NODATA synthesis from a pending NSEC
The #5872 reproducer plants a covering NSEC that is rejected inside the
cache (find_coveringnsec), so it never reaches the trust check on the
exact-match NODATA branch of query_coveringnsec(). This adds a companion
case: an NSEC owned by the victim name itself, injected at pending trust
via a CD=1 query, is returned by the cache as a NODATA proof for the
exact node and must not be used to synthesize a NODATA that would deny
the victim's real A record.

Reuses the f004.test fixture with a victim-owned forged NSEC.

Assisted-by: Claude:claude-fable-5
(cherry picked from commit dc02732883)
2026-07-08 15:29:25 +02:00
Evan Hunt
b4d2a73e1d Merge NSEC synthesis tests
Merge the tests for "nsec_child_next" and "nsec_pending_cd" into
"nsec_synthesis".

(cherry picked from commit 91955ca087)
2026-07-08 15:29:25 +02:00
Alessio Podda
ffc281f029 Reproducer for #5887 out of zone NSEC-next syntheisis
Create the "nsec_child_next" system test.

Co-Authored-By: Evan Hunt <each@isc.org>
(cherry picked from commit 454bb99da4)
2026-07-08 15:29:25 +02:00
Alessio Podda
4b212c1a5f Reproducer for #5872 cache pending synthesis
Create the "nsec_pending_cd" system test.

Co-Authored-By: Matthijs Mekking <matthijs@isc.org>
(cherry picked from commit 760f63f147)
2026-07-08 15:29:25 +02:00
Alessio Podda
2795f4bece Reproducer for #5977 cache poison NSEC piggyback
Create a new "nsec_piggyback" system test.

Co-Authored-By: Matthijs Mekking <matthijs@isc.org>
(cherry picked from commit ace05a3cb8)
2026-07-08 15:29:25 +02:00
Ondřej Surý
b7178ff652
Add a system test resolving through a signed apex DNAME
The dnssec system test signs a DNAME-at-apex zone but only ever
queried the apex directly; nothing resolved a name under the DNAME
through the validating resolver, so a validator regression on that
path went unnoticed.

Assisted-by: Claude:claude-fable-5
(cherry picked from commit 38992e02bb)
2026-07-08 12:24:43 +02:00
Matthijs Mekking
dda2c57a28 Test multi-master dnssec-policy setup
Update the manual rollover test case with a multi-master setup.  In this
scenario, key files are generated, as well as rollovers are started
on one server (ns3) and key files are copied to the other server (ns4).

Add checks that the begin and end key states are the same.

(cherry picked from commit affe84e55b)
2026-07-07 14:59:08 +00:00
Evan Hunt
b358cea3cb Merge "nsec3_wrong_zone" into "dnssec_nsec3"
These tests are similar in structure and topic, and can be merged.

(cherry picked from commit abd274c1fd)
2026-07-03 00:37:28 -07:00
Alessio Podda
ae1e30f963 Reproducer for #5970 acceptance of unvalidated NSEC3
Add "dnssec_nsec3" system test.

Co-Authored-By: Evan Hunt <each@isc.org>
(cherry picked from commit fdecacf07a)
2026-07-03 00:37:28 -07:00
Ondřej Surý
ec75f25f47 Add a system test for CD=1 NXDOMAIN cache protection
Cache a DNSSEC-validated A record, then make a CD=1 query elicit an
unvalidated NXDOMAIN for the name: the secure RRset must survive, and an
uncached-type query must not get the wrong RRset back.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit ddb6cb5c93)
2026-07-02 15:04:19 -07:00
Mark Andrews
998416777e Test oversized private record is properly ignored
(cherry picked from commit 5725c4191f)
2026-07-03 04:07:30 +10:00
Nicki Křížek
f7c2ac088e Support serving signed child zone from its parent's nameserver
When a signed zone is served by the same nameserver instance as
its parent, the child's dnssec-signzone has already written
dsset-<child>. into that directory. Don't attempt to copy the dsset if
the destination and source files are the same.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 246cca357b)
2026-07-02 14:42:43 +00:00
Nicki Křížek
4a93ba83a9 Move algorithm definitions into a top-level isctest.algorithms module
The Algorithm type, the per-algorithm constants, and the ALL_ALGORITHMS*
lookup tables are general DNSSEC key definitions used across isctest
package and the tests. Move them into a dedicated module to separate
these from the environment-specific setup that remains in
isctest.vars.algorithms.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 4d76b7bd9e)
2026-07-02 15:45:49 +02:00
Nicki Křížek
9a420bde2f Add private_key support to all ZoneKey implementations
Extend the ZoneKeyFile to read the file-backed private key and return it
in a format suitable for use with dnspython. Add ZoneKey.private_key
property to unify the interface.

(cherry picked from commit ee73ba3bba)
2026-07-02 15:45:49 +02:00
Nicki Křížek
a7c9dfe169 Use the algorithm.number interface 2026-07-02 15:45:49 +02:00
Nicki Křížek
9d5b97db80 Add NSEC3RSASHA1 to list of algorithms
This algorithm is deprecated and not currently used in our system tests,
but it should be in the list of all algorithms.

(cherry picked from commit 596e41553c)
2026-07-02 15:45:49 +02:00
Nicki Křížek
cad0939602 Move dnskey method from kasp.Key to zone.FileZoneKey
Code move with one change - switch dnskey TTL from 300s (DEFAULT_TTL) to
3600s (DNSKEY_TTL).

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 55cd4a1e11)
2026-07-02 15:45:49 +02:00
Nicki Křížek
df7e8cf6bb Merge kasp.Key functionality into zone.FileZoneKey
Make zone.FileZoneKey the single representation of a file-backed key
(typically generated by dnssec-keygen). Move the common key-related
functionality into zone.FileZoneKey, and extend that functionality in
kasp.Key to also add state and timing related operations on top. Remove
duplicate into_ta() function.

Note that is_ksk() is implemented differently for kasp.Key: with the
metadata file available, the KSK status is loaded from that file, as it
indicates the authoritative policy decision which makes the key a KSK.
In zone.FileZoneKey which doesn't work with the metadata file, the KSK
status if inferred from the DNSKEY SEP flag - the best information
available for that class.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 35fc5ce8b4)
2026-07-02 15:45:49 +02:00
Nicki Křížek
c5f4d66e73 Read DNSKEY TTL from kasp.Key.dnskey
Remove the redundant ttl() method. The DNSKEY RR already provides the
TTL.

(cherry picked from commit 9dc039f735)
2026-07-02 15:45:49 +02:00
Michał Kępień
3665c94e56
Move ans.py-related information to README.md
COOKBOOK.md is supposed to be minimal and heavy on examples, so move the
lengthy section about implementing custom ans.py servers from
COOKBOOK.md to README.md.

(cherry picked from commit edd765a092)
2026-07-02 15:17:03 +02:00
Michał Kępień
1072686f46
Update AsyncDnsServer-related test cookbook parts
Add practical tips about specific handler classes.  Mention some good
practices and point developers at existing code written in the desired
manner.  Document common pitfalls.  Suggest preferred approaches for
splitting up complex response handling code.

(cherry picked from commit a48e5cd98d)
2026-07-02 15:17:03 +02:00
Alessio Podda
8e546f019f Add forward-first referral poisoning reproducer
Add a system test covering authority-section NS referrals returned by
configured forwarders under forward first.

The test verifies that a forwarder for fwd.hack cannot install the
parent hack zone cut and redirect resolution for the sibling zone
sibling.hack.

(cherry picked from commit ee34bbd208)
2026-07-02 11:50:20 +00:00
Ondřej Surý
173255127f Add the tcp-reuse-timeout option
The idle timeout that bounds how long a reused outgoing TCP/TLS
connection is held open for reuse was only tunable through the 'named -T
tcpidletimeout' developer hook added earlier on this branch. Make it a
proper configuration option, tcp-reuse-timeout (options block, in units
of 100 milliseconds like the other tcp-*-timeout options), and drop the
-T hook.

(cherry picked from commit 477130cf8e)
2026-06-25 11:37:51 +02:00
Ondřej Surý
dc78507aa0 Keep idle reused outgoing TCP connections under read
A reused TCP/TLS dispatch with no outstanding responses was left in the
reuse pool with no read pending, so a peer closing the idle connection
went unnoticed: the socket lingered in CLOSE-WAIT and the dead dispatch
was later handed to a new query, which failed and the fetch timed out.
Keep a read pending on an idle connected dispatch, bounded by an idle
timeout, so the close is seen promptly and the connection is dropped
from the pool instead of reused.

The idle read may only be (re)armed while the dispatch is still
connected; arming it on a dispatch that is already shutting down
re-reads a dying handle and double-schedules a netmgr job.

On shutdown, close the connection as soon as the dispatch reaches its
terminal state instead of waiting for the last reference to drop, so an
unexpected read (or a peer-side close) cannot leave the socket in
CLOSE-WAIT while a reference still lingers.

(cherry picked from commit febeac215d)
2026-06-25 11:37:51 +02:00
Nicki Křížek
7f86813245 Add dnssec_py/tests_sibling_ds: reject DS for sibling zones in referrals
Add a system test that verifies the resolver rejects DS records whose
owner name does not match the delegation (NS) name in a referral
response.

A custom authoritative server (ans4) serves the parent zone sibling-ds.
from zone file with delegations for child and sibling subzones.  Its
DomainHandler injects a DS record for sibling.sibling-ds into referrals
for child.sibling-ds.  The resolver must detect the mismatch, log "DS
doesn't match referral (NS)", and return SERVFAIL.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit a2b9dcff54)
2026-06-25 06:05:02 +00:00
Nicki Křížek
e9912d3ea5 Don't include ORIGIN for AsyncDnsServer zones
The zone template can't use $ORIGIN with AsyncDnsServer because
AsyncDnsServer._load_zone_file_with_origin() rejects it for non-root
zones.

(cherry picked from commit 95a268f119)
2026-06-25 06:05:02 +00:00
Alessio Podda
4802beb762 Reproducer for #5876 child apex self-loop NSEC
Added to "nsec_synthesis" system test.

Co-Authored-By: Evan Hunt <each@isc.org>
(cherry picked from commit 4fb662a171)
2026-06-24 21:50:08 +00:00
Štěpán Balážik
62cfb8bdae Simplify the packets in the formerr system test
Normalize the message ID to 0 and the TTL of records to 1 unless
required (OPT and UPDATE records require TTL=0).

Rename the questionclass test case to twoquestionclasses for
consistency.

(cherry picked from commit 62a3804a4c)
2026-06-24 22:22:35 +02:00
Štěpán Balážik
28e0c79b12 Reimplement the FORMERR system test in Python
Replace the shell and Perl based FORMERR system test with a Python
test that constructs the malformed DNS packets directly and checks
the responses.

Remove the legacy shell and Perl test script and the intermediate
packet files in hex, leaving the packet construction inline in
tests_formerr.py.

Preserve the same wire for all packets sent to the server, but
construct them in a more explicit and readable way.

(cherry picked from commit 151b2d6045)
2026-06-24 22:22:35 +02:00
Michal Nowak
8ce39fdcb1 Fix a false positive compiler warning/error on Alpine 3.24
On Alpine Linux 3.24, GCC 15 with fortify-headers produces a compiler
warning when building bin/nsupdate/nsupdate.c:

    In function 'fgets',
        inlined from 'get_next_command' at ../bin/nsupdate/nsupdate.c:2414:13:
    /usr/include/fortify/stdio.h:48:16: error: 'cmdlinebuf' may be used uninitialized [-Werror=maybe-uninitialized]
       48 |         return __orig_fgets(__s, __n, __f);
          |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/include/fortify/stdio.h:42:1: note: in a call to '*fgets' declared with attribute 'access (read_write, 1, 2)' here
       42 | _FORTIFY_FN(fgets) char *fgets(char * _FORTIFY_POS0 __s, int __n, FILE *__f)
          | ^~~~~~~~~~~
    ../bin/nsupdate/nsupdate.c:2405:14: note: 'cmdlinebuf' declared here
     2405 |         char cmdlinebuf[MAXCMD];
          |              ^~~~~~~~~~

This is a false positive, because fgets() only writes into the buffer;
the fortify-headers wrapper annotates the buffer argument with
'access (read_write, ...)', which makes GCC treat passing an
uninitialized buffer as a read of uninitialized memory.

Initialize the 'cmdlinebuf' buffer anyway to avoid the build error.

Assisted-by: Claude:claude-fable-5
(cherry picked from commit 62670aa1b7)
2026-06-24 18:06:47 +02:00
Michal Nowak
28142e98a5 Retry pipequeries on a transient EADDRINUSE in the pipelined test
On FreeBSD, the TCP connect() call can transiently fail with
EADDRINUSE under parallel CI load.  The netmgr already retries such
connects (see #3451), but it retries on the same socket, which is
already bound to the same ephemeral source port, so when the
four-tuple is genuinely busy (e.g. in TIME_WAIT) every retry fails
the same way.  pipequeries then exits with "request event result:
address in use", leaving raw.1 empty and failing the first check.

All eight requests share a single TCP dispatch, so the failed connect
means no query ever reached ns4 and its cache is still cold.  It is
therefore safe to run pipequeries again: a fresh process binds a new
ephemeral port, and the out-of-order check keeps its meaning.  Retry
for up to ten attempts, but only on this specific transient error.

Assisted-by: Claude:claude-fable-5
Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit b9cf877277)
2026-06-24 18:05:46 +02:00
Michal Nowak
20197027a1 Print OS platform in "named -V"
The "running on" line emitted by `named -V` (as well as the startup
log and `rndc status`, which share the same source) now appends the
PRETTY_NAME value from /etc/os-release in parentheses after the uname
output, e.g.:

    running on Linux x86_64 6.19.14-... (Fedora Linux 42 (Workstation Edition))

This helps disambiguate environments where the kernel string is not a
reliable indicator of the userspace, such as RHEL clones and
containers whose kernel does not match the host OS.

When /etc/os-release is absent, /usr/lib/os-release is tried as a
fallback per the systemd os-release(5) specification. When neither is
available or no PRETTY_NAME is found, the output is unchanged.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit b5ca9d3372)
2026-06-24 17:52:30 +02:00
Nicki Křížek
0c5242925d Add extra expired RRSIGs test to dnssec_py
The test verifies that a validating resolver enforces the
max-validations-per-fetch limit when encountering a record with multiple
expired RRSIGs followed by a valid one. One of the records is signed
three times: twice with expired timestamps (to produce two expired
RRSIGs for a.rrsigs-extra-expired/A) and once with valid timestamps,
after which the expired RRSIGs are injected back into the signed zone
file. max-validations-per-fetch is set to 2 via the template variable so
that the third (valid) RRSIG is never reached, causing SERVFAIL.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit fe2fea73a4)
2026-06-24 14:32:46 +00:00
Ondřej Surý
4467823700 Fix invalid free in statistics-channel JSON renderer
wrap_jsonfree() called json_object_put() on the response-body buffer
base, which is the JSON string returned by
json_object_to_json_string_ext(), not a struct json_object.  The root
object is already passed in as the callback argument; release only
that.

(cherry picked from commit f39089576a)
2026-06-24 15:39:24 +02:00
Ondřej Surý
b2f4b8af32 Add regression test for statistics-channel JSON free bug
Hit every JSON statistics endpoint several times.  The current code
calls json_object_put() on the response-body string pointer, which
doesn't crash just by accident - the memory position contains large
value from static string.

(cherry picked from commit 9608158d73)
2026-06-24 15:39:24 +02:00
Ondřej Surý
aafd969f6f Fail the fetch when a response fails the TSIG signature check
A response that failed the signature check with a missing or unexpected
TSIG used to set nextitem, so the resolver kept reading the dispatch for
another response.  When the response was truncated with the TSIG cut off
the end of the wire, no further response ever arrived and the fetch
stalled until resolver-query-timeout.

Treat an unauthenticated response like every other signature-check
failure and finish the fetch immediately.  A response carrying a missing
or bogus TSIG now yields SERVFAIL instead of being skipped in favour of
a later one; the cookie system test that fed a spoofed TSIG response is
updated to expect that.  The unauthenticated data is still never
returned.

(cherry picked from commit 2327277f90)
2026-06-24 14:48:35 +02:00
Michal Nowak
db441f662d Avoid writing through a const pointer in render_xsl()
render_xsl() cast away the const of the static xslmsg stylesheet and
passed it to isc_buffer_reinit(), which memmove()s into the base when
the buffer is non-empty -- a write to read-only memory that -fanalyzer
flags (-Wanalyzer-write-to-const).  It only stayed safe because the
body buffer is always empty here.

Use isc_buffer_constinit(), which never writes to the base, and assert
the empty-buffer contract with REQUIRE(isc_buffer_length(b) == 0).

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit a8368cdf17)
2026-06-24 09:31:30 +00:00
Aram Sargsyan
f4a77a59ef Add a new check in "inline" system test
This new check floods the server with DNS UPDATE messages for an
'inline-signing yes; sig-signing-signatures 1;' zone to see if
it manages to process the updates correctly.

(cherry picked from commit 37f265f59a)
2026-06-22 20:56:41 +00:00
Ondřej Surý
033a15061b
Add a regression test for an empty non-terminal under a wildcard
The NSEC3-signed entwild.test zone places an apex wildcard above empty
non-terminals; querying one of them with DNSSEC requested reproduces
the abort seen with the RBT zone database. The query must instead
return NODATA with an NSEC3 proof. The zone uses the default zone
database, so it only exercises RBTDB on a build that defaults to it.

Assisted-by: Claude:claude-opus-4-8
2026-06-22 21:58:25 +02:00
Matthijs Mekking
4bed09f3c4 Don't rely on smart signing in cds system test
With dnssec-signzone smart-signing (-S), the CDS and CDSNKEY are
derived from the key timing metadata and the configuration options (-G).

The test has specific test cases that smart signing (with the fix)
interferes with. Therefor, disable smart-signing in the cds system test.

(cherry picked from commit fdf74636e2)
2026-06-19 12:39:17 +02:00
Matthijs Mekking
75bfd8820d Add system test for reconfiguring CDS/CDNSKEY
When on an 'rndc reconfig' the DNSSEC policy changes such that it
changes the expected CDNSKEY/CDS records in the zone, the RRset should
be updated accordingly.

Add a test case where we reconfigure a zone with a policy such that
these records should be removed, and on a second reconfigure add
them back again.

Note the test deliberately adds a different CDS digest on the
second reconfigure.

(cherry picked from commit 89ebe61ad3)
2026-06-19 09:07:41 +00:00
Alessio Podda
d45ee682d8 Reproducer for #5971 NSEC3 from ancestor zone
Create a new nsec3_wrong_zone system test as a regression test.

Co-Authored By: Evan Hunt <each@isc.org>

(cherry picked from commit 680e0d8532)
2026-06-18 10:58:11 -07:00
Evan Hunt
9eeb8bde5a Check wildcard signer and NOQNAME signer match
A positive wildcard answer, and the NSEC3 proof that the requested
name doesn't exist in the zone, must both be from the same zone.
Otherwise, an NSEC3 from an ancestor zone could be used to interfere
with validation.

We now retrieve the signer name from a wildcard response's signature.
An NSEC3 record cannot be used as a NOQNAME proof for the wildcard
unless it exactly matches the name one level above the NSEC3.

Fixes: isc-projects/bind9#5971

(cherry picked from commit 45c9bd2603)
2026-06-18 10:58:11 -07:00
Colin Vidal
f35817f620 Use original query name when caching SERVFAIL
Instead of using `client->query.qname` when caching a SERVFAIL answer,
use `client->query.origqname` when available.

This avoids caching a SERVFAIL against a CNAME target when the failure
occurs while the resolver is following the CNAME chain. This is
problematic, for instance, when the SERVFAIL is triggered by the
`max-query-count` threshold being reached, which would incorrectly
prevent legitimate resolution of the CNAME target while in the SERVFAIL
cache.

Note that if the SERVFAIL genuinely originated from resolving the CNAME
target, that specific failure will no longer be cached, and a direct
query for the CNAME target will trigger a fresh (likely failing)
resolution attempt. However, this is still preferable to the previous
behaviour, which would wrongly prevent resolving the CNAME target if it
was cached for other reasons (like the example above).

(cherry picked from commit 66af5b464d)
2026-06-18 14:06:14 +02:00
Colin Vidal
a404d72d36 System test covering SERVFAIL cache and CNAME
Add a system test for the case where resolution SERVFAILs because the
fetch context reaches the `max-query-count` threshold while following a
CNAME.

Resolving the CNAME target independently should still work, because the
SERVFAIL cache stores the original query name rather than the target.

(cherry picked from commit d238b8eece)
2026-06-18 14:06:14 +02:00
Ondřej Surý
8f848851ef Poll for RPZ readiness in the servfail-until-ready test
RPZ is ready only once every policy zone has completed its first update,
and the zones do not finish in a fixed order, so whenever the updates
run serially (per-loop offload, or any single-CPU run): 'slow-rpz' zone
can finish before the others and the query still gets SERVFAIL.  Poll
the query until it returns NOERROR instead.

Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 153c9d3509)
2026-06-18 07:08:19 +02:00
Ondřej Surý
cd348cf255
Replace the shared work pool with per-loop, per-lane worker threads
Offloaded work used two different mechanisms: a per-loop isc_helper
thread for CPU-bound crypto (DNSSEC validation, message signature
checks) and the process-global libuv thread pool for blocking I/O (zone
load and dump, inbound transfer apply). Neither could cancel a queued
task, and the two disagreed about exclusive mode — the helper paused
with its loop under isc_loopmgr_pause() but the libuv pool did not, so
blocking offloaded work kept running while a loop held the exclusive
lock.

Unify both behind isc_work: each loop gets its own worker thread per
lane — FAST for short, bounded tasks and SLOW for long, blocking ones —
fed by a private queue. Separate lanes keep a short crypto task off the
path of a multi-second zone dump once both run on per-loop workers;
every lane parks with isc_loopmgr_pause() so exclusive mode now quiesces
offloaded work too; and a still-queued task can be canceled before it
starts (isc_work_cancel). isc_helper is removed and its callers select a
lane.

(cherry picked from commit a5f13b3410)
2026-06-17 21:15:17 +02:00
Evan Hunt
989c2701af Change tests to reflect new behavior
The removal of the secondary validator in lib/ns/query.c now means
that some responses will omit additional data or NS records in the
authority section that had pending trust. Some test cases have been
revised or deleted to take this into account.
2026-06-17 18:59:47 +00:00
Nicki Křížek
47f7e71b06 Don't run vulture on ansX system test dirs
Exclude ansX directories from vulture, as splitting up the handlers into
multiple files gets flagged as unused code.

(cherry picked from commit 72bda8335f)
2026-06-17 18:59:47 +00:00
Evan Hunt
93386681db Merge DNSSEC wildcard tests
Merge the tests for #5966 (F-043) and #5972 (F-045), previously called
dnssec_wildcard_additional and dnssec_replayed_parent_wildcard, into a
single directory with two modules.

(cherry picked from commit 05691b53da)
2026-06-17 18:59:47 +00:00