Compare commits

...

No commits in common. "c8" and "c8-beta" have entirely different histories.
c8 ... c8-beta

21 changed files with 8 additions and 6037 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
SOURCES/icannbundle.pem
SOURCES/unbound-1.16.2.tar.gz

View File

@ -1 +1,2 @@
9a2f73302a13f38dbf7cb3c5e34eb1665d2f156f SOURCES/icannbundle.pem
9aea0e923b9d6779b5bc360094e24a4017e2bb25 SOURCES/unbound-1.16.2.tar.gz

View File

@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO
TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV
BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX
DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O
IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB
MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb
cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S
G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg
ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2
paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7
MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29
iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3
DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH
6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD
2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h
15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF
0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg
j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk
-----END CERTIFICATE-----

View File

@ -1,9 +0,0 @@
# Remote control config section update.
# Previous defaults allowed any process to change settings, CVE-2024-1488
remote-control:
# set to an absolute path to use a unix local name pipe, certificates
# are not used for that, so key and cert files need not be present.
control-interface: "/run/unbound/control"
# For local sockets this option is ignored, and TLS is not used.
control-use-cert: "yes"

View File

@ -1,2 +1 @@
. 172800 IN DNSKEY 257 3 8 AwEAAa96jeuknZlaeSrvyAJj6ZHv28hhOKkx3rLGXVaC6rXTsDc449/cidltpkyGwCJNnOAlFNKF2jBosZBU5eeHspaQWOmOElZsjICMQMC3aeHbGiShvZsx4wMYSjH8e7Vrhbu6irwCzVBApESjbUdpWWmEnhathWu1jo+siFUiRAAxm9qyJNg/wOZqqzL/dL/q8PkcRU5oUKEpUge71M3ej2/7CPqpdVwuMoTvoB+ZOT4YeGyxMvHmbrxlFzGOHOijtzN+u1TQNatX2XBuzZNQ1K+s2CXkPIZo7s6JgZyvaBevYtxPvYLw4z9mR7K2vaF18UYH9Z9GNUUeayffKC73PYc= ;{id = 38696 (ksk), size = 2048b}
. 172800 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU= ;{id = 20326 (ksk), size = 2048b}

View File

@ -1,6 +1,5 @@
; // The root key in bind format. This can be read by most tools, including
; // named, unbound, et. For libunbound, use ub_ctx_trustedkeys() to load this
trusted-keys {
"." 257 3 8 "AwEAAa96jeuknZlaeSrvyAJj6ZHv28hhOKkx3rLGXVaC6rXTsDc449/cidltpkyGwCJNnOAlFNKF2jBosZBU5eeHspaQWOmOElZsjICMQMC3aeHbGiShvZsx4wMYSjH8e7Vrhbu6irwCzVBApESjbUdpWWmEnhathWu1jo+siFUiRAAxm9qyJNg/wOZqqzL/dL/q8PkcRU5oUKEpUge71M3ej2/7CPqpdVwuMoTvoB+ZOT4YeGyxMvHmbrxlFzGOHOijtzN+u1TQNatX2XBuzZNQ1K+s2CXkPIZo7s6JgZyvaBevYtxPvYLw4z9mR7K2vaF18UYH9Z9GNUUeayffKC73PYc="; // key id = 38696
"." 257 3 8 "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="; // key id = 20326
};

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
From acc84268e4156fb9a8dd36eafaf04d064ee5895a Mon Sep 17 00:00:00 2001
From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
Date: Thu, 25 Jul 2024 11:42:22 +0200
Subject: [PATCH] - Add root key 38696 from 2024 for DNSSEC validation. It is
added to the default root keys in unbound-anchor. The content can be
inspected with `unbound-anchor -l`.
---
unbound-1.20.0/smallapp/unbound-anchor.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/unbound-1.20.0/smallapp/unbound-anchor.c b/unbound-1.20.0/smallapp/unbound-anchor.c
index 137b2e9..8738cf2 100644
--- a/unbound-1.20.0/smallapp/unbound-anchor.c
+++ b/unbound-1.20.0/smallapp/unbound-anchor.c
@@ -183,7 +183,9 @@ static const char DS_TRUST_ANCHOR[] =
/* The anchors must start on a new line with ". IN DS and end with \n"[;]
* because the makedist script greps on the source here */
/* anchor 20326 is from 2017 */
-". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n";
+". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n"
+ /* anchor 38696 is from 2024 */
+". IN DS 38696 8 2 683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16\n";
/** verbosity for this application */
static int verb = 0;
--
2.53.0

View File

@ -1,249 +0,0 @@
From 34de24d58bb5aa6fe3551512fc17cac08f65d93e Mon Sep 17 00:00:00 2001
From: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Date: Thu, 3 Oct 2024 14:46:57 +0200
Subject: [PATCH] - Fix CVE-2024-8508, unbounded name compression could lead to
denial of service.
---
unbound-1.16.2/util/data/msgencode.c | 77 +++++++++++++++++-----------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/unbound-1.16.2/util/data/msgencode.c b/unbound-1.16.2/util/data/msgencode.c
index fe21cfb..f9e95e6 100644
--- a/unbound-1.16.2/util/data/msgencode.c
+++ b/unbound-1.16.2/util/data/msgencode.c
@@ -62,6 +62,10 @@
#define RETVAL_TRUNC -4
/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
#define RETVAL_OK 0
+/** Max compressions we are willing to perform; more than that will result
+ * in semi-compressed messages, or truncated even on TCP for huge messages, to
+ * avoid locking the CPU for long */
+#define MAX_COMPRESSION_PER_MESSAGE 120
/**
* Data structure to help domain name compression in outgoing messages.
@@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
static int
-compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
- struct regional* region, struct compress_tree_node** tree,
- size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
+compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
+ struct regional* region, struct compress_tree_node** tree,
+ size_t owner_pos, uint16_t* owner_ptr, int owner_labs,
+ size_t* compress_count)
{
struct compress_tree_node* p;
struct compress_tree_node** insertpt = NULL;
if(!*owner_ptr) {
/* compress first time dname */
- if((p = compress_tree_lookup(tree, key->rk.dname,
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ (p = compress_tree_lookup(tree, key->rk.dname,
owner_labs, &insertpt))) {
if(p->labs == owner_labs)
/* avoid ptr chains, since some software is
@@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
if(!write_compressed_dname(pkt, key->rk.dname,
owner_labs, p))
return RETVAL_TRUNC;
+ (*compress_count)++;
/* check if typeclass+4 ttl + rdatalen is available */
if(sldns_buffer_remaining(pkt) < 4+4+2)
return RETVAL_TRUNC;
@@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
if(owner_pos <= PTR_MAX_OFFSET)
*owner_ptr = htons(PTR_CREATE(owner_pos));
}
- if(!compress_tree_store(key->rk.dname, owner_labs,
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ !compress_tree_store(key->rk.dname, owner_labs,
owner_pos, region, p, insertpt))
return RETVAL_OUTMEM;
} else {
@@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
/** compress any domain name to the packet, return RETVAL_* */
static int
-compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
- struct regional* region, struct compress_tree_node** tree)
+compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
+ struct regional* region, struct compress_tree_node** tree,
+ size_t* compress_count)
{
struct compress_tree_node* p;
struct compress_tree_node** insertpt = NULL;
size_t pos = sldns_buffer_position(pkt);
- if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ (p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
if(!write_compressed_dname(pkt, dname, labs, p))
return RETVAL_TRUNC;
+ (*compress_count)++;
} else {
if(!dname_buffer_write(pkt, dname))
return RETVAL_TRUNC;
}
- if(!compress_tree_store(dname, labs, pos, region, p, insertpt))
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ !compress_tree_store(dname, labs, pos, region, p, insertpt))
return RETVAL_OUTMEM;
return RETVAL_OK;
}
@@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed_rrset_key* key)
/** compress domain names in rdata, return RETVAL_* */
static int
-compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
- struct regional* region, struct compress_tree_node** tree,
- const sldns_rr_descriptor* desc)
+compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
+ struct regional* region, struct compress_tree_node** tree,
+ const sldns_rr_descriptor* desc, size_t* compress_count)
{
int labs, r, rdf = 0;
size_t dname_len, len, pos = sldns_buffer_position(pkt);
@@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
switch(desc->_wireformat[rdf]) {
case LDNS_RDF_TYPE_DNAME:
labs = dname_count_size_labels(rdata, &dname_len);
- if((r=compress_any_dname(rdata, pkt, labs, region,
- tree)) != RETVAL_OK)
+ if((r=compress_any_dname(rdata, pkt, labs, region,
+ tree, compress_count)) != RETVAL_OK)
return r;
rdata += dname_len;
todolen -= dname_len;
@@ -449,7 +461,8 @@ static int
packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
uint16_t* num_rrs, time_t timenow, struct regional* region,
int do_data, int do_sig, struct compress_tree_node** tree,
- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
+ size_t* compress_count)
{
size_t i, j, owner_pos;
int r, owner_labs;
@@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
for(i=0; i<data->count; i++) {
/* rrset roundrobin */
j = (i + rr_offset) % data->count;
- if((r=compress_owner(key, pkt, region, tree,
- owner_pos, &owner_ptr, owner_labs))
- != RETVAL_OK)
+ if((r=compress_owner(key, pkt, region, tree,
+ owner_pos, &owner_ptr, owner_labs,
+ compress_count)) != RETVAL_OK)
return r;
sldns_buffer_write(pkt, &key->rk.type, 2);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
@@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust);
if(c) {
if((r=compress_rdata(pkt, data->rr_data[j],
- data->rr_len[j], region, tree, c))
- != RETVAL_OK)
+ data->rr_len[j], region, tree, c,
+ compress_count)) != RETVAL_OK)
return r;
} else {
if(sldns_buffer_remaining(pkt) < data->rr_len[j])
@@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
return RETVAL_TRUNC;
sldns_buffer_write(pkt, &owner_ptr, 2);
} else {
- if((r=compress_any_dname(key->rk.dname,
- pkt, owner_labs, region, tree))
- != RETVAL_OK)
+ if((r=compress_any_dname(key->rk.dname,
+ pkt, owner_labs, region, tree,
+ compress_count)) != RETVAL_OK)
return r;
if(sldns_buffer_remaining(pkt) <
4+4+data->rr_len[i])
@@ -544,7 +557,8 @@ static int
insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
struct regional* region, struct compress_tree_node** tree,
- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
+ size_t* compress_count)
{
int r;
size_t i, setstart;
@@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 1, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
/* Bad, but if due to size must set TC bit */
/* trim off the rrset neatly. */
@@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 0, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
sldns_buffer_set_position(pkt, setstart);
return r;
@@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 0, 1, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
sldns_buffer_set_position(pkt, setstart);
return r;
@@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
struct compress_tree_node* tree = 0;
int r;
size_t rr_offset;
+ size_t compress_count=0;
sldns_buffer_clear(buffer);
if(udpsize < sldns_buffer_limit(buffer))
@@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
arep.rrsets = &qinfo->local_alias->rrset;
if((r=insert_section(&arep, 1, &ancount, buffer, 0,
timezero, region, &tree, LDNS_SECTION_ANSWER,
- qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
+ qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 6, ancount);
@@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
/* insert answer section */
if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 6, ancount);
@@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
rep->an_numrrsets, timenow, region, &tree,
LDNS_SECTION_AUTHORITY, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 8, nscount);
@@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* no need to set TC bit, this is the additional */
sldns_buffer_write_u16_at(buffer, 10, arcount);
--
2.47.0

File diff suppressed because it is too large Load Diff

View File

@ -1,305 +0,0 @@
diff --git a/unbound-1.16.2/testdata/iter_ghost_ns_childapex.rpl b/unbound-1.16.2/testdata/iter_ghost_ns_childapex.rpl
new file mode 100644
index 0000000..2b046a8
--- /dev/null
+++ b/unbound-1.16.2/testdata/iter_ghost_ns_childapex.rpl
@@ -0,0 +1,299 @@
+; config options
+server:
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: no
+ minimal-responses: yes
+ log-servfail: yes
+ module-config: "iterator"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test for ghost domain with a child apex NS query.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+ ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET. IN A 193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+tld. IN NS
+SECTION AUTHORITY
+tld. IN NS ns.tld.
+SECTION ADDITIONAL
+ns.tld. IN A 1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.tld
+RANGE_BEGIN 0 15
+ ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+tld. IN NS
+SECTION ANSWER
+tld. IN NS ns.tld
+SECTION ADDITIONAL
+ns.tld. IN A 1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.tld. IN A
+SECTION ANSWER
+ns.tld. IN A 1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.tld. IN AAAA
+SECTION AUTHORITY
+tld. 3600 IN SOA ns.tld. host.tld. 20201 3600 1800 604800 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+mid.tld. IN NS
+SECTION AUTHORITY
+mid.tld. 5 IN NS ns.mid.tld.
+SECTION ADDITIONAL
+ns.mid.tld. 5 IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.tld
+RANGE_BEGIN 20 100
+ ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+tld. IN NS
+SECTION ANSWER
+tld. IN NS ns.tld
+SECTION ADDITIONAL
+ns.tld. IN A 1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.tld. IN A
+SECTION ANSWER
+ns.tld. IN A 1.2.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.tld. IN AAAA
+SECTION AUTHORITY
+tld. 3600 IN SOA ns.tld. host.tld. 20201 3600 1800 604800 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR AA NXDOMAIN
+SECTION QUESTION
+mid.tld. IN NS
+SECTION AUTHORITY
+tld. 3600 IN SOA ns.tld. host.tld. 20201 3600 1800 604800 3600
+ENTRY_END
+RANGE_END
+
+; ns.mid.tld.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+mid.tld. IN NS
+SECTION ANSWER
+mid.tld. 86400 IN NS ns.mid.tld.
+SECTION ADDITIONAL
+ns.mid.tld. 86400 IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.mid.tld. IN A
+SECTION ANSWER
+ns.mid.tld. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.mid.tld. IN AAAA
+SECTION AUTHORITY
+mid.tld. 3600 IN SOA ns.mid.tld. host.mid.tld. 20301 3600 1800 604800 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+sub.mid.tld. IN NS
+SECTION AUTHORITY
+sub.mid.tld. 3600 IN NS ns.sub.mid.tld.
+SECTION ADDITIONAL
+ns.sub.mid.tld. 3600 IN A 1.2.3.6
+ENTRY_END
+RANGE_END
+
+; ns.sub.mid.tld.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.6
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+sub.mid.tld. IN NS
+SECTION ANSWER
+sub.mid.tld. IN NS ns.sub.mid.tld.
+SECTION ADDITIONAL
+ns.sub.mid.tld. IN A 1.2.3.6
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.sub.mid.tld. IN A
+SECTION ANSWER
+ns.sub.mid.tld. IN A 1.2.3.6
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.sub.mid.tld. IN AAAA
+SECTION AUTHORITY
+sub.mid.tld. 3600 IN SOA ns.sub.mid.tld. host.sub.mid.tld. 20301 3600 1800 604800 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.sub.mid.tld. IN A
+SECTION ANSWER
+a.sub.mid.tld. 3600 IN A 10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+b.sub.mid.tld. IN A
+SECTION ANSWER
+b.sub.mid.tld. 3600 IN A 10.20.30.41
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD NOERROR
+SECTION QUESTION
+a.sub.mid.tld. IN A
+ENTRY_END
+
+STEP 2 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+a.sub.mid.tld. IN A
+SECTION ANSWER
+a.sub.mid.tld. 3600 IN A 10.20.30.40
+ENTRY_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD NOERROR
+SECTION QUESTION
+mid.tld. IN NS
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+mid.tld. IN NS
+SECTION ANSWER
+mid.tld. 86400 IN NS ns.mid.tld.
+SECTION ADDITIONAL
+ns.mid.tld. 86400 IN A 1.2.3.4
+ENTRY_END
+
+STEP 20 TIME_PASSES ELAPSE 10
+; The authority for .tld switches to NXDOMAIN for mid.tld.
+
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD NOERROR
+SECTION QUESTION
+b.sub.mid.tld. IN A
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NXDOMAIN
+SECTION QUESTION
+b.sub.mid.tld. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+tld. 3600 IN SOA ns.tld. host.tld. 20201 3600 1800 604800 3600
+ENTRY_END
+
+SCENARIO_END

View File

@ -1,36 +0,0 @@
diff --git a/unbound-1.16.2/services/cache/rrset.c b/unbound-1.16.2/services/cache/rrset.c
index 4e3d08b..b2c357f 100644
--- a/unbound-1.16.2/services/cache/rrset.c
+++ b/unbound-1.16.2/services/cache/rrset.c
@@ -143,6 +143,16 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
if(equal && cached->ttl >= timenow &&
cached->security == sec_status_bogus)
return 0;
+ /* ghost-domain: never let an NS overwrite extend lifetime
+ * past the entry it replaces, regardless of trust. */
+ if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
+ newd->ttl > cached->ttl) {
+ size_t i;
+ newd->ttl = cached->ttl;
+ for(i=0; i<(newd->count+newd->rrsig_count); i++)
+ if(newd->rr_ttl[i] > newd->ttl)
+ newd->rr_ttl[i] = newd->ttl;
+ }
return 1;
}
/* o item in cache has expired */
diff --git a/unbound-1.16.2/util/data/msgparse.h b/unbound-1.16.2/util/data/msgparse.h
index 0c458e6..f1319ff 100644
--- a/unbound-1.16.2/util/data/msgparse.h
+++ b/unbound-1.16.2/util/data/msgparse.h
@@ -92,6 +92,10 @@ extern time_t SERVE_EXPIRED_REPLY_TTL;
/** If we serve the original TTL or decrementing TTLs */
extern int SERVE_ORIGINAL_TTL;
+/** Check if TTL is expired. 0 TTL is considered expired.
+ * Used mainly to identify parts of the code that do this comparison. */
+#define TTL_IS_EXPIRED(ttl, now) ((ttl) <= (now))
+
/**
* Data stored in scratch pad memory during parsing.
* Stores the data that will enter into the msgreply and packet result.

View File

@ -1,64 +0,0 @@
diff --git a/unbound-1.16.2/util/data/msgparse.c b/unbound-1.16.2/util/data/msgparse.c
index 7a51441..0ffdb3d 100644
--- a/unbound-1.16.2/util/data/msgparse.c
+++ b/unbound-1.16.2/util/data/msgparse.c
@@ -50,6 +50,8 @@
#include "sldns/parseutil.h"
#include "sldns/wire2str.h"
+#define MAX_PARSED_EDNS_OPTIONS 100
+
/** smart comparison of (compressed, valid) dnames from packet */
static int
smart_compare(sldns_buffer* pkt, uint8_t* dnow,
@@ -957,7 +959,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
struct regional* region)
{
- int nsid_seen = 0, padding_seen = 0;
+ int i = 0, nsid_seen = 0, padding_seen = 0;
/* To respond with a Keepalive option, the client connection must have
* received one message with a TCP Keepalive EDNS option, and that
* option must have 0 length data. Subsequent messages sent on that
@@ -977,7 +979,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
/* while still more options, and have code+len to read */
/* ignores partial content (i.e. rdata len 3) */
- while(rdata_len >= 4) {
+ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
uint16_t opt_code = sldns_read_uint16(rdata_ptr);
uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
rdata_ptr += 4;
@@ -1054,6 +1056,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
}
rdata_ptr += opt_len;
rdata_len -= opt_len;
+ i++;
}
return LDNS_RCODE_NOERROR;
}
@@ -1068,6 +1071,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
struct rrset_parse* found_prev = 0;
size_t rdata_len;
uint8_t* rdata_ptr;
+ int i = 0;
/* since the class encodes the UDP size, we cannot use hash table to
* find the EDNS OPT record. Scan the packet. */
while(rrset) {
@@ -1125,7 +1129,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
/* while still more options, and have code+len to read */
/* ignores partial content (i.e. rdata len 3) */
- while(rdata_len >= 4) {
+ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
uint16_t opt_code = sldns_read_uint16(rdata_ptr);
uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
rdata_ptr += 4;
@@ -1140,6 +1144,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
}
rdata_ptr += opt_len;
rdata_len -= opt_len;
+ i++;
}
/* ignore rrsigs */
return LDNS_RCODE_NOERROR;

View File

@ -1,51 +0,0 @@
diff --git a/unbound-1.16.2/services/mesh.c b/unbound-1.16.2/services/mesh.c
index 30bcf7c..0f5a2a3 100644
--- a/unbound-1.16.2/services/mesh.c
+++ b/unbound-1.16.2/services/mesh.c
@@ -338,12 +338,14 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
if(mesh->num_reply_states < mesh->max_reply_states)
return 1;
/* try to kick out a jostle-list item */
- if(m && m->reply_list && m->list_select == mesh_jostle_list) {
+ if(m && m->list_select == mesh_jostle_list) {
/* how old is it? */
struct timeval age;
- timeval_subtract(&age, mesh->env->now_tv,
- &m->reply_list->start_time);
- if(timeval_smaller(&mesh->jostle_max, &age)) {
+ if(m->has_first_reply_time)
+ timeval_subtract(&age, mesh->env->now_tv,
+ &m->first_reply_time);
+ if(!m->has_first_reply_time ||
+ timeval_smaller(&mesh->jostle_max, &age)) {
/* its a goner */
log_nametypeclass(VERB_ALGO, "query jostled out to "
"make space for a new one",
@@ -1690,6 +1692,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
r->qid = qid;
r->qflags = qflags;
r->start_time = *s->s.env->now_tv;
+ if(s->reply_list == NULL && !s->has_first_reply_time) {
+ s->first_reply_time = r->start_time;
+ s->has_first_reply_time = 1;
+ }
r->next = s->reply_list;
r->qname = regional_alloc_init(s->s.region, qinfo->qname,
s->s.qinfo.qname_len);
diff --git a/unbound-1.16.2/services/mesh.h b/unbound-1.16.2/services/mesh.h
index 3be9b63..8194994 100644
--- a/unbound-1.16.2/services/mesh.h
+++ b/unbound-1.16.2/services/mesh.h
@@ -174,6 +174,12 @@ struct mesh_state {
struct module_qstate s;
/** the list of replies to clients for the results */
struct mesh_reply* reply_list;
+ /** if it has a first reply time */
+ int has_first_reply_time;
+ /** wall-clock time the first client reply was attached;
+ * used by mesh_make_new_space() so duplicate retransmits
+ * cannot reset jostle aging. */
+ struct timeval first_reply_time;
/** the list of callbacks for the results */
struct mesh_cb* cb_list;
/** set of superstates (that want this state's result)

View File

@ -1,34 +0,0 @@
diff --git a/unbound-1.16.2/util/data/msgparse.c b/unbound-1.16.2/util/data/msgparse.c
index 5bb69d6..7a51441 100644
--- a/unbound-1.16.2/util/data/msgparse.c
+++ b/unbound-1.16.2/util/data/msgparse.c
@@ -957,6 +957,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
struct regional* region)
{
+ int nsid_seen = 0, padding_seen = 0;
/* To respond with a Keepalive option, the client connection must have
* received one message with a TCP Keepalive EDNS option, and that
* option must have 0 length data. Subsequent messages sent on that
@@ -987,8 +988,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
/* handle parse time edns options here */
switch(opt_code) {
case LDNS_EDNS_NSID:
- if (!cfg || !cfg->nsid)
+ if (!cfg || !cfg->nsid || nsid_seen)
break;
+ nsid_seen = 1;
if(!edns_opt_list_append(&edns->opt_list_out,
LDNS_EDNS_NSID, cfg->nsid_len,
cfg->nsid, region)) {
@@ -1030,8 +1032,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
case LDNS_EDNS_PADDING:
if(!cfg || !cfg->pad_responses ||
- !c || c->type != comm_tcp ||!c->ssl)
+ !c || c->type != comm_tcp ||!c->ssl || padding_seen)
break;
+ padding_seen = 1;
if(!edns_opt_list_append(&edns->opt_list_out,
LDNS_EDNS_PADDING,
0, NULL, region)) {

View File

@ -1,17 +0,0 @@
diff --git a/unbound-1.24.2/validator/val_utils.c b/unbound-1.24.2/validator/val_utils.c
index 549264d..4495695 100644
--- a/unbound-1.24.2/validator/val_utils.c
+++ b/unbound-1.24.2/validator/val_utils.c
@@ -1066,10 +1066,10 @@ val_fill_reply(struct reply_info* chase, struct reply_info* orig,
if(query_dname_compare(name,
orig->rrsets[i]->rk.dname) == 0)
chase->rrsets[chase->an_numrrsets
- +orig->ns_numrrsets+chase->ar_numrrsets++]
+ +chase->ns_numrrsets+chase->ar_numrrsets++]
= orig->rrsets[i];
} else if(rrset_has_signer(orig->rrsets[i], name, len)) {
- chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+
+ chase->rrsets[chase->an_numrrsets+chase->ns_numrrsets+
chase->ar_numrrsets++] = orig->rrsets[i];
}
}

View File

@ -1,20 +0,0 @@
diff --git a/unbound-1.16.2/util/data/msgencode.c b/unbound-1.16.2/util/data/msgencode.c
index f9e95e6..f60b359 100644
--- a/unbound-1.16.2/util/data/msgencode.c
+++ b/unbound-1.16.2/util/data/msgencode.c
@@ -352,7 +352,6 @@ compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
(p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
if(!write_compressed_dname(pkt, dname, labs, p))
return RETVAL_TRUNC;
- (*compress_count)++;
} else {
if(!dname_buffer_write(pkt, dname))
return RETVAL_TRUNC;
@@ -360,6 +359,7 @@ compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
!compress_tree_store(dname, labs, pos, region, p, insertpt))
return RETVAL_OUTMEM;
+ (*compress_count)++;
return RETVAL_OK;
}

View File

@ -1,392 +0,0 @@
From b70994e8bc149c39d2022d554922ff9ac16cc8e2 Mon Sep 17 00:00:00 2001
From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
Date: Wed, 22 Jul 2026 11:56:08 +0200
Subject: [PATCH] - Unit test for CVE-2026-44690.
---
testdata/rrsig_agr_wild.rpl | 373 ++++++++++++++++++++++++++++++++++++
1 file changed, 373 insertions(+)
create mode 100644 testdata/rrsig_agr_wild.rpl
diff --git a/testdata/rrsig_agr_wild.rpl b/testdata/rrsig_agr_wild.rpl
new file mode 100644
index 0000000..85fe6f7
--- /dev/null
+++ b/testdata/rrsig_agr_wild.rpl
@@ -0,0 +1,373 @@
+; config options
+; The island of trust is at com.
+server:
+ trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b"
+ val-override-date: "20201020135527"
+ target-fetch-policy: "0 0 0 0 0"
+ qname-minimisation: "no"
+ fake-sha1: yes
+ trust-anchor-signaling: no
+ minimal-responses: no
+ aggressive-nsec: yes
+ local-zone: test. nodefault
+ log-servfail: yes
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test with RRSIG labels for wildcard with aggressive cache.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+ ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET. IN A 193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+test. IN NS
+SECTION AUTHORITY
+test. IN NS ns.test.
+SECTION ADDITIONAL
+ns.test. IN A 1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.test
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+test. IN NS
+SECTION ANSWER
+test. IN NS ns.test
+test. 3600 IN RRSIG NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s=
+SECTION ADDITIONAL
+ns.test. IN A 1.2.3.5
+ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.test. IN A
+SECTION ANSWER
+ns.test. IN A 1.2.3.5
+ns.test. 3600 IN RRSIG A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.test. IN AAAA
+SECTION AUTHORITY
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+ns.test. 3600 IN NSEC nz.test. A RRSIG
+ns.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+test. IN DNSKEY
+SECTION ANSWER
+test. 3600 IN DNSKEY 257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b}
+test. 3600 IN RRSIG DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc=
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA NXDOMAIN
+SECTION QUESTION
+domain1.test. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC
+test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo=
+cee.test. 3600 IN NSEC erts.test. RRSIG DS
+cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA NXDOMAIN
+SECTION QUESTION
+domain2.test. IN DS
+SECTION ANSWER
+SECTION AUTHORITY
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC
+test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo=
+cee.test. 3600 IN NSEC erts.test. RRSIG DS
+cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.test. IN DS
+SECTION ANSWER
+example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39
+example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN NS
+SECTION AUTHORITY
+example.test. IN NS ns.example.test.
+example.test. 3600 IN DS 55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39
+example.test. 3600 IN RRSIG DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I=
+SECTION ADDITIONAL
+ns.example.test. IN A 1.2.3.4
+ENTRY_END
+
+RANGE_END
+
+; ns.example.test.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN NS
+SECTION ANSWER
+example.test. IN NS ns.example.test.
+example.test. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4=
+SECTION ADDITIONAL
+ns.example.test. IN A 1.2.3.4
+ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.test. IN A
+SECTION ANSWER
+ns.example.test. IN A 1.2.3.4
+ns.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.test. IN AAAA
+SECTION AUTHORITY
+example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600
+example.test. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8=
+ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG
+example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN DNSKEY
+SECTION ANSWER
+example.test. 3600 IN DNSKEY 257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b}
+example.test. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g=
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+wild.example.test. IN A
+SECTION ANSWER
+wild.example.test. IN A 10.20.30.40
+; normal RRSIG:
+;wild.example.test. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55567 example.test. RzIsliJeEcLIHQGJqr5U2tfgxjzyxvwpqWYMdF2qOmb5a5erx3AFwRLbHhl7383Kdpdi+KxVKIWmkG6YCta0sWE42UeDXAVtZnFK/VeADRWpzWljQaTdIG8eN6FdB/X3gSPXnxMhsd9OoAWHPJYrwXtoFbciH6Hy0gl4Cosc+7Q=
+; with labelcount lower, 2 lower.
+; like it is : *.test. IN A 10.20.30.40
+wild.example.test. 3600 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA=
+SECTION AUTHORITY
+un.example.test. 3600 IN NSEC xy.example.test. A RRSIG
+un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+wild2.example.test. IN DS
+SECTION ANSWER
+wild2.example.test. IN DS 12345 250 2 00000000
+; normal RRSIG
+; wild2.example.test. 3600 IN RRSIG DS 8 3 3600 20201116135527 20201019135527 55567 example.test. GdSaD9J3c2QwsAPRbzY7lbuqguaBNEu/19jnZIrdMx4nmRRaMOS1MqMGZyOJdYvupVA0zg32bhCbmZdHSQLwzybjIgixGeiPC9MnfHdSqZKG7QG/AlUR2A/Mhmedp7RngROgIf6c7de88zsX+60xSfvBgNtg55YmODHqOICvTLs=
+; with labelcount lower, 2 lower.
+; for *.test. IN DS 12345 250 2 00000000
+wild2.example.test. 3600 IN RRSIG DS 8 1 3600 20201116135527 20201019135527 55567 example.test. qZQ/bfTCVuGISm6Pkq6OYDnyZMx8/uQQE3vq402UVWyy7ZrDBVI/CAErEIqz7Xl4cGgFUoezL2LCBIS7BMERCbQ0cVm3YTpnSzCgiDNJsu9W778SLOTcWlqJaiJn9EieFGkiFo2k3c1iuW++yufdhQmuXGk+DdLzE87tgvIkQm0=
+SECTION AUTHORITY
+un.example.test. 3600 IN NSEC xy.example.test. A RRSIG
+un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4=
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+domain1.test. IN A
+ENTRY_END
+
+; Picks up NSECs for aggressive negative cache.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD DO NXDOMAIN
+SECTION QUESTION
+domain1.test. IN A
+SECTION AUTHORITY
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC
+test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo=
+cee.test. 3600 IN NSEC erts.test. RRSIG DS
+cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA=
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+wild.example.test. IN A
+ENTRY_END
+
+; query for the wildcard record.
+STEP 30 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+wild.example.test. IN A
+ENTRY_END
+;REPLY QR RD RA AD DO NXDOMAIN
+;SECTION QUESTION
+;domain1.test. IN A
+;SECTION ANSWER
+;wild.example.test. IN A 10.20.30.40
+;wild.example.test. 3600 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA=
+;SECTION AUTHORITY
+;un.example.test. 3600 IN NSEC xy.example.test. A RRSIG
+;un.example.test. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55567 example.test. rP0p0viq8A3y/RSth9BNkDVAufPRVp8uohX+Wp1lby4naxlOjZCONz3aeLz8c0XgrIUtdU4t2sZZz9gF9jfr/QnAr5JDMDAIpMXKYGx/3dk5mSP/OBRX9sNVuBdr9YuyYy5N9K97aKTSQTRNU8FdTVYx9yjImVlwA8KI+SkztJ4=
+;ENTRY_END
+
+;STEP 40 QUERY
+;ENTRY_BEGIN
+;REPLY RD DO
+;SECTION QUESTION
+;domain2.test. IN A
+;ENTRY_END
+;
+;; aggressive cache synthesis, the '*.test' from the wildcard lookup.
+;STEP 50 CHECK_ANSWER
+;ENTRY_BEGIN
+;MATCH all
+;REPLY QR RD RA DO SERVFAIL
+;SECTION QUESTION
+;domain2.test. IN A
+;SECTION ANSWER
+;ENTRY_END
+
+STEP 60 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+wild2.example.test. IN DS
+ENTRY_END
+
+; wild2 is for *.test DS
+STEP 70 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+wild2.example.test. IN DS
+SECTION ANSWER
+ENTRY_END
+
+STEP 80 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+domain3.test. IN A
+ENTRY_END
+
+; aggressive cache synthesis, the '*.test' from the wildcard lookup.
+; with '*.test' DS record.
+STEP 90 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+
+; The bad answer
+;REPLY QR RD RA DO NOERROR
+;SECTION QUESTION
+;domain3.test. IN A
+;SECTION ANSWER
+;domain3.test. 0 IN A 10.20.30.40
+;domain3.test. 0 IN RRSIG A 8 1 3600 20201116135527 20201019135527 55567 example.test. XR1dPkaZmhIXoKRBmVLiDdIROYxlVNuII0kD/Nh/L3QteSvjwdfDBbVvwWGc+y011is0eFZBlFHWxmhw8BXytktlcJ3rZ1GPbcixkX7XPIIZER7jvZiFnKDS2Fwgh2wgpAXdo8KrmMgeUGPjP9scbzbBxLfSV/ja93PTuTSi6VA= ;{id = 55567}
+;SECTION AUTHORITY
+;cee.test. 0 IN NSEC erts.test. DS RRSIG
+;cee.test. 0 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA= ;{id = 1444}
+
+; The correct answer
+REPLY QR RD RA AD DO NXDOMAIN
+SECTION QUESTION
+domain3.test. IN A
+SECTION AUTHORITY
+test. 3600 IN NSEC abc.test. NS SOA DNSKEY RRSIG NSEC
+test. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 1444 test. SHU0veyxtCpPvwdJxn2xCEq9xXJZLIvAlYYy7/dBMSjo6ugBPSxs1+8hUZFxks+YQoPLR5nTU0C0yuhZ9dfg/2VGkCYLsDLYnh1lJj6uQ2VgwfhbwSJC0E9hwYvD7yl6LcmpySbGiyI0cCbK/wWHE8wVw4VBcbuv01f3Cj6F+mo=
+cee.test. 3600 IN NSEC erts.test. RRSIG DS
+cee.test. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 1444 test. kIveXrsXAeb7fsc3YNZ6UyJeCGxENpeUAl3mUCW2py+0vXfLjmDNs4FG5cwkLSIrni1z8k4939Bt+/3i+ABE84Utb77LpF29+dIay0L5V9c+avY2rJH8F1JU0kidtFQAccZqXuHtGSHHAi35w09UqghK+hNKfv+7qRUICX5ByCA=
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test. 3600 IN RRSIG SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+ENTRY_END
+
+SCENARIO_END
--
2.55.0

View File

@ -1,155 +0,0 @@
From e4ecb6040571b74e4f82f79838a9228355f40a6b Mon Sep 17 00:00:00 2001
From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
Date: Wed, 22 Jul 2026 10:12:38 +0200
Subject: [PATCH] - Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via
RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
---
services/cache/rrset.c | 32 ++++++++++++++++++++++++++++++++
validator/val_sigcrypt.c | 7 +++++++
validator/val_utils.c | 2 +-
validator/val_utils.h | 4 ++++
validator/validator.c | 15 +++++++++++++--
5 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/services/cache/rrset.c b/services/cache/rrset.c
index b2c357f2..1c70862d 100644
--- a/services/cache/rrset.c
+++ b/services/cache/rrset.c
@@ -49,6 +49,7 @@
#include "util/regional.h"
#include "util/alloc.h"
#include "util/net_help.h"
+#include "validator/val_utils.h"
void
rrset_markdel(void* key)
@@ -249,12 +250,43 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
return 0;
}
+/** See if the name is a within signer authority */
+static int
+dname_subdomain_rrsig_signers(uint8_t* dname,
+ struct ub_packed_rrset_key* rrset)
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)
+ rrset->entry.data;
+ size_t i;
+ if(!d || !d->rrsig_count)
+ return 0;
+ for(i=0; i<d->rrsig_count; i++) {
+ uint8_t* sname = NULL;
+ size_t slen = 0;
+ rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i],
+ &sname, &slen);
+ if(!sname || !slen)
+ return 0; /* malformed */
+ if(!dname_subdomain_c(dname, sname))
+ return 0; /* not a subdomain */
+ }
+ return 1;
+}
+
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
struct alloc_cache* alloc, time_t timenow)
{
struct rrset_ref ref;
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
+
+ /* See if the RRSIG signer name allows this wildcard,
+ * the new rrset should fall within the zone of the RRSIG signer(s). */
+ if(!dname_subdomain_rrsig_signers(ce, rrset)) {
+ verbose(VERB_ALGO, "wildcard canonical parent outside signer authority");
+ return;
+ }
+
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
if(!rrset) {
log_err("malloc failure in rrset_cache_update_wildcard");
diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c
index 8600a682..339c09c8 100644
--- a/validator/val_sigcrypt.c
+++ b/validator/val_sigcrypt.c
@@ -1689,6 +1689,13 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
+ if((int)sig[2+3] < dname_signame_label_count(signer)) {
+ verbose(VERB_QUERY, "verify: RRSIG label count too low for signer");
+ *reason = "signature labelcount lower than signature signer";
+ if(reason_bogus)
+ *reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
+ return sec_status_bogus;
+ }
/* original ttl, always ok */
diff --git a/validator/val_utils.c b/validator/val_utils.c
index 19e1eefe..b7f2b74c 100644
--- a/validator/val_utils.c
+++ b/validator/val_utils.c
@@ -134,7 +134,7 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf,
}
/** Get signer name from RRSIG */
-static void
+void
rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen)
{
/* RRSIG rdata is not allowed to be compressed, it is stored
diff --git a/validator/val_utils.h b/validator/val_utils.h
index e8cdcefa..b10529ae 100644
--- a/validator/val_utils.h
+++ b/validator/val_utils.h
@@ -413,4 +413,8 @@ int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset);
struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen,
uint16_t c, struct regional* region, uint8_t* topname);
+/** Get signer name from RRSIG, sname is NULL if malformed. */
+void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname,
+ size_t* slen);
+
#endif /* VALIDATOR_VAL_UTILS_H */
diff --git a/validator/validator.c b/validator/validator.c
index 01303a84..0a7fe8a1 100644
--- a/validator/validator.c
+++ b/validator/validator.c
@@ -957,6 +957,10 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
uint8_t* wc = NULL;
size_t wl;
int wc_cached = 0;
+ int wc_to_cache = 0;
+ uint8_t* cache_wc = NULL;
+ size_t cache_wl = 0;
+ struct ub_packed_rrset_key* cache_s = NULL;
int wc_NSEC_ok = 0;
int nsec3s_seen = 0;
size_t i;
@@ -979,8 +983,11 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
return;
}
if(wc && !wc_cached && env->cfg->aggressive_nsec) {
- rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl,
- env->alloc, *env->now);
+ /* Postpone cache adjust until proof has succeeded. */
+ wc_to_cache = 1;
+ cache_wc = wc;
+ cache_wl = wl;
+ cache_s = s;
wc_cached = 1;
}
@@ -1042,6 +1049,10 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
+ if(wc_to_cache) {
+ rrset_cache_update_wildcard(env->rrset_cache, cache_s,
+ cache_wc, cache_wl, env->alloc, *env->now);
+ }
verbose(VERB_ALGO, "Successfully validated positive response");
chase_reply->security = sec_status_secure;

View File

@ -989,7 +989,6 @@ remote-control:
# Set to no and use an absolute path as control-interface to use
# a unix local named pipe for unbound-control.
# For local sockets this option is ignored, and TLS is not used.
# control-use-cert: yes
# what interfaces are listened to for remote control.
@ -998,11 +997,14 @@ remote-control:
# are not used for that, so key and cert files need not be present.
# control-interface: 127.0.0.1
# control-interface: ::1
# moved to /etc/unbound/conf.d/remote-control.conf
# port number for remote control operations.
# control-port: 8953
# for localhost, you can disable use of TLS by setting this to "no"
# For local sockets this option is ignored, and TLS is not used.
control-use-cert: "no"
# Unbound server key file.
server-key-file: "/etc/unbound/unbound_server.key"

View File

@ -34,7 +34,7 @@
Summary: Validating, recursive, and caching DNS(SEC) resolver
Name: unbound
Version: 1.16.2
Release: 5.14%{?extra_version:.%{extra_version}}%{?dist}
Release: 5%{?extra_version:.%{extra_version}}%{?dist}
License: BSD
Url: https://www.unbound.net/
Source: https://www.unbound.net/downloads/%{name}-%{version}%{?extra_version}.tar.gz
@ -55,7 +55,6 @@ Source15: unbound-anchor.timer
Source16: unbound-munin.README
Source17: unbound-anchor.service
Source18: https://nlnetlabs.nl/downloads/%{name}/%{name}-%{version}%{?extra_version}.tar.gz.asc
Source21: remote-control.conf
# Reverts ABI change done in version 1.8.0 (bz#2027735)
# Makes possible backward binary compatibility with a new features
@ -63,40 +62,6 @@ Patch1: unbound-1.15-soversion2-compat.patch
Patch2: unbound-1.15-source-compat.patch
# https://github.com/NLnetLabs/unbound/commit/137719522a8ea5b380fbb6206d2466f402f5b554
Patch3: unbound-1.16-CVE-2022-3204.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2023-50387_CVE-2023-50868.diff
Patch4: unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch
# https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259
Patch5: unbound-1.21-CVE-2024-8508.patch
# The patch for CVE-2025-5994 requires certain changes fixing bugs in subnet module
# that is why we have to backport these commits. They have their respective tests
# backported with them.
# https://github.com/NLnetLabs/unbound/commit/0f08cc6d5577ad4747749c55229e16df8711ee32
# https://github.com/NLnetLabs/unbound/commit/6d0812b56731af130e8bc7e1572388934beb9b3b
# https://github.com/NLnetLabs/unbound/commit/be626f7c5330dc414a582a04b537ea79d5c452fb
# https://github.com/NLnetLabs/unbound/commit/5bf82f246481098a6473f296b21fc1229d276c0f
# https://github.com/NLnetLabs/unbound/commit/a1150078f29e14b36c8e4d9d05a263a5e6abbc5b
Patch6: unbound-1.23.1-CVE-2025-5994.patch
# https://github.com/NLnetLabs/unbound/commit/f094f4ea3c943c5b5b2b6fa8bee0e7a8f3cfdc51
Patch7: unbound-1.20-unbound-anchor-key-38696.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-42944.diff
Patch8: unbound-1.25.1-CVE-2026-42944.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-42959.diff
Patch9: unbound-1.25.1-CVE-2026-42959.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-40622.diff
Patch10: unbound-1.25.1-CVE-2026-40622.patch
# https://github.com/NLnetLabs/unbound/commit/b5f21f41658f65d6143df6a3208e8ccf1a01604d
Patch11: unbound-1.25.1-CVE-2026-40622-test.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-44390.diff
Patch12: unbound-1.25.1-CVE-2026-44390.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-41292.diff
Patch13: unbound-1.25.1-CVE-2026-41292.patch
# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2026-42534.diff
Patch14: unbound-1.25.1-CVE-2026-42534.patch
# https://github.com/NLnetLabs/unbound/commit/f7637a4f1811f4a9331707d8a95cf0af65a97c0f
Patch15: unbound-1.25.2-CVE-2026-44690.patch
# https://github.com/NLnetLabs/unbound/commit/3d5e6c06923eff9eac2f5e31a69c43a15ca9d3c2
Patch16: unbound-1.25.2-CVE-2026-44690-test.patch
BuildRequires: gdb
BuildRequires: gcc, make
@ -199,19 +164,7 @@ pushd %{pkgname}
%patch1 -p2 -b .solib2-compat
%patch2 -p1 -b .srccompat
%patch3 -p2 -b .CVE-2022-3204
%patch4 -p2 -b .CVE-2023-50387-CVE-2023-50868
%patch5 -p2 -b .CVE-2024-8508
%patch6 -p2 -b .CVE-2025-5994
%patch7 -p2 -b .dnssec-ta-2024
%patch8 -p2 -b .CVE-2026-42944
%patch9 -p2 -b .CVE-2026-42959
%patch10 -p2 -b .CVE-2026-40622
%patch11 -p2 -b .CVE-2026-40622-test
%patch12 -p2 -b .CVE-2026-44390
%patch13 -p2 -b .CVE-2026-41292
%patch14 -p2 -b .CVE-2026-42534
%patch15 -p1 -b .CVE-2026-44690
%patch16 -p1 -b .CVE-2026-44690-test
# copy common doc files - after here, since it may be patched
cp -pr doc pythonmod libunbound ../
@ -330,7 +283,6 @@ mkdir -p %{buildroot}%{_sysconfdir}/unbound/{keys.d,conf.d,local.d}
install -p %{SOURCE9} %{buildroot}%{_sysconfdir}/unbound/keys.d/
install -p %{SOURCE10} %{buildroot}%{_sysconfdir}/unbound/conf.d/
install -p %{SOURCE11} %{buildroot}%{_sysconfdir}/unbound/local.d/
install -p -m 0644 %{SOURCE21} %{buildroot}%{_sysconfdir}/unbound/conf.d/
# Link unbound-control-setup.8 manpage to unbound-control.8
echo ".so man8/unbound-control.8" > %{buildroot}/%{_mandir}/man8/unbound-control-setup.8
@ -478,48 +430,6 @@ popd
%verify(not md5 size mtime) %{_sharedstatedir}/%{name}/root.key
%changelog
* Wed Aug 05 2026 Fedor Vorobev <fvorobev@redhat.com> - 1.16.2-5.14
- Add unit test for CVE-2026-44690 from upstream.
* Tue Jul 28 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.16.2-5.13
- Fix CVE-2026-44690 (RHEL-212801)
* Tue Jun 23 2026 Fedor Vorobev <fvorobev@redhat.com> - 1.16.2-5.12
- Fix CVE-2026-40622 (RHEL-184832)
- Fix CVE-2026-44390 (RHEL-186680)
- Fix CVE-2026-41292 (RHEL-187346)
- Fix CVE-2026-42534 (RHEL-187081)
* Mon May 25 2026 Fedor Vorobev <fvorobev@redhat.com> - 1.16.2-5.11
- Fix CVE-2026-42944 (RHEL177909)
- Fix CVE-2026-42959 (RHEL-177809)
* Tue Nov 11 2025 Petr Menšík <pemensik@redhat.com> - 1.16.2-5.10
- Add new root key 38696 (RHEL-131172)
- Update unbound-anchor built-in dnssec key
* Thu Jul 24 2025 Tomas Korbar <tkorbar@redhat.com> - 1.16.2-5.9
- Fix RebirthDay Attack (CVE-2025-5994)
- Resolves: RHEL-104123
* Tue Nov 12 2024 Petr Menšík <pemensik@redhat.com> - 1.16.2-5.8
- Prevent unbounded name compression (CVE-2024-8508)
* Tue May 28 2024 Petr Menšík <pemensik@redhat.com> - 1.16.2-5.7
- Rebuild to propagate to CentOS Stream (RHEL-25500)
* Mon Mar 11 2024 Petr Menšík <pemensik@redhat.com> - 1.16.2-5.6
- Ensure group access correction reaches also updated configs (CVE-2024-1488)
* Wed Feb 28 2024 Petr Menšík <pemensik@redhat.com> - 1.16.2-5.3
- Ensure only unbound group can change configuration (CVE-2024-1488)
* Fri Feb 16 2024 Tomas Korbar <tkorbar@redhat.com> - 1.16.2-5.1
- Fix KeyTrap - Extreme CPU consumption in DNSSEC validator CVE-2023-50387
- Fix Preparing an NSEC3 closest encloser proof can exhaust CPU resources CVE-2023-50868
- Resolves: RHEL-25428
- Resolves: RHEL-25423
* Sat Oct 15 2022 Petr Menšík <pemensik@redhat.com> - 1.16.2-5
- Stop creating wrong devel manual pages (#2135322)