- Fix for consistent use of local zone CNAME alias for configured auth

zones. Now it also applies to downstream configured auth zones.
This commit is contained in:
Yorgos Thessalonikefs 2025-06-17 15:03:29 +02:00
parent f066d6d453
commit 9201c75013
8 changed files with 145 additions and 28 deletions

View file

@ -1818,8 +1818,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env,
&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
auth_zones_downstream_answer(worker->env.auth_zones,
&worker->env, &qinfo, &edns, repinfo, c->buffer,
worker->scratchpad)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
@ -1872,20 +1873,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* If we've found a local alias, replace the qname with the alias
* target before resolving it. */
if(qinfo.local_alias) {
struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset;
struct packed_rrset_data* d = rrset->entry.data;
/* Sanity check: our current implementation only supports
* a single CNAME RRset as a local alias. */
if(qinfo.local_alias->next ||
rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) ||
d->count != 1) {
log_err("assumption failure: unexpected local alias");
if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname,
&qinfo.qname_len)) {
regional_free_all(worker->scratchpad);
return 0; /* drop it */
}
qinfo.qname = d->rr_data[0] + 2;
qinfo.qname_len = d->rr_len[0] - 2;
}
/* If we may apply IP-based actions to the answer, build the client

View file

@ -1,3 +1,7 @@
17 June 2025: Yorgos
- Fix for consistent use of local zone CNAME alias for configured auth
zones. Now it also applies to downstream configured auth zones.
16 June 2025: Wouter
- Fix to check control-interface addresses in unbound-checkconf.
- Fix #1295: Windows 32-bit binaries download seems to be missing dll

View file

@ -630,8 +630,9 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
free(qinfo.qname);
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
if(ctx->env->auth_zones && auth_zones_downstream_answer(
ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
w->back->udp_buff, sec_status_insecure, NULL, 0);
@ -709,8 +710,9 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
w->back->udp_buff, sec_status_insecure, NULL, 0);
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
if(ctx->env->auth_zones && auth_zones_downstream_answer(
ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
@ -847,8 +849,9 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
free(qinfo.qname);
return;
}
if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
if(w->ctx->env->auth_zones && auth_zones_downstream_answer(
w->ctx->env->auth_zones, w->env, &qinfo, &edns, NULL,
w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);

View file

@ -3556,14 +3556,17 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env,
sldns_buffer_read_u16_at(buf, 2), edns);
}
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp)
struct comm_reply* repinfo, struct sldns_buffer* buf,
struct regional* temp)
{
struct dns_msg* msg = NULL;
struct auth_zone* z;
int r;
int fallback = 0;
/* Copy the qinfo in case of cname aliasing from local-zone */
struct query_info zqinfo = *qinfo;
lock_rw_rdlock(&az->lock);
if(!az->have_downstream) {
@ -3571,6 +3574,7 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env,
lock_rw_unlock(&az->lock);
return 0;
}
if(qinfo->qtype == LDNS_RR_TYPE_DS) {
uint8_t* delname = qinfo->qname;
size_t delnamelen = qinfo->qname_len;
@ -3578,8 +3582,14 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env,
z = auth_zones_find_zone(az, delname, delnamelen,
qinfo->qclass);
} else {
z = auth_zones_find_zone(az, qinfo->qname, qinfo->qname_len,
qinfo->qclass);
if(zqinfo.local_alias && !local_alias_shallow_copy_qname(
zqinfo.local_alias, &zqinfo.qname,
&zqinfo.qname_len)) {
lock_rw_unlock(&az->lock);
return 0;
}
z = auth_zones_find_zone(az, zqinfo.qname, zqinfo.qname_len,
zqinfo.qclass);
}
if(!z) {
/* no zone above it */
@ -3605,7 +3615,7 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env,
}
/* answer it from zone z */
r = auth_zone_generate_answer(z, qinfo, temp, &msg, &fallback);
r = auth_zone_generate_answer(z, &zqinfo, temp, &msg, &fallback);
lock_rw_unlock(&z->lock);
if(!r && fallback) {
/* fallback to regular answering (recursive) */

View file

@ -550,9 +550,10 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo,
* @param temp: temporary storage region.
* @return false if not answered
*/
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp);
struct comm_reply* repinfo, struct sldns_buffer* buf,
struct regional* temp);
/**
* Find the auth zone that is above the given qname.

View file

@ -57,6 +57,14 @@ server:
local-zone: synth.cname redirect
local-data: "synth.cname. IN CNAME *.from.resolution."
# CNAME is pointing to a downstream auth zone
local-zone: authdown.example.net. redirect
local-data: "authdown.example.net. IN CNAME downstream.zone."
# CNAME is pointing to an upstream auth zone
local-zone: authup.example.net. redirect
local-data: "authup.example.net. IN CNAME upstream.zone."
### template zone and tag intended to be used for tests with CNAME and
### other data.
##local-zone: ambiguous.example.com redirect
@ -67,14 +75,45 @@ server:
##@TAGDATA1@
##@TAGDATA2@
target-fetch-policy: "0 0 0 0 0"
# send the queries to the test server (see the 10.0.10.3 entries below)
forward-zone:
name: "."
forward-addr: 10.0.10.3
auth-zone:
name: "downstream.zone."
for-downstream: yes
for-upstream: no
fallback-enabled: no
## this line generates zonefile: \n"/tmp/xxx.downstream.zone"\n
zonefile:
TEMPFILE_NAME downstream.zone
## this is the inline file /tmp/xxx.downstream.zone
## the tempfiles are deleted when the testrun is over.
TEMPFILE_CONTENTS downstream.zone
$ORIGIN downstream.zone.
@ 3600 IN SOA a b 1 2 3 4 5
@ IN TXT "hello from downstream auth zone"
TEMPFILE_END
server: domain-insecure: upstream.zone.
auth-zone:
name: "upstream.zone."
for-downstream: no
for-upstream: yes
fallback-enabled: no
## this line generates zonefile: \n"/tmp/xxx.upstream.zone"\n
zonefile:
TEMPFILE_NAME upstream.zone
## this is the inline file /tmp/xxx.upstream.zone
## the tempfiles are deleted when the testrun is over.
TEMPFILE_CONTENTS upstream.zone
$ORIGIN upstream.zone.
@ 3600 IN SOA a b 1 2 3 4 5
@ IN TXT "hello from upstream auth zone"
TEMPFILE_END
CONFIG_END
; short one-line description of scenario:
@ -525,5 +564,44 @@ SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 290 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
authdown.example.net. IN TXT
ENTRY_END
STEP 300 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA DO NOERROR
SECTION QUESTION
authdown.example.net. IN TXT
SECTION ANSWER
authdown.example.net. IN CNAME downstream.zone.
downstream.zone. IN TXT "hello from downstream auth zone"
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 310 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
authup.example.net. IN TXT
ENTRY_END
STEP 320 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA DO NOERROR
SECTION QUESTION
authup.example.net. IN TXT
SECTION ANSWER
authup.example.net. IN CNAME upstream.zone.
upstream.zone. IN TXT "hello from upstream auth zone"
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END

View file

@ -1471,3 +1471,22 @@ struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
}
return NULL;
}
int local_alias_shallow_copy_qname(struct local_rrset* local_alias, uint8_t** qname,
size_t* qname_len)
{
struct ub_packed_rrset_key* rrset = local_alias->rrset;
struct packed_rrset_data* d = rrset->entry.data;
/* Sanity check: our current implementation only supports
* a single CNAME RRset as a local alias. */
if(local_alias->next ||
rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) ||
d->count != 1) {
log_err("assumption failure: unexpected local alias");
return 0;
}
*qname = d->rr_data[0] + 2;
*qname_len = d->rr_len[0] - 2;
return 1;
}

View file

@ -801,4 +801,14 @@ int edns_opt_compare(struct edns_option* p, struct edns_option* q);
*/
int edns_opt_list_compare(struct edns_option* p, struct edns_option* q);
/**
* Swallow copy the local_alias into the given qname and qname_len.
* @param local_alias: the local_alias.
* @param qname: the qname to copy to.
* @param qname_len: the qname_len to copy to.
* @return false on current local_alias assumptions, true otherwise.
*/
int local_alias_shallow_copy_qname(struct local_rrset* local_alias, uint8_t** qname,
size_t* qname_len);
#endif /* UTIL_DATA_MSGREPLY_H */