Commit graph

16334 commits

Author SHA1 Message Date
Aram Sargsyan
aed9cafd5c Lock the catalog zone when reconfiguring it
A catalog zone is updated in an offloaded thread, which is not
stopped during a reconfiguration in an exclusive mode, and so
can cause a race condition with it.

Waiting for the offloaded threads to complete their work before
entering into the exclusive mode can potentially cause unwanted
delays, because offloaded threads are generally "allowed" to take
a longer amount of time before they complete.

Add a dns_catz_zone_prereconfig()/dns_catz_zone_postreconfig() pair
of functions which currently just lock the catalog zone when
reconfiguring it. The change should eliminate the race.

As a side note, there was already a similar pair of functions,
dns_catz_prereconfig() and dns_catz_postreconfig() which are called
before and after reconfiguring a 'dns_catz_zones_t' object.

Below are the stack traces of the reconfiguration thread which has
asserted, and a catalog zone update thread which was caught in the
middle of its work despite the fact that the exclusive mode is
turned on.

                Stack trace of thread 23859:
                #0  0x00007f80e7b8e52f raise (libc.so.6)
                #1  0x00007f80e7b61e65 abort (libc.so.6)
                #2  0x0000000000422558 assertion_failed (named)
                #3  0x00007f80eaa6799e isc_assertion_failed (libisc-9.18.41.so)
                #4  0x00007f80ea5bc788 dns_catz_entry_getname (libdns-9.18.41.so)
                #5  0x000000000042ce0e catz_reconfigure (named)
                #6  0x000000000042d3c5 configure_catz_zone (named)
                #7  0x000000000042d7a4 configure_catz (named)
                #8  0x0000000000430645 configure_view (named)
                #9  0x000000000043d998 load_configuration (named)
                #10 0x000000000044184f loadconfig (named)
                #11 0x0000000000442525 named_server_reconfigcommand (named)
                #12 0x000000000041b277 named_control_docommand (named)
                #13 0x000000000041c74a control_command (named)
                #14 0x00007f80eaa912ae task_run (libisc-9.18.41.so)
                #15 0x00007f80eaa914cd isc_task_run (libisc-9.18.41.so)
                #16 0x00007f80eaa46435 isc__nm_async_task (libisc-9.18.41.so)
                #17 0x00007f80eaa467aa process_netievent (libisc-9.18.41.so)
                #18 0x00007f80eaa475a6 process_queue (libisc-9.18.41.so)
                #19 0x00007f80eaa46227 process_all_queues (libisc-9.18.41.so)
                #20 0x00007f80eaa462a1 async_cb (libisc-9.18.41.so)
                #21 0x00007f80e8d01893 uv__async_io.part.3 (libuv.so.1)
                #22 0x00007f80e8d13ac4 uv__io_poll (libuv.so.1)
                #23 0x00007f80e8d023fb uv_run (libuv.so.1)
                #24 0x00007f80eaa45ced nm_thread (libisc-9.18.41.so)
                #25 0x00007f80eaa9bda3 isc__trampoline_run (libisc-9.18.41.so)
                #26 0x00007f80e7f1e1ca start_thread (libpthread.so.0)
                #27 0x00007f80e7b798d3 __clone (libc.so.6)
    ...
    ...
                Stack trace of thread 23912:
                #0  0x00007f80ea5bc2da dns_catz_options_setdefault (libdns-9.18.41.so)
                #1  0x00007f80ea5bd411 dns__catz_zones_merge (libdns-9.18.41.so)
                #2  0x00007f80ea5c3c2f dns__catz_update_cb (libdns-9.18.41.so)
                #3  0x00007f80eaa4fee9 isc__nm_work_run (libisc-9.18.41.so)
                #4  0x00007f80eaa9bda3 isc__trampoline_run (libisc-9.18.41.so)
                #5  0x00007f80eaa4ff48 isc__nm_work_cb (libisc-9.18.41.so)
                #6  0x00007f80e8cfc75e worker (libuv.so.1)
                #7  0x00007f80e7f1e1ca start_thread (libpthread.so.0)
                #8  0x00007f80e7b798d3 __clone (libc.so.6)
2025-12-17 14:54:49 +00:00
Ondřej Surý
bd074ff0ea
Cleanup the extra dns_rdataset_disassociate() code
Manually go through the code using dns_rdataset_isassociated() and
use dns_rdataset_cleanup() where appropriate in places that a simple
semantic patch is not able to find automatically.
2025-12-17 15:19:55 +01:00
Ondřej Surý
8320faf64b
Apply the dns_rdataset_cleanup patch through the codebase
Add a semantic patch to turn the conditional rdataset disassociate into
dns_rdataset_cleanup() call and run it.
2025-12-17 15:19:55 +01:00
Ondřej Surý
cabe3aee3b
Add dns_rdataset_cleanup() that conditionally disassociate rdataset
We had a common pattern in the code that looks like this:

	if (dns_rdataset_isassociated(rdataset)) {
		dns_rdataset_disassociate(rdataset);
	}

add a helper macro that checks for rdataset != NULL and the above
called dns_rdataset_cleanup(rdataset).
2025-12-17 15:19:55 +01:00
Colin Vidal
a95a049963 add support for EDE 9
Extended DNS Error 9 (Missing DNSKEY) is now sent when a validating resolver
attempts to validate a response but can't get the DNSKEY from the authoritative
server of the zone, while the DS record is present in the parent zone.

Note the EDE 9 is send as part of the proveunsecure flow, after the
validator successfully fetched the DS of the zone from the parent. So if
the DS is also missing, the EDE 9 won't be sent.
2025-12-17 09:43:13 +01:00
Ondřej Surý
62cb5b30da Copy only the raw data when we are copying dns_slab{header,vec}
The makeslab function in rdataslab.c contains an optimization for cases
where the source is already an rdataslab. In these cases, it copies the
entire slab using memmove.  However, this creates a race condition: while
the target slab is protected by a node lock, the source slab is not
protected.  This becomes problematic because the TTL heap needs to
modify the heap index stored in the slab header, potentially while the
memmove operation is reading from it.

A closer look at makeslab shows that copying the header part of the slab
is unnecessary, the header can be default-initialized instead. This MR
modifies makeslab to copy only the raw part of the slab, while
default-initializing the header, eliminating the race condition.  For
consistency, it also applies the same change to vecheader/makevec.
2025-12-16 18:09:09 +01:00
Alessio Podda
46f96b0543 Unpack struct vecheader
The bitset packing of the resign_lsb and heap_index in struct vecheader
was causing a race condition, since both bindrdataset and heap
operations tried to access the same byte (even though they are accessing
different fields).

While heap operations are protected by the node lock of the header being
inserted, they aren't protected by the node locks of the headers being
displaced, leading to the race condition.

This commit fixes the issue by reverting the struct packing
optimization.
2025-12-16 17:30:46 +01:00
Alessio Podda
814634f582 Rename rdatavec flags
Qpzone was still using the RDATASLAB constants, instead of the RDATAVEC
ones. While both have the same definition, using the RDATAVEC ones is
correct.
2025-12-16 16:49:58 +01:00
Matthijs Mekking
a4e6fef81c Log serial when IXFR version not in journal
It may be useful to know which version (begin serial) is missing when
the IXFR version cannot be found.
2025-12-10 15:24:29 +00:00
Matthijs Mekking
6f7abbfaac Don't create NSEC3 nodes for unsigned delegations
Instead of creating new nodes for every possible NSEC3 record, only
create them if we are actually going to add a new NSEC3 record.
2025-12-10 14:18:52 +01:00
Matthijs Mekking
41159e9062 Implement dns_dbiterator_seek3
This is a new seek function for dbiterator that is meant to find an
NSEC3 node in a zone database. The difference with dns_dbiterator_seek
is that if the node does not exist, this seek function will point the
iterator to the next NSEC3 name.
2025-12-10 14:18:52 +01:00
Alessio Podda
f1d8c3059c Fix formatting 2025-12-10 12:18:34 +01:00
Alessio Podda
9d74a91301 Add DNS_VECHEADER_FOREACH
Add a FOREACH macro modelled around the DNS_RDATASET_FOREACH one, that
uses vecheader directly. Useful when you want to manipulate a vecheader
without binding it to avoid having to take the node lock inside qpzone.c.
2025-12-10 12:18:34 +01:00
Alessio Podda
4eb0b23efc Switch qpzone to rdatavec
Replaces rdataslab with rdatavec inside qpzone.c. This leads to a 19.92%
reduction of used memory across perflab workloads.
2025-12-10 12:18:34 +01:00
Alessio Podda
f465976536 Document the memory layout of rdatavec 2025-12-10 12:18:34 +01:00
Alessio Podda
b2cad77aa7 Add rdatavec
Add an implementation of rdataset specialized for authoritative
workloads. For now, it is a copy of rdataslab, with redundant fields
from the header removed.
2025-12-10 12:18:34 +01:00
Alessio Podda
04fdf242a8 Add slist.h
Add a macro-based singly-linked list implementation to the codebase,
inspired by the doubly-linked list in list.h.
2025-12-10 12:18:34 +01:00
Alessio Podda
4d698ee0e3 Fix formatting after refactor
The removal of the foundname and name parameters from various qp.c
functions led to formatting issues. Restore the correct formatting via
clang-format.
2025-12-10 11:28:10 +01:00
Alessio Podda
46e25bd0db Remove maybe_set_name
Outside of unit tests, the name parameter in dns_qpiter_<...> and
dns_qpchain_<...> is only used in context where the name can be
extracted directly from the underlying node.

This commits modifies the signatures of dns_qpiter_<...> and
dns_qpchain_<...> not to have a name parameter. Where the name parameter
was needed, we now query the node and copy the name directly from it.

This allows us to remove maybe_set_name from qp.c. Besides simplifying
the API, this leads to a performance speedup for NXDOMAIN handling,
as we avoid calling maybe_set_name inside step, and maybe_set_name is
very inefficient.

A copy of the implementation maybe_set_name is retained for the unit
tests.
2025-12-10 11:28:10 +01:00
Alessio Podda
14f880761b Remove unused foundname parameter
The `foundname` parameter in dns_qp_lookup is used only in the unit
tests. This commit simplifies the API by removing it, and modifying the
unit tests to extract the name from pval.
2025-12-10 11:28:10 +01:00
Evan Hunt
4236d6a325 dns_name_totext() can now resize dynamic buffers
When dns_name_totext() is called with a dynamically allocated
target buffer which is too small for the name, it will resize
the buffer instead of returning ISC_R_NOSPACE.
2025-12-09 12:26:30 -08:00
Ondřej Surý
23ae5544be
Add more information to the rndc recursing output about fetches
It is possible to have a fetch that is active, but it has been cloned,
so it won't be used when found in the hash table.   The fetch options
also prevent matching in the hash table, so add a hexadecimal dump of
the fctx->options to the output.
2025-12-09 17:31:45 +01:00
Alessio Podda
ad0a382092 Fix formatting
Cleanup formatting after IXFR changes.
2025-12-09 13:32:24 +01:00
Alessio Podda
da53708dcb Implement qpzone specific update path
This commit implements a batch update function for qpzone. The main
reason for this is speed: using addrdataset would cause a qp transaction
per rrdataset added, leading to a substantial slowdown compared to
RBTDB. The new API results in a qp transaction per applied diff.
2025-12-09 12:55:30 +01:00
Alessio Podda
e36dc0ca76 Abstract updates into a vtable
This commit adds a layer of indirection to the apply_diff logic used by
IXFR and resigning by having the database updates go through a vtable.

We do this in three steps:
 - We extend dns_rdatacallbacks_t vtable to allow subtraction and
   resigning.
 - We add a new set of api (begin|commit|abort)update to the dbmethods
   vtable, that model an incremental update that can be aborted.
 - We extract the core logic of diff_apply into a function that
   satisfies the new interface.
 - We make diff_apply use this new function, and log the results.

The intent of this commit is to allow databases to expose a batch
incremental update implementation, just like they expose a custom
batch creation implementation through (begin|end)load.
2025-12-09 12:55:30 +01:00
Alessio Podda
6f726ae3db Move setresign to rdataset.c and rename it
The setresign method is not diff specific, it only returns the minimum
resign time of an rdataset. Move it to rdataset.c to simplify late
refactoring.
2025-12-09 12:55:10 +01:00
Alessio Podda
399f0c191a Clean up ixfr transaction API
Make the API tighter. The idea of this commit is to highlight the
distinction between a database transaction and a journal transaction,
and ensure we run dns_zone_verifydb on error.

Done to simplify a later refactor.
2025-12-09 12:55:10 +01:00
Aram Sargsyan
684d7e008a Fix a bug in dns_catz_generate_zonecfg()
The dns_catz_generate_zonecfg() function generates a zone configuration
string to use with a new catalog zone member zone. The buffer for the
string is 512 bytes initially (ISC_BUFFER_INCR), but can be reallocated
when required, when using corresponding isc_buffer functions like
isc_buffer_reserve(), isc_buffer_putstr(), isc_buffer_copyregion(), etc.

However, the dns_name_totext() function, which expects the buffer as an
argument, doesn't automatically resize it if the name doesn't fit there,
but instead just returns ISC_R_NOSPACE.

The chance of this occurring increases when the configuration string is
large due to, for example, long zone name, long list of primary servers
which have keys configured and/or TLS configured.

Use dns_name_format() accompanied with isc_buffer_putstr() instead of
dns_name_totext().
2025-12-09 18:09:45 +11:00
Ondřej Surý
e93eed28f7
Create list of dirty dirty headers that needs cleaning
Instead of just flagging the qpcache node to be dirty, add the headers
to be cleaned to the dirty list and when cleaning the node, only walk
through the dirty node, not all the slabtops.
2025-12-08 19:23:34 +01:00
Ondřej Surý
9914bd383e
In dns_qpiter_{prev,next}, defer dereference_iter_node call
dns_qpiter_{prev,next} requires the current iterator node to still be
valid which might not always the case after dereference_iter_node was
called.  Currently, this is ensured via closeversion() mechanism, but it
is not guaranteed to be true in the future.

Move the call to dereference_iter_node to after the dns_qpiter_prev()
and dns_qpiter_next() to prevent a possible use-after-free of the
current iterator node.
2025-12-08 09:44:58 +01:00
Mark Andrews
b2a3a2ebcf Missing unlock
'kasp->lock' was not released before returning.
2025-12-08 09:59:29 +11:00
Colin Vidal
9c82d15bc2 shrunk cfgobj down from 48 bytes to 40 bytes
Follow-up of 38ce2906 as the size of the `cfg_obj_t` can actually goes
down to 40 bytes "for free", by using bitfields to only use 31 bits for
the `line` field, so the remaining bit can be use to hold the `cloned`
state without paying the extra 8 bytes padding.
2025-12-06 08:51:23 +01:00
Colin Vidal
430c0ce76a support EDE 13 (Cached Error)
Extended DNS Error 13 (Cached Error) is now returned when the server
answers a message from a cached SERVFAIL.

See RFC 8914 section 4.14.
2025-12-05 23:28:29 +01:00
Matthijs Mekking
b19871f8a2 Make keymgr state machine more robust
If the keymgr state machine is in an invalid state, it tries to move
it self to a valid state. But when you do key rollovers during an
invalid state, and the next state is also an invalid state, the keymgr
will happily do the transition.

It would be good to not do key rollovers if there is not a KSK and ZSK
fully omnipresent. But also it would be good to safeguard against
unexpected transitions.

This commit does that by not moving things to unretentive (which is
the state where we would remove the corresponding record from the zone)
if the state machine is currently in an invalid state.
2025-12-05 12:14:14 +01:00
Colin Vidal
77e0104cf4 shrunk cfgobj down to 48bytes
Make all non-scalar properties of `cfg_obj_t` allocated values, which
ensures the union size is the width of one pointer. Also reorder the
fields inside `cfg_obj_t` to avoid alignment padding that would increase
the size. As a result, a `cfg_obj_t` instance is now 48 bytes on a
64-bit platform.

Add a static assertion to avoid increasing the size of the struct by
mistake.

The function `parse_sockaddrsub` was taking advantage of the fact that
both sockaddr and sockaddrtls were in the same position, and used to
initialize the sockaddr field independently if this was a -tls one or
not. This doesn't work anymore now that all fields are allocated,
so it has been slightly rewritten to take both cases into account
separately.
2025-12-05 08:59:53 +01:00
Colin Vidal
c3b7b56dd0 document usage of BIND9 constructors/destructors
Document the way `__attribute__((__constructor__))` and
`__attribute__((__destructor__))` must be used in BIND9 libraries in
order to avoid unexpected behaviors with other third-party libraries.
2025-12-04 16:09:40 +01:00
Colin Vidal
93f8b2f5bf remove memory context from parser context
As the isccfg library now uses the global memory context, it is now
used directly instead of passing the parser context around to grab its
memory context.

Also remove the memory context from the parser, as well as from
`cfg_obj_t`, as it's now useless.
2025-12-04 16:09:40 +01:00
Colin Vidal
f7b64e2e87 cfg_parse_ API doesn't need memory context
Because the parser now uses global memory context, the cfg_parse_* API
doesn't take a memory context anymore.
2025-12-04 16:09:40 +01:00
Colin Vidal
bc82db7b82 remove references from cfg_parser_t
The parser used to be referenced by `cfg_obj_t`, but not anymore.
Removing the reference counter from `cfg_parser_t`.
2025-12-04 16:09:40 +01:00
Colin Vidal
870b7329f8 parser: add cfg_string_create() API
The parser has a static function `create_string()` used
internally. But there was duplicate code to create a string node
in `namedconf.c`.  Instead of implementing the same logic twice,
`create_string()` is now publicly exposed as `cfg_string_create()`.
2025-12-04 16:09:40 +01:00
Evan Hunt
d4ebea1037 use a standard CLEANUP macro
CLEANUP is a macro similar to CHECK but unconditional, jumping
to cleanup even if the result is ISC_R_SUCCESS. It is now used
in place of DST_RET, CLEANUP_WITH, and CHECK(<non-success constant>).
2025-12-03 13:45:43 -08:00
Mark Andrews
6c0f1b212e Remove unreachable code
Remove some code checking for return values that are not possible.
2025-12-03 13:45:43 -08:00
Mark Andrews
5bd9f16ec0 Use isc_result_t more consistently
Some functions to check private data when parsing keys previously
used integer return codes, and have been updated to use isc_result_t.
2025-12-03 13:45:43 -08:00
Mark Andrews
0e230c86d2 Rename isc_result_t ret; to isc_result_t result;
Standardize result variable naming by using 'result' in most places.
2025-12-03 13:45:43 -08:00
Evan Hunt
6b33b7fc77 switch to RETERR where it wasn't being used
replace all instances of the pattern:

        result = <statement>
        if (result != ISC_R_SUCCESS) {
                return result;
        }

with:

        RETERR(<statement>);
2025-12-03 13:45:43 -08:00
Evan Hunt
38e94cc7da switch to CHECK where it wasn't being used
replace all instances of the pattern:

        result = <statement>
        if (result != ISC_R_SUCCESS) {
                goto cleanup;
        }

with:

        CHECK(<statement>);
2025-12-03 13:45:42 -08:00
Evan Hunt
52bba5cc34 standardize CHECK and RETERR macros
previously, there were over 40 separate definitions of CHECK macros, of
which most used "goto cleanup", and the rest "goto failure" or "goto
out". there were another 10 definitions of RETERR, of which most were
identical to CHECK, but some simply returned a result code instead of
jumping to a cleanup label.

this has now been standardized throughout the code base: RETERR is for
returning an error code in the case of an error, and CHECK is for jumping
to a cleanup tag, which is now always called "cleanup". both macros are
defined in isc/util.h.
2025-12-03 13:26:28 -08:00
Colin Vidal
3048b2a578 add RRSIG if required as soon as they are found
When EDNS DO flag (`dig +dnssec`) flag is set, an rdataset is allocated
to hold the RRSIG of an RR, if present in DB. However, this allocation
is not done if the zone DB is not considered as secure
(`dns_db_issecure() == false`). Changes this behaviour by allocating the
rdataset anyway, so the RRSIG can be associated in the answer section of
the response as soon it is found from the DB.
2025-12-03 15:49:47 +01:00
Evan Hunt
76b6fb3802 pass isc_buffer_t pointers when applicable
In commit aea251f3bc, `isc_buffer_reserve()` was changed to
take a simple `isc_buffer_t *` instead of `isc_buffer_t **`.
A number of functions calling it have now been similarly
modified.
2025-11-28 18:47:49 +00:00
Matthijs Mekking
0941b5754c Change output of rndc dnssec -status
Wrap 'dns_keymgr_status()' in 'dns_zone_dnssecstatus()' so we can easily
retrieve the zone string name and refresh key time value.

In addition to the current time, output when the next key event is
expected.

Don't log keys that are completely hidden unless verbose is set.
Don't log key state values unless verbose is set, or they are in a
weird state.

For expected key states, log a more useful message of the stage of
the rollover. If we are in the middle of a key rollover, don't log
when the next key rollover is scheduled.

Condense the output for better readability.
2025-11-28 15:32:17 +01:00