Nicki Křížek [Mon, 26 Jan 2026 09:45:34 +0000 (10:45 +0100)]
Fix a race condition in dnssec test
When dumpdb command is executed, it might take a while until the file is
written. Rather than checking the file once, use the WatchLog mechanism
to allow the desired line to appear before a timeout happens.
This affected test_validation_recovery and test_cache tests which have
been intermittently failing on EL8 in our CI.
Štěpán Balážik [Thu, 25 Dec 2025 15:58:35 +0000 (16:58 +0100)]
Store the most specific matched domain in DomainHandler
Store the most specific matching domain in DomainHandler and
expose it through the `matched_domain` property for subclasses
to use in their implementations of `get_responses`.
Mark Andrews [Fri, 23 Jan 2026 14:24:04 +0000 (01:24 +1100)]
fix: usr: DSYNC record incorrectly used two octets for the Scheme Field
When creating the `DSYNC` record from a structure, `uint16_tobuffer` was used instead of `uint8_tobuffer` when adding the scheme, causing a `DSYNC` record that was one octet too long. This has been fixed.
Closes #5711
Merge branch '5711-dsync_fromstruct-produces-an-invalid-record' into 'main'
Mark Andrews [Fri, 23 Jan 2026 02:32:41 +0000 (13:32 +1100)]
dsync_from struct produced an invalid record
uint16_tobuffer was used instead of uint8_tobuffer when adding the
scheme to the buffer. This produced a record that was one octet
too long. This has been fixed.
Matthijs Mekking [Fri, 23 Jan 2026 12:46:51 +0000 (12:46 +0000)]
chg: usr: Lowercase the NSEC next owner name when signing
When building the NSEC rdata, lowercase the next owner name before
storing it in the Next Domain Name Field.
Note that this is not required according to RFC 6840, but since there
is inconsistency in the documents over time, having uppercase next
owner names in the NSEC records may cause validation failures if
validators are not following RFC 6840.
Closes #5702
Merge branch '5702-lowercase-nsec-next-owner-name' into 'main'
When building the NSEC rdata, lower case the next owner name before
storing it in the Next Domain Name Field.
Note that this is not required according to RFC 6840, Section 5.1:
When canonicalizing DNS names (for both ordering and signing), DNS
names in the RDATA section of NSEC resource records are not converted
to lowercase. DNS names in the RDATA section of RRSIG resource
records are converted to lowercase.
The guidance in the above paragraph differs from what has been
published before but is consistent with current common practice.
Item 3 of Section 6.2 of [RFC4034] says that names in both of these
RR types should be converted to lowercase. The earlier [RFC3755]
says that they should not.
Since there is inconsistency in the documents over time, having
uppercase next owner names in the NSEC records may cause validation
failures if validators are not implementing RFC 6840.
Also, RFC 4034 section 6.2 is not about how NSEC record content is
created, but how RRset content is normalized in order to produce and
validate RRSIG records for a given RRset. Since the next owner name
of the NSEC record is about ordening, and the canonical DNS name order
requires that uppercase US-ASCII letters must be treated as if they
were lowercase US-ASCII letters, case is not meaningful for NSEC
next owner names, as it cannot be compressed on the wire, so we may
lowercase the next owner name in the NSEC rdata before signing, being
more kind to validators.
Andoni Duarte [Fri, 23 Jan 2026 11:33:53 +0000 (11:33 +0000)]
chg: ci: Use a small always-on runner for lightweight CI jobs
Some CI jobs spend more time pulling the docker image and setting up their environment than running the script. This MR adds a tag `smalljob` to jobs considered lightweight in order to run them on a dedicated small VM.
Merge branch 'andoni/try-small-vm-for-lightweight-ci-jobs' into 'main'
Move CI stage "other-checks" right after "quick-checks"
Move CI stage "other-checks" right after "quick-checks" and get the jobs
in it as close to each other as possible in .gitlab-ci.yml.
Since no job is allowed to depend (via "needs") on any job that is
assigned to a stage later than its own, move the "tsan:stress" and
"gcov" jobs to the "system" stage.
Rename the "postcheck" stage to "other-checks" in CI
Rename the "postcheck" CI stage to the more generic "other-checks".
Slower jobs that still run in autoscaled runners belong here, as opposed
to the lightweight ones in "quick-checks".
Rename the "precheck" stage in CI to "quick-checks"
Most jobs in the "precheck" stage spend more time setting up their
environment than running the script (seconds), this allows us to add a
small always on dedicated runner instead of the autoscaled ones.
Hence, the stage is renamed to "quick-checks", and a tag "smalljob" is
added to the anchor so that these jobs are picked by the dedicated
runner.
Andoni Duarte [Thu, 22 Jan 2026 18:40:33 +0000 (18:40 +0000)]
fix: ci: Read the Docs picking old version when stable tag is updated
Read the Docs fails to pick the latest version when updating the `stable` tag, i.e. a build is triggered but it takes the previous version of it. This is a known bug in RtD: https://github.com/readthedocs/readthedocs.org/issues/10838.
The only approach that seems to solve this on our end, is to wait some time and trigger the build again so that it picks the latest version of the tag.
Merge branch 'andoni/fix-rtd-picking-old-version-when-stable-branch-update' into 'main'
Read the Docs fails to pick the latest version of the stable tag when
updated, i.e. a build is triggered but it takes the previous version.
This commit triggers a second build after 5 minutes to ensure that the
correct tag version is used for the documentation.
This is a known bug in RtD:
https://github.com/readthedocs/readthedocs.org/issues/10838.
Colin Vidal [Mon, 19 Jan 2026 14:52:30 +0000 (15:52 +0100)]
resolver: add comment when recursing
When a fetch result gets a delegation, `rctx_referral()` sets the
`rctx->get_nameserver = true`, which tells the resolver to retry another
server, not because of an error with the current server, but simply to
follow the delegation.
Update the comment of `rctx_nextserver()` which is quite confusing here
(as it's not immediately obvious from the code how we recurse when
getting a delegation back from a query).
Also add a log line, which helps figuring out this is happening.
Colin Vidal [Mon, 19 Jan 2026 12:46:03 +0000 (13:46 +0100)]
fix resolver query response doc
In case on positive response, the `rctx_authority_positive()` function
is called to scan the AUTHORITY section to find NS servers and related
RR (glues) to be cached.
The doc says the function was called `rctx_authority_scan()`, but it is
called `rctx_authority_positive()`.
Nicki Křížek [Wed, 21 Jan 2026 15:11:25 +0000 (16:11 +0100)]
chg: pkg: Update requirements for system test suite
Python 3.10 or newer is now required for running the system test suite. The required python packages and their version requirements are now tracked in `bin/tests/system/requirements.txt`.
Support for pytest 9.0.0 has been added its minimum supported version has been raised to 7.0.0. The minimum supported dnspython version has been raised to 2.3.0.
Nicki Křížek [Tue, 30 Dec 2025 12:36:41 +0000 (13:36 +0100)]
Prefer Python 3.12 if available
This ensures that python3.12 is used testing on older distributions
like EL8 and EL9, where the platform default python3 is older.
python3.11 was explicitly added due to FreeBSD, which doesn't have that
binary symlinked to any other name (like python3). Previously, it worked
only incidentally - when python3 was listed first, it triggered special
meson code for python detection, which is no longer the case when
python3.12 is listed first.
Nicki Křížek [Tue, 30 Dec 2025 12:45:50 +0000 (13:45 +0100)]
Bump the minimum required python version to 3.10
Drop support of EoL python versions for running system tests. The
maintenance cost of supporting end of life ecosystem, especially Python
3.6 on EL8 and the related outdated packages (pytest, dnspython, ...),
has become unreasonable.
Nicki Křížek [Tue, 16 Dec 2025 17:27:20 +0000 (18:27 +0100)]
Add requirements.txt for system tests
This file lists the required Python packages and versions for running
system tests. The easiest way to obtain them is:
pip install -r requirements.txt
The minimum dnspython version is 2.7.0 because it supports TSIG parsing
without validation (for tsig/tests_tsig_hypothesis.py) and wire() (for
names/tests_names.py).
The minimum pytest version was bumped to 7.0.0 because it supports the
collection hook API required by pytest 9.
The minimum hypothesis version was set to 4.41.2 as prior versions might
have issues on FIPS systems.
Arаm Sаrgsyаn [Wed, 21 Jan 2026 10:47:31 +0000 (10:47 +0000)]
fix: dev: Fix a bug in qpzone.c:first_existing_header_indirect()
There is a bug in qpzone.c:first_existing_header_indirect() where
it does not advance the pointer in the FOREACH type loop.
Remove the static function altogether, as it was used only once and
had some other problems too, and use simpler custom code instead in
the place where it was used.
Closes #5691
Merge branch '5691-qpzone.c-first_existing_header_indirect-fix' into 'main'
Aram Sargsyan [Tue, 20 Jan 2026 16:20:35 +0000 (16:20 +0000)]
Add a new dbversion unit test
Test that closing a writer with a rollback, then opening another
writer and adding a rdataset (while still holding the node reference)
works correctly.
This test checks that the bugfix in the previous commit is correct.
Aram Sargsyan [Fri, 16 Jan 2026 14:07:39 +0000 (14:07 +0000)]
Remove qpzone.c:first_existing_header_indirect() which had bugs
The first_existing_header_indirect() static function is used only
in one place and it has bugs:
1. It doesn't advance the pointer and can cause an infinite loop
if it doesn't break out from the loop on the first iteration.
2. It doesn't check if the header EXISTS, though its name indicates
that it should.
3. Even if the infinite loop bug is fixed, it would eventually
return the last checked header's pointer even if all the
candidates do not match the criteria of the selection.
Instead of fixing it, remove the function and use simpler code in
the place where it was being called.
Mark Andrews [Fri, 19 Dec 2025 01:32:33 +0000 (12:32 +1100)]
Use const pointer with strchr of const pointer
C23 now has qualifier preserving standard functions for strchr,
bsearch, strpbrk, strrchr, strstr, memchr. There where a few places
where the return value was not assigned to a const qualified pointer.
These have been fixed.
Colin Vidal [Fri, 16 Jan 2026 07:29:45 +0000 (08:29 +0100)]
chg: dev: remove `sigrdataset` from `dns_view_findzonecut()`
Since the `sigrdataset` "output" parameter of `dns_view_findzonecut()` is never used (always called with NULL), it is now removed. As the resolver is moving towards a parent-centric direction, there is no point having a signature for the NS record (which is not authoritative in the parent, so never signed) when `dns_view_findzonecut()` is called.
Also, rename `dns_view_findzonecut()` as `dns_view_bestzonecut()` as it is used only in the context where the closest name servers for a name need to be queried and to avoid ambiguities with other code flows using `dns_db_findzonecut()`.
Merge branch 'colin/findzonecut-removesig' into 'main'
Colin Vidal [Mon, 12 Jan 2026 08:23:01 +0000 (09:23 +0100)]
rename `dns_view_findzonecut()` into `dns_view_bestzonecut()`
`dns_view_findzonecut()` is used only in the context where the closest
name servers for a name need to be queried. In the future, this API
will also return the glues (if known) for those name servers, as well
as (exclusively, if both NS and DELEG exist) the DELEG record.
To avoid ambiguities with other code flows using `dns_db_findzonecut()`,
`dns_view_findzonecut()` has been renamed into `dns_view_bestzonecut()`.
Colin Vidal [Fri, 9 Jan 2026 14:47:52 +0000 (15:47 +0100)]
remove `sigrdataset` from `dns_view_findzonecut()`
Since the `sigrdataset` "output" parameter of `dns_view_findzonecut()`
is never used (always called with NULL), it is now removed.
Also, since the resolver is moving towards a parent-centric direction,
there is no point having a signature for the NS record (which is not
authoritative in the parent, so never signed) in the contextes where
`dns_view_findzonecut()` is called.
Arаm Sаrgsyаn [Thu, 15 Jan 2026 17:50:33 +0000 (17:50 +0000)]
fix: test: Fix a false positive compiler warning/error
When built with '-Doptimization=1', GCC produces a compiler warning:
In file included from ../lib/isc/include/isc/lib.h:44,
from ../tests/dns/qp_test.c:26:
../tests/dns/qp_test.c: In function ‘check_predecessors_withchain’:
../lib/isc/include/isc/util.h:182:33: error: ‘ival’ may be used uninitialized [-Werror=maybe-uninitialized]
182 | (((a) == (b)) ? (void)0 : (_assert_int_equal(a, b, f, l), abort()))
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/cmocka.h:1234:5: note: in expansion of macro ‘_assert_int_equal’
1234 | _assert_int_equal(cast_to_largest_integral_type(a), \
| ^~~~~~~~~~~~~~~~~
../tests/dns/qp_test.c:859:18: note: ‘ival’ was declared here
859 | uint32_t ival;
| ^~~~
This is apparently a false positive, because the qpiter_prev_with_name()
function, when returning ISC_R_SUCCESS, sets the 'ival' (passed to
it by a pointer), and the caller checks that the return value is
ISC_R_SUCCESS before using 'ival'.
Initialize the 'ival' variable to 0 anyway to avoid the build error.
Closes #5704
Merge branch '5704-qp_test-uninitialized-false-positive-error-fix' into 'main'
Aram Sargsyan [Thu, 15 Jan 2026 11:26:47 +0000 (11:26 +0000)]
Fix a false positive compiler warning/error
When built with '-Doptimization=1', GCC produces a compiler warning:
In file included from ../lib/isc/include/isc/lib.h:44,
from ../tests/dns/qp_test.c:26:
../tests/dns/qp_test.c: In function ‘check_predecessors_withchain’:
../lib/isc/include/isc/util.h:182:33: error: ‘ival’ may be used uninitialized [-Werror=maybe-uninitialized]
182 | (((a) == (b)) ? (void)0 : (_assert_int_equal(a, b, f, l), abort()))
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/cmocka.h:1234:5: note: in expansion of macro ‘_assert_int_equal’
1234 | _assert_int_equal(cast_to_largest_integral_type(a), \
| ^~~~~~~~~~~~~~~~~
../tests/dns/qp_test.c:859:18: note: ‘ival’ was declared here
859 | uint32_t ival;
| ^~~~
This is apparently a false positive, because the qpiter_prev_with_name()
function, when returning ISC_R_SUCCESS, sets the 'ival' (passed to
it by a pointer), and the caller checks that the return value is
ISC_R_SUCCESS before using 'ival'.
Initialize the 'ival' variable to 0 anyway to avoid the build error.
Štěpán Balážik [Tue, 23 Dec 2025 13:36:56 +0000 (14:36 +0100)]
Add SwitchControlCommand for ControllableAsyncServer
To provide feature parity with `bin/tests/system/ans.pl` add a control
command to allow easy switching between different sequences of
ResponseHandlers.
Štěpán Balážik [Wed, 17 Dec 2025 13:08:03 +0000 (14:08 +0100)]
Use variadic positional parameters for plural install_* methods
It saves an indent and brackets on the call sites.
Also sort the handlers alphabetically where their order doesn't matter
and split the fallback handlers into a separate call to signify that
their position in the end matters.
Aram Sargsyan [Thu, 25 Dec 2025 12:25:48 +0000 (12:25 +0000)]
Make catalog zones' entry names case-insensitive
Previously, the isc_ht hash table module was case-sensitive, but now
it supports case-insensitive mode. Use the case-insensitive mode
for the catalog zones' entry names.
Aram Sargsyan [Fri, 19 Dec 2025 17:51:08 +0000 (17:51 +0000)]
Make catalog zone names case-insensitive
Previously, the isc_ht hash table module was case-sensitive, but now
it supports case-insensitive mode. Use the case-insensitive mode
for catalog zone names.
Nicki Křížek [Fri, 28 Nov 2025 15:41:44 +0000 (16:41 +0100)]
Replace digdelv/ans8 with AsyncDnsServer
Previously, the ans8 server had different response modes that applied to
all queries. Replace it with AsyncDnsServer that has serves the different
response modes under different domains without the need to change the
server behaviour at runtime.
Add the new queries that require an ns3 fallback to the ns3/example.db
zone.
Nicki Křížek [Fri, 28 Nov 2025 15:13:43 +0000 (16:13 +0100)]
Replace digdelv/ans5 with ControllableAsyncDnsServer
The server has three modes of operation - either no response, a partial
AXFR or a complete AXFR. To test the fallback behaviour of dig, these
actions are be combined in a specific sequences. To set up the desired
server behaviour, use the _control queries for the server.
Nicki Křížek [Fri, 28 Nov 2025 14:34:38 +0000 (15:34 +0100)]
Rename ResponseDropAndCloseConnection action
The action can be used to close the connection even after some response
was sent, depending on the ordering of actions in the handler that uses
it. Rename it to CloseConnection to use a more fitting name.
Štěpán Balážik [Fri, 9 Jan 2026 15:22:31 +0000 (15:22 +0000)]
chg: test: Avoid sending manually created responses in asyncserver
If at all possible, all the responses should be created by
AsyncDnsServer's internal methods. To ensure this, mark them with a
magic attribute and check it on send and crash the server if a manually
created response is detected.
Merge branch 'stepan/avoid-using-hand-rolled-responses-in-asyncserver' into 'main'
Štěpán Balážik [Fri, 2 Jan 2026 19:36:29 +0000 (20:36 +0100)]
Avoid sending manually created responses in asyncserver
If at all possible, all the responses should be created by
AsyncDnsServer's internal methods. To ensure this, mark them with a
magic attribute and check it on send and crash the server if a manually
created response is detected.
Fix the qmin test server which uses `make_response`.
Colin Vidal [Thu, 8 Jan 2026 20:01:22 +0000 (21:01 +0100)]
chg: dev: Split and refactor dns_view_findzonecut()
The function `dns_view_findzonecut()` was previously a complex bit of code (multiple pages long with multiple gotos and mutating states) into a simpler main entry point making explicit the various steps and layers involved into the delegation lookup.
Separate helper functions are added for specific sub-tasks (lookup from the zones, from the cache, deciding which result to use if there are valid candidates from the zone or cache, etc.)
Finally, the range of result values returned by `dns_view_findzonecut()` is simplified and clearly specified. This simplifies a bit the callers code.
See #5681
Merge branch 'colin/refactor-findzonecut' into 'main'
Colin Vidal [Wed, 17 Dec 2025 14:27:39 +0000 (15:27 +0100)]
simplify usage of dns_view_findzonecut()
As `dns_view_findzonecut()` only returns either ISC_R_SUCCESS or
DNS_R_NXDOMAIN, and since it automatically disassociates the rdatasets
in case of failure, some call sites are simplified.
Colin Vidal [Tue, 16 Dec 2025 13:24:41 +0000 (14:24 +0100)]
findzonecut: helper function to choose zone or cache
When a delegation is found at a zone level, the cache is also looked up,
in case a more specific delegation is found. If it is, then the records
from the zone are disassociated and then associated with those from the
cache.
There is no return value, because even if the cache lookup fails, there
is a valid delegation from the zone, so this is a success either way.
The main function `dns_view_findzonecut()` is also strongly refactored,
as `findzonecut_zoneorcache()` allows a sequential flow between the
various DB lookup attempts, instead of jumping back to the begining of
the lookup code using `goto`.
From the caller's point of view, the API is slightly simplified: the
return value can only be ISC_R_SUCCESS (a delegation is found) or
DNS_R_NXDOMAIN (no delegation is found). Also, if no delegation is
found, this guarantees that the rdatasets passed as parameter are
disassociated.