It was discovered during research for an upcoming academic paper that a
xoshiro128\*\* internal state can be recovered by an external 3rd party,
allowing the prediction of UDP ports and DNS IDs in outgoing queries.
This could lead to an attacker spoofing the DNS answers with great
efficiency and poisoning the DNS cache.
The internal random generator has been changed to a cryptographically
secure pseudo-random generator.
ISC would like to thank Prof. Amit Klein and Omer Ben Simhon from Hebrew
University of Jerusalem for bringing this vulnerability to our
attention.
Closesisc-projects/bind9#5484
Merge branch '5484-security-make-isc_random-csprng' into 'v9.21.13-release'
See merge request isc-private/bind9!831
Use arc4random on platforms where available. arc4random() provides high
quality cryptographically-secure pseudo-random numbers and is generally
recommended for application use.
The uv_random() call unfortunately uses getentropy() on platforms like
MacOS, OpenBSD or NetBSD which is not recommended for application use.
It was discovered in an upcoming academic paper that a xoshiro128**
internal state can be recovered by an external 3rd party allowing to
predict UDP ports and DNS IDs in the outgoing queries. This could lead
to an attacker spoofing the DNS answers with great efficiency and
poisoning the DNS cache.
Change the internal random generator to system CSPRNG with buffering to
avoid excessive syscalls.
Thanks Omer Ben Simhon and Amit Klein of Hebrew University of Jerusalem
for responsibly reporting this to us. Very cool research!
Previously, several issues could be exploited to poison a DNS cache with
spoofed records for zones which were not DNSSEC-signed or if the
resolver was configured to not do DNSSEC validation. These issues were
assigned CVE-2025-40778 and have now been fixed.
As an additional layer of protection, :iscman:`named` no longer accepts
DNAME records or extraneous NS records in the AUTHORITY section unless
these are received via spoofing-resistant transport (TCP, UDP with DNS
cookies, TSIG, or SIG(0)).
ISC would like to thank Yuxiao Wu, Yunyi Zhang, Baojun Liu, and Haixin
Duan from Tsinghua University for bringing this vulnerability to our
attention.
Closesisc-projects/bind9#5414
Merge branch '5414-security-check-name-vs-qname-again' into 'v9.21.13-release'
See merge request isc-private/bind9!838
To prevent spoofed unsigned DNAME responses being accepted retry
response with unsigned DNAMEs over TCP if the response is not TSIG
signed or there isn't a good DNS CLIENT COOKIE.
Use the owner name of the NS record as the bailwick apex name
when determining which additional records to cache, rather than
the name of the delegating zone (or a parent thereof).
To prevent certain spoofing attacks, a new check has been added
to the existing rules for whether NS data can be cached: the owner
name of the NS RRset must be an ancestor of the name being queried.
Previously, if a matching but cryptographically invalid key was encountered during
DNSSEC validation, the key was skipped and not counted
towards validation failures. :iscman:`named` now treats such DNSSEC keys
as hard failures and the DNSSEC validation fails immediately, instead of
continuing with the next DNSKEYs in the RRset.
ISC would like to thank Zuyao Xu and Xiang Li from the All-in-One
Security and Privacy Laboratory at Nankai University for bringing this
vulnerability to our attention.
Closesisc-projects/bind9#5343
Merge branch '5343-security-count-invalid-keys-into-validation-fails' into 'v9.21.13-release'
See merge request isc-private/bind9!821
If a matching but cryptographically invalid key was encountered during
the DNSSEC validation, the key would be just skipped and not counted
towards validation failures. Treat such DNSSEC keys as hard failures
and fail the DNSSEC validation immediatelly instead of continuing the
DNSSEC validation with the next DNSKEYs in the RRset.
Co-authored-by: Matthijs Mekking <matthijs@isc.org>
bin/tests/system/synthrecord/tests_synthrecord.py imports hypothesis
before importing isctest.hypothesis, which causes the "synthrecord"
system test to fail on platforms on which the Hypothesis module is not
available. Reorganize Python imports in tests_synthrecord.py to fix the
above issue and also to make it more in line with other similar test
scripts.
Closes#1586
Merge branch '1586-reorganize-imports-in-tests_synthrecord.py' into 'main'
See merge request isc-projects/bind9!11046
bin/tests/system/synthrecord/tests_synthrecord.py imports hypothesis
before importing isctest.hypothesis, which causes the "synthrecord"
system test to fail on platforms on which the Hypothesis module is not
available. Reorganize Python imports in tests_synthrecord.py to fix the
above issue and also to make it more in line with other similar test
scripts.
Follow-up on the discussion on the kasp system test rewrite to pytest.
Closes#5289
Merge branch '5289-kasp-system-test-follow-up-2' into 'main'
See merge request isc-projects/bind9!11043
The type `ns_pluginregister_ctx_t` was initially added to pass plugin
contextual data when the plugin is registered, but this is also now
passed into `plugin_check`. Furthermore, those various data are not
specific to the registration in particular. Rename the type into
`ns_pluginctx_t` for clarity.
Merge branch 'colin/rename-pluginctx-rename' into 'main'
See merge request isc-projects/bind9!11035
The type `ns_pluginregister_ctx_t` was initially added to pass plugin
contextual data when the plugin is registered, but this is also now
passed into `plugin_check`. Furthermore, those various data are not
specific to the registration in particular. Rename the type into
`ns_pluginctx_t` for clarity.
In the 'release' stage, create an MR automatically with the
corresponding release announcement. The input for this is taken from
metadata.json in bind9-qa.
Merge branch 'andoni/release-announcement-preparation' into 'main'
See merge request isc-projects/bind9!11039
In the 'release' stage, create an MR automatically with the
corresponding release announcement. The input for this is taken from
metadata.json in bind9-qa.
Convert the defines to enums. Initialize the tags more explicitly and less ugly.
Merge branch 'matthijs-ugly-kid-joe' into 'main'
See merge request isc-projects/bind9!11000
Add a query plugin which, in "reverse" mode, enables the server to build a synthesized response to a PTR query when the PTR record requested is not found in the zone.
The dynamically-built name is constructed from a static prefix (passed as a plugin parameter), the IP address (extracted from the query name) and a suffix (also passed as a plugin parameter). An `allow-synth` address-match list can be used to limit the network addresses for which the plugin may generate responses.
The plugin can also be used in "forward" mode, to build synthesized A/AAAA records from names using the same format as the dynamically-built PTR names. The same parameters are used: the plugin will react and answer a query if the name matches the configured prefix and origin, and encodes an IP address that is within `allow-synth`.
Closes#1586
Merge branch '1586-synthreverse' into 'main'
See merge request isc-projects/bind9!10348
The "origin" parameter for synthrecord is now mandatory for reverse
zones, but when configured in a non-reverse zone, it will default to
the zone name.
the plugin's operating mode is now determined automatically
from the zone name: if the name ends in "ip6.arpa" or "in-addr.arpa",
then the plugin is in reverse mode, otherwise forward.
Names for reverse resolution are now shared and accessible from
dns/name.h header as those are used by ptr_12.c and byaddr.c files.
(Also, for consistency, move deprecated ip6.int. name in name.h, even
though it is used only by ptr_12.c).
Add system tests for the dynamically synthesized record plugin. This
covers the various cases the plugin should handle: generating a PTR
record only when (1) no answer is found locally and (2) the IP address
extracted from the query name is part of an allowed network. This also
covered the cases of forward synthesized records; answering a A/AAAA/ANY
query from a PTR address when this match the prefix, ACL and origin.
Add a BIND9 plugin which, in "reverse" mode, enables the server to build
a synthesized response to a PTR query when the PTR record requested is
not found in the zone. (The plugin won't be called for names below a
delegation point, because it couldn't know whether a name actually
exists within the delegation.)
The dynamically-built name is constructed from a static prefix (passed
as a plugin parameter), the IP address (extracted from the query name)
and a suffx (also passed as a plugin parameter). An "allow-synth"
address-match list is used to limit the network addresses for which
the plugin may generate responses.
The plugin can also be used in "forward" mode, to build synthesized
A/AAAA records from names using the same format as he dynamically-built
PTR names, if the query name and type are not found in the zone.
The same parameters are used when the plugin is in forward mode:
the plugin will react and answer a query if the name matches the
configured prefix and origin, and encodes an IP address that is
within "allow-synth".
Add an API to parse and extract either an IPv4 or IPv6 address from
a name using the reverse format. It takes care of family detection,
and returns a generic error in case of syntax error.
Functions hex_decode_init(), hex_decode_char() and hex_decode_finish()
are now exposed, as well as the context hex_decode_ctx_t. They now are
respectively called isc_hex_decodeinit(), isc_hex_decodechar(),
isc_hex_decodefinish() and isc_hex_decodectx_t.
This enable to re-implement the functionality of isc_hex_decodestring()
in contextes where the input is not a NULL-terminated string, but, for
example, individual characters extracted (and avoid creating an
intermediate buffer to store them). This also enable to decode a stream
of hex characters where only hex characters are expected (i.e. no white
spaces).
Add a new type, `ns_pluginregister_ctx_t`, which is passed to `plugin_register()` in place of the `source` parameter. The source value is now just part of the structure, which also holds a pointer to the zone origin if the plugin is loaded at a zone level.
This provides more contextual information, enabling the plugin to make specific configuration decisions based on the name of the zone for which it is loaded.
It's also flexible if more contextual data are needed in the future: add a new field to `ns_pluginregister_ctx_t`, and new plugins can use it without affecting compatibility with existing plugins.
Closes#5533
Merge branch '5533-plugin-register-ctx' into 'main'
See merge request isc-projects/bind9!11019
Make sure all zone's plugin are unloaded before the zone gets freed.
This makes passing zone metadata like its origin to the plugin
registering function safe, as this garantee that the origin would always
be valid from the plugin lifecycle.
This commit introduces a new type, ns_pluginregister_ctx_t,
which is passed to plugin_check() and plugin_register() in place of the
'source' parameter. The source value is now just part of the structure,
which also holds a pointer to the zone origin if the plugin is loaded at
a zone level.
This provides more contextual information, enabling the plugin to make
specific configuration decisions based on the name of the zone for which
it is loaded.
It's also flexible if more contextual data are needed in the future:
add a new field to ns_pluginregister_ctx_t, and new plugins can use
it without affecting compatibility with existing plugins.
In `named_config_parsefile()`, when checking the validity of
`named.conf`, the checking of plugin correctness was deliberately
postponed until the plugin is loaded and registered. However,
the checking was never actually done: the `plugin_register()`
implementation was called, but `plugin_check()` was not.
`ns_plugin_register()` (used by `named`) now calls the check function
before the register function, and aborts if either one fails.
`ns_plugin_check()` (used by `named-checkconf`) calls only
the check function.
Merge branch 'each-check-plugin-named' into 'main'
See merge request isc-projects/bind9!11031
In named_config_parsefile(), when checking the validity of
named.conf, the checking of plugin correctness was deliberately
postponed until the plugin is loaded and registered. However,
when the plugin was registered, the checking was never actually
done: the plugin_register() implementation was called, but
plugin_check() was not.
This made it necessary to duplicate the correctness checking in both
functions, so that both named-checkconf and named could catch errors.
That should not be required.
ns_plugin_register() now calls the check function before the register
function, and aborts if either one fails. ns_plugin_check() calls only
the check function. ns_plugin_check() is used by named-checkconf, and
ns_plugin_register() is used by named. (Note: this design has a
side effect that a call to ns_plugin_register() will result in the
plugin parameters being parsed twice at registration time.)
ns_plugin_check() now takes an additional argument for the hook
source: zone or view.
Macro CHECK_FOR_GLUE_IN_ANSWER is defined in `lib/dns/resolver.c` only,
documented nowhere and not exposed as build configuration. This is valid
at least for 9.21+, 9.20 and 9.18. Furthermore, it doesn't compile
anymore on 9.21+ with -DCHECK_FOR_GLUE_IN_ANSWER=1.
Considering it is very unlikely that anyone build named with this,
remove the code rather than fixing it.
Closes#5538
Merge branch '5538-remove-check-for-glue-in-answer' into 'main'
See merge request isc-projects/bind9!11029
Macro CHECK_FOR_GLUE_IN_ANSWER is defined in `lib/dns/resolver.c` only,
documented nowhere and not exposed as build configuration. This is valid
at least for 9.21+, 9.20 and 9.18. Furthermore, it doesn't compile
anymore on 9.21+ with -DCHECK_FOR_GLUE_IN_ANSWER=1.
Considering it is very unlikely that anyone build named with this,
remove the code rather than fixing it.
Currently the fuzzer binaries are only built when someone requests a
fuzzer. This might cause us to inadvertently break fuzzing when changing
function signatures. It also deviates with the behaviour we had with
autotools, where the fuzz binaries were built with make test.
This commit splits the -Dfuzzing option into two: fuzzing, and
fuzzing-backend. The fuzzing option controls whether the fuzzing
binaries are built. The fuzzing-backend option controls which backend to
use, and defaults to none. If the value none is used the binaries are
built, but no backend is used or guaranteed, which means that the
binaries might be non-functional.
Closes#5526
Merge branch '5526-add-meson-option-to-always-build-fuzz-binaries' into 'main'
See merge request isc-projects/bind9!10990
Currently the fuzzer binaries are only built when someone requests a
fuzzer. This might cause us to inadvertently break fuzzing when changing
function signatures. It also deviates with the behaviour we had with
autotools, where the fuzz binaries were built with make test.
This commit splits the -Dfuzzing option into two: fuzzing, and
fuzzing-backend. The fuzzing option controls whether the fuzzing
binaries are built. The fuzzing-backend option controls which backend to
use, and defaults to none. If the value none is used the binaries are
built, but no backend is used or guaranteed, which means that the
binaries might be non-functional.
Add a CI job to merge tags back to the respective base branch in tag pipelines.
Merge branch 'andoni/add-merge-tag-to-tag-pipeline' into 'main'
See merge request isc-projects/bind9!11001
The field `ns_hookasync_t` was initially named `hook_actx` and wrongly
renamed `hook_aclctx` during a mass-renaming of various names for the
config acl context into a consistent `aclctx` name (see !11003). Of
course this is wrong as `ns_hookasync_t` has nothing to do with ACL but
about _async_ context. This commit fixes the mistake by renaming this
field `hookasyncctx`
Merge branch 'colin/fix-hookasyncctx-rename' into 'main'
See merge request isc-projects/bind9!11021
The field `ns_hookasync_t` was initially named `hook_actx` and wrongly
renamed `hook_aclctx` during a mass-renaming of various names for the
config acl context into a consistent `aclctx` name (see !11003). Of
course this is wrong as `ns_hookasync_t` has nothing to do with ACL but
about _async_ context. This commit fixes the mistake by renaming this
field `hookasyncctx`
When a re-configuration fails, `apply_configuration` flows jump to a
cleanup label and, at some point, leave the exclusive mode and cleanup
the viewlist. It looks fine as the viewlist is at this point only
locally known (if this is a configuration failure, this is the new view
list, if this is a success, this is the old list which has been swapped
out from the production list during the exclusive mode).
However, the view and zone initialization code enqueues job callbacks,
for instance from `dns_zone_setsigninginterval` (but there are others
cases) which will be called for the new views and zones after the
exclusive mode is over.
Depending where the configuration fails, those views and zones can be
half-configured, for instance a view might have an unfrozen resolver.
Hence, leaving the exclusive mode before cleaning up those views ans
zones will immediately called the previously enqueued callbacks and lead
to this reconfiguration-failure crash stack:
```
isc_assertion_failed
dns_resolver_createfetch
do_keyfetch
isc__async_cb
...
uv_run
loop_thread
thread_body
thread_run
start_thread
...
```
To avoid the problem, the views are now cleaned up before leaving the
exclusive mode (which also clean up the zones and enqueued callbacks).
As context, the bug was introduced by !10910 which moved the creation
(not configuration) of the view outsides of the exclusive mode. This is
a safe move (as at this point, the newly view are only known locally by
`apply_configuration`) but the re-order was wrong regarding the point
where the exclusive mode was ended (before the change, the exclusive
mode as always ended before the new view are detached).
Merge branch 'colin/leave-exclusive-mode-after-view-cleanup' into 'main'
See merge request isc-projects/bind9!11016
Adds a log-based test ensuring that when a reconfiguration fails inside
the view configuration, the newly created view are always detached
before the exclusive mode is ended.
When a re-configuration fails, `apply_configuration` flows jump to a
cleanup label and, at some point, leave the exclusive mode and cleanup
the viewlist. It looks fine as the viewlist is at this point only
locally known (if this is a configuration failure, this is the new view
list, if this is a success, this is the old list which has been swapped
out from the production list during the exclusive mode).
However, the view and zone initialization code enqueues job callbacks,
for instance from `dns_zone_setsigninginterval` (but there are others
cases) which will be called for the new views and zones after the
exclusive mode is over.
Depending where the configuration fails, those views and zones can be
half-configured, for instance a view might have an unfrozen resolver.
Hence, leaving the exclusive mode before cleaning up those views ans
zones will immediately called the previously enqueued callbacks and lead
to this reconfiguration-failure crash stack:
```
isc_assertion_failed
dns_resolver_createfetch
do_keyfetch
isc__async_cb
...
uv_run
loop_thread
thread_body
thread_run
start_thread
...
```
To avoid the problem, the views are now cleaned up before leaving the
exclusive mode (which also clean up the zones and enqueued callbacks).
As context, the bug was introduced by !10910 which moved the creation
(not configuration) of the view outsides of the exclusive mode. This is
a safe move (as at this point, the newly view are only known locally by
`apply_configuration`) but the re-order was wrong regarding the point
where the exclusive mode was ended (before the change, the exclusive
mode as always ended before the new view are detached).
When performing a ZSK rollover, if the new DNSKEY is omnipresent, the :option:`rndc sign` command now signs the zone completely with the successor key, replacing all zone signatures from the predecessor key with new ones.
Closes#5483
Merge branch '5483-smooth-operator-bug' into 'main'
See merge request isc-projects/bind9!10867
After a full sign we no longer have to need to take the sign delay into
account. Update the timing checks in keymgr_transition_time to determine
the start of the interval: Either the last change, or if SigPublish/
SigDelete is set. The latter case indicates a full sign was done and
so we no longer have to take the sign delay into account.
When introducing the kasp logic, a full sign of the zone did not
generate new signatures for the new active keys during a ZSK rollover.
The introduced kasp logic ensured that the rollover is performed
smoothly, as in the signatures are only replaced if the old signature
is close to expiring (depending on the signatures-refresh option).
Fix by maintaining a fullsign boolean value in the signing structure,
that will ensure the RRsets are signed with the correct key, rather
than a similar good key.
In case of a fullsign, we can also remove signatures from inactive
keys.
Remove the unused dns_zone_signwithkey function.