]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Fix bug#307: 0x20 fallback outstanding query count, together with rec_lame,
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 26 Apr 2010 14:59:44 +0000 (14:59 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 26 Apr 2010 14:59:44 +0000 (14:59 +0000)
and canonical rrset comparison.

git-svn-id: file:///svn/unbound/trunk@2097 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c

index 72ccc508c1c13d9008f4d32c5d9982ca40dc77f4..2ab1ae68ec031eaa9b3bf8f87a7b26e026e18240 100644 (file)
@@ -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
index 9082055c0c62a3b7b6d07e5f311be36fd9a68467..6124650890b67b4c1244f8a01d086ffcd5c713c3 100644 (file)
@@ -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; i<p->rrset_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;
+       }
+}
index 9a1db5fe9d9f597ee7e24fd09b8f22da51b7adb6..a9f4247ee1d8b3d11476dc8f698c3674d392e705 100644 (file)
@@ -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 */
index c7cdbc8763f05389821a80d03ac1e47898bd3afa..b1a948d9f62d3202e87d17389002286cbde50571 100644 (file)
@@ -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);