Martin Basti [Tue, 21 Jul 2026 20:01:42 +0000 (20:01 +0000)]
fix: usr: dig +yaml producing invalid YAML when a lookup fails
When "dig +yaml" was run and no server could be reached, dig printed its plain-text startup banner (the "; \<\<\>\> DiG ..." and ";; global options" lines) ahead of the machine-readable output, so the result was not valid YAML and could not be parsed. dig no longer emits that banner in YAML mode. As part of the same change, the banner is now built only after the whole command line has been read, so options given after the query name (such as +nocmd, +short and +yaml) are correctly reflected in it.
Closes #1230
Merge branch '1230-dig-fix-error-comments' into 'main'
Martin Basti [Tue, 21 Jul 2026 13:49:00 +0000 (13:49 +0000)]
Test that +short does not leak the ";; " comments
Plain +short already turns lookup->comments off, so the regression it
guards against only surfaces with "+short +comments", where +comments
re-enables the comment toggle while short form is still in effect. The
existing silent-then-servfail scenario is reused because its retry path
reliably prints a "Got SERVFAIL reply from ..." comment; the +comments
case (without +short) is asserted first so the absence check is
meaningful.
Martin Basti [Wed, 15 Jul 2026 17:15:25 +0000 (19:15 +0200)]
Don't print dig's startup banner with +nocmd when the lookup fails
This only affects the failure path. On a successful lookup dig
reprints the banner and re-evaluates the final options as it does so,
so a late +nocmd is honored; but the "no servers could be reached"
error path prints the pre-built banner verbatim, without that
re-check, and that banner had been built too early to be correct.
printgreeting() was called the moment the first query name was seen,
so options appearing later on the command line (e.g. +[no]cmd, +short,
+yaml) were not yet in effect and the banner captured stale state.
That is why a failing "dig . soa @host +yaml" emitted the ";"-prefixed
banner ahead of the error, and why "+nocmd" placed after the query
name was ignored.
Martin Basti [Wed, 15 Jul 2026 16:58:39 +0000 (18:58 +0200)]
Suppress the dig startup banner in +yaml error output
The two "no servers could be reached" error paths printed the
lookup's startup banner (";"-prefixed "<<>> DiG ..." lines) ahead of
the "- type: DIG_ERROR" block. Those lines are not valid YAML, so
with +yaml the whole output failed to parse whenever every server was
unreachable. Guard the banner with the existing yaml flag, matching
how the successful path in printmessage() already gates it.
The isc_crypto_aead_open() and isc_crypto_aead_seal() functions
in ossl3.c didn't check if 'additional_data' exists before using
it. The checks were in place in the ossl1_1.c implementation. Use
the same conditions in the ossl3.c implementation too.
Additionally, the ciphertext length passed to the EVP_DecryptUpdate()
function included the tag length too which caused errors when decrypting.
Use the 'len' variable instead which doesn't include the tag length.
The ciphertext length passed to the EVP_DecryptUpdate() function
included the tag length too. Use the 'len' variable instead which
doesn't include the tag length.
The isc_crypto_aead_open() and isc_crypto_aead_seal() functions
in ossl3.c didn't check if 'additional_data' exists before using
it. The checks were in place in the ossl1_1.c implementation. Use
the same conditions in the ossl3.c implementation too.
The qpdb unit test intermittently aborts on the
`isc_mem_inuse(mctx) >= hiwater` assertion in the overmempurge tests
(#6267) and is not reliably reproducible. Extend the flaky-test retry
mechanism from tests/isc to tests/dns so CI re-runs qpdb before
declaring the job failed.
new: usr: Disclose active Negative Trust Anchors with Extended DNS Error 33
A Negative Trust Anchor (RFC 7646) turns off DNSSEC validation for a domain,
so a name that would normally fail validation resolves instead. named now
marks such answers with Extended DNS Error code 33, "Negative Trust Anchor",
so operators can see at a glance when a response came back only because
an NTA was in effect.
Test Negative Trust Anchor disclosure via Extended DNS Error 33
Extend the EDE unit test to cover the newly registered code 33 and to
verify it does not collide with lower codes in the used-code bitmap.
Add a resolver system test: a name whose validation is suppressed by a
Negative Trust Anchor is answered with EDE 33 present, while the same
name without an NTA still fails validation and carries no such error.
Disclose Negative Trust Anchors with Extended DNS Error 33
A Negative Trust Anchor (RFC 7646) makes a validating resolver treat an
otherwise-secure name as insecure, but there was no in-band way for a
client to tell that an answer which should have failed DNSSEC validation
was returned because an NTA was in place.
Register Extended DNS Error INFO-CODE 33, "Negative Trust Anchor"
(draft-farrokhi-dnsop-ede-nta), and attach it to a response whenever a
covering NTA suppresses validation for the queried name.
fix: usr: Resolver could return expired records instead of a negative answer
When an unvalidated negative answer (such as one obtained for
a query with the "checking disabled" flag set) arrived for
a name that had DNSSEC-validated records in the cache, those
records blocked the negative answer from being cached even
after they had passed their TTL, and the expired records could
be returned to the client instead. Validated records that have
expired no longer prevent negative answers from being cached.
Merge branch '5877-skip-inactive-headers' into 'main'
Test that an expired RRset does not block negative caching
Cover the inverse of the CD=1 NXDOMAIN guard: a validated RRset that
has passed its TTL, but has not yet been cleaned from the cache, must
not block the unvalidated negative entry. Before the fix the CD=1
query failed with SERVFAIL until the expired header was reaped.
Only active secure data should block negative cache entries
Expired secure headers linger in the node's header list until they
are reaped, so the secure-data check could match a header already
past its TTL, reject the new negative entry, and hand the expired
data back to the caller. Require the matching header to be active.
The authdb variable is used either to check that, on restarts, we
do not cross to a different zone unless recursion is enabled, and to
lookup the zone version when filling the additional section.
Neither use requires the pointer to be attached, and attaching the
pointer causes scalability issues. This commit solves the problem by
turning the pointer into an integer id.
Merge branch 'alessio/authdb-version-lookup' into 'main'
Previously query_validatezonedb would not save the current version of
mirror zones, which would cause the mirror zone not to be found when
non-glue additional data.
We fix this by storing the mirror zone version in the client, and
deferring the acl check in query_validatezonedb.
Returning isc_result_t is more idiomatic. Also, there was some shared
code between ns_client_findversionid and ns_client_findversion that
has now been extracted into an helper function.
The authdb variable is used either to check that, on restarts, we
do not cross to a different zone unless recursion is enabled, and to
lookup the zone version when filling the additional section.
Neither use requires the pointer to be attached, and attaching the
pointer causes scalability issues. This commit solves the problem by
turning the pointer into an integer id.
Mark Andrews [Thu, 16 Jul 2026 20:07:48 +0000 (06:07 +1000)]
fix: usr: Unterminated OpenSSL private-key `Label:` field can be read past its parser buffer
Check that the string encoded in the Label: field of the .private
file of a key pair is NUL terminated and the correct length. Reject
the .private file if it is not.
Closes #6193
Merge branch '6193-check-that-label-is-nul-terminated' into 'main'
Mark Andrews [Wed, 8 Jul 2026 01:18:44 +0000 (11:18 +1000)]
Malformed Label: data in .private files was not detected
Check that the string encoded in the Label: field of the .private
file of a key pair is NUL terminated and the correct length. Reject
the .private file if it is not.
Mark Andrews [Wed, 15 Jul 2026 23:36:30 +0000 (09:36 +1000)]
fix: nil: Extend meson.build to support python 3.13 and 3.14
The later releases of python are not supported by meson.build
requiring the built environment to maintain / install older
versions of python to be able build and test.
Merge branch 'marka-support-python-3.14' into 'main'
When adding a new key into a full list, the newly inserted key
could be evicted just after the insertion if all the existing
keys were marked as visited. This has been fixed.
Closes #6263
Merge branch '6263-tkey-quota-bug-fix' into 'main'
When adding a new key to the SIEVE list, make the eviction decision
first, and then add the new key, so that it doesn't get evicted
immediately after insertion.
The new check creates more TSIG keys than the maximum allowed number,
and expectes that all the newly created keys are findable just after
they were created. I.e., when full, the newly created key should not
evicted.
fix: test: Increase timeout for zone update in multisigner test
In slower platforms in CI (e.g. freebsd14), the 10s timeout could be too
short causing the test to fail. Increase it to make the test stable even
during heavy CI load.
Increase timeout for zone update in multisigner test
In slower platforms in CI (e.g. freebsd14), the 10s timeout could be too
short causing the test to fail. Increase it to make the test stable even
during heavy CI load.
fix: test: Extend the check_dnssec_verify retry window to 60 seconds
A fixed ten-iteration poll could be too short for a freshly signed
zone to become fully valid on a heavily loaded host, occasionally
yielding a spurious "zone not verified".
Bump the budget to a 60-second window and, in the process, replace the
hand-rolled retry loop with the standard isctest.run.retry_with_timeout
helper already used by check_next_key_event.
---
Example of the failure: https://gitlab.isc.org/isc-private/bind9/-/jobs/7773885
Merge branch 'nicki/widen-dnssec-verify-timeout' into 'main'
Extend the check_dnssec_verify retry window to 60 seconds
A fixed ten-iteration poll could be too short for a freshly signed
zone to become fully valid on a heavily loaded host, occasionally
yielding a spurious "zone not verified".
Bump the budget to a 60-second window and, in the process, replace the
hand-rolled retry loop with the standard isctest.run.retry_with_timeout
helper already used by check_next_key_event.
Catalog zones might need to inspect the change-of-ownership records
of other catalog zones, which required to release the lock in the
middle of certain operations, leading to possible race conditions.
Since the operations on change-of-ownership records are limited, we
can instead use a design with a second lock protecting the
change-of-ownership records on read. We structure the API so that
holding two change-of-ownership locks at the same time is impossible.
Closes #6131
Merge branch '6131-catz-dns__catz_zones_merge-uaf-fix-v2' into 'main'
Alessio Podda [Wed, 10 Jun 2026 13:24:06 +0000 (15:24 +0200)]
Split lock coos check design
Catalog zones might need to inspect the change-of-ownership records
of other catalog zones, which required to release the lock in the
middle of certain operations, leading to possible race conditions.
Since the operations on change-of-ownership records are limited, we
can instead use a design with a second lock protecting the
change-of-ownership records on read. We structure the API so that
holding two change-of-ownership locks at the same time is impossible.
fix: dev: Use correct port and target for NOTIFY(CDS)
If there is a DSYNC RRset with multiple records, and unsupported scheme/type records follow supported ones, the port and target of the last record were being used to queue the notify. This does not necessarily match the port and target of the supported record. This has been fixed.
Closes #6080
Merge branch '6080-dsync-mismatch-queue' into 'main'
Only save the DSYNC target and port when a record matches CDS NOTIFY,
then after scanning the complete RRset require count == 1 before using
the stored values.
Current system tests cover a mixed RRset in but the unsupported and
supported records use the same target and port, so the test does not
catch that the wrong port and target are being used for the supported
type.
Change the test such that the supported DSYNC record is followed
by the unsupported ones, and use different port and target for
supported and unsupported DSYNC records.
Mark Andrews [Tue, 14 Jul 2026 23:08:44 +0000 (09:08 +1000)]
fix: test: test-syncplugin treats firstlbl as a prefix, not an exact label
The label length and the string length where not being checked so
a label that started with a string that matched the skip label would
incorrectly match.
Closes #6212
Merge branch '6212-fix-syncplugin-test-driver' into 'main'
Mark Andrews [Wed, 8 Jul 2026 02:08:38 +0000 (12:08 +1000)]
Properly check test-syncplugin skip label for equality
The label length and the string length where not being checked so
a label that started with a string that matched the skip label would
incorrectly match.
Mark Andrews [Thu, 9 Jul 2026 04:47:28 +0000 (14:47 +1000)]
cdnxdomain test is failing on some platforms
Ensure the modification time is newer (second granuality) when the
zone file is rewritten as named uses the file modification time to
determine if it needs to reload a file.
Aydın Mercan [Thu, 12 Feb 2026 07:07:57 +0000 (10:07 +0300)]
clear the error stack at the end of fetching
Clearning the error stack at the very end will get rid of any other
optional fetch failures since fetch failures are treated as-if they are
unsupported by the provider.
Aydın Mercan [Thu, 12 Feb 2026 06:08:56 +0000 (09:08 +0300)]
add quic header protection to isc_crypto
QUIC uses a custom PRF construction to protect parts of the packet
header. This PRF is derived from the negotiated AEAD key and uses
unauthenticated encryption internally.
We do not expose the primitives underneath (AES-ECB and ChaCha20) as
they shouldn't be within the reach of contributors for their own safety.
Allowing such functionality to be used easily can only result it
problems not to dissimilar to leaving a baby with open bottles of
cleaning supplies.
Aydın Mercan [Mon, 9 Feb 2026 05:03:02 +0000 (08:03 +0300)]
add aead api to isc_crypto
The new AEAD API exists to cather to the needs for QUIC but is still
usable in other future contexts. Only AES-128-GCM, AES-256-GCM and
ChaCha20-Poly1305 are supported.
AES-128-CCM is intentionally skipped as the algorithm is neither
encountered in the wild nor has any useful advantages comapred to the
more popular AES-128-GCM mode.
Aydın Mercan [Tue, 3 Feb 2026 07:56:00 +0000 (10:56 +0300)]
add types compatible builtin
This builtin function makes macros gain type safety and also the ability
to statically assert the correctness of typedefs that target external
libraries.
Martin Basti [Tue, 14 Jul 2026 13:08:01 +0000 (13:08 +0000)]
fix: test: Replace python deprecated datetime utc functions
Functions `utcnow` and `utcfromtimestamp` are deprecated in python and
print warnings into tests logs about it.
Use the python prefered way by defining `timezone.utc` in `now` and
`fromtimestamp` functions. Which are equivalent but safer than naive
objects without timezone.
To ensure comptibility `%z` was added to format string to properly
process `Z` as UTC timezone.
Assisted-by: Claude Code:claude-opus-4-8[1m]
Merge branch 'mbasti/python-fix-deprecated-utcfromtimestamp' into 'main'
Martin Basti [Tue, 14 Jul 2026 09:09:10 +0000 (11:09 +0200)]
Replace python deprecated datetime utc functions
Functions `utcnow` and `utcfromtimestamp` are deprecated in python and
print warnings into tests logs about it.
Use the python prefered way by defining `timezone.utc` in `now` and
`fromtimestamp` functions. Which are equivalent but safer than naive
objects without timezone.
To ensure comptibility `%z` was added to format string to properly
process `Z` as UTC timezone.
Martin Basti [Tue, 14 Jul 2026 12:24:27 +0000 (12:24 +0000)]
new: usr: Built-in hints can be printed with named -H command
Additionally root hints were updated to precisely match authoritative source including comments. This is a cosmetic change IP addresses haven't been changed.
new: dev: Add development guidance for AI coding agents under .agents/skills/
This adds a set of skill documents that give AI coding agents the
project's established practices up front instead of having them
rediscovered (or gotten wrong) in every session: the canonical build
and test invocations, the memory-allocator contract, the disciplines
for RCU mutation, per-loop sharded structures, struct-layout work, and
flight-recorder debugging of concurrency bugs, plus the commit and
merge-request conventions.
Merge branch 'ondrej/add-agents-skills' into 'main'
Explain that MR titles and descriptions feed the generated release
notes, so agents must write them for system administrators: one short
paragraph in operational terms, no internal names or jargon, no
hand-written doc/notes/ entries, and bug framing rather than security
framing for local-filesystem misbehavior.
Walk agents through the full commit workflow: the git-clang-format
staging sequence, reason-focused messages hard-wrapped at 72 columns
with no type prefixes, the Assisted-by trailer and the forbidden ones,
amend and fixup discipline for HEAD and non-HEAD commits, and the rule
that agents commit locally and leave publishing to the user.
Capture the ownership-instead-of-locking pattern for per-loop sharded
structures: owner-only mutation under isc_tid() affinity, foreign
deletion as mark plus wait-free handoff of the exact entry to the
owner (never an O(shard) scan for marked entries), shard-held
references with bounded zombie lifetime, and eviction pressure spread
across shards instead of draining one before the next.
Point agents at pahole on the developer build's DWARF instead of
compiling throwaway sizeof programs, and document the cacheline-padding
idiom (union arm with a plain ISC_OS_CACHELINE_SIZE multiplier plus a
STATIC_ASSERT) over the enumerated-sizeof formula, which silently
miscounts when members are added.
Add the lttng-tracing-root-cause-analysis agent skill
Describe the LTTng flight-recorder methodology for concurrency bugs
that static reading, printf and debuggers all miss: small snapshot
buffers to keep timing faithful, a self-diagnosing violation tracepoint
followed by snapshot-and-abort, and the trace-reading patterns —
notably that a stale-read-after-write "paradox" indicates a missing
happens-before edge, not a timing problem.
Capture the build-invisible/publish/reclaim discipline for mutating
RCU-read structures: what makes a node observable (forward, backward
and secondary-index channels), why allocation failure must stay in the
invisible phase, publish-ordering rules for reader consistency, and the
anti-patterns (mutate-then-rollback, wiring clusters via read-side
recovery) that lead to use-after-free. Includes a worked
compressed-split example.
Condense the isc_mem/isc_mempool contract into agent guidance: the two
allocation families and why mixing them detonates the inuse INSIST at
context destroy, the pointer-NULLing put/free macros, water-mark and
striped-statistics behavior, ISC_MEM_DEBUG* facilities, and mempool
locking/ASAN caveats. Ends with a review checklist for allocation code.
fix: usr: Properly prevent TSIG generation command line injection attacks
When key names are generated with `rndc-confgen`, `tsig-keygen` and `ddns-confgen`, special characters must be escaped to ensure the configuration is parsed correctly.
Closes #6071
Merge branch '6071-allow-all-valid-keynames' into 'main'
Mark Andrews [Tue, 7 Jul 2026 01:02:34 +0000 (11:02 +1000)]
Update tests_rndc_confgen.py to show escaped double quotes
The old INJECTION string was failing due to not being a valid
DNS name providing a false assertion that injections where
no longer possible. Shorten it to fit in a single label then
check that it is properly escaped to prevent the injection attack.
Mark Andrews [Tue, 5 May 2026 01:54:35 +0000 (11:54 +1000)]
Allow all valid key names
TSIG keys names need to be able to be set to any valid name so that
update self rules can work for any valid name. Restore this ability
to the key generating tool while preventing rndc.conf and named.conf
from being compromised due to specially crafted key names.
Mark Andrews [Mon, 6 Jul 2026 02:59:50 +0000 (12:59 +1000)]
Add DNS_NAME_QUOTED flag for dns_name_totext()
Names that are to be printed within a pair of double quotes,
(for example, in named.conf), don't need spaces and special
characters to be fully escaped.
fix: usr: Ensure NSEC authority does not cross zonecut boundary
When using a cached NSEC record to prove that a delegation is insecure,
we now check that the signer name in the corresponding RRSIG is not
above a known secure delegation point. This prevents a signed namespace
from being downgraded to insecure using an NSEC record from the
grandparent zone.
Alessio Podda [Thu, 4 Jun 2026 14:40:03 +0000 (16:40 +0200)]
Add a system test for the grandparent NSEC downgrade
A resolver must not accept an NSEC or NSEC3 record signed by a zone
above a known secure delegation as proof that the delegation is
insecure. Otherwise anyone able to answer for the grandparent can
downgrade the signed namespace below it and serve forged, unsigned
records for any name in it.
Checking for SERVFAIL alone would not pin this down: a resolver that
rejects the forged proof but keeps walking down fails too, on the
unvalidatable answer it meets further along. The tests therefore
assert the refusal itself -- it is logged, and no DS query for a name
below the forged proof ever reaches the authoritative server -- and
they do so both for a proof fetched on demand and for one already in
the cache.
Evan Hunt [Fri, 22 May 2026 02:34:00 +0000 (19:34 -0700)]
Ensure NSEC authority does not cross zonecut boundary
When using a cached NSEC record to prove that a delegation is insecure,
we now check that the signer name in the corresponding RRSIG is not
above a known secure delegation point. This prevents a signed namespace
from being downgraded to insecure using an NSEC record from the
grandparent zone.
chg: dev: Pass the work callback result to the done callback
The `isc_work` callback now returns `isc_result_t` and the value is
handed to the done callback, so the callers no longer need their own
result-passing state.
Merge branch 'ondrej/pass-result-from-work-callback' into 'main'
Pass the work callback result to the done callback
The isc_work callback returned void, so every user that cared about
the outcome of the offloaded work had to smuggle it through its own
context state (xfrin_work_t, the catz/rpz updateresult fields, result
members in the dump/load/checksig contexts). Make the work callback
return isc_result_t and have isc_work deliver that value to the done
callback.
fix: usr: Prevent aborts during expired cache dumps
Running rndc dumpdb -expired could cause named to abort when the cache contained internal deletion markers for records that had already been removed. BIND now skips those markers when preparing expired cache dumps, so the dump includes only real cached records and completes normally.
Closes #6064
Merge branch '6064-skip-nonexistent-headers' into 'main'
Add a regression test that deletes a cached rdataset and then walks
all rdatasets with expired entries allowed. The iterator must report no
datasets for the deleted type rather than exposing the tombstone.
The cache rdataset iterator must never bind delete tombstones, even
when expired cache entries are requested for dumpdb. Treat non-existent
slab headers as inactive so expired dumps cannot expose headers without
a backing rdataslab.
Remove prereq.sh support from the system test runner
With every prereq.sh converted to pytest markers, the conftest
fixture no longer needs to locate and run a per-directory prereq.sh.
Drop check_prerequisites() and the README entry for the file.
The libxml2/json-c requirement becomes with_libxml2_or_json_c. The
stale Net::DNS check and the core-Perl File::Fetch check are dropped
rather than carried over.
Nicki Křížek [Tue, 30 Jun 2026 14:53:10 +0000 (14:53 +0000)]
Move Perl-module prereq.sh checks to pytest markers
fetchlimit and nsupdate still invoke ungated Perl helpers that
need Net::DNS (ditch.pl, packet.pl); reclimit and serve_stale
still run Perl ans.pl servers needing Net::DNS::Nameserver and
Time::HiRes. Replace the directory-scoped prereq.sh with new
runtime-probing markers applied only to the tests.sh wrappers
that actually run the Perl code -- native pytest modules in the
same directory (e.g. nsupdate) no longer skip when these modules
are absent.
fix: usr: Negative caching stopped working with stale-answer-client-timeout 0
With "stale-answer-client-timeout 0" configured, every client query for a
name cached as NXDOMAIN or NODATA was sent on to the authoritative servers,
even while the cached negative answer was still within its TTL, so the
resolver effectively lost negative caching. Negative answers are now
refreshed only once they have actually gone stale.
Closes #6245
Merge branch '6245-fix-query_stale_refresh_ncache' into 'main'
Test that a fresh negative cache entry is not refreshed
The existing serve-stale tests all use negative answers with a two
second TTL, because they are there to exercise stale data. Nothing
covered the far more common case of a negative answer that is still
fresh, which is how the needless refresh went unnoticed.
ans2 grows a NODATA and an NXDOMAIN name backed by a SOA with a 600
second TTL and MINIMUM, so the cached entry cannot go stale while the
test runs, and the test counts the queries that reach ans2: priming the
cache may send one, the repeated client queries must send none.
Only refresh negative cache entries that are actually stale
query_ncache() always passed a NULL rdataset to query_stale_refresh(),
which reads NULL as "this RRset is stale". NULL is only meaningful for
the DNS64 caller, whose rdataset has already been detached by the time
the answer is turned into an NXDOMAIN; everywhere else a perfectly fresh
negative cache entry was taken for a stale one.
With stale-answer-client-timeout 0 the staleness check is the only gate
left on the refresh, so every client query for a cached NXDOMAIN or
NODATA name started another fetch and negative caching stopped having
any effect.