]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Perform canonical sort for 0x20 capsforid compare of replies,
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 4 Feb 2019 15:22:08 +0000 (15:22 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 4 Feb 2019 15:22:08 +0000 (15:22 +0000)
  this sorts rrsets in the authority and additional section before
  comparison, so that out of order rrsets do not cause failure.

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

doc/Changelog
iterator/iter_utils.c

index b746e9979d0c649ca1ba1a0816d88aa510f2bebc..3e43447fe10165748a5c85c775465559f8192e6d 100644 (file)
@@ -4,6 +4,9 @@
          It logs the original query name, not the target of the CNAME.
        - Add local-zone type inform_redirect, which logs like type inform,
          and redirects like type redirect.
+       - Perform canonical sort for 0x20 capsforid compare of replies,
+         this sorts rrsets in the authority and additional section before
+         comparison, so that out of order rrsets do not cause failure.
 
 31 January 2019: Wouter
        - Set ub_ctx_set_tls call signature in ltrace config file for
index 4ac8efd0d17ac0f40431670d80727cb74e232784..6eacaf2ce75d5f2a933d96bf46c97b1b05303418 100644 (file)
@@ -882,10 +882,35 @@ rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
        return 1;
 }
 
+/** compare rrsets and sort canonically.  Compares rrset name, type, class.
+ * return 0 if equal, +1 if x > y, and -1 if x < y.
+ */
+static int
+rrset_canonical_sort_cmp(const void* x, const void* y)
+{
+       struct ub_packed_rrset_key* rrx = (struct ub_packed_rrset_key*)x;
+       struct ub_packed_rrset_key* rry = (struct ub_packed_rrset_key*)y;
+       int r = dname_canonical_compare(rrx->rk.dname, rry->rk.dname);
+       if(r != 0)
+               return r;
+       if(rrx->rk.type != rry->rk.type) {
+               if(ntohs(rrx->rk.type) > ntohs(rry->rk.type))
+                       return 1;
+               else    return -1;
+       }
+       if(rrx->rk.rrset_class != rry->rk.rrset_class) {
+               if(ntohs(rrx->rk.rrset_class) > ntohs(rry->rk.rrset_class))
+                       return 1;
+               else    return -1;
+       }
+       return 0;
+}
+
 int 
 reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
 {
        size_t i;
+       struct ub_packed_rrset_key** sorted_p, **sorted_q;
        if(p->flags != q->flags ||
                p->qdcount != q->qdcount ||
                /* do not check TTL, this may differ */
@@ -899,16 +924,40 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
                p->ar_numrrsets != q->ar_numrrsets ||
                p->rrset_count != q->rrset_count)
                return 0;
+       /* sort the rrsets in the authority and additional sections before
+        * compare, the query and answer sections are ordered in the sequence
+        * they should have (eg. one after the other for aliases). */
+       sorted_p = (struct ub_packed_rrset_key**)regional_alloc_init(
+               region, p->rrsets, sizeof(*sorted_p)*p->rrset_count);
+       if(!sorted_p) return 0;
+       log_assert(p->an_numrrsets + p->ns_numrrsets + p->ar_numrrsets <=
+               p->rrset_count);
+       qsort(sorted_p + p->an_numrrsets, p->ns_numrrsets,
+               sizeof(*sorted_p), rrset_canonical_sort_cmp);
+       qsort(sorted_p + p->an_numrrsets + p->ns_numrrsets, p->ar_numrrsets,
+               sizeof(*sorted_p), rrset_canonical_sort_cmp);
+
+       sorted_q = (struct ub_packed_rrset_key**)regional_alloc_init(
+               region, q->rrsets, sizeof(*sorted_q)*q->rrset_count);
+       if(!sorted_q) return 0;
+       log_assert(q->an_numrrsets + q->ns_numrrsets + q->ar_numrrsets <=
+               q->rrset_count);
+       qsort(sorted_q + q->an_numrrsets, q->ns_numrrsets,
+               sizeof(*sorted_q), rrset_canonical_sort_cmp);
+       qsort(sorted_q + q->an_numrrsets + q->ns_numrrsets, q->ar_numrrsets,
+               sizeof(*sorted_q), rrset_canonical_sort_cmp);
+
+       /* compare the rrsets */
        for(i=0; i<p->rrset_count; i++) {
-               if(!rrset_equal(p->rrsets[i], q->rrsets[i])) {
-                       if(!rrset_canonical_equal(region, p->rrsets[i],
-                               q->rrsets[i])) {
+               if(!rrset_equal(sorted_p[i], sorted_q[i])) {
+                       if(!rrset_canonical_equal(region, sorted_p[i],
+                               sorted_q[i])) {
                                regional_free_all(region);
                                return 0;
                        }
-                       regional_free_all(region);
                }
        }
+       regional_free_all(region);
        return 1;
 }