diff options
author | Riccardo Spagni <ric@spagni.net> | 2015-05-31 16:36:48 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2015-05-31 16:36:48 +0200 |
commit | 6a1190792b0409e7a996400614e5e2c6ba02e5f6 (patch) | |
tree | fa324d2f9f02668a6d56d2e4d195a59ab1d3710e /external/unbound/iterator | |
parent | fixed static assert test (diff) | |
download | monero-6a1190792b0409e7a996400614e5e2c6ba02e5f6.tar.xz |
update libunbound
Diffstat (limited to 'external/unbound/iterator')
-rw-r--r-- | external/unbound/iterator/iter_utils.c | 45 | ||||
-rw-r--r-- | external/unbound/iterator/iterator.c | 77 | ||||
-rw-r--r-- | external/unbound/iterator/iterator.h | 7 |
3 files changed, 127 insertions, 2 deletions
diff --git a/external/unbound/iterator/iter_utils.c b/external/unbound/iterator/iter_utils.c index 5ec5752bf..bc94ef682 100644 --- a/external/unbound/iterator/iter_utils.c +++ b/external/unbound/iterator/iter_utils.c @@ -65,6 +65,7 @@ #include "validator/val_utils.h" #include "validator/val_sigcrypt.h" #include "sldns/sbuffer.h" +#include "sldns/str2wire.h" /** time when nameserver glue is said to be 'recent' */ #define SUSPICION_RECENT_EXPIRY 86400 @@ -105,6 +106,40 @@ read_fetch_policy(struct iter_env* ie, const char* str) return 1; } +/** apply config caps whitelist items to name tree */ +static int +caps_white_apply_cfg(rbtree_t* ntree, struct config_file* cfg) +{ + struct config_strlist* p; + for(p=cfg->caps_whitelist; p; p=p->next) { + struct name_tree_node* n; + size_t len; + uint8_t* nm = sldns_str2wire_dname(p->str, &len); + if(!nm) { + log_err("could not parse %s", p->str); + return 0; + } + n = (struct name_tree_node*)calloc(1, sizeof(*n)); + if(!n) { + log_err("out of memory"); + free(nm); + return 0; + } + n->node.key = n; + n->name = nm; + n->len = len; + n->labs = dname_count_labels(nm); + n->dclass = LDNS_RR_CLASS_IN; + if(!name_tree_insert(ntree, n, nm, len, n->labs, n->dclass)) { + /* duplicate element ignored, idempotent */ + free(n->name); + free(n); + } + } + name_tree_init_parents(ntree); + return 1; +} + int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) { @@ -128,6 +163,16 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) log_err("Could not set private addresses"); return 0; } + if(cfg->caps_whitelist) { + if(!iter_env->caps_white) + iter_env->caps_white = rbtree_create(name_tree_compare); + if(!iter_env->caps_white || !caps_white_apply_cfg( + iter_env->caps_white, cfg)) { + log_err("Could not set capsforid whitelist"); + return 0; + } + + } iter_env->supports_ipv6 = cfg->do_ip6; iter_env->supports_ipv4 = cfg->do_ip4; return 1; diff --git a/external/unbound/iterator/iterator.c b/external/unbound/iterator/iterator.c index 02de86e12..96918fa97 100644 --- a/external/unbound/iterator/iterator.c +++ b/external/unbound/iterator/iterator.c @@ -61,6 +61,7 @@ #include "util/data/msgencode.h" #include "util/fptr_wlist.h" #include "util/config_file.h" +#include "util/random.h" #include "sldns/rrdef.h" #include "sldns/wire2str.h" #include "sldns/parseutil.h" @@ -83,6 +84,16 @@ iter_init(struct module_env* env, int id) return 1; } +/** delete caps_whitelist element */ +static void +caps_free(struct rbnode_t* n, void* ATTR_UNUSED(d)) +{ + if(n) { + free(((struct name_tree_node*)n)->name); + free(n); + } +} + void iter_deinit(struct module_env* env, int id) { @@ -93,6 +104,10 @@ iter_deinit(struct module_env* env, int id) free(iter_env->target_fetch_policy); priv_delete(iter_env->priv); donotq_delete(iter_env->donotq); + if(iter_env->caps_white) { + traverse_postorder(iter_env->caps_white, caps_free, NULL); + free(iter_env->caps_white); + } free(iter_env); env->modinfo[id] = NULL; } @@ -120,6 +135,7 @@ iter_new(struct module_qstate* qstate, int id) iq->query_restart_count = 0; iq->referral_count = 0; iq->sent_count = 0; + iq->ratelimit_ok = 0; iq->target_count = NULL; iq->wait_priming_stub = 0; iq->refetch_glue = 0; @@ -457,6 +473,16 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq, return 1; } +/** see if target name is caps-for-id whitelisted */ +static int +is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq) +{ + if(!ie->caps_white) return 0; /* no whitelist, or no capsforid */ + return name_tree_lookup(ie->caps_white, iq->qchase.qname, + iq->qchase.qname_len, dname_count_labels(iq->qchase.qname), + iq->qchase.qclass) != NULL; +} + /** create target count structure for this query */ static void target_count_create(struct iter_qstate* iq) @@ -1125,6 +1151,32 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, * results of priming. */ return 0; } + if(!iq->ratelimit_ok && qstate->prefetch_leeway) + iq->ratelimit_ok = 1; /* allow prefetches, this keeps + otherwise valid data in the cache */ + if(!iq->ratelimit_ok && infra_ratelimit_exceeded( + qstate->env->infra_cache, iq->dp->name, + iq->dp->namelen, *qstate->env->now)) { + /* and increment the rate, so that the rate for time + * now will also exceed the rate, keeping cache fresh */ + (void)infra_ratelimit_inc(qstate->env->infra_cache, + iq->dp->name, iq->dp->namelen, + *qstate->env->now); + /* see if we are passed through with slip factor */ + if(qstate->env->cfg->ratelimit_factor != 0 && + ub_random_max(qstate->env->rnd, + qstate->env->cfg->ratelimit_factor) == 1) { + iq->ratelimit_ok = 1; + log_nametypeclass(VERB_ALGO, "ratelimit allowed through for " + "delegation point", iq->dp->name, + LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); + } else { + log_nametypeclass(VERB_ALGO, "ratelimit exceeded with " + "delegation point", iq->dp->name, + LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + } /* see if this dp not useless. * It is useless if: @@ -1914,6 +1966,15 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, return 0; } + /* if not forwarding, check ratelimits per delegationpoint name */ + if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) { + if(!infra_ratelimit_inc(qstate->env->infra_cache, iq->dp->name, + iq->dp->namelen, *qstate->env->now)) { + verbose(VERB_ALGO, "query exceeded ratelimits"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + } + /* We have a valid target. */ if(verbosity >= VERB_QUERY) { log_query_info(VERB_QUERY, "sending query:", &iq->qchase); @@ -1928,11 +1989,15 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->qchase.qname, iq->qchase.qname_len, iq->qchase.qtype, iq->qchase.qclass, iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD, - iq->dnssec_expected, iq->caps_fallback, &target->addr, - target->addrlen, iq->dp->name, iq->dp->namelen, qstate); + iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( + ie, iq), &target->addr, target->addrlen, iq->dp->name, + iq->dp->namelen, qstate); if(!outq) { log_addr(VERB_DETAIL, "error sending query to auth server", &target->addr, target->addrlen); + if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) + infra_ratelimit_dec(qstate->env->infra_cache, iq->dp->name, + iq->dp->namelen, *qstate->env->now); return next_state(iq, QUERYTARGETS_STATE); } outbound_list_insert(&iq->outlist, outq); @@ -2083,6 +2148,14 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, * delegation point, and back to the QUERYTARGETS_STATE. */ verbose(VERB_DETAIL, "query response was REFERRAL"); + if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) { + /* we have a referral, no ratelimit, we can send + * our queries to the given name */ + infra_ratelimit_dec(qstate->env->infra_cache, + iq->dp->name, iq->dp->namelen, + *qstate->env->now); + } + /* if hardened, only store referral if we asked for it */ if(!qstate->env->cfg->harden_referral_path || ( qstate->qinfo.qtype == LDNS_RR_TYPE_NS diff --git a/external/unbound/iterator/iterator.h b/external/unbound/iterator/iterator.h index cb8043fd5..aaf0fb383 100644 --- a/external/unbound/iterator/iterator.h +++ b/external/unbound/iterator/iterator.h @@ -51,6 +51,7 @@ struct iter_forwards; struct iter_donotq; struct iter_prep_list; struct iter_priv; +struct rbtree_t; /** max number of targets spawned for a query and its subqueries */ #define MAX_TARGET_COUNT 32 @@ -96,6 +97,9 @@ struct iter_env { /** private address space and private domains */ struct iter_priv* priv; + /** whitelist for capsforid names */ + struct rbtree_t* caps_white; + /** The maximum dependency depth that this resolver will pursue. */ int max_dependency_depth; @@ -259,6 +263,9 @@ struct iter_qstate { * subqueries, the malloced-array is shared, [0] refcount. */ int* target_count; + /** if true, already tested for ratelimiting and passed the test */ + int ratelimit_ok; + /** * The query must store NS records from referrals as parentside RRs * Enabled once it hits resolution problems, to throttle retries. |