Remove the dbiterator_{last,prev} from the qpcache
The dbiterator_{last,prev} functions are not used in the cache, and the
implementation would get quite complicated when we squash the main and
nsec trees together. It's easier to just not implement these.
Petr Špaček [Fri, 11 Jul 2025 19:10:19 +0000 (21:10 +0200)]
Add ability to load root zone into AsyncServer
We would prefer if explicit $ORIGIN is used only for root zone and
nothing else, solely to avoid zone files named "..db". For all other
zones the file name should match zone name.
Some of the API calls in `dns_db` were obsolete, and have been removed. Others were more complicated than necessary, and have been refactored to simplify.
Evan Hunt [Thu, 14 Aug 2025 23:28:11 +0000 (16:28 -0700)]
remove dns_db_{un,}locknode
remove the dns_db_locknode() and _unlocknode() calls, so that callers no
longer have the ability to directly manipulate the internal locking of
cache and zone databases.
Evan Hunt [Mon, 11 Aug 2025 19:13:53 +0000 (12:13 -0700)]
make getoriginnode implementation optional
if the dns_db_getoriginnode() call is not implemented, we can
fall back to running dns_db_findnode() on the database origin.
we now only implement getoriginnode directly in databases where
it's clearly faster than the fallback implementation would be.
Evan Hunt [Thu, 7 Aug 2025 21:24:01 +0000 (14:24 -0700)]
minor cleanup in sdlz.c
dns_db_issecure() and dns_db_nodecount() return false and 0,
respectively, if they are not implemented, so there's no need to
have implementation functions that only return false and 0.
Evan Hunt [Mon, 4 Aug 2025 23:54:08 +0000 (16:54 -0700)]
merge dns_db_find/findext and dns_db_findnode/findnodeext
the dns_db_findext and _findnodeext calls are extended versions
of dns_db_find and _findnode, which take additional arguments for
client information in order to support ECS. previously, database
implementations could support either API call, with cross-compatibility
so that, for example, dns_db_findext() could call a find implementation
if findext was not implemented, and dns_db_find() could call findext
if find was not implemented.
this has now been simplified. the find and findnodeext implementations
now support client info. all database implementations will now provide
these calls. implementations which do not support ECS will simply
ignore the clientinfo and clientinfomethods parameters.
this only affects the underlying implementation; callers will still
use the same interface. dns_db_find() and dns_db_findnode() are now
macros which pass NULL to the clientinfo parameters, so that callers
don't have to do so explicitly. dns_db_findext() and dns_db_findnodeext()
are still available for callers that do wish to pass clientinfo pointers.
Evan Hunt [Mon, 4 Aug 2025 23:24:09 +0000 (16:24 -0700)]
remove obsolete dns_db_hashsize()
this function's purpose was to populate the "CacheBuckets" statistic,
but there are no databases left that implemented it, so the return
value was always 0. "CacheBuckets" has now been removed from the
statistics, and the dns_db_hashsize() API call has been removed.
Evan Hunt [Mon, 4 Aug 2025 23:06:23 +0000 (16:06 -0700)]
dns_rdatalist functions are not for general use
the rdataset method implementation functions in dns/rdatalist.c (i.e.,
dns_rdatalist_first, _next, etc) are not meant to be called directly;
they're called via dns_rdataset_first(), dns_rdataset_next(), etc.
in dnssec-ksr.c, a list-based rdataset was iterated using these
functions. this has been fixed, and the functions have been renamed
to use the `dns__` prefix as a signal that they aren't meant to be
used outside the rdataset implementation.
fix: dev: Fix detection of whether node is active in find_wildcard()
The current code would fail during the write transaction. The first
header would not match the search->serial and the node might be
incorrectly detected as inactive.
Merge branch 'ondrej/fix-find-wildnode-active-node-detection' into 'main'
Fix detection whether node is active in find_wildcard()
The current code would fail during the write transaction. The first
header would not match the search->serial and the node might be
incorrectly detected as inactive.
chg: dev: Make the database ownercase modifiable only via addrdataset()
Simplify the implementation around the database ownercase. Remove the
dns_rdataset_setownercase() implementation for the slabheaders and only
allow setting ownercase on rdatalists and rdatasets. The ownercase in
the database can now be set only with dns_db_addrdataset() by passing
rdataset with correctly set ownercase.
Merge branch 'ondrej/make-database-ownercase-mostly-constant' into 'main'
Make the database ownercase modifiable only via addrdataset()
Simplify the implementation around the database ownercase. Remove the
dns_rdataset_setownercase() implementation for the slabheaders and only
allow setting ownercase on rdatalists and rdatasets. The ownercase in
the database can now be set only with dns_db_addrdataset() by passing
rdataset with correctly set ownercase.
Colin Vidal [Thu, 11 Sep 2025 12:21:24 +0000 (14:21 +0200)]
fix: dev: do not inline dns_zone_gethooktable
Since !10959 `dns_zone_gethooktable()` is only called once per query,
and the suspicion (from perflab analysis) that this (simple, as just
returning a pointer) call was slowing things down (perhaps because of
code locality reasons?) doesn't matter anymore. So even if !10959
inlined it, it shouldn't matter anymore.
Merge branch 'colin/minimize-hooktable-lookup-followup' into 'main'
Colin Vidal [Thu, 11 Sep 2025 09:51:06 +0000 (11:51 +0200)]
do not inline dns_zone_gethooktable
Since !10959 `dns_zone_gethooktable()` is only called once per query,
and the suspicion (from perflab analysis) that this (simple, as just
returning a pointer) call was slowing things down (perhaps because of
code locality reasons?) doesn't matter anymore. So even if !10959
inlined it, it shouldn't matter anymore.
Petr Špaček [Thu, 11 Sep 2025 09:06:21 +0000 (11:06 +0200)]
Prevent Sphinx from messing up syntax with "smartquotes" feature
Sphinx's smartquotes feature was rewriting -- to en-dash, "" to proper
English quotes etc. This was messing up syntax at unpredictable places.
Disable this feature instead of attempting to escape all the places in
the manual.
Colin Vidal [Thu, 11 Sep 2025 06:37:03 +0000 (08:37 +0200)]
fix: dev: minimize zone hooktable lookups
Merging !10483 caused a performance regression because the zone hooktable had to be looked up every time a hook point was reached, even if no zone plugins were configured. We now look up the zone hooktable when a zone is attached to the query context, and keep a pointer to it until the qctx is destroyed.
Merge branch 'each-zoneplugin-zonehook-once' into 'main'
query_reset() is called during query initialization, but the only
time the NS_QUERY_SETUP hook runs is when it's called from
query_cleanup(). it makes more sense to move the hook point to
there and rename it to NS_QUERY_CLEANUP.
this change caused a crash in the unit tests due to the view being
unnecessarily detached before ns__client_reset_cb() was called.
this has also been fixed.
Colin Vidal [Wed, 10 Sep 2025 20:40:44 +0000 (22:40 +0200)]
don't call hooks when a query hasn't started
guard the call to the NS_QUERY_RESET hook so it's called only if
the view has been set. If the view is NULL, it means the client has
been reset _before_ the query even started, and no other hook could
have been called, so it doesn't make sense to call this one.
this also enables us to avoid a NULL-check on the qctx->view in the
CALL_HOOK macros.
add a 'zhooks' member to the query_ctx structure, so that we only
need to look up the hook table for the zone once when iniitalizing
a qctx, and not once for every hook point.
chg: nil: Reduce the code duplication around getting slabheaders from slabtop
There was a lot of duplicated code around getting the first header that
exists, is active, and matches the version header from the qpzonedb.
Move the duplicate code into a helper function and unify the same
approach for the qpcache too even though the code is much simpler there.
It should come handy when top->header is something more complicated than
a pointer to first slabheader.
Merge branch 'ondrej/refactor-getting-the-first-slabheader-from-slabtop' into 'main'
Reduce the code duplication around getting slabheaders from slabtop
There was a lot of duplicated code around getting the first header that
exists, is active, and matches the version header from the qpzonedb.
Move the duplicate code into a helper function and unify the same
approach for the qpcache too even though the code is much simpler there.
It should come handy when top->header is something more complicated than
a pointer to first slabheader.
Mark Andrews [Wed, 3 Sep 2025 23:57:10 +0000 (09:57 +1000)]
Fix missing RRSIGs for "glue" lookups with CD=1
The code to test whether to store the RRSIGs on DNS_R_UNCHANGED
with CD=1 was failing because the comparison methods of the two
rdatatset instances were not compatible. Move the testing into
dns_db_addrdataset(), and request it by setting the DNS_ADD_EQUALOK
option. If the option is set and the old and new rrsets compare
as equal, dns_db_addrdataset() returns ISC_R_SUCCESS instead of
DNS_R_UNCHANGED.
When the `dnssec-signzone` tests were moved to the `dnssectools`
system test, an unused copy of the `signer` directory was left in
the `dnssec` test. This has been removed.
Merge branch 'each-cleanup-dnssec-files' into 'main'
Evan Hunt [Wed, 20 Aug 2025 18:28:32 +0000 (11:28 -0700)]
remove 'signer' files from dnssec test
when the dnssec-signzone tests were moved to the dnssectools
system test, a unused copy of the 'signer' directory was left in
the dnssec test. This has been removed.
Colin Vidal [Tue, 9 Sep 2025 19:56:03 +0000 (21:56 +0200)]
new: usr: support for zone-specific plugins
Query plugins can now be configured at the `zone` level, as well as globally or at the `view` level. A plugin's hooks are then called only while that specific zone's database is being used to answer a query.
This simplifies the implementation of plugins that are only needed for specific namespaces for which the server is authoritative. It can also enable quicker responses, since plugins will only be called when they are needed.
Colin Vidal [Mon, 8 Sep 2025 08:12:53 +0000 (10:12 +0200)]
remove query_ctx_t detach_client property
Since the removal of NS_QUERY_QCTX_DESTROYED hook, there is no need for
the `qctx->detach_client` object anymore, as this was designed to tell
the plugin whether the client object is about to be, or is already,
freed from memory. This is not needed anymore, as NS_QUERY_RESET is
called _always_ when the client object is about to be freed from memory.
Remove `detach_client` and tidy up the code a bit by including the
freeing of the qctx object (when allocated) inside the qctx_destroy
function instead of requiring extra calls.
Colin Vidal [Mon, 8 Sep 2025 08:12:29 +0000 (10:12 +0200)]
update hooks tests to use NS_QUERY_RESET
Update hooks-related unit tests since the removal of
NS_QUERY_QCTX_DESTROY and the introduction of NS_QUERY_RESET hook. This
also simplifies (a bit) the plugin usage as NS_QUERY_RESET is _always_
called when the client plugin is about to be freed from memory.
Colin Vidal [Mon, 8 Sep 2025 08:10:37 +0000 (10:10 +0200)]
replace QCTX_INIT/_DESTROY hooks with QUERY_SETUP/_RESET
The hook NS_QUERY_QCTX_DESTROY is problematic with zone plugins because
it can be called in some contexts where `qctx->client` is invalid (the
pointer is dangling); which would lead to a use-after-free (spotted by
TSAN build) as `qctx->client` is used to get the zone hooktable, to find
out whether there is an authoritive zone which would have
NS_QUERY_QCTX_DESTROY registered.
This can't easily be fixed, because there is no easy way to know from
query.c code if `client` is still a valid object: `client->reqhandle`,
representing the request from a client, is refcounted, and the `client`
object is freed from memory once its refcounter gets to 0. While
`reqhandle` is attached from query.c code, it can be attached more than
once from asynchronous code and there is no clear path where detaching
it would lead to a client free. Hence, there is no way to know for sure
when to set `qctx->client = NULL` (this is why the pointer remains
dangling).
Back to the original problem; this is why the NS_QUERY_QCTX_DESTROY hook
is incompatible with zone plugins. `qctx->detach_client`, which is used
to tell a plugin that the `client` object is either free or about to be
free can't be use either, because in some cases the client is still
there, and should be used.
Code issue aside, the `qctx` object is really just an aggregate of
various data to pass easily in the various functions and callbacks,
initially stored on the stack, but allocated in some cases (for some
asynchronous flow, when recursion is needed), so the point it gets
created/"destroyed" is really just an implementation "detail", and
providing a higher level hook for the plugin would be beneficial. Hence,
NS_QUERY_RESET and NS_QUERY_INIT are removed, and instead, the existing
NS_QUERY_SETUP can be used as well as the newly introduced
NS_QUERY_RESET (which replaces NS_QUERY_QCTX_DESTROY). The advanage is
that NS_QUERY_RESET is called _only_ when the client object is _always_
about to be freed, which avoids usage of the extra `qctx->detach_client`
usage from the plugin.
The way NS_QUERY_RESET works is that when the `client` is freed, a
callback (from `query.c`) is called. This callback creates a transient
qctx object on the stack with a pointer to the view, and uses that
to call the hook.
Colin Vidal [Tue, 19 Aug 2025 12:45:56 +0000 (14:45 +0200)]
add unit test for plugin_register source param
Update the existing test's syncplugin plugin with a new parameter
indicating whether the plugin should be loaded in a view or a zone.
If it doesn't match where the plugin is actually loaded, it fails the
initialization. This covers the correctless of the `source` parameter of
`plugin_register` API.
Colin Vidal [Tue, 19 Aug 2025 12:38:36 +0000 (14:38 +0200)]
add plugin_register param telling the source
The plugin `plugin_register` API has a new parameter `source` indicating
whether the plugin is loaded from a view or a zone.
This extra parameter enables the plugin to fail early during
initialization if a plugin written to be used in a zone exclusively
is loaded at a view level, or vice versa.
Colin Vidal [Tue, 10 Jun 2025 14:32:04 +0000 (16:32 +0200)]
filter-aaaa can be used as zone or view plugin
Update the filter-aaaa system test so the two authoritative zones
in ns4 both configure filter-aaaa as a zone plugin.
In order to work in both contexts, the plugin must register both
the `NS_QUERY_QCTX_INITIALIZED` and `NS_QUERY_AUTHZONE_ATTACHED`
hooks.
When the plugin is configured at the zone level in an authoritative
server, `NS_QUERY_QCTX_INITIALIZED` is skipped, because no zone will
have been looked up by the time it is called. When the zone is
found, calling `NS_QUERY_AUTHZONE_ATTACHED` will allow the same
initialization to occur.
Colin Vidal [Tue, 10 Jun 2025 14:27:58 +0000 (16:27 +0200)]
add NS_QUERY_AUTHZONE_ATTACHED hook
Add a new query hook called `NS_QUERY_AUTHZONE_ATTACHED`. This hook is
called whenever an authoritative zone is found and attached during a
query answer.
From code level, this hook is called when `qctx->client->query->authzone`
is attached during a query. This enables zone-specific plugins to
initialize specific states whenever a local zone is found that can
answer a query.
Colin Vidal [Thu, 5 Jun 2025 15:31:12 +0000 (17:31 +0200)]
update hook developer documentation
Attempt to add zone plugin specificities into the hook developer
documentation. In particular about the hook call order and hookpoint
which can't be called on a zone plugin.
Colin Vidal [Wed, 4 Jun 2025 11:52:30 +0000 (13:52 +0200)]
add template support for zone plugins
The zone plugin loading code now also looks into the zone template
configuration property of a zone. If it exists, it checks whether there
is a plugin sub-tree defined in the template and, if that exists, loads
the plugin definition from the template.
Colin Vidal [Wed, 28 May 2025 09:54:19 +0000 (11:54 +0200)]
add query unit test
A new query unit test covers the logic where zone hooks must be called
first, then view ones, and finally the default hooks. It also ensures
that if any hook returns NS_HOOK_RETURN the chain immediately stops.
The rrset-order random doesn't offer uniform distribution of all
permutations and it isn't superior to cyclic order in any way. Make the
random ordering an alias to the cyclic ordering.
Closes: #5513
Merge branch 'ondrej/remove-rrset-order-random' into 'main'
Ondřej Surý [Thu, 28 Aug 2025 17:19:01 +0000 (19:19 +0200)]
Refactor the cyclic ordering to use query ID as offset
Mimic the Unbound behaviour where the cyclic offset is taken from query
ID, and remove recording of the current state. As the incoming query ID
should have random distribution, the cyclic ordering should also have
uniform distribution of the starting record.
Ondřej Surý [Thu, 28 Aug 2025 13:29:44 +0000 (15:29 +0200)]
Refactor the cyclic ordering to be more efficient
With random ordering removed, the cyclic ordering can be rewritten in a
that it uses thread_local static array to keep the cyclic order.
This could be further improved by keeping the current position inside
the slabheader and adding a function to start directly there instead at
dns_rdataset_first().
Ondřej Surý [Thu, 28 Aug 2025 10:24:17 +0000 (12:24 +0200)]
Remove the random ordering of resource records in RRset
The rrset-order random doesn't offer uniform distribution of all
permutations and it isn't superior to cyclic order in any way. Make the
random ordering an alias to the cyclic ordering.
Colin Vidal [Mon, 8 Sep 2025 10:46:48 +0000 (12:46 +0200)]
new: usr: add extra tokens to the zone file name template
Extend the `$name`, `$view` and `$type` tokens (expanding into the zone
name, zone's view name and type); the new following tokens are now also
accepted:
- `$name` or `%s` is replaced with the zone name in lower case;
- `$type` or `%t` is replaced with the zone type -- i.e., primary,
secondary, etc);
- `$view` or `%v` is replaced with the view name;
- `$char1` or `%1` is replaced with the first character of the zone name;
- `$char2` or `%2` is replaced with the second character of the zone name
(or a dot if there is no second character);
- `$char3` or `%3` is replaced with the third character of the zone name (or
a dot if there is no third character);
- `$label1` or `%z` is replaced with the toplevel domain of the zone (or a
dot if it is the root zone);
- `$label2` or `%y` is replaced with the next label under the toplevel
domain (or a dot if there is no next label);
- `$label3` or `%x` is replaced with the next-next label under the toplevel
domain (or a dot if there is no next-next label).
Colin Vidal [Thu, 24 Jul 2025 12:54:07 +0000 (14:54 +0200)]
add extra tokens to the zone file name template
Extend the `$name`, `$view` and `$type` tokens (expanding into the zone
name, zone's view name and type); the new following tokens are now also
accepted:
- $name or %s is replaced with the zone name in lower case;
- $type or %t is replaced with the zone type -- i.e., primary,
secondary, etc);
- $view or %v is replaced with the view name;
- $char1 or %1 is replaced with the first character of the zone name;
- $char2 or %2 is replaced with the second character of the zone name
(or a dot if there is no second character);
- $char3 or %3 is replaced with the third character of the zone name (or
a dot if there is no third character);
- $label1 or %z is replaced with the toplevel domain of the zone (or a
dot if it is the root zone);
- $label2 or %y is replaced with the next label under the toplevel
domain (or a dot if there is no next label);
- $label3 or %x is replaced with the next-next label under the toplevel
domain (or a dot if there is no next-next label).
Petr Špaček [Thu, 4 Sep 2025 06:26:57 +0000 (08:26 +0200)]
Tweak and reword release notes
Two inconsequential bug fixes are not release note worthy.
Use more user-centric terminology about dnssec-policy manual-mode.
Add links, shorten notes.
In order to not pollute the SERVFAIL cache with the configured
SERVFAIL answers while RPZ is loading, set the NS_CLIENTATTR_NOSETFC
attribute for the client.
Merge branch 'aram/rpz-servfail-until-ready-tunings' into 'main'
Aram Sargsyan [Wed, 27 Aug 2025 15:25:43 +0000 (15:25 +0000)]
Log the servfail-until-ready message not faster than once per second
Since the log level has been raised, busy servers can "explode" from
the amount of log messages. Use the usual practice of logging "every
once in a while".
Aram Sargsyan [Wed, 27 Aug 2025 14:35:09 +0000 (14:35 +0000)]
Change the "RPZ not ready yet" message and its log level
The "RPZ not ready yet" message is logged at debug 3 level. Use the
info level instead for better visibility.
After raising the log level, the rpz_log_fail_helper() function starts
appending " failed: " the the message. Change the log message so it
makes more sense.
In order to not pollute the SERVFAIL cache with the configured
SERVFAIL answers while RPZ is loading, set the NS_CLIENTATTR_NOSETFC
attribute for the client.
Mark Andrews [Tue, 2 Sep 2025 23:41:18 +0000 (09:41 +1000)]
fix: usr: RPZ canonical warning displays zone entry incorrectly
When an IPv6 rpz prefix entry is entered incorrectly the log
message was just displaying the prefix rather than the full
entry. This has been corrected.
Closes #5491
Merge branch '5491-rpz-canonical-warning-displays-zone-entry-incorrectly' into 'main'