Commit graph

45341 commits

Author SHA1 Message Date
Arаm Sаrgsyаn
175b121bc3 fix: usr: Fix a possible race condition during zone transfers
The :iscman:`named` process could terminate unexpectedly
when processing an IXFR message during a zone transfer.
This has been fixed.

Closes #5767

Merge branch '5767-use-after-free-xfrin_reset' into 'main'

See merge request isc-projects/bind9!11781
2026-04-03 12:05:17 +00:00
Nicki Křížek
187e571f4d Rewrite xfer/ans11/ans.py to use AsyncDnsServer
Replace the hand-rolled threaded socket server with the standard
AsyncDnsServer framework used by other ans.py servers in the test suite.

The DNS wire-format message builders (IXFR diff, AXFR, SOA, SERVFAIL)
are retained unchanged since they produce carefully crafted messages
needed to trigger the IXFR->AXFR race condition. The server
infrastructure is replaced:

- Manual TCP/UDP socket management and threading replaced by
  AsyncDnsServer, which handles both protocols, pidfile lifecycle,
  and signal handling.
- Query parsing replaced by the framework's dns.message-based parser;
  query dispatch moved into IxfrRaceHandler.get_responses().
- The axfr_done_event threading.Event replaced by a boolean instance
  variable on IxfrRaceHandler, safe within the single asyncio event
  loop.
- For IXFR over TCP, the handler yields two BytesResponseSend actions
  (msg1 then msg2) so the framework sends both with TCP length prefixes,
  preserving the race-triggering sequence.
- For IXFR over UDP, the TC flag is set on the response to force TCP
  retry.
- Unused encode_name_compressed() and parse_dns_query() removed.

Also fix a timing issue that might result in the initial transfer not
being done by the time the test is executed -- since ns11 is started
after ns6. Ensure the initial transfer has happened before running the
ixfr_race test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 11:01:34 +00:00
Aram Sargsyan
141ff7bfa7 Fix a race condition in xfrin_recv_done() when calling xfrin_reset()
When the xfrin_recv_done() function decides to retry the transfer
using AXFR because of a previous error, it calls the xfrin_reset()
function which calls dns_db_closeversion() on 'xfr->ver'. The problem
is that the ixfr processing of a previous message could be still
in process in a worker thread, which then can use freed 'xfr->ver'.

If there is an ongoing worker thread delay the AXFR retry until after
the worker thread has finished its work.
2026-04-03 11:01:34 +00:00
Aram Sargsyan
5c248e7d1a Add a test to check for IXFR->AXFR race-condition
The test initiates a zone transfer with IXFR, which produces
a big amount of differences and then generates an error. The
secondary should be able to gracefully shutdown the ongoing
IXFR transfer and retry with AXFR without race conditions
between them.

This test checks for an issue (GL#5767) but since a race
condition is usually time-sensitive it might require several
attempts before it reproduces the issue.
2026-04-03 11:01:34 +00:00
Ondřej Surý
15f058b5a2 fix: usr: Fix wrong NSEC proof for empty non-terminals after IXFR
When a secondary received an IXFR that transitioned a zone from unsigned to NSEC-signed, queries for empty non-terminal names returned the zone apex NSEC record instead of the NSEC that actually covers the queried name.  The issue only occurred with incremental transfers; a full AXFR or a server restart resolved it.

Closes #5824

Merge branch 'ondrej/fix-nsec-ixfr' into 'main'

See merge request isc-projects/bind9!11786
2026-04-03 06:33:54 +02:00
Ondřej Surý
3fe3751c22 Fix wrong NSEC proof for empty non-terminals after IXFR
When receiving NSEC records via IXFR, the node was not marked with
havensec because the condition checked the uninitialized output
rdataset type instead of the input rdataset type.  This caused
queries for empty non-terminal names in NSEC-signed zones received
via IXFR to return the zone apex NSEC instead of the correct
covering NSEC record.

The bug was introduced in f4b4f030.
2026-04-03 06:33:31 +02:00
Ondřej Surý
8a4990d6ff Add regression test for NSEC proof after unsigned-to-signed IXFR
Test that a secondary receiving an IXFR transitioning a zone from
unsigned to NSEC-signed returns the correct covering NSEC record
for empty non-terminal names.

Add isctest.query.wait_for_serial() shared helper for waiting until
a server has a specific SOA serial.
2026-04-03 06:33:31 +02:00
Ondřej Surý
245c71dfac chg: dev: Change NSEC3 and NSEC3PARAM rdata struct fields to use isc_region_t
Replace the separate pointer+length field pairs in the NSEC3 and NSEC3PARAM rdata structures (salt/salt_length, next/next_length, typebits/len) with isc_region_t, making the fields self-describing and eliminating a class of length-mismatch bugs.

Merge branch 'ondrej/change-nsec3-and-nsec3param-to-use-isc_region_t' into 'main'

See merge request isc-projects/bind9!11592
2026-04-02 18:05:58 +02:00
Ondřej Surý
14cebe4d61 Change NSEC3 and NSEC3PARAM struct fields to use isc_region_t
Replace the separate pointer+length field pairs in dns_rdata_nsec3_t
(salt/salt_length, next/next_length, typebits/len) and
dns_rdata_nsec3param_t (salt/salt_length) with isc_region_t.  This
makes the structs self-describing and eliminates a class of
length-mismatch bugs.

The dns_zone_setnsec3param() signature is updated to take
isc_region_t *salt instead of separate saltlen and salt arguments.

Function signatures for dns_nsec3_addnsec3, dns_db_getnsec3parameters,
and related internal functions still use separate pointer+length pairs
and should be updated in a follow-up.
2026-04-02 16:53:18 +02:00
Matthijs Mekking
ae739daec2 chg: dev: Fix off by one error in dnssec-ksr sign
If the inception time of the signature is exactly equal to the inactive time of the key, add the signature.

Merge branch 'matthijs-skr-off-by-one-bug' into 'main'

See merge request isc-projects/bind9!11791
2026-04-02 14:47:46 +00:00
Matthijs Mekking
d9b6036e0f Also fix off by one error in system test
The system test was also subject to the same off by one bug that also
existed in the code. That is: if the inception time of the signature
is exactly equal to the inactive time of the key, we still have to
expect the signature.
2026-04-02 14:47:18 +00:00
Matthijs Mekking
784a441e2d Add fast test case
This specific test case triggered a bug where the SKR included bundles
with unsigned DNSKEY RRsets (signatures where omitted because the
inception time was equal to the inactive time of the key).
2026-04-02 14:47:18 +00:00
Matthijs Mekking
bc6dad585d Fix off by one error in dnssec-ksr sign
If the inception time of the signature is exactly equal to the
inactive time of the key, still include the signature. Otherwise there
may be corner cases where signatures are omitted erroneously.
2026-04-02 14:47:18 +00:00
Matthijs Mekking
36acc92131 chg: dev: Split up zone.c (zone properties)
In order to make `zone.c` more readable, split it up in separate source files. This moves most of the set and get functions to `zoneproperties.c`.

Merge branch 'matthijs-refactor-zone-1' into 'main'

See merge request isc-projects/bind9!11501
2026-04-02 14:29:27 +00:00
Matthijs Mekking
93376b8f67 Return void in functions that cannot fail
dns_zone_getloadtime(), dns_zone_getexpiretime(),
dns_zone_getrefreshtime(), and dns_zone_getrefreshkeytime()
cannot fail, so return void instead of ISC_R_SUCCESS.
2026-04-02 15:50:09 +02:00
Matthijs Mekking
f015170ec7 Fix some documentation issues
dns_zone_setorigin() does not return ISC_R_SUCCESS, but void.

dns_zone_setalsonotify() referred to non-existing
dns_zone_alsonotifywithkeys().
2026-04-02 15:50:09 +02:00
Matthijs Mekking
f04590d006 Remove unneccesary functions
Remove dns_zone_getmem() (duplicate of dns_zone_getmctx()).
Remove dns_zone_getrdclass() (duplicate of dns_zone_getclass()).
Remove obsoleted dns_zone_getstatscounters().
Remove obsoleted dns_zone_setstatistics().
2026-04-02 15:50:09 +02:00
Matthijs Mekking
af505bc44f Small refactor 'dns_zone_set*acl()'
The various 'dns_zone_set*acl()' functions can be refactored to
call 'dns_zone_clear*acl()', to avoid code duplication.
2026-04-02 15:50:09 +02:00
Matthijs Mekking
6c69fd16d0 Lock zone when checking for inline raw/secure
The caller is supposed to hold the zone lock for 'inline_raw()' and
'inline_secure()', but when adding 'REQUIRE(LOCKED_ZONE(zone));' to
these functions it turned out to be not always the case.
2026-04-02 15:50:09 +02:00
Matthijs Mekking
94788446db Rename private zone functions
Rename functions that are defined in the private header file to start
with 'dns__zone_'.
2026-04-02 15:50:09 +02:00
Matthijs Mekking
2893e128a7 Move zone set/get properties to own source file
In order to make zone.c more readable, we are splitting it up in
separate source files. This moves the set and get functions to its
own file ("zoneproperties.c").

Since this code accesses the zone structure directly, move the
'struct dns_zone' and its prerequisites to "zone_p.h".

The helper functions 'inline_raw()', 'inline_secure()',
'dns_zone_setview_helper()', 'zone_settimer(), 'set_resigntime()', and
'zone_freedbargs()' need to be internally accessible to both source
files.

A few set/get functions remain in zone.c for now:
- dns_zone_getserial
- dns_zone_getversion
- dns_zone_setviewcommit
- dns_zone_setviewrevert
- dns_zone_get_rpz_num
- dns_zone_set_parentcatz
- dns_zone_get_parentcatz
- dns_zone_setrawdata
- dns_zone_setskr
- dns_zone_getskrbundle
- dns_zone_setnsec3param
- dns_zone_setoption
- dns_zone_getoptions
- dns_zone_getrequesttransporttype
- dns_zone_getredirecttype
- dns__zone_getnotifyctx
- dns_zone_getgluecachestats
- dns_zone_setplugins
- dns_zone_setserial
- dns_zone_getxfr
- dns_zone_getkeystores
2026-04-02 15:50:07 +02:00
Matthijs Mekking
c56d4c13f9 fix: usr: Fix rndc modzone behavior for a zone in named.conf
If a zone was present in the configuration file and not originally added by `rndc addzone`, `rndc modzone` for that zone would succeed once but subsequent `modzone` attempts would fail. This has been fixed.

Closes #5826

Merge branch '5826-fix-subsequenrt-rndc-modzone' into 'main'

See merge request isc-projects/bind9!11744
2026-04-02 13:27:32 +00:00
Matthijs Mekking
ccb01b15e5 Also remove modded catalog zones from NZD
In the rare case where a catalog zone member is being modified with
'rndc modzone', also mark the zone as modded, so when the zone is
deleted again with 'rndc delzone', the configuration is also removed
from the NZD.
2026-04-02 12:35:54 +00:00
Matthijs Mekking
daa9e57448 Remove modified zone configuration from NZD
When a zone that is configured in named.conf is modified with
'rndc modzone', the new zone configuration is now also stored in the
NZD.

This must be removed when the zone is deleted with 'rndc delzone',
otherwise a restart will fail.
2026-04-02 12:35:54 +00:00
Matthijs Mekking
b8e16cf1cb Test restart works after rndc modzone
When a zone that is configured in named.conf is modified with
'rndc modzone', the new zone configuration is now also stored in the
NZD. Add a test to ensure that after a restart, the old zone
configuration is used.
2026-04-02 12:35:54 +00:00
Matthijs Mekking
98784ed753 Add the modified zone configuration to NZD
When a zone that is configured in named.conf is modified with
'rndc modzone', the zone configuration is deleted from the effective
config. Store the new configuration in the NZD. Mark the zone
as 'modified by rndc modzone'. Otherwise, subsequent calls to
'rndc modzone' would fail because the zone configuration cannot be
found.
2026-04-02 12:35:54 +00:00
Matthijs Mekking
e1bd1a4003 Introduce zone functions dns_zone_(get|set)modded
Introduce new functions to set and get whether the zone configuration
has been modified with 'rndc modzone'.
2026-04-02 12:35:54 +00:00
Matthijs Mekking
13414c640b Remove unused zoneconf from do_addzone
This is unused, so we can make the function call shorter.
2026-04-02 12:35:54 +00:00
JINMEI Tatuya
cbd1d71a1f Test rndc modzone succeeds twice for a zone in named.conf
If a zone is in named.conf, not originally added by rndc addzone,
rndc modzone for that zone succeeds once, but subsequent modzone
attempts fail. This is because do_modzone removes the zone config
from global or view options, but it would fail due to 'not found'
once the config is removed.

The test is copied from commit b737171ee215446701e7c8d4ac55d8a0e13426aa.
2026-04-02 12:35:54 +00:00
Colin Vidal
b8dcabbd72 fix: usr: possible crash when a resolver validate a static-stub zone
A NULL pointer dereference could be made in some circumstances when resolving and validating a name under a `static-stub` zone. This is now fixed.

Merge branch 'colin/fix-dns_view_bestzonecut-nullptrderef' into 'main'

See merge request isc-projects/bind9!11788
2026-04-02 14:16:58 +02:00
Colin Vidal
fc03a876ae fix NULL dereference in dns_view_bestzonecut()
When `dns_view_bestzonecut()` is called with a NULL `delegsetp`, it
calls `bestzonecut_zone()` with a NULL `rdataset` pointer but there is a
non-guarded de-reference of the `rdataset` pointer in
`bestzonecut_zone()`.

In practice, the only current situation where `dns_view_bestzonecut()`
is called with NULL `delegsetp` is from a case of `seek_ds()` _and_ the
non-guarded dereference occurs only if there is a static-stub local
zone matching the zonecut `seek_ds()` is looking for. It's unclear if
such flow is actually possible.

The `rdataset` is now always valid inside `dns_view_bestzonecut()`. (It
was initially set only if `delegsetp` was set to avoid extra works in
the qpzone, which can be skipped when `rdataset` is NULL, but this
doesn't really make a difference, considering we are in a slow path
considering the result wasn't found in this case.)
2026-04-02 12:16:12 +02:00
Colin Vidal
43c58dafcc fix: dev: remove deadcode in query_addbestns()
The local variable `zfname` was released in the cleanup part of the
function if not NULL, but it turns out it is now always NULL at that
point.

The flow can get to that part only in two cases: either `zfname` is not
NULL, and then it's ownership is moved to a different variable (thus, it
is now NULL), or `zfname` is already NULL.

Removing the bit of deadcode releasing it.

Merge branch 'colin/fix-getbestns-deadcode' into 'main'

See merge request isc-projects/bind9!11790
2026-04-02 11:51:25 +02:00
Colin Vidal
50a2fce68f remove deadcode in query_addbestns()
The local variable `zfname` was released in the cleanup part of the
function if not NULL, but it turns out it is now always NULL at that
point.

The flow can get to that part only in two cases: either `zfname` is not
NULL, and then it's ownership is moved to a different variable (thus, it
is now NULL), or `zfname` is already NULL.

Removing the bit of deadcode releasing it.
2026-04-02 11:51:12 +02:00
Michal Nowak
5eda8a2543 chg: doc: Revert "Add Sphinx 9.1.0"
This reverts commit a31a4c2d2d.

ReadTheDocs will not work with this version:

    python -m pip install -r https://gitlab.isc.org/isc-projects/bind9/-/raw/main/doc/arm/requirements.txt
    ERROR: Ignored the following yanked versions: 8.3.0
    ERROR: Ignored the following versions that require a different python version: 9.1.0 Requires-Python >=3.12; 9.1.0rc1 Requires-Python >=3.12; 9.1.0rc2 Requires-Python >=3.12
    ERROR: Could not find a version that satisfies the requirement Sphinx==9.1.0 (from versions: 0.1.61611, ..., 9.0.4)
    ERROR: No matching distribution found for Sphinx==9.1.0

Merge branch 'mnowak/revert-sphinx-9.1.0' into 'main'

See merge request isc-projects/bind9!11793
2026-04-02 11:46:44 +02:00
Michal Nowak
aef329b18d
Revert "Add Sphinx 9.1.0"
This reverts commit a31a4c2d2d.

ReadTheDocs will not work with this version:

    python -m pip install -r https://gitlab.isc.org/isc-projects/bind9/-/raw/main/doc/arm/requirements.txt
    ERROR: Ignored the following yanked versions: 8.3.0
    ERROR: Ignored the following versions that require a different python version: 9.1.0 Requires-Python >=3.12; 9.1.0rc1 Requires-Python >=3.12; 9.1.0rc2 Requires-Python >=3.12
    ERROR: Could not find a version that satisfies the requirement Sphinx==9.1.0 (from versions: 0.1.61611, ..., 9.0.4)
    ERROR: No matching distribution found for Sphinx==9.1.0
2026-04-02 11:45:46 +02:00
Michal Nowak
91d3c659d3 chg: doc: Add Sphinx 9.1.0
Update Sphinx Python package to the current version pulled in by "pip3
install sphinx_rtd_theme" run in a fresh Debian "trixie" container.

Merge branch 'mnowak/sphinx-9.1.0' into 'main'

See merge request isc-projects/bind9!11783
2026-04-02 10:35:02 +02:00
Michal Nowak
a31a4c2d2d Add Sphinx 9.1.0
Update Sphinx Python package to the current version pulled in by "pip3
install sphinx_rtd_theme" run in a fresh Debian "trixie" container.
2026-04-02 10:34:53 +02:00
Evan Hunt
08fa344014 fix: usr: Use the zone file's basename as origin in DNSSEC tools
In `dnssec-signzone` and `dnssec-verify`, when the zone origin is not specified using the `-o` parameter, the default behavior is to try to sign using the zone's file name as the origin. So, for example, `dnssec-signzone -S example.com` will work, so long as the file name matches the zone name.

This now also works if the zone is in a different directory. For example, `dnssec-signzone -S zones/example.com` will set the origin value to `example.com`.

Closes #5678

Merge branch '5678-signzone-basename' into 'main'

See merge request isc-projects/bind9!11360
2026-04-01 20:47:44 +00:00
Matthijs Mekking
1251ae896c Test dnssec tools using zone file basename as origin
Add test cases where dnssec-signzone and dnssec-verify use the
zone file's basename as the origin when '-o' is omitted.
2026-04-01 12:30:09 -07:00
Evan Hunt
b8cb65db93 use the zone file's basename as origin in dnssec tools
In dnssec-signzone and dnssec-verify, if the zone origin is not
specified using the `-o` parameter, the default behavior is to try
to use the zone's file name as the origin. So, for example,
`dnssec-signzone -S example.com` or 'dnssec-verify example.com'
will work, so long as the file name matches the zone name.

This now also works if the zone is in a different directory.
For example, `dnssec-signzone -S zones/example.com` or
'dnssec-verify zones/example.com' will set the origin value
to `example.com`.
2026-04-01 12:29:33 -07:00
Michal Nowak
22116110ff chg: ci: Drop allow_failure of cross-version-config-tests
!11446 is in the latest - 9.21.21 - release.

Merge branch 'mnowak/cross-version-config-tests-drop-allow_failure' into 'main'

See merge request isc-projects/bind9!11778
2026-04-01 18:21:41 +02:00
Michal Nowak
9357fb2bdc
Drop allow_failure of cross-version-config-tests
GL!11446 is in the latest - 9.21.21 - release.
2026-04-01 17:56:44 +02:00
Michal Nowak
f882d88c3c Merge tag 'v9.21.21' 2026-04-01 14:55:09 +00:00
Ondřej Surý
6b6913c83b chg: usr: Implement RFC 3645 Section 4.1.1 key expiry check in TKEY
Check for existing TSIG keys before accepting a new
GSS-API negotiation and delete the key if it has expired.
Previously, an expired GSS key would permanently block
re-negotiation for that name until the server was restarted.

Merge branch 'ondrej/cleanup-gssapi-and-tkey-api' into 'main'

See merge request isc-projects/bind9!11713
2026-04-01 09:38:55 +02:00
Ondřej Surý
80654250ee
Add regression test for RFC 3645 Section 4.1.1 duplicate TKEY name
Add 'tkeyname' command to nsupdate to allow specifying a fixed TKEY
name instead of the default random one.  This is used by the test to
send two GSS-API TKEY negotiations with the same name.

After a successful GSS-API TKEY negotiation via nsupdate -g, a second
attempt with the same TKEY name must be rejected with BADKEY
(error=17), not BADNAME (error=20).
2026-04-01 07:04:40 +02:00
Ondřej Surý
c0a6f3bf65
Fix GSS context leak on error paths in process_gsstkey()
After gss_accept_sec_context() succeeds, the GSS context is passed
to dst_key_fromgssapi() which transfers ownership to the dst_key.
If a subsequent operation fails (dst_key_fromgssapi itself,
dns_tsigkey_createfromkey, or dns_tsigkeyring_add), the cleanup
label frees the dst_key but only if it was created.  If the failure
happened before dst_key_fromgssapi, the GSS context was orphaned.

Delete the GSS context in the cleanup path when it was not
transferred to a dst_key.
2026-04-01 07:04:40 +02:00
Ondřej Surý
5305679633
Fix GSS context leak when principal name is empty
When gss_accept_sec_context() completes successfully but
gss_display_name() returns an empty principal, the GSS context
was leaked — it was neither stored in a key nor deleted.

Delete the context and reject with BADKEY in this case.  This
should only occur due to a GSS library bug, since a completed
context should always have a valid principal.
2026-04-01 07:04:39 +02:00
Ondřej Surý
8c1fe179e3
Fix off-by-one in TSIG generated key eviction
Use pre-increment (++ring->generated) instead of post-increment
(ring->generated++) so the comparison against DNS_TSIG_MAXGENERATEDKEYS
happens after counting the new key.  With post-increment, one extra key
beyond the limit was allowed before eviction kicked in.
2026-04-01 07:04:39 +02:00
Ondřej Surý
5e10fdc295
Implement RFC 3645 Section 4.1.1 key expiry check in TKEY
Check for existing non-expired TSIG keys before accepting a new
GSS-API negotiation.  Per RFC 3645 Section 4.1.1:

- If a key exists and has not expired, reject with BADNAME
- If a key exists but has expired, delete it and start fresh

Previously, an expired GSS key would permanently block
re-negotiation for that name until the server was restarted.

Use BADKEY rather than BADNAME to avoid creating an oracle for
key name enumeration by unauthenticated attackers.
2026-04-01 07:04:39 +02:00
Michal Nowak
ec2e1ce35a
Update BIND version for release 2026-03-31 18:30:02 +02:00