diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2019-02-06 12:31:02 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2019-02-06 12:31:02 +0000 |
commit | 9c9d011eed674ddd7e4a0a148691887afb9e75cd (patch) | |
tree | cd45bceeed24e66e5b2838e8589d2c111cf691c6 /edns-subnet | |
parent | 089d83fbd0b24f957b753d440f188ddadaabf4ff (diff) | |
download | src-9c9d011eed674ddd7e4a0a148691887afb9e75cd.tar.gz src-9c9d011eed674ddd7e4a0a148691887afb9e75cd.zip |
Notes
Diffstat (limited to 'edns-subnet')
-rw-r--r-- | edns-subnet/addrtree.c | 2 | ||||
-rw-r--r-- | edns-subnet/addrtree.h | 6 | ||||
-rw-r--r-- | edns-subnet/subnetmod.c | 58 | ||||
-rw-r--r-- | edns-subnet/subnetmod.h | 5 |
4 files changed, 58 insertions, 13 deletions
diff --git a/edns-subnet/addrtree.c b/edns-subnet/addrtree.c index 9a02db062c51..180a0227917c 100644 --- a/edns-subnet/addrtree.c +++ b/edns-subnet/addrtree.c @@ -119,7 +119,7 @@ node_size(const struct addrtree *tree, const struct addrnode *n) struct addrtree * addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *), - size_t (*sizefunc)(void *), void *env, unsigned int max_node_count) + size_t (*sizefunc)(void *), void *env, uint32_t max_node_count) { struct addrtree *tree; log_assert(delfunc != NULL); diff --git a/edns-subnet/addrtree.h b/edns-subnet/addrtree.h index 71d9d2ec6c9b..1aea54e01f79 100644 --- a/edns-subnet/addrtree.h +++ b/edns-subnet/addrtree.h @@ -66,10 +66,10 @@ struct addrtree { struct addrnode *root; /** Number of elements in the tree (not always equal to number of * nodes) */ - unsigned int node_count; + uint32_t node_count; /** Maximum number of allowed nodes, will be enforced by LRU list. * Excluding the root node, 0 for unlimited */ - unsigned int max_node_count; + uint32_t max_node_count; /** Size of tree in bytes */ size_t size_bytes; /** Maximum prefix length we are willing to cache. */ @@ -137,7 +137,7 @@ size_t addrtree_size(const struct addrtree *tree); */ struct addrtree * addrtree_create(addrlen_t max_depth, void (*delfunc)(void *, void *), - size_t (*sizefunc)(void *), void *env, unsigned int max_node_count); + size_t (*sizefunc)(void *), void *env, uint32_t max_node_count); /** * Free tree and all nodes below. diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c index 1a5044e427cc..69e743ddc364 100644 --- a/edns-subnet/subnetmod.c +++ b/edns-subnet/subnetmod.c @@ -55,8 +55,7 @@ #include "util/config_file.h" #include "util/data/msgreply.h" #include "sldns/sbuffer.h" - -#define ECS_MAX_TREESIZE 100 +#include "iterator/iter_utils.h" /** externally called */ void @@ -93,6 +92,7 @@ subnet_new_qstate(struct module_qstate *qstate, int id) return 0; qstate->minfo[id] = sq; memset(sq, 0, sizeof(*sq)); + sq->started_no_cache_store = qstate->no_cache_store; return 1; } @@ -150,7 +150,9 @@ int ecs_whitelist_check(struct query_info* qinfo, /* Cache by default, might be disabled after parsing EDNS option * received from nameserver. */ - qstate->no_cache_store = 0; + if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo)) { + qstate->no_cache_store = 0; + } if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream && qstate->env->cfg->client_subnet_always_forward) || @@ -177,6 +179,14 @@ int ecs_whitelist_check(struct query_info* qinfo, } +void +subnet_markdel(void* key) +{ + struct msgreply_entry *e = (struct msgreply_entry*)key; + e->key.qtype = 0; + e->key.qclass = 0; +} + int subnetmod_init(struct module_env *env, int id) { @@ -193,6 +203,7 @@ 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("subnet: could not create cache"); free(sn_env); @@ -291,13 +302,13 @@ get_tree(struct subnet_msg_cache_data *data, struct ecs_data *edns, if (!data->tree4) data->tree4 = addrtree_create( cfg->max_client_subnet_ipv4, &delfunc, - &sizefunc, env, ECS_MAX_TREESIZE); + &sizefunc, env, cfg->max_ecs_tree_size_ipv4); tree = data->tree4; } else { if (!data->tree6) data->tree6 = addrtree_create( cfg->max_client_subnet_ipv6, &delfunc, - &sizefunc, env, ECS_MAX_TREESIZE); + &sizefunc, env, cfg->max_ecs_tree_size_ipv6); tree = data->tree6; } return tree; @@ -487,9 +498,11 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) * is still usefull to put it in the edns subnet cache for * when a client explicitly asks for subnet specific answer. */ verbose(VERB_QUERY, "subnet: Authority indicates no support"); - lock_rw_wrlock(&sne->biglock); - update_cache(qstate, id); - lock_rw_unlock(&sne->biglock); + if(!sq->started_no_cache_store) { + lock_rw_wrlock(&sne->biglock); + update_cache(qstate, id); + lock_rw_unlock(&sne->biglock); + } if (sq->subnet_downstream) cp_edns_bad_response(c_out, c_in); return module_finished; @@ -515,7 +528,9 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) } lock_rw_wrlock(&sne->biglock); - update_cache(qstate, id); + if(!sq->started_no_cache_store) { + update_cache(qstate, id); + } sne->num_msg_nocache++; lock_rw_unlock(&sne->biglock); @@ -526,6 +541,19 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) 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; + /* 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 > + qstate->env->cfg->max_client_subnet_ipv4) { + c_out->subnet_scope_mask = + qstate->env->cfg->max_client_subnet_ipv4; + } + } + else if(c_out->subnet_scope_mask > + qstate->env->cfg->max_client_subnet_ipv6) { + c_out->subnet_scope_mask = + qstate->env->cfg->max_client_subnet_ipv6; + } c_out->subnet_validdata = 1; } return module_finished; @@ -697,6 +725,17 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, return; } + /* Limit to minimum allowed source mask */ + if(sq->ecs_client_in.subnet_source_mask != 0 && ( + (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 && + sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv4) || + (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6 && + sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv6))) { + qstate->return_rcode = LDNS_RCODE_REFUSED; + qstate->ext_state[id] = module_finished; + return; + } + lock_rw_wrlock(&sne->biglock); if (lookup_and_reply(qstate, id, sq)) { sne->num_msg_cache++; @@ -753,6 +792,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, ecs_opt_list_append(&sq->ecs_client_out, &qstate->edns_opts_front_out, qstate); } + qstate->no_cache_store = sq->started_no_cache_store; return; } if(sq && outbound) { diff --git a/edns-subnet/subnetmod.h b/edns-subnet/subnetmod.h index f417a64a45b0..e408627b0abd 100644 --- a/edns-subnet/subnetmod.h +++ b/edns-subnet/subnetmod.h @@ -83,6 +83,8 @@ struct subnet_qstate { struct ecs_data ecs_server_out; int subnet_downstream; int subnet_sent; + /** has the subnet module been started with no_cache_store? */ + int started_no_cache_store; }; void subnet_data_delete(void* d, void* ATTR_UNUSED(arg)); @@ -131,4 +133,7 @@ int ecs_edns_back_parsed(struct module_qstate* qstate, int id, void* cbargs); int ecs_query_response(struct module_qstate* qstate, struct dns_msg* response, int id, void* cbargs); +/** mark subnet msg to be deleted */ +void subnet_markdel(void* key); + #endif /* SUBNETMOD_H */ |