aboutsummaryrefslogtreecommitdiff
path: root/edns-subnet
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2019-02-06 12:31:02 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2019-02-06 12:31:02 +0000
commit9c9d011eed674ddd7e4a0a148691887afb9e75cd (patch)
treecd45bceeed24e66e5b2838e8589d2c111cf691c6 /edns-subnet
parent089d83fbd0b24f957b753d440f188ddadaabf4ff (diff)
downloadsrc-9c9d011eed674ddd7e4a0a148691887afb9e75cd.tar.gz
src-9c9d011eed674ddd7e4a0a148691887afb9e75cd.zip
Notes
Diffstat (limited to 'edns-subnet')
-rw-r--r--edns-subnet/addrtree.c2
-rw-r--r--edns-subnet/addrtree.h6
-rw-r--r--edns-subnet/subnetmod.c58
-rw-r--r--edns-subnet/subnetmod.h5
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 */