diff --git a/doc/Changelog b/doc/Changelog index f1b38fbc0..26394c237 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -4,6 +4,11 @@ - iana portlist updated. - fix EDNS1480 change memleak and TCP fallback. - fix various compiler warnings (reported by Paul Wouters). + - max sent count. EDNS1480 only for rtt < 5000. No promiscuous + fetch if sentcount > 3, stop query if sentcount > 16. Count is + reset when referral or CNAME happens. This makes unbound better + at managing large NS sets, they are explored when there is continued + interest (in the form of queries). 15 September 2011: Wouter - release 1.4.13. diff --git a/iterator/iterator.c b/iterator/iterator.c index 71682b234..cf35d0f32 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -117,6 +117,7 @@ iter_new(struct module_qstate* qstate, int id) iq->num_current_queries = 0; iq->query_restart_count = 0; iq->referral_count = 0; + iq->sent_count = 0; iq->wait_priming_stub = 0; iq->refetch_glue = 0; iq->dnssec_expected = 0; @@ -1537,8 +1538,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, log_query_info(VERB_QUERY, "processQueryTargets:", &qstate->qinfo); verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, " - "currentqueries %d", iq->num_target_queries, - iq->num_current_queries); + "currentqueries %d sentcount %d", iq->num_target_queries, + iq->num_current_queries, iq->sent_count); /* Make sure that we haven't run away */ /* FIXME: is this check even necessary? */ @@ -1547,6 +1548,11 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "number of referrrals with %d", iq->referral_count); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } + if(iq->sent_count > MAX_SENT_COUNT) { + verbose(VERB_QUERY, "request has exceeded the maximum " + "number of sends with %d", iq->sent_count); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } /* Make sure we have a delegation point, otherwise priming failed * or another failure occurred */ @@ -1573,7 +1579,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* < not <=, because although the array is large enough for <=, the * generated query will immediately be discarded due to depth and * that servfail is cached, which is not good as opportunism goes. */ - if(iq->depth < ie->max_dependency_depth) { + if(iq->depth < ie->max_dependency_depth + && iq->sent_count < TARGET_FETCH_STOP) { tf_policy = ie->target_fetch_policy[iq->depth]; } @@ -1596,7 +1603,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* the current caps_server is the number of fallbacks sent. * the original query is one that matched too, so we have * caps_server+1 number of matching queries now */ - if(iq->caps_server+1 >= naddr*3) { + if(iq->caps_server+1 >= naddr*3 || + iq->caps_server+1 >= MAX_SENT_COUNT) { /* we're done, process the response */ verbose(VERB_ALGO, "0x20 fallback had %d responses " "match for %d wanted, done.", @@ -1720,6 +1728,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, } outbound_list_insert(&iq->outlist, outq); iq->num_current_queries++; + iq->sent_count++; qstate->ext_state[id] = module_wait_reply; return 0; @@ -1896,6 +1905,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, delegpt_log(VERB_ALGO, iq->dp); /* Count this as a referral. */ iq->referral_count++; + iq->sent_count = 0; /* see if the next dp is a trust anchor, or a DS was sent * along, indicating dnssec is expected for next zone */ iq->dnssec_expected = iter_indicates_dnssec(qstate->env, @@ -1953,6 +1963,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->dp = NULL; /* Note the query restart. */ iq->query_restart_count++; + iq->sent_count = 0; /* stop current outstanding queries. * FIXME: should the outstanding queries be waited for and diff --git a/iterator/iterator.h b/iterator/iterator.h index 9137b404b..0272fe103 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -56,6 +56,10 @@ struct iter_priv; #define MAX_RESTART_COUNT 8 /** max number of referrals. Makes sure resolver does not run away */ #define MAX_REFERRAL_COUNT 130 +/** max number of queries-sent-out. Make sure large NS set does not loop */ +#define MAX_SENT_COUNT 16 +/** at what query-sent-count to stop target fetch policy */ +#define TARGET_FETCH_STOP 3 /** how nice is a server without further information, in msec * Equals rtt initial timeout value. */ @@ -252,6 +256,9 @@ struct iter_qstate { /** the number of times this query as followed a referral. */ int referral_count; + /** number of queries fired off */ + int sent_count; + /** * The query must store NS records from referrals as parentside RRs * Enabled once it hits resolution problems, to throttle retries. diff --git a/services/outside_network.c b/services/outside_network.c index 6c9664c9f..297e454ea 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1585,7 +1585,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, * by EDNS. */ sq->status = serviced_query_UDP_EDNS; } - if(sq->status == serviced_query_UDP_EDNS) { + if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000) { /* fallback to 1480/1280 */ sq->status = serviced_query_UDP_EDNS_FRAG; log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10,