import UBI unbound-1.20.0-12.el10_0

This commit is contained in:
eabdullin 2025-07-29 11:27:55 +00:00
parent 6f6f61e78d
commit 216132d4bf
2 changed files with 916 additions and 1 deletions

View File

@ -0,0 +1,906 @@
commit 81cb270d19a0e016b8b74af931d9c6647ae00b16
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Tue Jul 22 09:26:44 2025 +0200
Fix CVE-2025-5994 and add tests for it
diff --git a/unbound-1.20.0/edns-subnet/subnetmod.c b/unbound-1.20.0/edns-subnet/subnetmod.c
index 1dff429..d31ecb3 100644
--- a/unbound-1.20.0/edns-subnet/subnetmod.c
+++ b/unbound-1.20.0/edns-subnet/subnetmod.c
@@ -51,6 +51,7 @@
#include "services/cache/dns.h"
#include "util/module.h"
#include "util/regional.h"
+#include "util/fptr_wlist.h"
#include "util/storage/slabhash.h"
#include "util/config_file.h"
#include "util/data/msgreply.h"
@@ -155,7 +156,8 @@ int ecs_whitelist_check(struct query_info* qinfo,
/* Cache by default, might be disabled after parsing EDNS option
* received from nameserver. */
- if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
+ if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)
+ && sq->ecs_client_in.subnet_validdata) {
qstate->no_cache_store = 0;
}
@@ -522,6 +524,69 @@ common_prefix(uint8_t *a, uint8_t *b, uint8_t net)
return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]);
}
+/**
+ * Create sub request that looks up the query.
+ * @param qstate: query state
+ * @param sq: subnet qstate
+ * @return false on failure.
+ */
+static int
+generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
+{
+ struct module_qstate* subq = NULL;
+ uint16_t qflags = 0; /* OPCODE QUERY, no flags */
+ int prime = 0;
+ int valrec = 0;
+ struct query_info qinf;
+ qinf.qname = qstate->qinfo.qname;
+ qinf.qname_len = qstate->qinfo.qname_len;
+ qinf.qtype = qstate->qinfo.qtype;
+ qinf.qclass = qstate->qinfo.qclass;
+ qinf.local_alias = NULL;
+
+ qflags |= BIT_RD;
+ if((qstate->query_flags & BIT_CD)!=0) {
+ qflags |= BIT_CD;
+ valrec = 1;
+ }
+
+ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
+ if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
+ &subq)) {
+ return 0;
+ }
+ if(subq) {
+ /* It is possible to access the subquery module state. */
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
+ edns_opt_list_find(qstate->edns_opts_front_in,
+ qstate->env->cfg->client_subnet_opcode)) {
+ subq->no_cache_store = 1;
+ }
+ }
+ return 1;
+}
+
+/**
+ * Perform the query without subnet
+ * @param qstate: query state
+ * @param sq: subnet qstate
+ * @return module state
+ */
+static enum module_ext_state
+generate_lookup_without_subnet(struct module_qstate *qstate,
+ struct subnet_qstate* sq)
+{
+ verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
+ if(!generate_sub_request(qstate, sq)) {
+ verbose(VERB_ALGO, "Could not generate sub query");
+ qstate->return_rcode = LDNS_RCODE_FORMERR;
+ qstate->return_msg = NULL;
+ return module_finished;
+ }
+ sq->wait_subquery = 1;
+ return module_wait_subquery;
+}
+
static enum module_ext_state
eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
{
@@ -557,14 +622,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
* is still useful to put it in the edns subnet cache for
* when a client explicitly asks for subnet specific answer. */
verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
- if(!sq->started_no_cache_store) {
- lock_rw_wrlock(&sne->biglock);
- update_cache(qstate, id);
- lock_rw_unlock(&sne->biglock);
- }
- if (sq->subnet_downstream)
- cp_edns_bad_response(c_out, c_in);
- return module_finished;
+ return generate_lookup_without_subnet(qstate, sq);
}
/* Purposefully there was no sent subnet, and there is consequently
@@ -589,14 +647,14 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
!common_prefix(s_out->subnet_addr, s_in->subnet_addr,
s_out->subnet_source_mask))
{
- /* we can not accept, restart query without option */
+ /* we can not accept, perform query without option */
verbose(VERB_QUERY, "subnetcache: forged data");
s_out->subnet_validdata = 0;
(void)edns_opt_list_remove(&qstate->edns_opts_back_out,
qstate->env->cfg->client_subnet_opcode);
sq->subnet_sent = 0;
sq->subnet_sent_no_subnet = 0;
- return module_restart_next;
+ return generate_lookup_without_subnet(qstate, sq);
}
lock_rw_wrlock(&sne->biglock);
@@ -795,6 +853,9 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
} else if(sq->subnet_sent_no_subnet) {
/* The answer can be stored as scope 0, not in global cache. */
qstate->no_cache_store = 1;
+ } else if(sq->subnet_sent) {
+ /* Need another query to be able to store in global cache. */
+ qstate->no_cache_store = 1;
}
return 1;
@@ -812,6 +873,32 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
strmodulevent(event));
log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo);
+ if(sq && sq->wait_subquery_done) {
+ /* The subquery lookup returned. */
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
+ edns_opt_list_find(qstate->edns_opts_front_in,
+ qstate->env->cfg->client_subnet_opcode)) {
+ if(!sq->started_no_cache_store &&
+ qstate->return_msg) {
+ lock_rw_wrlock(&sne->biglock);
+ update_cache(qstate, id);
+ lock_rw_unlock(&sne->biglock);
+ }
+ if (sq->subnet_downstream)
+ cp_edns_bad_response(&sq->ecs_client_out,
+ &sq->ecs_client_in);
+ /* It is a scope zero lookup, append edns subnet
+ * option to the querier. */
+ subnet_ecs_opt_list_append(&sq->ecs_client_out,
+ &qstate->edns_opts_front_out, qstate,
+ qstate->region);
+ }
+ sq->wait_subquery_done = 0;
+ qstate->ext_state[id] = module_finished;
+ qstate->no_cache_store = sq->started_no_cache_store;
+ qstate->no_cache_lookup = sq->started_no_cache_lookup;
+ return;
+ }
if((event == module_event_new || event == module_event_pass) &&
sq == NULL) {
struct edns_option* ecs_opt;
@@ -822,6 +909,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
}
sq = (struct subnet_qstate*)qstate->minfo[id];
+ if(sq->wait_subquery)
+ return; /* Wait for that subquery to return */
if((ecs_opt = edns_opt_list_find(
qstate->edns_opts_front_in,
@@ -851,6 +940,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
/* No clients are interested in result or we could not
* parse it, we don't do client subnet */
sq->ecs_server_out.subnet_validdata = 0;
+ if(edns_opt_list_find(qstate->edns_opts_front_in,
+ qstate->env->cfg->client_subnet_opcode)) {
+ /* aggregated this deaggregated state */
+ qstate->ext_state[id] =
+ generate_lookup_without_subnet(
+ qstate, sq);
+ return;
+ }
verbose(VERB_ALGO, "subnetcache: pass to next module");
qstate->ext_state[id] = module_wait_module;
return;
@@ -891,6 +988,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
}
lock_rw_unlock(&sne->biglock);
}
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
+ edns_opt_list_find(qstate->edns_opts_front_in,
+ qstate->env->cfg->client_subnet_opcode)) {
+ /* client asked for resolution without edns subnet */
+ qstate->ext_state[id] = generate_lookup_without_subnet(
+ qstate, sq);
+ return;
+ }
sq->ecs_server_out.subnet_addr_fam =
sq->ecs_client_in.subnet_addr_fam;
@@ -927,6 +1032,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
qstate->ext_state[id] = module_wait_module;
return;
}
+ if(sq && sq->wait_subquery)
+ return; /* Wait for that subquery to return */
/* Query handed back by next module, we have a 'final' answer */
if(sq && event == module_event_moddone) {
qstate->ext_state[id] = eval_response(qstate, id, sq);
@@ -975,10 +1082,27 @@ subnetmod_clear(struct module_qstate *ATTR_UNUSED(qstate),
}
void
-subnetmod_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
- int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super))
+subnetmod_inform_super(struct module_qstate *qstate, int id,
+ struct module_qstate *super)
{
- /* Not used */
+ struct subnet_qstate* super_sq =
+ (struct subnet_qstate*)super->minfo[id];
+ log_query_info(VERB_ALGO, "subnetcache inform_super: query",
+ &super->qinfo);
+ super_sq->wait_subquery = 0;
+ super_sq->wait_subquery_done = 1;
+ if(qstate->return_rcode != LDNS_RCODE_NOERROR ||
+ !qstate->return_msg) {
+ super->return_msg = NULL;
+ super->return_rcode = LDNS_RCODE_SERVFAIL;
+ return;
+ }
+ super->return_rcode = LDNS_RCODE_NOERROR;
+ super->return_msg = dns_copy_msg(qstate->return_msg, super->region);
+ if(!super->return_msg) {
+ log_err("subnetcache: copy response, out of memory");
+ super->return_rcode = LDNS_RCODE_SERVFAIL;
+ }
}
size_t
diff --git a/unbound-1.20.0/edns-subnet/subnetmod.h b/unbound-1.20.0/edns-subnet/subnetmod.h
index 1ff8a23..3893820 100644
--- a/unbound-1.20.0/edns-subnet/subnetmod.h
+++ b/unbound-1.20.0/edns-subnet/subnetmod.h
@@ -102,6 +102,10 @@ struct subnet_qstate {
int started_no_cache_store;
/** has the subnet module been started with no_cache_lookup? */
int started_no_cache_lookup;
+ /** Wait for subquery that has been started for nonsubnet lookup. */
+ int wait_subquery;
+ /** The subquery waited for is done. */
+ int wait_subquery_done;
};
void subnet_data_delete(void* d, void* ATTR_UNUSED(arg));
diff --git a/unbound-1.20.0/testdata/subnet_noecs_mult.rpl b/unbound-1.20.0/testdata/subnet_noecs_mult.rpl
new file mode 100644
index 0000000..3e2acef
--- /dev/null
+++ b/unbound-1.20.0/testdata/subnet_noecs_mult.rpl
@@ -0,0 +1,334 @@
+# config
+server:
+ send-client-subnet: 1.2.3.4
+ max-client-subnet-ipv4: 17
+ module-config: "subnetcache iterator"
+ qname-minimisation: no
+ minimal-responses: yes
+ target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test subnet with no edns subnet from server multiple times
+; Multiple queries are sent to a server that does not reply with the
+; edns-subnet option.
+
+; 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
+com. IN NS
+SECTION AUTHORITY
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+ ADDRESS 192.5.6.30
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 50 52
+ ADDRESS 1.2.3.4
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com. IN NS ns.example.com.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA ns.example.com. host.example.com. 4 86400 3600 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname ednsdata
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+SECTION ADDITIONAL
+ ; Match this subnet option
+ HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 11 00 ; source mask, scopemask
+ 7f 00 00 ; address
+ HEX_EDNSDATA_END
+ ; This is the response, without the subnet option
+ HEX_ANSWER_BEGIN;
+ 00 00 84 00 00 01 00 01 ; ID 0 QR AA NOERROR
+ 00 00 00 01 03 77 77 77 ; www.example.com A (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01
+ C0 0C 00 01 00 01 00 00 0E 10 ; www.example.com. A IN 3600
+ 00 04 0A 14 1E 2C ; rdata 10.20.30.44
+ 00 00 29 10 00 00 00
+ 80 00 00 00
+ HEX_ANSWER_END
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname ednsdata
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+SECTION ADDITIONAL
+ ; Match this subnet option
+ HEX_EDNSDATA_BEGIN
+ ; client is 127.2.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 11 00 ; source mask, scopemask
+ 7f 02 00 ; address
+ HEX_EDNSDATA_END
+ ; This is the response, without the subnet option
+ HEX_ANSWER_BEGIN;
+ 00 00 84 00 00 01 00 01 ; ID 0 QR AA NOERROR
+ 00 00 00 01 03 77 77 77 ; www.example.com A (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01
+ C0 0C 00 01 00 01 00 00 0E 10 ; www.example.com. A IN 3600
+ 00 04 0A 14 1E 2C ; rdata 10.20.30.44
+ 00 00 29 10 00 00 00
+ 80 00 00 00
+ HEX_ANSWER_END
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname ednsdata
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+SECTION ADDITIONAL
+ ; Match this subnet option
+ HEX_EDNSDATA_BEGIN
+ ; client is 127.3.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 11 00 ; source mask, scopemask
+ 7f 03 00 ; address
+ HEX_EDNSDATA_END
+ ; This is the response, without the subnet option
+ HEX_ANSWER_BEGIN;
+ 00 00 84 00 00 01 00 01 ; ID 0 QR AA NOERROR
+ 00 00 00 01 03 77 77 77 ; www.example.com A (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01
+ C0 0C 00 01 00 01 00 00 0E 10 ; www.example.com. A IN 3600
+ 00 04 0A 14 1E 2C ; rdata 10.20.30.44
+ 00 00 29 10 00 00 00
+ 80 00 00 00
+ HEX_ANSWER_END
+ENTRY_END
+
+; The answer for a query without subnet
+;ENTRY_BEGIN
+;MATCH opcode qtype qname
+;ADJUST copy_id
+;REPLY QR AA NOERROR
+;SECTION QUESTION
+;www.example.com. IN A
+;SECTION ANSWER
+;www.example.com. IN A 10.20.30.40
+;ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 53 57
+ ADDRESS 1.2.3.4
+; The answer for a query without subnet
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+ENTRY_END
+RANGE_END
+
+STEP 10 QUERY
+ENTRY_BEGIN
+ HEX_ANSWER_BEGIN;
+ 00 00 01 00 00 01 00 00 ; ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 11 00 ; ip4, scope 17, source 0
+ 7f 00 00 ; 127.0.0.0/17
+ HEX_ANSWER_END
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+ HEX_ANSWER_BEGIN;
+ 00 00 01 00 00 01 00 00 ; ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 11 00 ; ip4, scope 17, source 0
+ 7f 02 00 ; 127.2.0.0/17
+ HEX_ANSWER_END
+ENTRY_END
+
+STEP 30 QUERY
+ENTRY_BEGIN
+ HEX_ANSWER_BEGIN;
+ 00 00 01 00 00 01 00 00 ; ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 11 00 ; ip4, scope 17, source 0
+ 7f 03 00 ; 127.3.0.0/17
+ HEX_ANSWER_END
+ENTRY_END
+
+; recursion happens here.
+; The upstream server RANGE starts responding at STEP 50.
+STEP 50 TRAFFIC
+
+; The upstream server now responds for the nonsubnet response.
+STEP 55 TRAFFIC
+
+STEP 60 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+;www.example.com. IN A 10.20.30.44
+SECTION ADDITIONAL
+; HEX_EDNSDATA_BEGIN
+; ; client is 127.3.0.1
+; 00 08 ; OPC
+; 00 07 ; option length
+; 00 01 ; Family
+; 11 00 ; source mask, scopemask
+; 7f 03 00 ; address
+; HEX_EDNSDATA_END
+ENTRY_END
+
+STEP 70 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+;www.example.com. IN A 10.20.30.44
+SECTION ADDITIONAL
+; HEX_EDNSDATA_BEGIN
+; ; client is 127.2.0.1
+; 00 08 ; OPC
+; 00 07 ; option length
+; 00 01 ; Family
+; 11 00 ; source mask, scopemask
+; 7f 02 00 ; address
+; HEX_EDNSDATA_END
+ENTRY_END
+
+STEP 80 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+;www.example.com. IN A 10.20.30.44
+SECTION ADDITIONAL
+; HEX_EDNSDATA_BEGIN
+; ; client is 127.0.0.1
+; 00 08 ; OPC
+; 00 07 ; option length
+; 00 01 ; Family
+; 11 00 ; source mask, scopemask
+; 7f 00 00 ; address
+; HEX_EDNSDATA_END
+ENTRY_END
+
+SCENARIO_END
diff --git a/unbound-1.20.0/testdata/subnet_noecs_refused.rpl b/unbound-1.20.0/testdata/subnet_noecs_refused.rpl
new file mode 100644
index 0000000..39fbe85
--- /dev/null
+++ b/unbound-1.20.0/testdata/subnet_noecs_refused.rpl
@@ -0,0 +1,159 @@
+# config
+server:
+ send-client-subnet: 1.2.3.4
+ max-client-subnet-ipv4: 17
+ module-config: "subnetcache iterator"
+ qname-minimisation: no
+ minimal-responses: yes
+ target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test subnet with no edns subnet support but it is refused
+; The query is sent to a server that does not reply with the edns-subnet
+; option. The upstream server sends rcode refused. That results in a
+; NULL return_msg.
+
+; 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
+com. IN NS
+SECTION AUTHORITY
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+ ADDRESS 192.5.6.30
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com. IN NS ns.example.com.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA ns.example.com. host.example.com. 4 86400 3600 86400 3600
+ENTRY_END
+
+; This matches the no EDNS subnet info queries that are made for the
+; fallback without subnet. The answer is refused.
+ENTRY_BEGIN
+MATCH opcode qtype qname ednsdata
+ADJUST copy_id
+REPLY QR AA REFUSED
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+;www.example.com. IN A 10.20.30.40
+ENTRY_END
+
+; This matches the initial query with edns subnet in the query,
+; the answer has no edns subnet in the reply.
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+;ENTRY_BEGIN
+;REPLY RD DO
+;SECTION QUESTION
+;www.example.com. IN A
+; but send this query with subnet scope zero in the query, because that
+; makes the reply possibly get stored in the cache.
+;
+; query with subnet 0.0.0.0/0.
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 08
+
+ 00 08 00 04 ; OPC, optlen
+ 00 01 00 00 ; ip4, scope 0, source 0
+ ;0.0.0.0/0
+HEX_ANSWER_END
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+;www.example.com. IN A 10.20.30.40
+ENTRY_END
+SCENARIO_END
diff --git a/unbound-1.20.0/testdata/subnet_noecs_support.rpl b/unbound-1.20.0/testdata/subnet_noecs_support.rpl
new file mode 100644
index 0000000..0c9826c
--- /dev/null
+++ b/unbound-1.20.0/testdata/subnet_noecs_support.rpl
@@ -0,0 +1,127 @@
+# config
+server:
+ send-client-subnet: 1.2.3.4
+ max-client-subnet-ipv4: 17
+ module-config: "subnetcache iterator"
+ qname-minimisation: no
+ minimal-responses: yes
+ target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test subnet with no edns subnet support from the server
+; The query is sent to a server that does not reply with the edns-subnet
+; option.
+
+; 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
+com. IN NS
+SECTION AUTHORITY
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+ ADDRESS 192.5.6.30
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com. IN NS ns.example.com.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA ns.example.com. host.example.com. 4 86400 3600 86400 3600
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+ENTRY_END
+SCENARIO_END

View File

@ -2,7 +2,7 @@
## (rpmautospec version 0.6.5)
## RPMAUTOSPEC: autorelease, autochangelog
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
release_number = 10;
release_number = 12;
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
print(release_number + base_release_number - 1);
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
@ -76,6 +76,9 @@ Source27: unbound-initrd.conf
Patch1: unbound-fedora-config.patch
# https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259
Patch2: unbound-1.21-CVE-2024-8508.patch
# https://github.com/NLnetLabs/unbound/commit/5bf82f246481098a6473f296b21fc1229d276c0f
# https://github.com/NLnetLabs/unbound/commit/a1150078f29e14b36c8e4d9d05a263a5e6abbc5b
Patch3: unbound-1.23.1-CVE-2025-5994.patch
BuildRequires: gcc, make
BuildRequires: flex, openssl-devel
@ -545,6 +548,12 @@ popd
%changelog
## START: Generated by rpmautospec
* Tue Jul 22 2025 Tomas Korbar <tkorbar@redhat.com> - 1.20.0-12
- Fix RebirthDay Attack (CVE-2025-5994)
* Thu Jun 05 2025 psklenar@redhat.com <psklenar@redhat.com> - 1.20.0-11
- https://issues.redhat.com/browse/RHELMISC-13073
* Wed May 14 2025 Petr Menšík <pemensik@redhat.com> - 1.20.0-10
- Prevent unbounded name compression (CVE-2024-8508)