Colin Vidal [Wed, 24 Jun 2026 06:40:52 +0000 (08:40 +0200)]
chg: dev: Disambiguate `query_cname()` and `query_dname()` usage
Make explicit the fact that `query_cname()` and `query_dname()` must be
called only from a context where the resolver is answering a question
which is _not_ respectively `CNAME` or `DNAME`.
Merge branch 'colin/explicit-dname-cname-libns-query-usage' into 'security-main'
Colin Vidal [Wed, 1 Jul 2026 08:58:41 +0000 (10:58 +0200)]
Follow-up of disambiguate `query_cname()` and `query_dname()` usage
Previous commit "Disambiguate `query_cname()` and `query_dname()` usage"
was harmless but also useless, as it was checking `qctx->result` which
is always set to `ISC_R_SUCCESS` when `qctx` is initialized. The intent
was to check `qctx->fresp->result` (which is the result provided by the
resolver). But this was also wrong (this is actually the case we do
expect `query_cname()`/`query_dname()` to be called, to follow the
chain).
The actual invarant that needs to be checked is if the qtype is CNAME
then we do not follow the chain, so we can't call `query_cname()`. This
invariant has been added.
If the qtype is DNAME, it's more complex, because a DNAME can be found
from a local zone or cache and the chain can be locally followed. In
which case, calling `query_dname()` is legit, as soon as the qname is a
subname of the DNAME target. This invariant is already checked.
Ondřej Surý [Tue, 23 Jun 2026 05:05:01 +0000 (07:05 +0200)]
[CVE-2026-11605] sec: usr: Prevent excessive validation work from crafted negative responses
A validating resolver could be made to perform a large amount of DNSSEC
validation work in response to a single answer, consuming excessive CPU. A
malicious authoritative server triggers this by returning a signed negative
answer (NXDOMAIN or NODATA) padded with many denial-of-existence proof
records, which the resolver continued to verify beyond its per-query
validation limit. It now enforces that limit on negative answers and returns
SERVFAIL once the limit is reached.
Closes: https://gitlab.isc.org/isc-projects/bind9/-/work_items/4463
Merge branch '4463-limit-the-number-of-negative-validations' into 'security-main'
Colin Vidal [Mon, 22 Jun 2026 11:27:09 +0000 (13:27 +0200)]
Disambiguate `query_cname()` and `query_dname()` usage
Make explicit the fact that `query_cname()` and `query_dname()` must be
called only from a context where the resolver is answering a question
which is _not_ respectively `CNAME` or `DNAME`.
Mark Andrews [Mon, 22 Jun 2026 11:27:01 +0000 (21:27 +1000)]
[CVE-2026-11721] sec: usr: Invalid signed wildcard records were being accepted
Signed wildcard responses in which the Labels field in the `RRSIG` record was less than the number of labels in the Signer Name field were being incorrectly accepted. This in turn broke `synth-from-dnssec`, which depends on such records being correctly validated. This has been fixed.
ISC thanks Qifan Zhang of Palo Alto Networks for bringing this issue to our attention.
Mark Andrews [Mon, 15 Jun 2026 01:29:54 +0000 (11:29 +1000)]
[CVE-2026-10822] sec: usr: Malformed DNSKEY records could trigger an assertion
Previously, `dns_name_fromwire()` did not honor the record boundary when reading names from the wire, allowing malformed records to be accepted when they should not have been. In particular, malformed DNSKEY records could trigger an assertion failure when being printed. This has been fixed.
Closes: https://gitlab.isc.org/isc-projects/bind9/-/issues/6004
Merge branch '6004-confidential-issue' into 'security-main'
Tests that BIND rejects RRSIGs where Labels < (signer_labels - 1), the
underflow condition described in the fix to lib/dns/dnssec.c.
A crafted authoritative server (ans4) serves the zone
attacker.rrsig-labels-signer. with synthetically constructed responses:
an A record covered by an RRSIG whose Labels=1 was produced by signing
*.rrsig-labels-signer. with a key whose signer name sits two labels
deeper (attacker.rrsig-labels-signer., 3 non-root labels). On unfixed
BIND, the resolver accepts the signature and caches the wildcard with
SECURE rank, enabling a synth-from-dnssec cache-poisoning attack on
subsequent queries.
The test verifies two properties: the poison query returns SERVFAIL
(DNS_R_SIGINVALID), and a follow-up victim query is not answered from
the poisoned wildcard cache.
Ondřej Surý [Sun, 7 Jun 2026 08:19:44 +0000 (10:19 +0200)]
Limit DNSSEC denial proof validation per fetch
Negative response validation reuses the per-fetch validation counters,
but NSEC/NSEC3 subvalidator quota failures were not terminal. The
parent validator logged the child failure and resumed validate_nx(),
so a response stuffed with many denial proof RRsets could keep driving
more validation work and still eventually validate.
Treat ISC_R_QUOTA from an NSEC/NSEC3 subvalidator as terminal and
propagate the quota reason to the parent validator. This lets the
existing fctx->nvalidations and fctx->nfails limits stop excessive
negative proof validation without a separate resolver-side pre-scan.
Mark Andrews [Fri, 12 Jun 2026 05:48:37 +0000 (15:48 +1000)]
[CVE-2026-11331] sec: usr: Fix handling of rpz CNAME expansion that returns name too long
Previously, if the expansion of a wildcard CNAME RPZ policy resulted in a name that exceeded the length limit, a self referential CNAME and the original address record were returned, allowing the policy to be bypassed. In branches up to 9.20, this also left query processing in an inconsistent state which could trigger an assertion failure. We now return a YXDOMAIN response, without the address.
ISC would like to thank Laith Mash'al (0xmshal) for bringing this issue to our attention.
Mark Andrews [Thu, 4 Jun 2026 23:18:30 +0000 (09:18 +1000)]
POC for PRIVATEDNS DNSKEY overrun not being detected
Construct a DNS message where a PRIVATEDNS DNSKEY identifier
overruns the record boundary by 3 byte so that the label ends
at the end of the compression pointer for the next record. The
next type is less than 256 so the next octet is 00 terminating
the identifier name. The transfered zone is then written to
disk using master-format text triggering the assertion when the
truncated identier is discovered.
Note this test will produce a false result in versions of
BIND that do not check the PRIVATEDNS identifier as it looks
for the error message when the transfer is aborted.
Mark Andrews [Tue, 14 Apr 2026 02:24:33 +0000 (12:24 +1000)]
Invalid signed wildcard records were being accepted
An RRSIG whose Labels field indicates fewer labels than its signer
name requires was being accepted. When such a record covers a
wildcard, the validator reconstructs a wildcard owner name above the
signer's zone and caches it as secure. RFC 8198 cache synthesis
(synth-from-dnssec) then serves that forged wildcard for unrelated
names, poisoning the cache.
These records are now rejected, both when an RRSIG is parsed and when
its signature is verified.
Mark Andrews [Tue, 19 May 2026 01:24:01 +0000 (11:24 +1000)]
Make it clearer that decompression is not allowed here
For DNSKEY and RRSIG as per RFC 4034, A.1.1. Private Algorithm Types
For KEY, SIG as per RFC 2535 3.2 The KEY Algorithm Number Specification,
which only allowed local domain compression which itself is no
longer allowed.
Other key types inherit from these or the general proscription that
compression is not allow in new types.
Mark Andrews [Tue, 19 May 2026 01:12:46 +0000 (11:12 +1000)]
Fix dns_name_fromwire to honour the active region
dns_name_fromwire was not honouring the source buffer's active
region when reading names from the wire. This allowed malformed
records to be accepted when they shouldn't have been. This has
been corrected.
Mark Andrews [Tue, 19 May 2026 05:14:06 +0000 (15:14 +1000)]
Fix dst_algorithm_fromdata to set the active range
When the buffer to check extract the PRIVATEDNS name was constructed
isc_buffer_setactive was not called. This is now needed as
dns_name_fromwire is being corrected to check the active region.
Mark Andrews [Tue, 19 May 2026 05:00:17 +0000 (15:00 +1000)]
Fix the yaml query zone name code in dnstap-read
When the buffer to read the query zone name was constructed
isc_buffer_setactive was not called. This is now needed as
dns_name_fromwire is being corrected to check the active region.
Mark Andrews [Tue, 19 May 2026 01:09:02 +0000 (11:09 +1000)]
Fix EDNS Report Channel checking code
When the buffer to check the Report Channel domain was constructed
isc_buffer_setactive was not called. This is now needed as
dns_name_fromwire is being corrected to check the active region.
Mark Andrews [Tue, 19 May 2026 00:44:04 +0000 (10:44 +1000)]
Check that dns_name_fromwire honours the active region
When reading DNS records from the wire the active region of the
source buffer is set to the end of the current record. dns_name_fromwire
should fail if it attempts to read past this setting.
The OID printed in the "; alg = ..." comment of a PRIVATEOID KEY,
DNSKEY, CDNSKEY or RKEY record was truncated to sixteen characters:
1.2.840.113549.1.1.11 came out as 1.2.840.113549.1. Only the comment
was ever affected, never the record itself.
fix: dev: Fix a crash when resolving names below a cached DNAME
A recursive resolver could crash when it answered a query for a name beneath a
cached DNAME while that same DNAME record was concurrently refreshed or evicted
from the cache.
Closes #6182
Merge branch '6182-qpcache-dname-zonecut-uaf' into 'main'
check_dname() cached the DNAME header and its RRSIG in the search block
and dropped the node lock holding only a node reference. Since cache
headers became reference counted and are freed synchronously, and
delegation adds no longer take the tree write lock, a concurrent refresh
or eviction can free the header before setup_delegation() reads it. Take
a reference on the headers in check_dname() and release it once the
lookup finishes.
chg: dev: Support larger DNSSEC keys and signatures
Some DNSSEC tools and trust-anchor handling could fail when
working with unusually large DNSSEC keys or signatures,
including those used by post-quantum algorithms. These paths
now accept DNSKEY, CDNSKEY, CDS, and RRSIG data up to the DNS
record size limits, so large key material can be parsed, written,
checked, and signed consistently.
Merge branch 'ondrej/dynamic-dnssec-buffers' into 'main'
Remove the fixed DST_KEY_MAXSIZE limit from key parsing paths
The buffers receiving DNSKEY (and SKR resource record) rdata parsed
from text or wire form were sized by DST_KEY_MAXSIZE (1280 octets),
which is too small for post-quantum public keys. Parse into
DNS_RDATA_MAXLENGTH sized buffers instead, which cannot be exceeded
by construction, and drop the DST_KEY_MAXSIZE and DST_KEY_MAXTEXTSIZE
constants that no longer have any users.
Size RRSIG rdata buffers by the maximum rdata length
The buffers receiving the RRSIG rdata built by dns_dnssec_sign() were
fixed-size arrays (1024 or 2048 octets), which is too small for
post-quantum signatures. Use DNS_RDATA_MAXLENGTH sized buffers
instead, which no RRSIG rdata can exceed by construction.
Size DNSKEY rdata buffers by the maximum rdata length
Post-quantum signature algorithms have public keys that do not fit
into the fixed DST_KEY_MAXSIZE (1280 octets) buffers used when
converting a dst_key to DNSKEY rdata. Use DNS_RDATA_MAXLENGTH sized
buffers instead, which no DNSKEY rdata can exceed by construction.
Cover exact-name NODATA synthesis from a pending NSEC
The #5872 reproducer plants a covering NSEC that is rejected inside the
cache (find_coveringnsec), so it never reaches the trust check on the
exact-match NODATA branch of query_coveringnsec(). This adds a companion
case: an NSEC owned by the victim name itself, injected at pending trust
via a CD=1 query, is returned by the cache as a NODATA proof for the
exact node and must not be used to synthesize a NODATA that would deny
the victim's real A record.
Reuses the f004.test fixture with a victim-owned forged NSEC.
Colin Vidal [Wed, 8 Jul 2026 09:03:52 +0000 (11:03 +0200)]
fix: dev: Detect UTF-16 surrogates in `isc_utf8_valid()`
UTF-8 standard forbid usage of unicode character between the range of
0xD800..0xDFFF (reserved, and used as UTF-16 surrogates, see RFC 3629).
However, `usc_utf8_valid()` was not checking if the encoded unicode
character was in this range, which then would accept invalid UTF-8
strings. This is now fixed.
Closes #6151
Merge branch '6151-utf16-surrogates-detection' into 'main'
Colin Vidal [Thu, 2 Jul 2026 07:52:09 +0000 (09:52 +0200)]
Detect UTF-16 surrogates in `isc_utf8_valid()`
UTF-8 standard forbid usage of unicode character between the range of
0xD800..0xDFFF (reserved, and used as UTF-16 surrogates, see RFC 3629).
However, `usc_utf8_valid()` was not checking if the encoded unicode
character was in this range, which then would accept invalid UTF-8
strings. This is now fixed.
Colin Vidal [Wed, 8 Jul 2026 06:02:53 +0000 (08:02 +0200)]
fix: dev: Remove ACL detach deadcode from dyndb
Since `188aa43e`, `dns_acl_any()` can't
fail (and thus would always set memory to its target). Removing deadcode
that would detach the ACL if `dns_acl_any()` would return some error
while the ACL would be created and attached.
Merge branch 'colin/remove-acl-detach-deadcode' into 'main'
Colin Vidal [Wed, 1 Jul 2026 08:30:53 +0000 (10:30 +0200)]
Remove ACL detach deadcode from dyndb
Since `188aa43e48379572ffa758e45333c67214917d39`, `dns_acl_any()` can't
fail (and thus would always set memory to its target). Removing deadcode
that would detach the ACL if `dns_acl_any()` would return some error
while the ACL would be created and attached.
chg: dev: Mark the related slabheader as visited on cache hit
A cache hit only marked the looked-up header as SIEVE-visited, leaving
its related header (the flattened counterpart) a candidate for eviction.
Mark both so related slabheaders age together.
Merge branch 'ondrej/mark-related-header-visited-on-cache-hit' into 'main'
Ondřej Surý [Wed, 24 Jun 2026 05:13:16 +0000 (07:13 +0200)]
Mark the related slabheader as visited on cache hit
A cache hit only marked the looked-up header as SIEVE-visited, leaving
its related header (the flattened counterpart) a candidate for eviction.
Mark both so related slabheaders age together.
fix: dev: Improve the input validation of the isc_url_parse() function
The isc_url_parse() function failed to check the input buffer's
length and assumed that it can't be bigger than UINT16_MAX, because
both the 'off' and 'len' fields of the 'isc_url_parser_t' structure
are uint16_t.
Add a check to not accept a buffer longer than 8192 octets.
Closes #6150
Merge branch '6150-isc_url_parse-buffer-size-check-fix' into 'main'
Ondřej Surý [Wed, 17 Jun 2026 04:41:29 +0000 (06:41 +0200)]
Add IPv6 and authority cases to the isc_url_t unit test
Cover IPv6 literal hosts (the brackets are stripped from the host, zone
identifiers are kept verbatim), userinfo, explicit ports and case
preservation, plus inputs that isc_url_parse() rejects although a generic
RFC 3986 parser would accept them: a '+' in the scheme, an IPvFuture
literal, and a percent-encoded port. The cases are drawn from the
Addressable URI test suite. The shared table runner is factored out so
both table-driven tests reuse it.
Ondřej Surý [Wed, 17 Jun 2026 04:30:51 +0000 (06:30 +0200)]
Extend the isc_url_t unit test with RFC 3986 cases
Parse the absolute URIs from RFC 3986 section 5.4 and verify the
component split, and assert the input-length boundary (UINT16_MAX is
accepted, UINT16_MAX + 1 is rejected). isc_url_parse() splits request
targets but does not resolve relative references, so the dot-segments
in path/query/fragment are expected to survive verbatim.
Aram Sargsyan [Tue, 16 Jun 2026 11:08:14 +0000 (11:08 +0000)]
Add a maximum length for isc_url_parse() input buffer
The isc_url_parse() function failed to check the input buffer's
length and assumed that it can't be bigger than UINT16_MAX, because
both the 'off' and 'len' fields of the 'isc_url_parser_t' structure
are uint16_t.
Add a check to not accept a buffer longer than UINT16_MAX.
The 'isc_proxy2_handler_t' structure stores some size values in a
'uint16_t' type, while the maximum size can be bigger, which results
in truncation. Change the affected types to 'size_t'.
Closes #6142
Merge branch '6142-proxyv2-header-length-fix' into 'main'
Aram Sargsyan [Sat, 20 Jun 2026 14:56:17 +0000 (14:56 +0000)]
Fix PROXYv2 header size truncation bug
The 'isc_proxy2_handler_t' structure stores some size values in a
'uint16_t' type, while the maximum size can be bigger, which results
in truncation. Change the affected types to 'size_t'.
Matthijs Mekking [Mon, 24 Nov 2025 08:45:51 +0000 (09:45 +0100)]
Test multi-master dnssec-policy setup
Update the manual rollover test case with a multi-master setup. In this
scenario, key files are generated, as well as rollovers are started
on one server (ns3) and key files are copied to the other server (ns4).
Add checks that the begin and end key states are the same.
fix: usr: Unvalidated opt-out NSEC3 could be accepted in insecurity proof
When determining whether an insecure delegation is legitimate, NSEC3 opt-out records which had not yet passed validation could be used. This has been fixed.
fix: usr: Fix DNSSEC validation failures for names under an apex DNAME
DNSSEC validation could fail with SERVFAIL for names covered by a DNAME
at the apex of a signed zone, unless the zone's keys were already validated
in the cache. This regression was introduced by the recent fix for resolver
stalls on CNAME responses to DS queries.
Closes #6176
Merge branch '6176-validator-apex-dname' into 'main'
Add a system test resolving through a signed apex DNAME
The dnssec system test signs a DNAME-at-apex zone but only ever
queried the apex directly; nothing resolved a name under the DNAME
through the validating resolver, so a validator regression on that
path went unnoticed.
Restrict the alias-chain deadlock check to chaining CNAMEs
check_deadlock() aborted any fetch whose name equals the owner of a
chaining rdataset, assuming nothing the validator needs can live at an
alias. That is true for a CNAME, but a DNAME aliases only the names
below its owner: with a DNAME at a zone apex, the DNSKEY signing the
DNAME lives at the owner name itself, so every answer synthesized from
a signed apex DNAME failed validation whenever that key was not
already validated in the cache.
Chaining CNAMEs, including those synthesized from a DNAME, still cover
the self-join case the check was added for.
fix: test: Support serving signed child zone from its parent's nameserver
When a signed zone is served by the same nameserver instance as
its parent, the child's dnssec-signzone has already written
dsset-<child>. into that directory. Don't attempt to copy the dsset if
the destination and source files are the same.
Assisted-by: Claude:claude-opus-4-8
Merge branch 'nicki/serve-signed-child-same-ns' into 'main'
Support serving signed child zone from its parent's nameserver
When a signed zone is served by the same nameserver instance as
its parent, the child's dnssec-signzone has already written
dsset-<child>. into that directory. Don't attempt to copy the dsset if
the destination and source files are the same.
Michał Kępień [Thu, 2 Jul 2026 13:09:50 +0000 (15:09 +0200)]
chg: test: Update AsyncDnsServer-related test cookbook parts
Add practical tips about specific handler classes. Mention some good
practices and point developers at existing code written in the desired
manner. Document common pitfalls. Suggest preferred approaches for
splitting up complex response handling code.
Merge branch 'michal/update-asyncdnsserver-related-test-cookbook-parts' into 'main'
Michał Kępień [Thu, 2 Jul 2026 13:07:40 +0000 (15:07 +0200)]
Move ans.py-related information to README.md
COOKBOOK.md is supposed to be minimal and heavy on examples, so move the
lengthy section about implementing custom ans.py servers from
COOKBOOK.md to README.md.
Michał Kępień [Thu, 2 Jul 2026 13:07:40 +0000 (15:07 +0200)]
Update AsyncDnsServer-related test cookbook parts
Add practical tips about specific handler classes. Mention some good
practices and point developers at existing code written in the desired
manner. Document common pitfalls. Suggest preferred approaches for
splitting up complex response handling code.
Nicki Křížek [Tue, 16 Jun 2026 16:23:23 +0000 (16:23 +0000)]
Move algorithm definitions into a top-level isctest.algorithms module
The Algorithm type, the per-algorithm constants, and the ALL_ALGORITHMS*
lookup tables are general DNSSEC key definitions used across isctest
package and the tests. Move them into a dedicated module to separate
these from the environment-specific setup that remains in
isctest.vars.algorithms.
Nicki Křížek [Tue, 16 Jun 2026 14:38:53 +0000 (16:38 +0200)]
Add private_key support to all ZoneKey implementations
Extend the ZoneKeyFile to read the file-backed private key and return it
in a format suitable for use with dnspython. Add ZoneKey.private_key
property to unify the interface.
Nicki Křížek [Tue, 16 Jun 2026 15:56:00 +0000 (17:56 +0200)]
Replace get_dnsalg() with kasp.Key.algorithm
The get_dnsalg() was just a compatibility layer for 9.18 which lacked
the Algorithm support - remove it in favor of using the .algorithm
property.
In order to properly support private OID algorithms, use the DST value
which is unique across all algorithms.
Also fix private_type_record(): the choice between the 5- and 7-byte
signing record depends on the DST value (256/257 for the private-OID
algorithms), not the on-wire number, which never reaches 256.
Nicki Křížek [Tue, 16 Jun 2026 12:34:48 +0000 (12:34 +0000)]
Merge kasp.Key functionality into zone.FileZoneKey
Make zone.FileZoneKey the single representation of a file-backed key
(typically generated by dnssec-keygen). Move the common key-related
functionality into zone.FileZoneKey, and extend that functionality in
kasp.Key to also add state and timing related operations on top. Remove
duplicate into_ta() function.
Note that is_ksk() is implemented differently for kasp.Key: with the
metadata file available, the KSK status is loaded from that file, as it
indicates the authoritative policy decision which makes the key a KSK.
In zone.FileZoneKey which doesn't work with the metadata file, the KSK
status if inferred from the DNSKEY SEP flag - the best information
available for that class.
chg: dev: Replace query and inner client attribute bitfields with named bools
Replace the unsigned int attributes field in struct ns_query and the unsigned int attributes field in struct ns_client_inner with individual bool bitfields.
Merge branch 'ondrej/query-attributes-to-bitfields' into 'main'
Ondřej Surý [Sat, 21 Mar 2026 16:13:56 +0000 (17:13 +0100)]
Replace query and client attribute bitfield with named bools
Replace the unsigned int attributes field in struct ns_query with
individual bool bitfields. This removes the NS_QUERYATTR_* constants
and the 12 accessor macros (USECACHE, RECURSIONOK, RECURSING, etc.)
from query.c, replacing all bit manipulation with direct bool access.
And replace the unsigned int attributes field in struct ns_client_inner
with individual bool bitfields. This removes the NS_CLIENTATTR_*
constants and the accessor macros (TCP, WANTDNSSEC, etc.), replacing
all bit manipulation with direct bool access.
fix: usr: Resolver could terminate unexpectedly when processing a malformed RRSIG
A recursive resolver could terminate unexpectedly when an authoritative
server returned a crafted RRSIG(RRSIG) record for an insecure zone. Such
records are now rejected.
Closes #6184
Merge branch '6184-reject-rrsig-covering-signature' into 'main'
Add a regression test for an RRSIG that covers a signature
The qpcache_rrsig_any test enumerated only meta-types as the covered
type, so an RRSIG covering RRSIG -- a non-meta signature type -- slipped
through the earlier meta-type hardening. Probe that case too.
An RRSIG whose Type-Covered field is RRSIG is not a meta-type, so it
passed the message parser, and for an insecure domain the resolver
cached it as a standalone signature. The QP cache pairs every RRSIG
header with the non-signature header it covers and never expects the
covered type to itself be a signature, so a signature covering a
signature broke that invariant and aborted named on a crafted response.
Reject the record in the parser, and tighten the cache precondition so
a positive signature header must cover a non-signature type.
fix: dev: Correct locator decoding for NID, L64, and L32 records
NID, L64, and L32 records were decoded incorrectly when converted into their
parsed structures, because the preference field was not skipped before the
locator.
Closes #6097
Merge branch '6097-nid-l64-l32-tostruct-consume' into 'main'
Add NID/L64/L32 round-trip coverage to the rdata unit test
These types had no entries in the rdata test table, so the
tostruct/fromstruct round-trip in check_struct_conversions() never ran
against them -- which is why the missing preference consume in their
tostruct routines went unnoticed for years. Add text and wire vectors
for all three.
Consume the preference before reading the locator in NID/L64/L32 tostruct
tostruct_nid() and tostruct_l64() read the 16-bit preference with the
non-consuming uint16_fromregion() and then memmove()'d the whole
remaining region -- still ten octets, still anchored at the preference
-- into the eight-octet nid[]/l64[] arrays. That folded the preference
into the first two locator octets and stored two octets past the end of
the array. tostruct_l32() shares the root cause: it read the 32-bit
locator from the same unconsumed offset, so the value was built from the
preference plus the first two locator octets.
Consume the two preference octets first, matching the sibling
tostruct_lp(), and assert the expected framing on the fixed-size types.
fix: usr: Don't evict DNSSEC-validated cache data on a CD=1 NXDOMAIN
When a client sent a query with the checking-disabled (CD) bit set and the
answer was NXDOMAIN, the resolver cached that unvalidated negative response and
discarded any DNSSEC-validated records it already held for the same name, even
though the validated data was more trustworthy. A single such response -
including a forged one - could flush validated records from the cache and force
the resolver to fetch them again. The resolver now checks the trust level of the
existing data first and leaves the cache unchanged when it is already validated.
Ondřej Surý [Thu, 4 Jun 2026 18:01:37 +0000 (20:01 +0200)]
Add a system test for CD=1 NXDOMAIN cache protection
Cache a DNSSEC-validated A record, then make a CD=1 query elicit an
unvalidated NXDOMAIN for the name: the secure RRset must survive, and an
uncached-type query must not get the wrong RRset back.
Evan Hunt [Fri, 1 May 2026 19:15:07 +0000 (12:15 -0700)]
Check for secure data before caching CD=1 NXDOMAIN
An unvalidated NXDOMAIN (e.g. from a CD=1 query) marked every RRset at
the name ancient without checking trust, evicting DNSSEC-validated data.
Keep the cache unchanged when any existing RRset is already secure.
dns_ncache_add() now returns DNS_R_UNCHANGED for the rejected add;
negcache() serves a matching cached negative or the queried type, else
SERVFAIL (never the unrelated RRset the add bound), and rctx_ncache()
forwards it so the fetch fails fast.
Mark Andrews [Thu, 2 Jul 2026 01:10:32 +0000 (11:10 +1000)]
fix: usr: Properly detect private records before copying
We were triggering an assertion when trying to copy a private record
to a buffer for modifying. Extend the private type detection and
copy the contents after we have rejected invalid private records.
Closes #5857
Merge branch '5857-properly-detect-private-records-before-copying' into 'main'
Mark Andrews [Wed, 8 Apr 2026 04:43:23 +0000 (14:43 +1000)]
Properly detect private records before copying
We were triggering an assertion when trying to copy a private record
to a buffer for modifying. Extend the private type detection and
copy the contents after we have rejected invalid private records.
chg: doc: Add non-IN RR classes to list of unsupported configurations
This adds a note to the security documentation that configuring
resources with non-Internet DNS classes (CHAOS, HESIOD, ...) is not
a supported configuration and could potentially cause issues.
Closes #5805
Merge branch '5805-add-clarification-on-non-IN-classes' into 'main'
Nicki Křížek [Mon, 29 Jun 2026 13:34:29 +0000 (13:34 +0000)]
amend! Add non-IN RR classes to list of unsupported configurations
Document that non-IN RR class issues are out of CVE scope
CVE-2026-5946 covered assertion failures reachable only through the
handling of resource record classes other than Internet (IN).
Configuring zones or views with such classes is a supported feature;
document in the security assumptions that problems reachable only
through it cannot be the basis for CVE assignment.
Ondřej Surý [Wed, 11 Mar 2026 18:18:32 +0000 (19:18 +0100)]
Add non-IN RR classes to list of unsupported configurations
This adds a note to the security documentation that configuring
resources with non-Internet DNS classes (CHAOS, HESIOD, ...) is not
a supported configuration and could potentially cause issues.