Ondřej Surý [Fri, 5 Dec 2025 11:29:32 +0000 (12:29 +0100)]
In dns_qpiter_{prev,next}, defer dereference_iter_node call
dns_qpiter_{prev,next} requires the current iterator node to still be
valid which might not always the case after dereference_iter_node was
called. Currently, this is ensured via closeversion() mechanism, but it
is not guaranteed to be true in the future.
Move the call to dereference_iter_node to after the dns_qpiter_prev()
and dns_qpiter_next() to prevent a possible use-after-free of the
current iterator node.
Aram Sargsyan [Tue, 25 Nov 2025 18:30:20 +0000 (18:30 +0000)]
Fix a bug in dns_catz_generate_zonecfg()
The dns_catz_generate_zonecfg() function generates a zone configuration
string to use with a new catalog zone member zone. The buffer for the
string is 512 bytes initially (ISC_BUFFER_INCR), but can be reallocated
when required, when using corresponding isc_buffer functions like
isc_buffer_reserve(), isc_buffer_putstr(), isc_buffer_copyregion(), etc.
However, the dns_name_totext() function, which expects the buffer as an
argument, doesn't automatically resize it if the name doesn't fit there,
but instead just returns ISC_R_NOSPACE.
The chance of this occurring increases when the configuration string is
large due to, for example, long zone name, long list of primary servers
which have keys configured and/or TLS configured.
Use dns_name_format() accompanied with isc_buffer_putstr() instead of
dns_name_totext().
Ondřej Surý [Mon, 8 Dec 2025 18:23:58 +0000 (19:23 +0100)]
chg: dev: Create list of dirty headers that needs cleaning
Instead of just flagging the qpcache node to be dirty, add the headers
to be cleaned to the dirty list and when cleaning the node, only walk
through the dirty node, not all the headers in the node.
Merge branch 'ondrej/optimize-qpcache-dirty-cleaning' into 'main'
Ondřej Surý [Tue, 28 Oct 2025 22:11:37 +0000 (23:11 +0100)]
Create list of dirty dirty headers that needs cleaning
Instead of just flagging the qpcache node to be dirty, add the headers
to be cleaned to the dirty list and when cleaning the node, only walk
through the dirty node, not all the slabtops.
Nicki Křížek [Mon, 8 Dec 2025 17:46:55 +0000 (18:46 +0100)]
new: test: Add FEATURE_* environment variables to system tests
The purpose of these variables is to be able to detect feature support
without calling feature-test. This becomes useful when detecting feature
support in jinja2 templates.
Merge branch 'nicki/featurest-system-test-env' into 'main'
Nicki Křížek [Tue, 2 Dec 2025 16:37:31 +0000 (17:37 +0100)]
Add FEATURE_* environment variables to system tests
The purpose of these variables is to be able to detect feature support
without calling feature-test. This becomes useful when detecting feature
support in jinja2 templates.
Nicki Křížek [Mon, 8 Dec 2025 15:14:11 +0000 (16:14 +0100)]
new: test: Regex support for logs and cmd output in pytest
Improve and unify the handling of regular expressions when searching in logs, files and command output in system tests.
- Use `Re()` for constructing regular expressions, which is an imported shorthand for `re.compile()` (imported as `from re import compile as Re`
- Add new `isctest.text.Text` interface which is a text wrapper that supports the `in` operator for line matching operation for both strings and regular expressions, e.g.:
- `assert "running" in ns1.log`
- `assert Re("a.example..*10.0.0.1") in response.out`
- Use the new `isctest.text.Text` for:
- `isctest.run.cmd()` output, where `.out` and `.err` can be used for stdout and stderr contents
- `NamedInstance.log` rather than the previous log interface (`.expect()` and `.prohibit()` is no longer available or needed. The `in` operator along with an `assert` statement can be used now instead.)
- `NamedInstance.rndc()` output, which returns identical output as `isctest.run.cmd()`
Nicki Křížek [Thu, 23 Oct 2025 13:08:35 +0000 (15:08 +0200)]
Refactor NamedInstance.rndc() to use EnvCmd() interface
To unify the command handling, utilize EnvCmd() to handle rndc commands:
1. Remove isctest.rndc abstractions. They were intended for an upcoming
python-only implementation. A couple of years later, it doesn't seem
to be coming any time soon, so let's stick with the interface that
makes sense today, i.e. use the same command handling interface
everywhere.
2. Remove the specialized rndc.log in favor of the generic logging
already implemented by isctest.run.cmd(). I believe the cause of the
many rndc(log=False) invocations was that nobody wanted this extra
file. Yet, logging everything by default makes sense for debugging,
unless there's a good reason not to. In almost all cases, logging was
switched to the default (enabled).
3. With the NamedInstance.rndc() call now returning CmdResult rather
than combined stdout+stderr string, adjust all the invocations to use
`.out` or `.err` as necessary.
4. Replace some manual rndc invocation and its base argument
construction with the standardized nsX.rndc() call.
5. In cases where rndc is expected to fail, utilize
raise_on_exception=False and check the `.rc` from the result, rather
than handling an exception.
6. In addzone/tests_rndc_deadlock.py, refactor the test slightly to
avoid using EnvCmd() entirely to avoid spamming the logs. This test
calls rndc in a loop from multiple threads and such test case is an
exception which doesn't warrant changing the `isctest.run.cmd()`
implementation.
Nicki Křížek [Thu, 23 Oct 2025 10:36:56 +0000 (12:36 +0200)]
Add generic isctest.run.EnvCmd helper to pytest
A generic helper that calls the environment-specified binaries in a
developer-friendly manner, i.e. passing arguments as strings rather than
having to split them first.
The isctest.run.cmd() remains as the basis which provides a clean and
robust interface, while the isctest.run.EnvCmd() can be used as a
convenient wrapper for tests, or when there are some shared default
parameters.
The isctest.run.Dig() is superseded with the isctest.run.EnvCmd(). In
the future, we might revisit adding Dig() or command-specific helpers
again, but it probably only makes sense if they offer command-aware
attributes / methods, rather than just being shortcuts to
isctest.run.EnvCmd().
Nicki Křížek [Thu, 2 Oct 2025 15:06:25 +0000 (17:06 +0200)]
Refactor LogFile into TextFile with Grep support
Add a new Grep-like interface which can be used for searching for
regular expressions in files. Replace the prior LogFile used for named
logs with the new TextFile interface.
Nicki Křížek [Thu, 2 Oct 2025 10:05:27 +0000 (12:05 +0200)]
Move text-related operations into isctest.text module
Add a new module for working with text and keep the isctest.log.watchlog
module focused on its purpose. Move LogFile and LineReader into the new
module. Add compile_pattern() helper which will be useful in subsequent
commits.
Nicki Křížek [Thu, 2 Oct 2025 09:47:56 +0000 (11:47 +0200)]
Use Re() for creating regular expressions
It's a fairly common pattern to use regular expression in our tests.
Instead of using the fairly verbose re.compile(), import that function
as Re() instead to allow for more brevity in the test syntax.
Ondřej Surý [Mon, 8 Dec 2025 09:20:19 +0000 (10:20 +0100)]
fix: usr: Adding NSEC3 opt-out records could leave invalid records in chain
When creating an NSEC3 opt-out chain, a node in the chain could be removed too soon, causing the previous NSEC3 being unable to be found, resulting in invalid NSEC3 records to be left in the zone. This has been fixed.
Closes #5671
Merge branch '5671-fix-dbiterator-prev' into 'main'
Ondřej Surý [Fri, 5 Dec 2025 11:29:32 +0000 (12:29 +0100)]
In dns_qpiter_{prev,next}, defer dereference_iter_node call
dns_qpiter_{prev,next} requires the current iterator node to still be
valid which might not always the case after dereference_iter_node was
called. Currently, this is ensured via closeversion() mechanism, but it
is not guaranteed to be true in the future.
Move the call to dereference_iter_node to after the dns_qpiter_prev()
and dns_qpiter_next() to prevent a possible use-after-free of the
current iterator node.
Mark Andrews [Mon, 8 Dec 2025 08:39:21 +0000 (19:39 +1100)]
fix: usr: Missing unlock
'kasp->lock' was not released before returning. This could result in
named locking up if 'dns_keymgr_status' fails when 'rndc dnssec -status'
is called.
Colin Vidal [Sat, 6 Dec 2025 08:25:26 +0000 (09:25 +0100)]
chg: dev: Shrunk cfgobj down from 48 bytes to 40 bytes
Follow-up of 38ce2906 as the size of the `cfg_obj_t` can actually goes
down to 40 bytes "for free", by using bitfields to only use 31 bits for
the `line` field, so the remaining bit can be use to hold the `cloned`
state without paying the extra 8 bytes padding.
Colin Vidal [Fri, 5 Dec 2025 21:02:36 +0000 (22:02 +0100)]
shrunk cfgobj down from 48 bytes to 40 bytes
Follow-up of 38ce2906 as the size of the `cfg_obj_t` can actually goes
down to 40 bytes "for free", by using bitfields to only use 31 bits for
the `line` field, so the remaining bit can be use to hold the `cloned`
state without paying the extra 8 bytes padding.
A manual rollover when the zone is in an invalid DNSSEC state causes predecessor keys to be removed too quickly. Additional safeguards to prevent this have been added. DNSSEC records will not be removed from the zone until the underlying state machine has moved back into a valid DNSSEC state.
Closes #5458
Merge branch '5458-safeguard-against-key-rollovers-when-in-invalid-state' into 'main'
The manykeys test case relies on keys being removed. Make sure the
zone is fully signed with the keys that will stay, so the other keys
may be removed safely.
This means the expected number of signatures generated and refreshed
will change. The CDS and CDNSKEY RRset also need to be signed now.
Configure the test case with sig-signing-signatures 100, large enough
that the entire zone is processed in a single step.
The nsec3 system test has a couple of cases where the configured policy
changes the algorithm, effectively triggering an algorithm rollover. Fix
those cases to start in a valid DNSSEC state. Then fix the expected key
states, no longer should the old algorithm be removed immediately.
When creating keys, set Publish and Activate times so that keys will
be initialized as omnipresent. This way we start with a safe DNSSEC
state. In most cases at least, because some tests depend on special
key timings.
The ttl[1-4].example cases have become incorrect. With dnssec-policy
we require the TTL to match the dnskey-ttl from the policy.
The delzsk.example will have a ZSK removed from the zone. It also
requires that the DNSKEY RRset is already published. This means
that for the existing keys the, no longer "is now published"
messages will be logged.
The nsec-only.example and reconf.example zones are fixed to have a
correct matching policy.
This all means the expected count of log messages changes slightly.
This test case enables DNSSEC and has a mismatch in policy. Fix the
policy so that it matches the existing key set, and adjust the
expected answer count because no longer a new key is generated.
If the keymgr state machine is in an invalid state, it tries to move
it self to a valid state. But when you do key rollovers during an
invalid state, and the next state is also an invalid state, the keymgr
will happily do the transition.
It would be good to not do key rollovers if there is not a KSK and ZSK
fully omnipresent. But also it would be good to safeguard against
unexpected transitions.
This commit does that by not moving things to unretentive (which is
the state where we would remove the corresponding record from the zone)
if the state machine is currently in an invalid state.
Colin Vidal [Fri, 5 Dec 2025 08:35:58 +0000 (09:35 +0100)]
chg: dev: Shrunk cfgobj down from 72 bytes to 48 bytes
Make all non-scalar properties of `cfg_obj_t` allocated values, which
ensures the union size is the width of one pointer. Also reorder the
fields inside `cfg_obj_t` to avoid alignment padding that would increase
the size. As a result, a `cfg_obj_t` instance is now 48 bytes on a
64-bit platform.
Add a static assertion to avoid increasing the size of the struct by
mistake.
The function `parse_sockaddrsub` was taking advantage of the fact that
both sockaddr and sockaddrtls were in the same position, and used to
initialize the sockaddr field independently if this was a -tls one or
not. This doesn't work anymore now that all fields are allocated,
so it has been slightly rewritten to take both cases into account
separately.
Colin Vidal [Fri, 7 Nov 2025 13:58:36 +0000 (14:58 +0100)]
shrunk cfgobj down to 48bytes
Make all non-scalar properties of `cfg_obj_t` allocated values, which
ensures the union size is the width of one pointer. Also reorder the
fields inside `cfg_obj_t` to avoid alignment padding that would increase
the size. As a result, a `cfg_obj_t` instance is now 48 bytes on a
64-bit platform.
Add a static assertion to avoid increasing the size of the struct by
mistake.
The function `parse_sockaddrsub` was taking advantage of the fact that
both sockaddr and sockaddrtls were in the same position, and used to
initialize the sockaddr field independently if this was a -tls one or
not. This doesn't work anymore now that all fields are allocated,
so it has been slightly rewritten to take both cases into account
separately.
Colin Vidal [Thu, 4 Dec 2025 15:42:42 +0000 (16:42 +0100)]
chg: dev: Remove memory context form `cfg_obj_t`
Removes the `cfg_obj_t` memory context pointer, as the parser always uses `isc_g_mctx`. This simplifies the parser API/configuration tree API (no need to pass the memory context); and the `cfg_obj_t` size goes down from 80 bytes to 72 bytes.
While not directly related to the changes, also remove the `cfg_parser_t` `references` field as it is not used anymore (since the `cfg_obj_t` types doesn't reference it anymore).
Merge branch 'colin/remove-memctx-cfgobj' into 'main'
Colin Vidal [Thu, 4 Dec 2025 13:02:01 +0000 (14:02 +0100)]
document usage of BIND9 constructors/destructors
Document the way `__attribute__((__constructor__))` and
`__attribute__((__destructor__))` must be used in BIND9 libraries in
order to avoid unexpected behaviors with other third-party libraries.
Colin Vidal [Fri, 7 Nov 2025 17:56:39 +0000 (18:56 +0100)]
remove --memstats from cfg_test
The `--memstats` option from cfg_test is unused, and even if used, does
nothing because `--memstats` relies on `isc_mem_stats` which dump memory
pools statistics, which are not used at all for configuration.
Also, dropping the option avoid to add a parser API to get the memory
stats (as the parser now uses the global memory context).
Colin Vidal [Tue, 4 Nov 2025 09:49:40 +0000 (10:49 +0100)]
remove memory context from parser context
As the isccfg library now uses the global memory context, it is now
used directly instead of passing the parser context around to grab its
memory context.
Also remove the memory context from the parser, as well as from
`cfg_obj_t`, as it's now useless.
Colin Vidal [Mon, 3 Nov 2025 16:24:22 +0000 (17:24 +0100)]
parser: add cfg_string_create() API
The parser has a static function `create_string()` used
internally. But there was duplicate code to create a string node
in `namedconf.c`. Instead of implementing the same logic twice,
`create_string()` is now publicly exposed as `cfg_string_create()`.
Evan Hunt [Thu, 4 Dec 2025 03:15:12 +0000 (03:15 +0000)]
fix: dev: Standardize CHECK and RETERR macros
Previously, there were over 40 separate definitions of `CHECK` macros, of
which most used `goto cleanup`, and the rest `goto failure` or `goto out`.
There were another 10 definitions of `RETERR`, of which most were identical
to `CHECK`, but some simply returned a result code instead
of jumping to a cleanup label.
This has now been standardized throughout the code base: `RETERR` is for
returning an error code in the case of an error, and `CHECK` is for jumping
to a cleanup tag, which is now always called `cleanup`. Both macros are
defined in `isc/util.h`.
Evan Hunt [Thu, 16 Oct 2025 22:05:01 +0000 (15:05 -0700)]
use a standard CLEANUP macro
CLEANUP is a macro similar to CHECK but unconditional, jumping
to cleanup even if the result is ISC_R_SUCCESS. It is now used
in place of DST_RET, CLEANUP_WITH, and CHECK(<non-success constant>).
Evan Hunt [Wed, 21 May 2025 20:22:58 +0000 (13:22 -0700)]
standardize CHECK and RETERR macros
previously, there were over 40 separate definitions of CHECK macros, of
which most used "goto cleanup", and the rest "goto failure" or "goto
out". there were another 10 definitions of RETERR, of which most were
identical to CHECK, but some simply returned a result code instead of
jumping to a cleanup label.
this has now been standardized throughout the code base: RETERR is for
returning an error code in the case of an error, and CHECK is for jumping
to a cleanup tag, which is now always called "cleanup". both macros are
defined in isc/util.h.
Colin Vidal [Wed, 3 Dec 2025 15:26:22 +0000 (16:26 +0100)]
chg: dev: Add RRSIG if required as soon as they are found
When EDNS DO flag (`dig +dnssec`) flag is set, an rdataset is allocated
to hold the RRSIG of an RR, if present in DB. However, this allocation
is not done if the zone DB is not considered as secure
(`dns_db_issecure() == false`). Changes this behaviour by allocating the
rdataset anyway, so the RRSIG can be associated in the answer section of
the response as soon it is found from the DB.
The fact we attach the rrsig potentially more often (though it probably
occurs in edge cases) doesn't seems to affect performance in any ways:
Merge branch 'colin/rrsig-nonsecure-db' into 'main'
Colin Vidal [Tue, 2 Dec 2025 18:00:55 +0000 (19:00 +0100)]
test for RRSIG provided as soon as they are found
Add a system test which checks that a server authoritative on zone which
is not fully signed (here, it is missing the DNSKEY records as well as the
RRSIG on the RR `b`) still return the RRSIG associated with an RR if
provided in the zone.
Colin Vidal [Tue, 2 Dec 2025 15:53:40 +0000 (16:53 +0100)]
add RRSIG if required as soon as they are found
When EDNS DO flag (`dig +dnssec`) flag is set, an rdataset is allocated
to hold the RRSIG of an RR, if present in DB. However, this allocation
is not done if the zone DB is not considered as secure
(`dns_db_issecure() == false`). Changes this behaviour by allocating the
rdataset anyway, so the RRSIG can be associated in the answer section of
the response as soon it is found from the DB.
Arаm Sаrgsyаn [Wed, 3 Dec 2025 10:16:08 +0000 (10:16 +0000)]
fix: test: Fix an issue with unreachable cache's unit test
The isc_stdtime_now() function used by dns_unreachcache_find() to
check if the entry needs to be expired has a one-second resolution,
and the test sleeps for 1 second and then for the amount of the
expiration interval, which in a worst-case scenario can cause the
test to fail, because the entry was expected to be expired but it
wasn't. Sleep for 2 seconds instead of 1 to avoid the timing
resolution issue.
Closes #5601
Merge branch '5601-unreachable-cache-expire-test-fix' into 'main'
Aram Sargsyan [Thu, 6 Nov 2025 11:33:41 +0000 (11:33 +0000)]
Fix an issue with unreachable cache's unit test
The isc_stdtime_now() function used by dns_unreachcache_find() to
check if the entry needs to be expired has a one-second resolution,
and the test sleeps for 1 second and then for the amount of the
expiration interval, which in a worst-case scenario can cause the
test to fail, because the entry was expected to be expired but it
wasn't. Sleep for 2 seconds instead of 1 to avoid the timing
resolution issue.
Matthijs Mekking [Thu, 20 Nov 2025 13:10:45 +0000 (14:10 +0100)]
Wait for log zone_needdump is more reliable
In some cases we wait for the log message "sending notifies" before
proceeding with the test case. Notifies are rate limited. They are not
sent on every change to the zone. The "zone_needdump" messages happen on
every change.
Evan Hunt [Fri, 28 Nov 2025 19:07:48 +0000 (19:07 +0000)]
fix: dev: Pass isc_buffer_t pointers when applicable
In commit aea251f3bce7, `isc_buffer_reserve()` was changed to
take a simple `isc_buffer_t *` instead of `isc_buffer_t **`.
A number of functions calling it have now been similarly
modified.
Evan Hunt [Wed, 26 Nov 2025 07:23:19 +0000 (23:23 -0800)]
pass isc_buffer_t pointers when applicable
In commit aea251f3bce7, `isc_buffer_reserve()` was changed to
take a simple `isc_buffer_t *` instead of `isc_buffer_t **`.
A number of functions calling it have now been similarly
modified.
Matthijs Mekking [Fri, 28 Nov 2025 15:15:39 +0000 (15:15 +0000)]
chg: usr: Improve output of 'rndc dnssec -status'
Add a new parameter ``-v`` to the ``rndc dnssec -status`` command for more verbose output. Previously, key states were printed, and keys that can be purged were listed. This made the output hard to read. This information is now only shown in the verbose output.
Add more meaningful messages to the status output, making it clearer what the state of a rollover is.
This makes the output more condense, improving its readability.
Closes #3938
Merge branch '3938-improve-rndc-dnssec-status-output' into 'main'
Matthijs Mekking [Wed, 15 Oct 2025 14:04:28 +0000 (16:04 +0200)]
Change output of rndc dnssec -status
Wrap 'dns_keymgr_status()' in 'dns_zone_dnssecstatus()' so we can easily
retrieve the zone string name and refresh key time value.
In addition to the current time, output when the next key event is
expected.
Don't log keys that are completely hidden unless verbose is set.
Don't log key state values unless verbose is set, or they are in a
weird state.
For expected key states, log a more useful message of the stage of
the rollover. If we are in the middle of a key rollover, don't log
when the next key rollover is scheduled.
Matthijs Mekking [Wed, 26 Nov 2025 07:31:45 +0000 (08:31 +0100)]
Update misleading comments in multisigner test
We are not actually retrieving these records from the other provider,
they are available as key files to us and we are using those files
to send a dynamic update to the server.
Matthijs Mekking [Sun, 12 Oct 2025 09:49:00 +0000 (11:49 +0200)]
Convert model2.secondary test to pytest
This test is similar to model2.multisigner, but now the two providers
are both secondary, both using the same hidden primary. The DNSKEY,
CDNSKEY, and CDS records need to be published at the hidden primary,
ns5, the zone is transferred to both secondaries, ns3 and ns4.
To avoid intermittent test failures, we wait for the line
"zone {zone}/IN (signed): serial {serial2} (unsigned {serial1})" in
the secondary server logs. This is a signal that the unsigned zone
with serial <serial1> has a signed version ready with serial <serial2>.
Matthijs Mekking [Fri, 10 Oct 2025 16:02:58 +0000 (18:02 +0200)]
Update multisigner system test to set primary
When testing multi-signer as bump-in-the-wire (upcoming test), we want
to be able to do dynamically updates to a hidden primary. Update the
test functions such that we can set a specific primary server.
Matthijs Mekking [Fri, 10 Oct 2025 08:57:50 +0000 (10:57 +0200)]
Convert model2.multisigner test to pytest
This converts the model2.multisigner tests from the multisigner system
test to pytest based code. Crappy shell test functions such as
'zsks_are_published', 'records_published' and others are replaced with
the standard test code from isctest.kasp and by setting 'private=False'
and 'legacy=True' on the keys from the other providers so we don't do
any key file testing.
Ondřej Surý [Mon, 24 Nov 2025 09:06:51 +0000 (10:06 +0100)]
Provide more information when the memory allocation fails
Instead of just crashing when memory allocation fails, also print a
message saying "Out of memory!", the size of the allocation that failed,
total allocated memory from all memory contexts and value of errno.
Ondřej Surý [Fri, 28 Nov 2025 13:34:04 +0000 (14:34 +0100)]
fix: nil: Fix missing field 'merge' initializer for the new cfg_clausedef_t
In !11121, a .merge member was added to cfg_clausedef_t. This caused
a build failure with -Werror,-Wmissing-field-initializers enabled.
Add the missing initializer and set them all to NULL to match the
intent.
Merge branch 'ondrej/fix-compilation-on-macos' into 'main'
Ondřej Surý [Fri, 28 Nov 2025 10:38:41 +0000 (11:38 +0100)]
Fix missing field 'merge' initializer for the new cfg_clausedef_t
In !11121, a .merge member was added to cfg_clausedef_t. This caused
a build failure with -Werror,-Wmissing-field-initializers enabled.
Add the missing initializer and set them all to NULL to match the
intent.