]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix for consistent use of local zone CNAME alias for configured auth
authorYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 17 Jun 2025 13:03:29 +0000 (15:03 +0200)
committerYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 17 Jun 2025 13:03:29 +0000 (15:03 +0200)
  zones. Now it also applies to downstream configured auth zones.

daemon/worker.c
doc/Changelog
libunbound/libworker.c
services/authzone.c
services/authzone.h
testdata/local_cname.rpl
util/data/msgreply.c
util/data/msgreply.h

index ead20938e17251b4d9d7d76775d05694ebd72454..1cc094c36b44da07c25cd43fc88f4ad81ed49ab1 100644 (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
index a966c08ed4a251ac9c5960cfe1d54719b3f3fb40..2c1dcf710a0f19f2074f636574492d8310e177c8 100644 (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
index f0496452b521a6f7ad02b01c97657c1ef1d4d8b7..6e7244c03fee5ea2f8b6aa39c1e1ab141bf686bd 100644 (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);
index 40530d3a5426920c45afd49ff7fad81cc93e29f4..591a76cd98d996857a35e192ce3a816a5eeae075 100644 (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) */
index 722781a063a8c9bd7da4fad711a5163b6ab3ad84..b11e7f1449e0038cfbbf8f3354d16ad62dcda7d1 100644 (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.
index 69a8b098bdf717f40f339434da97ff7f9439a50e..2e7edeaefe083ca7fc0ecff8726e96c29ffdaf9d 100644 (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
index 090490d7a44aa6323d3961ae5d6c3e1636c25155..6b65e1eb18829809f88cc6000bdce367542152d1 100644 (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;
+}
index 9c701f07d0c4bdf9919c2fc3ac1625311db0a1ef..b65abd922b05478a2374a407ae7667e17c4cea6e 100644 (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 */