From: Yorgos Thessalonikefs Date: Tue, 17 Jun 2025 13:03:29 +0000 (+0200) Subject: - Fix for consistent use of local zone CNAME alias for configured auth X-Git-Tag: release-1.24.0rc1~77 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9201c750135efdd22acf464a51bcb11610710eb9;p=thirdparty%2Funbound.git - Fix for consistent use of local zone CNAME alias for configured auth zones. Now it also applies to downstream configured auth zones. --- diff --git a/daemon/worker.c b/daemon/worker.c index ead20938e..1cc094c36 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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 diff --git a/doc/Changelog b/doc/Changelog index a966c08ed..2c1dcf710 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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 diff --git a/libunbound/libworker.c b/libunbound/libworker.c index f0496452b..6e7244c03 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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); diff --git a/services/authzone.c b/services/authzone.c index 40530d3a5..591a76cd9 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -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) */ diff --git a/services/authzone.h b/services/authzone.h index 722781a06..b11e7f144 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -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. diff --git a/testdata/local_cname.rpl b/testdata/local_cname.rpl index 69a8b098b..2e7edeaef 100644 --- a/testdata/local_cname.rpl +++ b/testdata/local_cname.rpl @@ -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 diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 090490d7a..6b65e1eb1 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -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; +} diff --git a/util/data/msgreply.h b/util/data/msgreply.h index 9c701f07d..b65abd922 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -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 */