Commit graph

45421 commits

Author SHA1 Message Date
Ondřej Surý
c2d2605e9d new: doc: Document opt-in 🤖 marker for agent-authored issues and MRs
Add short notes in CONTRIBUTING.md telling automated agents to append
🤖 to the title of issues and merge requests so they can be routed
through the streamlined agent triage/merge process.

Merge branch 'ondrej/agent-contributing' into 'main'

See merge request isc-projects/bind9!11861
2026-04-16 19:00:03 +02:00
Ondřej Surý
2ec8d3ce7c
Document opt-in 🤖 marker for agent-authored issues and MRs
Add short notes in CONTRIBUTING.md telling automated agents to append
🤖 to the title of issues and merge requests so they can be routed
through the streamlined agent triage/merge process.
2026-04-16 18:51:01 +02:00
Alessio Podda
a8d412ab21 fix: dev: Add missing parenthesis to fxhash
The fxhash implementation had a missing parenthesis that caused it to
diverge from Rust's reference implementation. This commit fixes this.

Closes #5882

Merge branch '5882-fxhash-fix' into 'main'

See merge request isc-projects/bind9!11857
2026-04-16 14:48:19 +00:00
Alessio Podda
bcfa2adaa3 Add missing parenthesis to fxhash
The fxhash implementation had a missing parenthesis that caused it to
diverge from Rust's reference implementation. This commit fixes this.
2026-04-16 16:03:40 +02:00
Ondřej Surý
5f8624df76 fix: usr: Prevent excessive priming queries to the root servers
BIND was sending a priming query to the root servers on nearly every
recursive lookup instead of only when the cached root information
expired.  Priming now rearms only after the TTL of the fetched records
elapses, and the refreshed root NS set is used for query routing until
the next cycle.

Merge branch 'ondrej/fix-delegdb-priming' into 'main'

See merge request isc-projects/bind9!11847
2026-04-16 14:33:44 +02:00
Ondřej Surý
0c007d8659
Rename view->hints to view->rootdb and rearm priming
With the parent-centric resolver, dns_view_bestzonecut() consults the
delegation DB (view->deleg) rather than the main cache for the closest
zonecut.  Root is never the target of a referral, so it never lands in
delegdb; bestzonecut therefore falls through to the hints lookup on
every query whose closest ancestor is root.  prime_done() only called
dns_root_checkhints(), which logs discrepancies but does not update
any store bestzonecut looks at, so the fresh root NS records obtained
by priming were never used and priming kept re-firing.

Rename view->hints to view->rootdb and refresh it when a priming
fetch completes: the '.' NS rdataset is replaced with the fetched
one, and for each listed nameserver the matching A/AAAA glue is
copied from the response's ADDITIONAL section.  Only glue for names
that actually appear as NS targets is accepted, so a hostile response
cannot inject unrelated records.  Glue the response did not carry is
left untouched, so the hints-file records loaded at startup remain as
a fallback.

Each view gets its own rootdb: the previous shared
named_g_server->in_roothints is gone, and configure_view() calls
dns_rootns_create() per view when the class-IN defaults are needed.
That keeps the priming writer one-per-DB, so concurrent priming in
different views cannot race on the same zone-DB version.

The rootdb refresh runs synchronously from the resolver response path,
so records go straight from the wire into rootdb with no cache round
trip and no dependency on DNSSEC validation state.  A new
DNS_FETCHOPT_PRIMING option marks the priming fetch; prime_done()
itself is now pure cleanup.

Track the rootdb freshness window in view->rootdb_expires and trigger
re-priming lazily from dns_view_find() and bestzonecut_rootdb() only
when the window has elapsed.  Stale records are still served while the
fresh priming fetch is in flight.

Drop dns_root_checkhints() and its helpers; the rootdb is now the
authoritative source the resolver consults.
2026-04-16 13:39:18 +02:00
Arаm Sаrgsyаn
ef29555ba4 fix: usr: Fix zone filename token-parsing bug
The :iscman:`named` process could terminate unexpectedly when
processing a catalog member zone containing special characters
like '%' or '$' which could be interpreted as zone filename tokens
and trigger a case-sensitivity bug in the token-parsing code. This
has been fixed.

Closes #5849

Merge branch '5849-catz-filename-and-token-parsing-fix' into 'main'

See merge request isc-projects/bind9!11839
2026-04-16 11:37:17 +00:00
Aram Sargsyan
e30a535760 Treat '%' and '$' as special characters for catalog member zone names
The filename of the catalog member zones are generated dynamically
based on the zone's name. If the zone's name is too long or if it
contains special characters the name's digest is used instead.

Since '%' and '$' are now treated as special characters in the zone
names (see !10779), add these characters to the list of the special
characters.
2026-04-16 11:37:02 +00:00
Aram Sargsyan
979ae7d9d6 A a test to check zone filename case-insensitivity
The test adds a catalog member zone which has '%X' in its name and
it ends up in the zone filename parser's code because the filename
is currently generated (by the catalog zone code) based on the zone's
name.

Zones which have a name with the '%' special character should be
filtered and their name's digest should be used instead for filenane
generation (like it is implemented for other special characters), and
that fix is coming next.
2026-04-16 11:37:02 +00:00
Aram Sargsyan
d2f7b969fe Fix case-sensitivity bug in zone filename token-parsing
The setfilename() function uses case-insensitive strcasestr() when
matching the possible tokens, but then one of the token parsers
uses case-sensitive INSIST checks which can assert when, for example,
matching '%X' and INSIST only accepts '%x'.

The case-insensitivity is documented, which means it's the parser
that needs to be fixed, not the matcher.

Convert the character to lowercase before checking the token's
validity.
2026-04-16 11:37:02 +00:00
Ondřej Surý
07c8cddb4c fix: usr: Avoid extra round trips for DS lookups when the parent delegation is already cached
DS queries could take two unnecessary extra round trips when the resolver sent them to the child zone instead of the parent. The child responds with NODATA, forcing a recovery path to rediscover the parent delegation even though it was already cached.  The resolver now consults its delegation cache before starting DS fetches, sending queries directly to the correct parent nameservers and eliminating the extra latency.

Merge branch 'ondrej/fix-ds-chase' into 'main'

See merge request isc-projects/bind9!11835
2026-04-16 13:16:34 +02:00
Colin Vidal
c280029d4d
Add system test for the chase DS fix
Add a system test which ensures, whenever the DS record can't be found
in the local cache, that the resolver first tries to get the parent NS
from the delegation cache to ask them the DS record, directly, rather
than running the fallback flow where the resolver attempts to query the
DS record from NS of the validating name (which would fails, then the
resolver would remove one label and fetch again, fails, and so on until
it reach the closest zonecut).

The test relies on the fact that when the fallback flow is run, the
`rctx_chaseds()` function is run, adding the "chase DS servers ..." and
"suspending DS lookup to find parent's..." logs.
2026-04-16 12:34:52 +02:00
Colin Vidal
1d10e4513f rename DNS_DBFIND_NOEXACT to DNS_DBFIND_ABOVE
The `DNS_DBFIND_NOEXACT` flag name is ambiguous, as it does not clearly
indicate the lookup behavior (e.g., sibling, child, or parent).

Rename it to `DNS_DBFIND_ABOVE` to better reflect that the lookup
targets a closer ancestor name.
2026-04-16 11:28:13 +02:00
Ondřej Surý
ec024735df Replace FIXME with rationale for not cleaning expired delegdb nodes
Expired delegation nodes are naturally replaced when the resolver
fetches fresh data, and any remaining stale nodes are reclaimed by
SIEVE eviction under memory pressure.
2026-04-16 11:28:13 +02:00
Colin Vidal
193e01ab20 Remove hiwater/lowater fields from delegdb
The delegdb does not directly use the hiwater and lowater values during
the cleaning flow, so these fields are no longer necessary.
2026-04-16 11:28:13 +02:00
Ondřej Surý
4d772cda3c Reclaim only what the new delegation needs
delegdb_cleanup() was overwriting the caller-supplied 'requested'
value with (hiwater - lowater), so every overmem cleanup tried to
free the full watermark band regardless of how much memory the new
delegation actually needed.  Drop the override so the caller's size
is used: we now walk the SIEVE only until we have reclaimed enough
room for the new node, leaving unrelated entries in place.
2026-04-16 11:28:13 +02:00
Ondřej Surý
876a896f0f Account transient delegsets against the caller's memory context
dns_delegset_fromnsrdataset() used isc_g_mctx for the transient
delegset it builds from a DNS NS rdataset.  That hides delegation
data in the global default context instead of accounting it against
the subsystem that owns it: a resolver fctx, a view, or a query
context.

Take an explicit mctx parameter so callers can direct the allocation
to the right place, and update the three call sites:
- lib/dns/view.c:1189 (dns_view_bestzonecut fallback) uses view->mctx
- lib/dns/resolver.c:7071 (resume_dslookup) uses fctx->mctx
- lib/ns/query.c:8672 (query_delegation_recurse) uses the client
  manager's mctx

Also tighten delegdb cleanup to run inside the same write transaction
as the insert: delegdb_node_prepare() now returns the size of the new
node, and delegdb_cleanup() takes the caller's open qp so that the
overmem reclamation and the insert share one commit instead of doing
two nested write transactions.
2026-04-16 11:28:13 +02:00
Ondřej Surý
9191dc7acb Fix delegation database NOEXACT lookup for top-level names
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.
2026-04-16 11:28:13 +02:00
Ondřej Surý
764625ee5b Use the delegation database in get_dsset()
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.
2026-04-16 11:28:13 +02:00
Evan Hunt
436b2771d5 rem: nil: Continue removal of license headers from test zones
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
2026-04-15 19:26:35 +00:00
Evan Hunt
15cb1e50cb Continue removal of license headers from test zones
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.
2026-04-15 19:26:23 +00:00
Nicki Křížek
4197958d03 fix: test: Use virtualenv's Python interpreter when running tests from a venv
Merge branch 'nicki/pytest-venv-python' into 'main'

See merge request isc-projects/bind9!11854
2026-04-15 16:05:16 +02:00
Štěpán Balážik
261185ecb5 Log the Python interpreter used to run the system tests during setup
This is useful when running in an virtual environment or on a machine
where multiple Python versions are installed.
2026-04-15 15:12:38 +02:00
Nicki Křížek
68cfca1788 Use virtualenv's Python interpreter when running tests from a venv
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>
2026-04-15 14:26:35 +02:00
Evan Hunt
cf11b88e0e fix: dev: Fix a bug with template filename reuse
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
2026-04-15 06:57:27 +00:00
Mark Andrews
b4ba11f151 Fix a bug with template filename reuse
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.
2026-04-14 21:50:31 -07:00
Mark Andrews
20f8e9eb56 Make zone filename expansion accessible from outside dns_zone
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().
2026-04-14 21:49:59 -07:00
Mark Andrews
bbdca691c0 fix: usr: Remove unnecessary dns_name_free call
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
2026-04-15 11:36:50 +10:00
Mark Andrews
9f411c93c4 Remove unnecessary dns_name_free call
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.
2026-04-15 09:00:26 +10:00
Mark Andrews
213e59ccf5 Checking invalid TSIG key name in a catalog zone 2026-04-15 09:00:26 +10:00
Ondřej Surý
a61427e8ee fix: usr: Implement seamless outgoing TCP connection reuse
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
2026-04-14 19:29:54 +02:00
Ondřej Surý
4654796683
Include disptype and transport in dispatch hash key
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.
2026-04-14 17:48:24 +02:00
Ondřej Surý
6e78094ebd
Do not reuse shared TCP dispatches for zone transfers
Zone transfers (XFRIN) need a dedicated TCP connection because they
are long-lived and stream the entire zone.
2026-04-14 17:48:23 +02:00
Ondřej Surý
3e364aec2b
Use sequential per-dispatch message IDs for TCP
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.
2026-04-14 17:48:21 +02:00
Ondřej Surý
385ceabe8f
Limit TCP pipelining per shared dispatch
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'.
2026-04-14 17:48:16 +02:00
Ondřej Surý
05e8b58307
Disable TCP pipelining in tcp and masterformat system test
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.
2026-04-14 17:48:15 +02:00
Ondřej Surý
d5ee86b799
Implement seamless TCP connection reuse in dns_dispatch
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.
2026-04-14 17:48:13 +02:00
Arаm Sаrgsyаn
09a4b80301 fix: usr: Fix 'rndc modzone' issue with non-existing zones
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
2026-04-14 09:36:17 +00:00
Aram Sargsyan
d5720cd821 Add a new check in "addzone" system test
Check that named handles requests to modify non-existing zones
without issues.
2026-04-14 08:57:12 +00:00
Aram Sargsyan
a227e4606f Fix a lock/unlock bug in server.c:do_modzone()
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.
2026-04-14 08:57:12 +00:00
Štěpán Balážik
a72a17c882 chg: ci: Test development version of libuv in CI
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
2026-04-13 16:59:41 +00:00
Štěpán Balážik
23d11de2b4 Test development version of libuv in CI
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
2026-04-13 18:21:23 +02:00
Štěpán Balážik
28c3b990f9 fix: test: Actually retry the flaky unit tests
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
2026-04-13 15:50:35 +00:00
Štěpán Balážik
604f721ef8 Actually retry the flaky unit tests
In 237489caf I mistakenly put the environment variables controlling
the retry wrapper in a separate never used environment.
2026-04-13 11:01:05 +02:00
Mark Andrews
0633effb5b fix: usr: Fix zone verification of NSEC3 signed zones
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
2026-04-10 16:23:27 +10:00
Mark Andrews
e9a58de251 Checking maximal sized compresses bit map works
Add records that will be at end of each compressed bitmap less 1
of the NSEC3 record. Zone verification should still work.
2026-04-10 15:45:01 +10:00
Mark Andrews
e43e4bd20a Use the correct maximal compressed bit map buffer size
There are up to 256 windows in a NSEC/NSEC3 compressed bit
map of 32 + 2 octets each.
2026-04-10 15:45:01 +10:00
Michal Nowak
67507f01b0 new: test: System test requires the h2 module
Merge branch 'mnowak/require-h2' into 'main'

See merge request isc-projects/bind9!11829
2026-04-09 17:38:47 +02:00
Michal Nowak
8b4b1aa6d9
System test requires the h2 module 2026-04-09 16:53:29 +02:00
Michał Kępień
8107510738 fix: ci: Purge distros token in a separate CI job
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
2026-04-09 13:25:14 +02:00