From: Ralph Dolmans Date: Fri, 15 May 2020 11:13:49 +0000 (+0200) Subject: - Cache ECS answers with longest scope of CNAME chain. X-Git-Tag: 1.11.0rc1~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99fd6cf7118389128c8016d211f1f432abcab523;p=thirdparty%2Funbound.git - Cache ECS answers with longest scope of CNAME chain. --- diff --git a/doc/Changelog b/doc/Changelog index 0b2a86aa9..4e0c07c42 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c index 37dc550cd..f1b401b90 100644 --- a/edns-subnet/subnetmod.c +++ b/edns-subnet/subnetmod.c @@ -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; diff --git a/edns-subnet/subnetmod.h b/edns-subnet/subnetmod.h index e408627b0..27ba2ee74 100644 --- a/edns-subnet/subnetmod.h +++ b/edns-subnet/subnetmod.h @@ -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; };