diff options
Diffstat (limited to 'contrib/unbound/edns-subnet/subnetmod.c')
-rw-r--r-- | contrib/unbound/edns-subnet/subnetmod.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/contrib/unbound/edns-subnet/subnetmod.c b/contrib/unbound/edns-subnet/subnetmod.c index c5e215b8b684..88310a785d7a 100644 --- a/contrib/unbound/edns-subnet/subnetmod.c +++ b/contrib/unbound/edns-subnet/subnetmod.c @@ -154,6 +154,21 @@ int ecs_whitelist_check(struct query_info* qinfo, return 1; sn_env = (struct subnet_env*)qstate->env->modinfo[id]; + if(sq->is_subquery_nonsubnet) { + if(sq->is_subquery_scopezero) { + /* Check if the result can be stored in the global cache, + * this is okay if the address and name are not configured + * as subnet address and subnet zone. */ + if(!ecs_is_whitelisted(sn_env->whitelist, + addr, addrlen, qinfo->qname, qinfo->qname_len, + qinfo->qclass)) { + verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment."); + qstate->no_cache_store = 0; + } + } + return 1; + } + /* Cache by default, might be disabled after parsing EDNS option * received from nameserver. */ if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0) @@ -234,13 +249,13 @@ subnetmod_init(struct module_env *env, int id) HASH_DEFAULT_STARTARRAY, env->cfg->msg_cache_size, msg_cache_sizefunc, query_info_compare, query_entry_delete, subnet_data_delete, NULL); - slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel); if(!sn_env->subnet_msg_cache) { log_err("subnetcache: could not create cache"); free(sn_env); env->modinfo[id] = NULL; return 0; } + slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel); /* whitelist for edns subnet capable servers */ sn_env->whitelist = ecs_whitelist_create(); if(!sn_env->whitelist || @@ -527,11 +542,12 @@ common_prefix(uint8_t *a, uint8_t *b, uint8_t net) /** * Create sub request that looks up the query. * @param qstate: query state + * @param id: module id. * @param sq: subnet qstate * @return false on failure. */ static int -generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq) +generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate* sq) { struct module_qstate* subq = NULL; uint16_t qflags = 0; /* OPCODE QUERY, no flags */ @@ -557,10 +573,22 @@ generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq) } if(subq) { /* It is possible to access the subquery module state. */ + struct subnet_qstate* subsq; + if(!subnet_new_qstate(subq, id)) { + verbose(VERB_ALGO, "Could not allocate new subnet qstate"); + return 0; + } + subsq = (struct subnet_qstate*)subq->minfo[id]; + subsq->is_subquery_nonsubnet = 1; + + /* When the client asks 0.0.0.0/0 and the name is not treated + * as subnet, it is to be stored in the global cache. + * Store that the client asked for that, if so. */ if(sq->ecs_client_in.subnet_source_mask == 0 && edns_opt_list_find(qstate->edns_opts_front_in, qstate->env->cfg->client_subnet_opcode)) { subq->no_cache_store = 1; + subsq->is_subquery_scopezero = 1; } } return 1; @@ -569,17 +597,18 @@ generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq) /** * Perform the query without subnet * @param qstate: query state + * @param id: module id. * @param sq: subnet qstate * @return module state */ static enum module_ext_state -generate_lookup_without_subnet(struct module_qstate *qstate, +generate_lookup_without_subnet(struct module_qstate *qstate, int id, struct subnet_qstate* sq) { verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet"); - if(!generate_sub_request(qstate, sq)) { + if(!generate_sub_request(qstate, id, sq)) { verbose(VERB_ALGO, "Could not generate sub query"); - qstate->return_rcode = LDNS_RCODE_FORMERR; + qstate->return_rcode = LDNS_RCODE_SERVFAIL; qstate->return_msg = NULL; return module_finished; } @@ -622,7 +651,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) * is still useful to put it in the edns subnet cache for * when a client explicitly asks for subnet specific answer. */ verbose(VERB_QUERY, "subnetcache: Authority indicates no support"); - return generate_lookup_without_subnet(qstate, sq); + return generate_lookup_without_subnet(qstate, id, sq); } /* Purposefully there was no sent subnet, and there is consequently @@ -654,7 +683,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) qstate->env->cfg->client_subnet_opcode); sq->subnet_sent = 0; sq->subnet_sent_no_subnet = 0; - return generate_lookup_without_subnet(qstate, sq); + return generate_lookup_without_subnet(qstate, id, sq); } lock_rw_wrlock(&sne->biglock); @@ -945,7 +974,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, /* aggregated this deaggregated state */ qstate->ext_state[id] = generate_lookup_without_subnet( - qstate, sq); + qstate, id, sq); return; } verbose(VERB_ALGO, "subnetcache: pass to next module"); @@ -993,7 +1022,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, qstate->env->cfg->client_subnet_opcode)) { /* client asked for resolution without edns subnet */ qstate->ext_state[id] = generate_lookup_without_subnet( - qstate, sq); + qstate, id, sq); return; } |