]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Cache ECS answers with longest scope of CNAME chain.
authorRalph Dolmans <ralph@nlnetlabs.nl>
Fri, 15 May 2020 11:13:49 +0000 (13:13 +0200)
committerRalph Dolmans <ralph@nlnetlabs.nl>
Fri, 15 May 2020 11:13:49 +0000 (13:13 +0200)
doc/Changelog
edns-subnet/subnetmod.c
edns-subnet/subnetmod.h

index 0b2a86aa9e5a2aa44309194d5ca58fcf8e560341..4e0c07c4203a3527ee1774fa2533b3d51bf1ed10 100644 (file)
@@ -1,3 +1,6 @@
+15 May 2020: Ralph
+       - Cache ECS answers with longest scope of CNAME chain.
+
 22 April 2020: George
        - Explicitly use 'rrset-roundrobin: no' for test cases.
 
index 37dc550cd69c36d768c4b95baf206ebd0cebf0a5..f1b401b9080ce508b33e0c9ec6f99aee6917dc42 100644 (file)
@@ -386,8 +386,7 @@ update_cache(struct module_qstate *qstate, int id)
        rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
        rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache   */
        addrtree_insert(tree, (addrkey_t*)edns->subnet_addr, 
-               edns->subnet_source_mask, 
-               sq->ecs_server_in.subnet_scope_mask, rep,
+               edns->subnet_source_mask, sq->max_scope, rep,
                rep->ttl, *qstate->env->now);
 
        lock_rw_unlock(&lru_entry->lock);
@@ -543,7 +542,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
                c_out->subnet_addr_fam = c_in->subnet_addr_fam;
                c_out->subnet_source_mask = c_in->subnet_source_mask;
                memcpy(&c_out->subnet_addr, &c_in->subnet_addr, INET6_SIZE);
-               c_out->subnet_scope_mask = s_in->subnet_scope_mask;
+               c_out->subnet_scope_mask = sq->max_scope;
                /* Limit scope returned to client to scope used for caching. */
                if(c_out->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) {
                        if(c_out->subnet_scope_mask >
@@ -648,6 +647,19 @@ ecs_query_response(struct module_qstate* qstate, struct dns_msg* response,
                        qstate->env->cfg->client_subnet_opcode);
                sq->subnet_sent = 0;
                memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out));
+       } else if (!sq->track_max_scope &&
+               FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR &&
+               response->rep->an_numrrsets > 0
+               ) {
+               struct ub_packed_rrset_key* s = response->rep->rrsets[0];
+               if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
+                       query_dname_compare(qstate->qinfo.qname,
+                       s->rk.dname) == 0) {
+                       /* CNAME response for QNAME. From now on keep track of
+                        * longest received ECS prefix for all queries on this
+                        * qstate. */
+                       sq->track_max_scope = 1;
+               }
        }
        return 1;
 }
@@ -663,16 +675,19 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
                return 1;
        if((ecs_opt = edns_opt_list_find(
                qstate->edns_opts_back_in,
-               qstate->env->cfg->client_subnet_opcode))) {
-               if(parse_subnet_option(ecs_opt, &sq->ecs_server_in) &&
-                       sq->subnet_sent &&
-                       sq->ecs_server_in.subnet_validdata)
+               qstate->env->cfg->client_subnet_opcode)) &&
+               parse_subnet_option(ecs_opt, &sq->ecs_server_in) &&
+               sq->subnet_sent && sq->ecs_server_in.subnet_validdata) {
                        /* Only skip global cache store if we sent an ECS option
                         * and received one back. Answers from non-whitelisted
                         * servers will end up in global cache. Answers for
                         * queries with 0 source will not (unless nameserver
                         * does not support ECS). */
                        qstate->no_cache_store = 1;
+                       if(!sq->track_max_scope || (sq->track_max_scope &&
+                               sq->ecs_server_in.subnet_scope_mask >
+                               sq->max_scope))
+                               sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
        }
 
        return 1;
index e408627b0abdf25f0799519c68306b104dcf288f..27ba2ee7412989b6c10557c24bfa0ec054179711 100644 (file)
@@ -45,6 +45,7 @@
 #include "util/alloc.h"
 #include "util/net_help.h"
 #include "util/storage/slabhash.h"
+#include "util/data/dname.h"
 #include "edns-subnet/addrtree.h"
 #include "edns-subnet/edns-subnet.h"
 
@@ -83,6 +84,12 @@ struct subnet_qstate {
        struct ecs_data ecs_server_out;
        int subnet_downstream;
        int subnet_sent;
+       /** keep track of longest received scope, set after receiving CNAME for
+        * incoming QNAME. */
+       int track_max_scope;
+       /** longest received scope mask since track_max_scope is set. This value
+        * is used for caching and answereing to client. */
+       uint8_t max_scope;
        /** has the subnet module been started with no_cache_store? */
        int started_no_cache_store;
 };