aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/iterator
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2015-05-31 16:36:48 +0200
committerRiccardo Spagni <ric@spagni.net>2015-05-31 16:36:48 +0200
commit6a1190792b0409e7a996400614e5e2c6ba02e5f6 (patch)
treefa324d2f9f02668a6d56d2e4d195a59ab1d3710e /external/unbound/iterator
parentfixed static assert test (diff)
downloadmonero-6a1190792b0409e7a996400614e5e2c6ba02e5f6.tar.xz
update libunbound
Diffstat (limited to 'external/unbound/iterator')
-rw-r--r--external/unbound/iterator/iter_utils.c45
-rw-r--r--external/unbound/iterator/iterator.c77
-rw-r--r--external/unbound/iterator/iterator.h7
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.