]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4718. [func] Avoid seaching for a owner name compression pointer
authorMark Andrews <marka@isc.org>
Tue, 12 Sep 2017 23:24:34 +0000 (09:24 +1000)
committerMark Andrews <marka@isc.org>
Tue, 12 Sep 2017 23:24:34 +0000 (09:24 +1000)
                        more than once when writing out a RRset. [RT #45802]

CHANGES
lib/dns/include/dns/name.h
lib/dns/name.c
lib/dns/rdataset.c

diff --git a/CHANGES b/CHANGES
index 02b0a655622b7f2dd10e13646023d430d70e7407..5fd606305ca206d1ec6324fc67cb67f8ac34453f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4718.  [func]          Avoid seaching for a owner name compression pointer
+                       more than once when writing out a RRset. [RT #45802]
+
 4717.  [bug]           Treat replies with QCOUNT=0 as truncated if TC=1,
                        FORMERR if TC=0, and log the error correctly.
                        [RT #45836]
index 5b12fb697881e1f78029e72c0afd4b8b587f9b3f..9bb859aeaacbbc4f47eb6fe395743b8f3031697b 100644 (file)
@@ -739,6 +739,9 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
 isc_result_t
 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
                isc_buffer_t *target);
+isc_result_t
+dns_name_towire2(const dns_name_t *name, dns_compress_t *cctx,
+                isc_buffer_t *target, isc_uint16_t *comp_offsetp);
 /*%<
  * Convert 'name' into wire format, compressing it as specified by the
  * compression context 'cctx', and storing the result in 'target'.
index f56263840a9d59a5dd5c9ccb86322fcce3a3b8b5..0b8c6ddf519ac77f073b2d5f22e5473b54f8a134 100644 (file)
@@ -1987,6 +1987,13 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
 isc_result_t
 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
                isc_buffer_t *target)
+{
+       return (dns_name_towire2(name, cctx, target, NULL));
+}
+
+isc_result_t
+dns_name_towire2(const dns_name_t *name, dns_compress_t *cctx,
+                isc_buffer_t *target, isc_uint16_t *comp_offsetp)
 {
        unsigned int methods;
        isc_uint16_t offset;
@@ -2005,6 +2012,23 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
        REQUIRE(cctx != NULL);
        REQUIRE(ISC_BUFFER_VALID(target));
 
+       /*
+        * If this exact name was already rendered before, and the
+        * offset of the previously rendered name is passed to us, write
+        * a compression pointer directly.
+        */
+       methods = dns_compress_getmethods(cctx);
+       if (comp_offsetp != NULL && *comp_offsetp < 0x4000 &&
+           (name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
+           (methods & DNS_COMPRESS_GLOBAL14) != 0) {
+               if (ISC_UNLIKELY(target->length - target->used < 2))
+                       return (ISC_R_NOSPACE);
+               offset = *comp_offsetp;
+               offset |= 0xc000;
+               isc_buffer_putuint16(target, offset);
+               return (ISC_R_SUCCESS);
+       }
+
        /*
         * If 'name' doesn't have an offsets table, make a clone which
         * has one.
@@ -2022,8 +2046,6 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
 
        offset = target->used;  /*XXX*/
 
-       methods = dns_compress_getmethods(cctx);
-
        if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
            (methods & DNS_COMPRESS_GLOBAL14) != 0)
                gf = dns_compress_findglobal(cctx, name, &gp, &go);
@@ -2034,7 +2056,7 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
         * If the offset is too high for 14 bit global compression, we're
         * out of luck.
         */
-       if (gf && go >= 0x4000)
+       if (gf && ISC_UNLIKELY(go >= 0x4000))
                gf = ISC_FALSE;
 
        /*
@@ -2044,25 +2066,32 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
                gf = ISC_FALSE;
 
        if (gf) {
-               if (target->length - target->used < gp.length)
+               if (ISC_UNLIKELY(target->length - target->used < gp.length))
                        return (ISC_R_NOSPACE);
                (void)memmove((unsigned char *)target->base + target->used,
                              gp.ndata, (size_t)gp.length);
                isc_buffer_add(target, gp.length);
-               go |= 0xc000;
-               if (target->length - target->used < 2)
+               if (ISC_UNLIKELY(target->length - target->used < 2))
                        return (ISC_R_NOSPACE);
-               isc_buffer_putuint16(target, go);
-               if (gp.length != 0)
+               isc_buffer_putuint16(target, go | 0xc000);
+               if (gp.length != 0) {
                        dns_compress_add(cctx, name, &gp, offset);
+                       if (comp_offsetp != NULL)
+                               *comp_offsetp = offset;
+               } else if (comp_offsetp != NULL) {
+                       *comp_offsetp = go;
+               }
        } else {
-               if (target->length - target->used < name->length)
+               if (ISC_UNLIKELY(target->length - target->used < name->length))
                        return (ISC_R_NOSPACE);
                (void)memmove((unsigned char *)target->base + target->used,
                              name->ndata, (size_t)name->length);
                isc_buffer_add(target, name->length);
                dns_compress_add(cctx, name, name, offset);
+               if (comp_offsetp != NULL)
+                       *comp_offsetp = offset;
        }
+
        return (ISC_R_SUCCESS);
 }
 
index 6355832e6138b875d85c87732b1632039251c7a1..b20eadf4e6db6e4dfe30d70327ddbf8c986bbe9b 100644 (file)
@@ -324,6 +324,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
        struct towire_sort *out = out_fixed;
        dns_fixedname_t fixed;
        dns_name_t *name;
+       isc_uint16_t offset;
 
        UNUSED(state);
 
@@ -464,6 +465,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
        name = dns_fixedname_name(&fixed);
        dns_name_copy(owner_name, name, NULL);
        dns_rdataset_getownercase(rdataset, name);
+       offset = 0xffff;
 
        name->attributes |= owner_name->attributes &
                DNS_NAMEATTR_NOCOMPRESS;
@@ -475,7 +477,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
 
                rrbuffer = *target;
                dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
-               result = dns_name_towire(name, cctx, target);
+               result = dns_name_towire2(name, cctx, target, &offset);
                if (result != ISC_R_SUCCESS)
                        goto rollback;
                headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);