summaryrefslogtreecommitdiff
path: root/iterator/iterator.c
diff options
context:
space:
mode:
Diffstat (limited to 'iterator/iterator.c')
-rw-r--r--iterator/iterator.c71
1 files changed, 61 insertions, 10 deletions
diff --git a/iterator/iterator.c b/iterator/iterator.c
index df5f645cc28c8..6e05c99a0e954 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -120,6 +120,7 @@ iter_new(struct module_qstate* qstate, int id)
iq->query_restart_count = 0;
iq->referral_count = 0;
iq->sent_count = 0;
+ iq->target_count = NULL;
iq->wait_priming_stub = 0;
iq->refetch_glue = 0;
iq->dnssec_expected = 0;
@@ -257,7 +258,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
verbose(VERB_ALGO, "error response for prefetch in cache");
/* attempt to adjust the cache entry prefetch */
if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo,
- NORR_TTL))
+ NORR_TTL, qstate->query_flags))
return error_response(qstate, id, rcode);
/* if that fails (not in cache), fall through to store err */
}
@@ -270,7 +271,8 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
/* do not waste time trying to validate this servfail */
err.security = sec_status_indeterminate;
verbose(VERB_ALGO, "store error response in message cache");
- iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL);
+ iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL,
+ qstate->query_flags);
return error_response(qstate, id, rcode);
}
@@ -453,6 +455,26 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
return 1;
}
+/** create target count structure for this query */
+static void
+target_count_create(struct iter_qstate* iq)
+{
+ if(!iq->target_count) {
+ iq->target_count = (int*)calloc(2, sizeof(int));
+ /* if calloc fails we simply do not track this number */
+ if(iq->target_count)
+ iq->target_count[0] = 1;
+ }
+}
+
+static void
+target_count_increase(struct iter_qstate* iq, int num)
+{
+ target_count_create(iq);
+ if(iq->target_count)
+ iq->target_count[1] += num;
+}
+
/**
* Generate a subrequest.
* Generate a local request event. Local events are tied to this module, and
@@ -486,6 +508,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qflags = 0; /* OPCODE QUERY, no flags */
struct query_info qinf;
int prime = (finalstate == PRIME_RESP_STATE)?1:0;
+ int valrec = 0;
qinf.qname = qname;
qinf.qname_len = qnamelen;
qinf.qtype = qtype;
@@ -499,12 +522,15 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
* the resolution chain, which might have a validator. We are
* uninterested in validating things not on the direct resolution
* path. */
- if(!v)
+ if(!v) {
qflags |= BIT_CD;
+ valrec = 1;
+ }
/* attach subquery, lookup existing or make a new one */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
- if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, &subq)) {
+ if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
+ &subq)) {
return 0;
}
*subq_ret = subq;
@@ -524,6 +550,10 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
subiq = (struct iter_qstate*)subq->minfo[id];
memset(subiq, 0, sizeof(*subiq));
subiq->num_target_queries = 0;
+ target_count_create(iq);
+ subiq->target_count = iq->target_count;
+ if(iq->target_count)
+ iq->target_count[0] ++; /* extra reference */
subiq->num_current_queries = 0;
subiq->depth = iq->depth+1;
outbound_list_init(&subiq->outlist);
@@ -938,7 +968,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
} else {
msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
iq->qchase.qname_len, iq->qchase.qtype,
- iq->qchase.qclass, qstate->region, qstate->env->scratch);
+ iq->qchase.qclass, qstate->query_flags,
+ qstate->region, qstate->env->scratch);
if(!msg && qstate->env->neg_cache) {
/* lookup in negative cache; may result in
* NOERROR/NODATA or NXDOMAIN answers that need validation */
@@ -1350,6 +1381,12 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
if(iq->depth == ie->max_dependency_depth)
return 0;
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return 0;
+ }
iter_mark_cycle_targets(qstate, iq->dp);
missing = (int)delegpt_count_missing_targets(iq->dp);
@@ -1532,6 +1569,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
if(qs != 0) {
qstate->ext_state[id] = module_wait_subquery;
return 0; /* and wait for them */
@@ -1541,6 +1579,12 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
/* mark cycle targets for parent-side lookups */
iter_mark_pside_cycle_targets(qstate, iq->dp);
/* see if we can issue queries to get nameserver addresses */
@@ -1570,6 +1614,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
if(query_count != 0) { /* suspend to await results */
verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count;
+ target_count_increase(iq, query_count);
qstate->ext_state[id] = module_wait_subquery;
return 0;
}
@@ -1725,6 +1770,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -1765,6 +1811,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
}
/* Add the current set of unused targets to our queue. */
@@ -1810,6 +1857,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return 1;
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
}
/* Since a target query might have been made, we
* need to check again. */
@@ -1991,7 +2039,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
- qstate->region);
+ qstate->region, qstate->query_flags);
/* close down outstanding requests to be discarded */
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
@@ -2029,7 +2077,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* Store the referral under the current query */
/* no prefetch-leeway, since its not the answer */
iter_dns_store(qstate->env, &iq->response->qinfo,
- iq->response->rep, 1, 0, 0, NULL);
+ iq->response->rep, 1, 0, 0, NULL, 0);
if(iq->store_parent_NS)
iter_store_parentside_NS(qstate->env,
iq->response->rep);
@@ -2128,7 +2176,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* prefetchleeway applied because this updates answer parts */
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1, qstate->prefetch_leeway,
- iq->dp&&iq->dp->has_parent_side_NS, NULL);
+ iq->dp&&iq->dp->has_parent_side_NS, NULL,
+ qstate->query_flags);
/* set the current request's qname to the new value. */
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
@@ -2209,7 +2258,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
}
/**
- * Return priming query results to interestes super querystates.
+ * Return priming query results to interested super querystates.
*
* Sets the delegation point and delegation message (not nonRD queries).
* This is a callback from walk_supers.
@@ -2640,7 +2689,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
iter_dns_store(qstate->env, &qstate->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
- qstate->region);
+ qstate->region, qstate->query_flags);
}
}
qstate->return_rcode = LDNS_RCODE_NOERROR;
@@ -2921,6 +2970,8 @@ iter_clear(struct module_qstate* qstate, int id)
iq = (struct iter_qstate*)qstate->minfo[id];
if(iq) {
outbound_list_clear(&iq->outlist);
+ if(iq->target_count && --iq->target_count[0] == 0)
+ free(iq->target_count);
iq->num_current_queries = 0;
}
qstate->minfo[id] = NULL;