dns__deleg_lookup() with DNS_DBFIND_NOEXACT is supposed to return
the deepest proper ancestor of the lookup name. It called
getparentnode() to step up from an exact match, but getparentnode()
only iterated while the chain length was >= 2. When the chain
contained a single entry (the exact match itself with no ancestor
stored in the trie), the loop did not execute and left the caller
looking at the exact match. The subsequent isactive() check then
returned success and the function reported the exact match as the
"deepest ancestor", violating NOEXACT semantics.
This was observable as the resolver picking the child-side
delegation for an at-parent type (e.g. a DS query for a TLD), then
sending the query to the child's own nameservers and recovering via
the "chase DS servers" path.
Have getparentnode() set '*node' to NULL when it cannot find an
active proper ancestor, and make dns__deleg_lookup() NULL-check
before returning, matching the canonical NOEXACT implementation in
dns_zt_find(). Update the deleg unit test to expect NOTFOUND for
the top-level-no-parent case.
When the validator needs a DS RRset and the cache does not have it,
get_dsset() falls back to creating a fresh fetch. Without a hint, the
resolver picks the closest known zone cut for the DS query, and in the
parent-centric resolver that can land on a delegation at the DS owner
name itself (the child side). This can happens when the parent
delegation is expired, or if the zonecut of the parent doesn't match the
labels in the name.
Querying the child for its own DS records yields NODATA from the apex of
the zone, which sends the resolver into the "chase DS servers" recovery
path and costs two extra round trips for a parent delegation we already
had cached in the delegation database.
Look up the parent zone in the delegation database before kicking
off the fetch, and pass any usable delegation to the resolver as a
hint. When the hint is present, the resolver sends the DS query
straight to the parent's nameservers and the chase path is avoided
entirely.
To support this, create_fetch() now takes optional 'domain' and
'delegset' parameters that are forwarded to dns_resolver_createfetch().
All other call sites pass NULL.
Copyright license headers were removed from system test zone files in
commit f144db6b68, but this change only applied to files named '*.db',
'*.db.in', etc. There were some zone files called '*.zone' which were
left unchanged; these have been updated now as well.
Merge branch 'each-cleanup-zonefiles' into 'main'
See merge request isc-projects/bind9!11853
Copyright license headers were removed from system test zone files in
commit f144db6b68, but this change only applied to files named '*.db',
'*.db.in', etc. There were some zone files called '*.zone' which were
left unchanged; these have been updated now as well.
Meson bakes the absolute path of the detected Python binary (e.g.
/usr/bin/python3.12) into the PYTHON build variable. When tests are run
from a virtualenv, that stored path might point to the system Python
which lacks the virtualenv's installed packages, causing test failures.
Fix this by checking whether the current process is running inside a
virtualenv (sys.prefix != sys.base_prefix) and, if so, replacing the
stored PYTHON build var with sys.executable — the interpreter that is
already running pytest and has all required dependencies available.
The behaviour on EL8/EL9 (where meson prefers python3.12 over the older
platform default) and on FreeBSD (python3.11) is unchanged, since those
workflows run pytest without an active virtualenv in our CI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a zone filename is defined in `named.conf` which will be
written to by the server - i.e., for secondary or dynamically updated
zones - there is a test at configuration time to ensure that the
filename is non-unique.
This test is run before the zone is actually created, so a zone
configured using a template may not have had its filename expanded
yet. This can cause a configuration to fail because, for example,
multiple zones appear to using the filename `$name.db`.
This has been fixed by adding a new function `dns_zone_expandzonefile()`
and calling it during the uniqueness check.
Merge branch 'each-template-file' into 'main'
See merge request isc-projects/bind9!11769
When a zone filename is defined in named.conf which will be
written to by the server - i.e., secondary or dynamically updated
zones - there is a test at configuration time to ensure that the
filename is non-unique.
This test is run before the zone is actually created, so a zone
configured using a template may not have had its filename expanded
yet. This can cause a configuration to fail because, for example,
multiple zones appear to using the filename "$name.db".
This has been fixed by calling dns_zone_expandzonefile() from
isccfg_check_zoneconf(), to expand the names when checking for
uniqueness.
This adds a new API call dns_zone_expandzonefie(), which will enable
named-checkconf to expand filenames the same way the server does in
dns_zone_setfile().
When processing a catalog zone member's primaries definition and
there is a TXT record containing an invalid name TSIG key name,
dns_name_free was incorrectly called triggering an assertion.
This has been fixed.
Closes#5858
Merge branch '5858-remove-unnecessary-dns-name-free-call' into 'main'
See merge request isc-projects/bind9!11832
When processing a catalog zone member's primaries definition and
there is a TXT record containing an invalid name TSIG key name,
dns_name_free was incorrectly called triggering an assertion.
This has been fixed.
The resolver can and will reuse outgoing TCP connections to the same host, as recommended by RFC 7766. This prevents a whole class of attacks that abuse the fact that establishing a TCP connection is expensive and it is fairly easy to deplete the outgoing TCP ports by putting them into TIME_WAIT state.
The number of pipelined queries per connection is capped at 256 to limit the impact of a connection drop.
Merge branch '3741-reuse-tcp-connections' into 'main'
See merge request isc-projects/bind9!11845
Move disptype and transport into dispatch_hash() and dispatch_match()
so that the match function is the single source of truth for whether
two TCP dispatches are interchangeable. This replaces the post-loop
disptype filter in dispatch_gettcp() and makes the disptype field in
struct dispatch_key actually used.
TCP dispentries no longer use the global QID hash table at all.
Responses are matched by scanning disp->active, and sequential
per-dispatch IDs (bounded by the pipelining limit) are unique
within a single dispatch by construction. Since TCP delivers
only data we asked for on a specific connection, the per-peer
uniqueness that the global table enforced was never actually
needed for TCP.
DNS_DISPATCHOPT_FIXEDID is plumbed through dns_request_createraw
-> get_dispatch -> dns_dispatch_createtcp so FIXEDID TCP requests
always get a fresh isolated dispatch — the caller-supplied ID
then cannot collide with any other in-flight query either.
Cap the number of in-flight queries on a single shared TCP dispatch.
When the limit is reached, the dispatch is removed from the hash
table so subsequent queries get a fresh connection. The existing
dispatch continues serving its queries until they complete.
This bounds the blast radius of a connection drop: at most N queries
fail simultaneously instead of all queries to that server.
The default limit is 256. It can be overridden for testing via
'named -T tcppipelining=N'.
Set tcppipelining=1 on recursive servers in the system tests to
restore one-query-per-connection behavior. The tests relies on
specific connection and query counting that breaks with TCP
connection sharing.
Previously, the user of dns_dispatch API had to first call
dns_dispatch_gettcp() and if that failed create a new TCP dispatch with
dns_dispatch_createtcp(). This has been changed and the TCP connection
reuse happens transparently inside dns_dispatch_createtcp(). There are
separate buckets for dns_resolver, dns_request and dns_xfrin units, so
these don't get mixed together.
The :iscman:`named` process could terminate unexpectedly or become
subject to undefined behavior when issued an :option:`rndc modzone`
operation for a non-existing zone. This has been fixed.
Closes#5848
Merge branch '5848-do_modzone-unlock-bug-fix' into 'main'
See merge request isc-projects/bind9!11844
The cleanup path always unlocks the 'view->newzone.lock' lock, but
there are 'goto cleanup;' operations even before the lock is locked,
which causes an assertion failure.
Don't use the cleanup path before the lock is locked.
Recently, a broken version of libuv was released breaking BIND on
several platforms. The offending [commit](https://github.com/libuv/libuv/issues/5030) was on the development branch
for months, but we didn't notice.
In nightly pipelines, build the current 'main' (actually 'v1.x') branch
of libuv and run the unit and system tests against it.
Merge branch 'stepan/prelease-testing-for-libuv' into 'main'
See merge request isc-projects/bind9!11647
Recently, a broken version of libuv was released breaking BIND on
several platforms. The offending commit [1] was on the development
branch for months, but we didn't notice.
In nightly pipelines, build the current 'main' (actually 'v1.x') branch
of libuv and run the unit and system tests against it.
[1]: https://github.com/libuv/libuv/issues/5030
In 237489caf I mistakenly put the environment variables controlling
the retry wrapper in a separate never used environment.
Merge branch 'stepan/actually-retry-flaky-unit-tests' into 'main'
See merge request isc-projects/bind9!11838
Previously, when computing the compressed bitmap during verification of an NSEC3-signed zone, an undersized buffer was used that resulted in an out-of-bounds write if there were too many active windows in the bitmap. This impacted mirror zones which are NSEC3-signed, `dnssec-signzone` and `dnssec-verifyzone`. This has been fixed.
Closes#5834
Merge branch '5834-fix-cbm-size' into 'main'
See merge request isc-projects/bind9!11804
The "publish" job runs on a dedicated, locked-down runner that lacks the
Python modules necessary to execute the manage_distros_token.py script.
Instead of deleting the token within the "publish" job, purge it in a
separate job that automatically runs on the "base" image after the
"publish" job succeeds. Define "rules" for the new job so that the
token is only deleted for security releases, as it should have been
initially.
Merge branch 'michal/purge-distros-token-in-a-separate-ci-job' into 'main'
See merge request isc-projects/bind9!11817
The "publish" job runs on a dedicated, locked-down runner that lacks the
Python modules necessary to execute the manage_distros_token.py script.
Instead of deleting the token within the "publish" job, purge it in a
separate job that automatically runs on the "base" image after the
"publish" job succeeds. Define "rules" for the new job so that the
token is only deleted for security releases, as it should have been
initially.
With AI agents widely available, delaying CVE reproducer publication no
longer provides any benefit, as feeding a patch with a fix to a large
language model can produce a usable exploit. Revise the CVE checklist
to ensure the reproducer and the fix are pushed to the same merge
request (as separate commits) and remove the post-disclosure step for
regression test publishing.
Nsupdate does not distinguish between a non-existing RDATA field
and an empty RDATA field when determining which action is desired
when the RDATA field is empty. This only affects a few data types,
like APL, which allow an empty RDATA field. Document a workaround
of using the '\# 0' form for entering these specific records. e.g.
# delete the APL RRset
update delete IN APL
# delete the APL record with a zero length rdata
update delete IN APL \# 0
Closes#5835
Merge branch '5835-nsupdate-doc-zero-length-rdata-how-to' into 'main'
See merge request isc-projects/bind9!11775
Nsupdate does not distinguish between a non-existing RDATA field
and an empty RDATA field when determining which action is desired
when the RDATA field is empty. This only affects a few data types,
like APL, which allow an empty RDATA field. Document a workaround
of using the '\# 0' form for entering these specific records. e.g.
# delete the APL RRset
update delete IN APL
# delete the APL record with a zero length rdata
update delete IN APL \# 0
Rarely, RNDC fails to reconfigure zones on FreeBSD in the default 10
seconds.
Merge branch 'mnowak/xfer-bump-reconfigure-timeout' into 'main'
See merge request isc-projects/bind9!11820
ADB `dns_adb_createaddrinfofind()` expects `maxaddrs` paramaters is
always strictly positive. Add an assertion to enforce it.
Merge branch 'colin/createaddrinfofind-invariant' into 'main'
See merge request isc-projects/bind9!11819
Previously, :iscman:`named` relied on the default allocator settings for
releasing unused memory back to the operating system, which could result in
unnecessarily high resident memory usage. :iscman:`named` now actively
manages memory page purging. On systems using jemalloc, background cleanup
threads are enabled and the dirty page decay time is reduced from 10 seconds
to 5 seconds. Additionally, a volume-based decay pass is triggered after
every 16 MiB of freed memory. On glibc-based systems, a similar
volume-based mechanism using malloc_trim() is used instead.
Merge branch 'ondrej/enable-background-cleaning-of-unused-memory' into 'main'
See merge request isc-projects/bind9!11761
Enable jemalloc background threads and reduce dirty page decay time from
10s to 1s so that unused memory is returned to the OS sooner. As an
additional safety net, trigger a decay pass after every 16 MiB of frees
(rate-limited to once per second) to handle bursts that the background
thread might not catch in time. On glibc, fall back to malloc_trim(0)
with the same volume-based trigger.
In order to make `zone.c` more readable, split it up in separate source files. This moves zone manager related code to `zonemgr.c`.
Merge branch 'matthijs-refactor-zone-2' into 'main'
See merge request isc-projects/bind9!11726
Move the following functions to the zoneproperties source files, as
they are simple get functions:
- dns_zone_getgluecachestats
- dns_zone_getkeystores
- dns_zone_getrequesttransporttype