From: Wouter Wijngaards Date: Mon, 26 Apr 2010 14:59:44 +0000 (+0000) Subject: Fix bug#307: 0x20 fallback outstanding query count, together with rec_lame, X-Git-Tag: release-1.4.5rc1~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a754ae461ad366692a6f8330e030f8850edfd92;p=thirdparty%2Funbound.git Fix bug#307: 0x20 fallback outstanding query count, together with rec_lame, and canonical rrset comparison. git-svn-id: file:///svn/unbound/trunk@2097 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 72ccc508c..2ab1ae68e 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -7,6 +7,11 @@ no more double include. - More strict scrubber (Thanks to George Barwood for the idea): NS set must be pertinent to the query (qname subdomain nsname). + - Fix bug#307: In 0x20 backoff fix fallback so the number of + outstanding queries does not become -1 and block the request. + Fixed handling of recursion-lame in combination with 0x20 fallback. + Fix so RRsets are compared canonicalized and sorted if the immediate + comparison fails, this makes it work around round-robin sites. 23 April 2010: Wouter - Squelch log message: sendto failed permission denied for diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 9082055c0..612465089 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -674,7 +674,7 @@ rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) } int -reply_equal(struct reply_info* p, struct reply_info* q) +reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* scratch) { size_t i; if(p->flags != q->flags || @@ -688,8 +688,29 @@ reply_equal(struct reply_info* p, struct reply_info* q) p->rrset_count != q->rrset_count) return 0; for(i=0; irrset_count; i++) { - if(!rrset_equal(p->rrsets[i], q->rrsets[i])) - return 0; + if(!rrset_equal(p->rrsets[i], q->rrsets[i])) { + /* fallback procedure: try to sort and canonicalize */ + ldns_rr_list* pl, *ql; + pl = packed_rrset_to_rr_list(p->rrsets[i], scratch); + ql = packed_rrset_to_rr_list(q->rrsets[i], scratch); + if(!pl || !ql) { + ldns_rr_list_deep_free(pl); + ldns_rr_list_deep_free(ql); + return 0; + } + ldns_rr_list2canonical(pl); + ldns_rr_list2canonical(ql); + ldns_rr_list_sort(pl); + ldns_rr_list_sort(ql); + if(ldns_rr_list_compare(pl, ql) != 0) { + ldns_rr_list_deep_free(pl); + ldns_rr_list_deep_free(ql); + return 0; + } + ldns_rr_list_deep_free(pl); + ldns_rr_list_deep_free(ql); + continue; + } } return 1; } @@ -792,3 +813,18 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z) i++; } } + +void iter_dec_attempts(struct delegpt* dp, int d) +{ + struct delegpt_addr* a; + for(a=dp->target_list; a; a = a->next_target) { + if(a->attempts >= OUTBOUND_MSG_RETRY) { + /* add back to result list */ + a->next_result = dp->result_list; + dp->result_list = a; + } + if(a->attempts > d) + a->attempts -= d; + else a->attempts = 0; + } +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 9a1db5fe9..a9f4247ee 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -211,9 +211,10 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, * @param p: reply one. The reply has rrset data pointers in region. * Does not check rrset-IDs * @param q: reply two + * @param buf: scratch buffer. * @return if one and two are equal. */ -int reply_equal(struct reply_info* p, struct reply_info* q); +int reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* buf); /** * Store in-zone glue in seperate rrset cache entries for later last-resort @@ -257,4 +258,11 @@ int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd, void iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z); +/** + * Remove query attempts from all available ips. For 0x20. + * @param dp: delegpt. + * @param d: decrease. + */ +void iter_dec_attempts(struct delegpt* dp, int d); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index c7cdbc876..b1a948d9f 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1416,6 +1416,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "match for %d wanted, done.", (int)iq->caps_server+1, (int)naddr*3); iq->caps_fallback = 0; + iter_dec_attempts(iq->dp, 3); /* space for fallback */ + iq->num_current_queries++; /* RespState decrements it*/ + iq->referral_count++; /* make sure we don't loop */ iq->state = QUERY_RESP_STATE; return 1; } @@ -2384,7 +2387,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, goto handle_it; } else { /* check if reply is the same, otherwise, fail */ - if(!reply_equal(iq->response->rep, iq->caps_reply)) { + if(!reply_equal(iq->response->rep, iq->caps_reply, + qstate->env->scratch_buffer)) { verbose(VERB_DETAIL, "Capsforid fallback: " "getting different replies, failed"); outbound_list_remove(&iq->outlist, outbound);