Commit graph

16595 commits

Author SHA1 Message Date
Ondřej Surý
46f6bb6364
Size HMAC key generation buffers to the maximum block size
hmac_generate() declared its on-stack nonce buffer as
unsigned char data[ISC_MAX_MD_SIZE], i.e. 64 bytes. That is the maximum
digest size, but the buffer is filled up to the algorithm's HMAC block
size, which is 128 bytes for SHA-384 and SHA-512. Asking rndc-confgen
for an HMAC-SHA-384 or HMAC-SHA-512 key with -b > 512 (the documented
range allows up to 1024) wrote past the end of the stack buffer; on
hardened builds this aborted with a stack-smash detector firing
instead of producing a key.

Use the existing ISC_MAX_BLOCK_SIZE (128) for the buffer so the full
1..1024 range advertised by -A hmac-sha{384,512} works as documented.
The matching key_rawsecret[64] in confgen's generate_key() is enlarged
the same way so the generated key fits when dumped to the buffer.

Add a system test that exercises rndc-confgen across the previously
overflowing keysizes; with -Db_sanitize=address it caught the abort
before the fix.

Assisted-by: Claude:claude-opus-4-7
2026-04-29 19:21:20 +02:00
Ondřej Surý
6082274450 Stop isc_file_safecreate from following symlinks
The function existence-checked the target with stat() and then opened
the same path without O_NOFOLLOW, so a symlink at the target path
passed the regular-file test against the link's destination and the
open() that followed truncated and wrote through the link.
rndc-confgen -a is typically run as root and writes the keyfile under
a directory that service accounts may have write access to, so a stray
symlink there would silently redirect the truncate, fchown, and
overwrite to whatever file the link pointed at.

Switch the existence check to lstat() and use S_ISREG() so a symlink's
S_IFLNK mode is detected directly (a plain bitmask of S_IFREG matches
both, since S_IFLNK shares its high bit). Add O_NOFOLLOW to both
open() flag sets to close the lstat/open TOCTOU window. Hardening
against unexpected symlinks on intermediate path components is out of
scope.

Assisted-by: Claude:claude-opus-4-7
2026-04-29 16:56:25 +02:00
Ondřej Surý
746fb28369
Drop unused DNS_MASTER_NOINCLUDE and warn about untrusted zone text
DNS_MASTER_NOINCLUDE was defined to suppress $INCLUDE processing, but
no caller ever set it, so the guarded code path was dead and the flag
gave the false impression that named-checkzone could be hardened
against untrusted input. The zone-file parser cannot safely read text
from a less-trusted source than the user running the tool: $INCLUDE
opens any local file readable by that user, and fragments of its
contents leak through tokenizer error messages.

Rather than wire up an opt-in flag that suggests this is a supported
mode, remove the dead flag and the dead guard, and document in the
named-checkzone and named-compilezone manual pages that these tools
must not be run on zone text from an untrusted source.

Assisted-by: Claude:claude-opus-4-7
2026-04-29 15:08:20 +02:00
Colin Vidal
aeee4c1c1d Do not add glues from different parent in delegdb
When processing a referral, the `cache_delegns()` function was accepting
glues from a different parent. For instance:

```
AUTHORITY
test.example.		NS	ns.test.example.
test.example.		NS	ns.foo.example.
test.example.		NS	ns.bar.

ADDITIONAL
ns.bar.			A	1.2.3.4
ns.foo.example.		A	5.6.7.8
ns.test.example.	A	9.8.7.6
```

In such situation, only the glues for `ns.foo.example.` and
`ns.test.example.` should be used, and the glue from `ns.bar.` should be
ignored as this is not either a sub-domain or a sibling domain, the
parent is different (`bar.` instead of `example.`). This is now fixed.

Sibling glue and cyclic sibling glues are defined in RFC 9471 section
2.2 and section 2.3.
2026-04-28 19:17:39 +01:00
Aram Sargsyan
4ede6edc54 Remove OpenSSL memory tracking support from the ossl3.c module
OPENSSL_cleanup() in OpenSSL 4 doesn't free the memory, and that is
not compatible with BIND 9's memory leak detection code. Don't use
custom allocation/deallocation functions for OpenSSL's internal memory
management in the ossl3.c module.

See https://github.com/openssl/openssl/pull/29721
2026-04-28 14:42:40 +00:00
Aydın Mercan
48a77a4bfc don't set named curves explicitly in pre-3.0 libcrypto
The function `EC_KEY_set_asn1_flag` is deprecated in AWS-LC. Fortunately
calling it to make sure we use named curve keys is entirely unnecessary.

More information for pre-3.0 libcrypto and significant forks are as
following:

OpenSSL: Named curves were the default between 1.1.0 and 3.6.1 [1],[2]
AWS-LC: Library only supports named curves in the first place [3]
BoringSSL: Likewise with AWS-LC [4]
LibreSSL: `EC_GROUP`s are named by default [5]

[1] 86f300d385
[2] 9db6af922c
[3] a605df416b/include/openssl/ec_key.h (L442-L445)
[4] 514abb73bb/include/openssl/ec_key.h (L279-L280)
[5] c933874518/src/lib/libcrypto/ec/ec_lib.c (L94)
2026-04-28 09:28:18 +03:00
Alessio Podda
0fe1d091f7 Fix race condition in getsigningtime()
Compute qpzone_get_lock(elem->node) into a local variable while the
heap lock is still held, rather than dereferencing the stale elem
pointer after releasing the lock. A concurrent thread running
setsigningtime() (e.g. via IXFR apply on a worker thread) could free
the top-of-heap element between the heap lock release and the
dereference, causing a use-after-free.
2026-04-27 18:09:47 +02:00
Evan Hunt
7e3561a477 remove unneeded options in dns_zonefetch
In the dns_zonefetch mechanism, some option flags for
dns_resolver_createfetch() were used for all fetches, but
were actually only needed by the DNSKEY refresh fetches.

(Specifially, these options were DNS_FETCHOPT_UNSHARED
and DNS_FETCHOPT_NOCACHED, which were used along with
DNS_FETCHOPT_NOVALIDATE to ensure we get a new copy of
the DNSKEY as it is currently published by the authority,
without prior validation.  Those conditions are needed
for RFC 5011 trust anchor maintenace, but not when looking
up parent-NS or DSYNC RRsets.)
2026-04-22 10:58:43 +00:00
Ondřej Surý
592f3cc671
Add DTRACE probes to dns_delegdb
Instrument the delegation cache (introduced to back both NS-based and
DELEG-based delegations) with 11 USDT probes in the libdns provider so
that hit rate, eviction pressure, and lookup latency can be measured
without recompiling or enabling logging.

The probes are:

- delegdb_lookup_start / delegdb_lookup_done wrap dns_delegdb_lookup()
  and pass the query name plus the result code.

- delegdb_insert_start / delegdb_insert_done wrap dns_delegset_insert().
  The early SHUTTINGDOWN return is funneled through the cleanup label
  so the done probe fires on every path.

- delegdb_cleanup_start / delegdb_cleanup_done bracket the SIEVE-based
  eviction triggered when the cache goes overmem, reporting the number
  of bytes requested and actually reclaimed.  An additional per-node
  delegdb_evict probe (guarded by _ENABLED() because it fires inside
  the loop) exposes which zones are being evicted.

- delegdb_create, delegdb_reuse, and delegdb_shutdown trace the per-view
  lifecycle across server reloads.

- delegdb_delete traces rndc flush-delegation paths, reporting whether
  a subtree or single name was removed.

Name arguments are stringified with dns_name_format() behind
LIBDNS_*_ENABLED() guards so that the hot lookup and insert paths remain
zero-cost when no consumer is attached.
2026-04-20 13:14:19 +02:00
Ondřej Surý
3a44a13232 Refuse SIG and NXT records in dynamic updates
SIG (24) and NXT (30) are obsolete DNSSEC record types, superseded by
RRSIG and NSEC in RFC 3755.  Allowing them through dynamic update
exposes two distinct bugs that the surrounding GL#5818 work already
fixes as defense-in-depth:

  - dns__db_findrdataset() used to REQUIRE that (covers == 0 ||
    type == RRSIG), which aborts named when a SIG update reaches the
    prescan foreach_rr() call.  Fixed to accept dns_rdatatype_issig().
  - diff.c rdata_covers() used to test only RRSIG, dropping the
    covered-type field for SIG rdatas; the zone DB then filed every
    SIG rdataset under typepair (SIG, 0) instead of
    (SIG, covered_type) and follow-up adds collided at that bucket.
    Fixed to use dns_rdatatype_issig().

Both underlying bugs are still reachable via inbound zone transfer
(diff.c rdata_covers() runs from both dns_diff_apply on the IXFR path
and dns_diff_load on the AXFR path), so the type-helper fixes above
remain necessary.  For the dynamic-update path, the simplest and
safest posture is to refuse SIG and NXT outright at the front door in
ns/update.c, alongside the existing NSEC/NSEC3/non-apex-RRSIG
refusals.  KEY remains permitted because it is still used to carry
public keys for SIG(0) transaction authentication.

The existing tcp-self SIG regression test is repointed to assert
REFUSED on the SIG add, a symmetric NXT test is added, and the
SIG-via-dyn-update covers-bucket test is removed because it is no
longer reachable through this entry point; AXFR-based coverage of
diff.c rdata_covers() follows in a separate commit.
2026-04-17 16:09:39 +02:00
Ondřej Surý
0a5ba57116 Fix dropped covers field for SIG records in dns_diff_apply
rdata_covers() in lib/dns/diff.c discriminated only on
dns_rdatatype_rrsig (46) and returned 0 for the legacy SIG (24), so
the covered-type field was silently discarded on the dynamic-update
and IXFR paths.  Every SIG rdataset was then filed in the zone DB
under typepair (SIG, 0) instead of (SIG, covered_type); a second SIG
add with a different covers but a different TTL collided at that
bucket, tripped DNS_DBADD_EXACTTTL in qpzone, returned
DNS_R_NOTEXACT, and came back to the client as SERVFAIL.

Use dns_rdatatype_issig() here so both SIG and RRSIG carry their
covers through the diff, matching the helper pattern already used in
lib/dns/master.c, lib/ns/xfrout.c, lib/dns/qpcache.c, and the
dns__db_findrdataset() REQUIRE that the surrounding merge request
just relaxed.
2026-04-17 16:09:39 +02:00
Mark Andrews
03edeccaa1 Fix assertion failure in dns_db_findrdataset() for SIG records
dns__db_findrdataset() had a REQUIRE() that only accepted
dns_rdatatype_rrsig when the covers parameter was set.  A dynamic
update containing a SIG record (type 24) would trigger this
assertion, crashing named.  Use dns_rdatatype_issig() to accept
both SIG and RRSIG.
2026-04-17 16:09:39 +02:00
Alessio Podda
c7a167c739 Fix strict weak ordering violation in resign_sooner()
resign_sooner_values() only checked whether rhs was SOA-typed when
resign times were equal, but did not check lhs. When both entries were
SOA-typed with equal resign times, the comparison returned true in both
directions, violating irreflexivity and corrupting heap invariants.

Add lhs_typepair parameter and require lhs to be non-SOA for the
tie-breaking logic to apply.
2026-04-17 14:31:15 +02: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ý
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
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
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
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
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
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
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ý
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
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
Colin Vidal
1bad080515 enforce dns_adb_createaddrinfofind() invariant
ADB `dns_adb_createaddrinfofind()` expects `maxaddrs` paramaters is
always strictly positive. Add an assertion to enforce it.
2026-04-08 17:26:49 +02:00
Ondřej Surý
ad6f4e1992 Reduce memory footprint by enabling background page purging
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.
2026-04-08 16:42:19 +02:00
Matthijs Mekking
9c420582be Move dns_zone_next/dns_zone_first to zonemgr
Walking the list of managed zones is a function that operates
on the zone manager object.
2026-04-08 14:27:06 +02:00
Matthijs Mekking
a320801042 Move three more functions to zoneproperties.c
Move the following functions to the zoneproperties source files, as
they are simple get functions:
- dns_zone_getgluecachestats
- dns_zone_getkeystores
- dns_zone_getrequesttransporttype
2026-04-08 14:24:17 +02:00
Matthijs Mekking
d36d775f0f Rename private zone functions
Rename functions that are defined in the private header file to start
with 'dns__zone_'.
2026-04-08 14:24:17 +02:00
Matthijs Mekking
1a0b419991 Lock zone when incrementing statistics
dns__zone_stats_increment() requires the zone to be locked. This was
not always the case. This commit fixes that.
2026-04-08 14:24:17 +02:00
Matthijs Mekking
d3eba4e78f Replace static functions with private functions
Replace 'inc_stats()' with 'dns__zone_stats_increment()'.

Replace 'get_request_transport_type()' with
'dns_zone_getrequesttransporttype()'.
2026-04-08 14:24:17 +02:00
Matthijs Mekking
080e849eaa Move zonemgr to own source file
In order to make zone.c more readable, we are splitting it up in
separate source files. This moves the zonemgr to its own file
("zonemgr.c").

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

The helper functions 'forward_cancel()', 'zone_xfrdone()',
'zmgr_start_xfrin_ifquota()', and 'zmgr_resume_xfrs() need to be
internally accessible to both source files.

Note: This commit does not compile.
2026-04-08 14:24:17 +02:00
Matthijs Mekking
e0f09bb374 Rename isdelegation() to is_insecure_referral()
The name 'isdelegation()' was confusing. This function is not checking
whether this message is a delegation, but whether the denial of
existence proofs in this message is a proof of a referral to an
unsigned zone.

The name 'is_unsecure_referral()' is more appropriate.
2026-04-07 08:38:57 +02:00
Matthijs Mekking
3ac1bb1c39 Revert isdelegation() to return boolean value again
The isdelegation() was changed to return an isc_result_t because the
idea was to have a separate return value DNS_R_NSEC3ITERRANGE to signal
to the caller we could not verify the proof because of too many
iterations in the NSEC3 record, or perhaps ISC_R_UNEXPECTED for a more
generic cause that verification was not done.

But this would make error handling more fragile and all we care about
is whether we can reliably say the NS bit was not set.

If we can not reliably say so, we have to treat it as an insecure
referrral.

Since the answer is either yes or no, we can revert back to returning
a boolean value.
2026-04-07 08:38:46 +02:00
Aydın Mercan
e16a3d7a8e
embed default sanitizer flags in executables
Replicating CI failures requires the developer to piece together the
sanitizer flags by hand, reducing ergonomics.

Fix this problem by embedding the relevant settings to the executables.
Symbol resolution still needs manual intervention by setting the env
variable `*SAN_SYMBOLIZER_PATH`. However, this doesn't affect any behavior.
2026-04-05 12:46:38 +03: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
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ý
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
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