diff options
Diffstat (limited to 'iterator/iterator.c')
-rw-r--r-- | iterator/iterator.c | 71 |
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; |