]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Use hashtable when parsing a message
authorOndřej Surý <ondrej@isc.org>
Mon, 11 Sep 2023 08:35:28 +0000 (10:35 +0200)
committerMichał Kępień <michal@isc.org>
Fri, 5 Jan 2024 10:52:05 +0000 (11:52 +0100)
When parsing messages use a hashtable instead of a linear search to
reduce the amount of work done in findname when there's more than one
name in the section.

There are two hashtables:

1) hashtable for owner names - that's constructed for each section when
we hit the second name in the section and destroyed right after parsing
that section;

2) per-name hashtable - for each name in the section, we construct a new
hashtable for that name if there are more than one rdataset for that
particular name.

(cherry picked from commit b8a96317544c7b310b4f74360825a87b6402ddc2)

lib/dns/include/dns/message.h
lib/dns/include/dns/name.h
lib/dns/message.c
lib/dns/name.c

index fafa86a252fc0d4c7992a976091fd0367c24d6e4..ea4574243985f333151fff29095b5ea766430ada 100644 (file)
@@ -801,44 +801,6 @@ dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type,
  *\li  #ISC_R_NOTFOUND         -- the desired type does not exist.
  */
 
-isc_result_t
-dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
-                dns_rdatatype_t type, dns_rdatatype_t covers,
-                dns_rdataset_t **rdataset);
-/*%<
- * Search the name for the specified rdclass and type.  If it is found,
- * *rdataset is filled in with a pointer to that rdataset.
- *
- * Requires:
- *\li  if '**rdataset' is non-NULL, *rdataset needs to be NULL.
- *
- *\li  'type' be a valid type, and NOT dns_rdatatype_any.
- *
- *\li  If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
- *     Otherwise it should be 0.
- *
- * Returns:
- *\li  #ISC_R_SUCCESS          -- all is well.
- *\li  #ISC_R_NOTFOUND         -- the desired type does not exist.
- */
-
-void
-dns_message_movename(dns_message_t *msg, dns_name_t *name,
-                    dns_section_t fromsection, dns_section_t tosection);
-/*%<
- * Move a name from one section to another.
- *
- * Requires:
- *
- *\li  'msg' be valid.
- *
- *\li  'name' must be a name already in 'fromsection'.
- *
- *\li  'fromsection' must be a valid section.
- *
- *\li  'tosection' must be a valid section.
- */
-
 void
 dns_message_addname(dns_message_t *msg, dns_name_t *name,
                    dns_section_t section);
index 683f71d79fe43cc1a39fe73334811b7d7c2af19c..2e1c5f882bf00d02bdf0950f4b4632bc985fb70d 100644 (file)
@@ -69,6 +69,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 
+#include <isc/ht.h>
 #include <isc/lang.h>
 #include <isc/magic.h>
 #include <isc/region.h> /* Required for storage size of dns_label_t. */
@@ -112,6 +113,7 @@ struct dns_name {
        isc_buffer_t  *buffer;
        ISC_LINK(dns_name_t) link;
        ISC_LIST(dns_rdataset_t) list;
+       isc_ht_t *ht;
 };
 
 #define DNS_NAME_MAGIC ISC_MAGIC('D', 'N', 'S', 'n')
@@ -167,30 +169,24 @@ LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_wildcardname;
  *     unsigned char offsets[] = { 0, 6 };
  *     dns_name_t value = DNS_NAME_INITABSOLUTE(data, offsets);
  */
-#define DNS_NAME_INITNONABSOLUTE(A, B)                         \
-       {                                                      \
-               DNS_NAME_MAGIC, A, (sizeof(A) - 1), sizeof(B), \
-                       DNS_NAMEATTR_READONLY, B, NULL,        \
-                       { (void *)-1, (void *)-1 }, {          \
-                       NULL, NULL                             \
-               }                                              \
+#define DNS_NAME_INITNONABSOLUTE(A, B)                                   \
+       {                                                                \
+               DNS_NAME_MAGIC, A, (sizeof(A) - 1), sizeof(B),           \
+                       DNS_NAMEATTR_READONLY, B, NULL,                  \
+                       { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \
        }
 
-#define DNS_NAME_INITABSOLUTE(A, B)                                       \
-       {                                                                 \
-               DNS_NAME_MAGIC, A, sizeof(A), sizeof(B),                  \
-                       DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, B, \
-                       NULL, { (void *)-1, (void *)-1 }, {               \
-                       NULL, NULL                                        \
-               }                                                         \
+#define DNS_NAME_INITABSOLUTE(A, B)                                            \
+       {                                                                      \
+               DNS_NAME_MAGIC, A, sizeof(A), sizeof(B),                       \
+                       DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, B,      \
+                       NULL, { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \
        }
 
-#define DNS_NAME_INITEMPTY                                 \
-       {                                                  \
-               DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \
-                       { (void *)-1, (void *)-1 }, {      \
-                       NULL, NULL                         \
-               }                                          \
+#define DNS_NAME_INITEMPTY                                               \
+       {                                                                \
+               DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL,               \
+                       { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \
        }
 
 /*%
@@ -1357,6 +1353,7 @@ ISC_LANG_ENDDECLS
                _n->buffer = NULL;                \
                ISC_LINK_INIT(_n, link);          \
                ISC_LIST_INIT(_n->list);          \
+               _n->ht = NULL;                    \
        } while (0)
 
 #define DNS_NAME_RESET(n)                                  \
index 7f34cd7bf812faedcc8bffa114a7ae6df2d78c2e..2f0075d5b37e51c6c0e8fa15160f6552f58c0e2c 100644 (file)
@@ -22,6 +22,8 @@
 #include <stdbool.h>
 
 #include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/ht.h>
 #include <isc/mem.h>
 #include <isc/print.h>
 #include <isc/string.h> /* Required for HP/UX (and others?) */
@@ -507,9 +509,11 @@ msgresetsigs(dns_message_t *msg, bool replying) {
                } else {
                        dns_rdataset_disassociate(msg->tsig);
                        isc_mempool_put(msg->rdspool, msg->tsig);
+                       msg->tsig = NULL;
                        if (msg->querytsig != NULL) {
                                dns_rdataset_disassociate(msg->querytsig);
                                isc_mempool_put(msg->rdspool, msg->querytsig);
+                               msg->querytsig = NULL;
                        }
                }
                dns_message_puttempname(msg, &msg->tsigname);
@@ -798,6 +802,22 @@ dns_message_detach(dns_message_t **messagep) {
        }
 }
 
+static isc_result_t
+name_hash_add(isc_ht_t *ht, dns_name_t *name, dns_name_t **foundp) {
+       dns_fixedname_t fixed;
+       dns_name_t *key = dns_fixedname_initname(&fixed);
+       dns_name_downcase(name, key, NULL);
+
+       isc_result_t result = isc_ht_find(ht, key->ndata, key->length,
+                                         (void **)foundp);
+       if (result == ISC_R_SUCCESS) {
+               return (ISC_R_EXISTS);
+       }
+       result = isc_ht_add(ht, key->ndata, key->length, (void *)name);
+       INSIST(result == ISC_R_SUCCESS);
+       return (ISC_R_SUCCESS);
+}
+
 static isc_result_t
 findname(dns_name_t **foundname, const dns_name_t *target,
         dns_namelist_t *section) {
@@ -817,29 +837,26 @@ findname(dns_name_t **foundname, const dns_name_t *target,
        return (ISC_R_NOTFOUND);
 }
 
-isc_result_t
-dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
-                dns_rdatatype_t type, dns_rdatatype_t covers,
-                dns_rdataset_t **rdataset) {
-       dns_rdataset_t *curr;
-
-       REQUIRE(name != NULL);
-       REQUIRE(rdataset == NULL || *rdataset == NULL);
-
-       for (curr = ISC_LIST_TAIL(name->list); curr != NULL;
-            curr = ISC_LIST_PREV(curr, link))
-       {
-               if (curr->rdclass == rdclass && curr->type == type &&
-                   curr->covers == covers)
-               {
-                       if (rdataset != NULL) {
-                               *rdataset = curr;
-                       }
-                       return (ISC_R_SUCCESS);
-               }
-       }
+typedef struct __attribute__((__packed__)) rds_key {
+       dns_rdataclass_t rdclass;
+       dns_rdatatype_t type;
+       dns_rdatatype_t covers;
+} rds_key_t;
 
-       return (ISC_R_NOTFOUND);
+static isc_result_t
+rds_hash_add(isc_ht_t *ht, dns_rdataset_t *rds, dns_rdataset_t **foundp) {
+       rds_key_t key = { .rdclass = rds->rdclass,
+                         .type = rds->type,
+                         .covers = rds->covers };
+       isc_result_t result = isc_ht_find(ht, (const unsigned char *)&key,
+                                         sizeof(key), (void **)foundp);
+       if (result == ISC_R_SUCCESS) {
+               return (ISC_R_EXISTS);
+       }
+       result = isc_ht_add(ht, (const unsigned char *)&key, sizeof(key),
+                           (void *)rds);
+       INSIST(result == ISC_R_SUCCESS);
+       return (ISC_R_SUCCESS);
 }
 
 isc_result_t
@@ -966,6 +983,18 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                }                            \
        } while (0)
 
+static void
+cleanup_name_hashmaps(dns_namelist_t *section) {
+       dns_name_t *name = NULL;
+       for (name = ISC_LIST_HEAD(*section); name != NULL;
+            name = ISC_LIST_NEXT(name, link))
+       {
+               if (name->ht != NULL) {
+                       isc_ht_destroy(&name->ht);
+               }
+       }
+}
+
 static isc_result_t
 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
             unsigned int options) {
@@ -975,13 +1004,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
        dns_name_t *name2 = NULL;
        dns_rdataset_t *rdataset = NULL;
        dns_rdatalist_t *rdatalist = NULL;
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        dns_rdatatype_t rdtype;
        dns_rdataclass_t rdclass;
        dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
        bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
        bool seen_problem = false;
        bool free_name = false;
+       bool free_ht = false;
+       isc_ht_t *name_map = NULL;
+
+       if (msg->counts[DNS_SECTION_QUESTION] > 1) {
+               isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
+       }
 
        for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
                name = NULL;
@@ -1002,13 +1037,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        goto cleanup;
                }
 
+               /* If there is only one QNAME, skip the duplicity checks */
+               if (name_map == NULL) {
+                       result = ISC_R_SUCCESS;
+                       goto skip_name_check;
+               }
+
                /*
                 * Run through the section, looking to see if this name
                 * is already there.  If it is found, put back the allocated
                 * name since we no longer need it, and set our name pointer
                 * to point to the name we found.
                 */
-               result = findname(&name2, name, section);
+               result = name_hash_add(name_map, name, &name2);
 
                /*
                 * If it is the first name in the section, accept it.
@@ -1020,19 +1061,25 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                 * this should be legal or not.  In either case we no longer
                 * need this name pointer.
                 */
-               if (result != ISC_R_SUCCESS) {
+       skip_name_check:
+               switch (result) {
+               case ISC_R_SUCCESS:
                        if (!ISC_LIST_EMPTY(*section)) {
                                DO_ERROR(DNS_R_FORMERR);
                        }
                        ISC_LIST_APPEND(*section, name, link);
-                       free_name = false;
-               } else {
+                       break;
+               case ISC_R_EXISTS:
                        dns_message_puttempname(msg, &name);
                        name = name2;
                        name2 = NULL;
-                       free_name = false;
+                       break;
+               default:
+                       UNREACHABLE();
                }
 
+               free_name = false;
+
                /*
                 * Get type and class.
                 */
@@ -1062,14 +1109,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        msg->tkey = 1;
                }
 
-               /*
-                * Can't ask the same question twice.
-                */
-               result = dns_message_find(name, rdclass, rdtype, 0, NULL);
-               if (result == ISC_R_SUCCESS) {
-                       DO_ERROR(DNS_R_FORMERR);
-               }
-
                /*
                 * Allocate a new rdatalist.
                 */
@@ -1083,6 +1122,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        result = ISC_R_NOMEMORY;
                        goto cleanup;
                }
+               dns_rdataset_init(rdataset);
 
                /*
                 * Convert rdatalist to rdataset, and attach the latter to
@@ -1091,7 +1131,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                rdatalist->type = rdtype;
                rdatalist->rdclass = rdclass;
 
-               dns_rdataset_init(rdataset);
                result = dns_rdatalist_tordataset(rdatalist, rdataset);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup;
@@ -1099,14 +1138,45 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 
                rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
 
+               /*
+                * Skip the duplicity check for first rdataset
+                */
+               if (ISC_LIST_EMPTY(name->list)) {
+                       result = ISC_R_SUCCESS;
+                       goto skip_rds_check;
+               }
+
+               /*
+                * Can't ask the same question twice.
+                */
+               if (name->ht == NULL) {
+                       isc_ht_init(&name->ht, msg->mctx, 1);
+                       free_ht = true;
+
+                       INSIST(ISC_LIST_HEAD(name->list) ==
+                              ISC_LIST_TAIL(name->list));
+
+                       dns_rdataset_t *old_rdataset =
+                               ISC_LIST_HEAD(name->list);
+
+                       result = rds_hash_add(name->ht, old_rdataset, NULL);
+
+                       INSIST(result == ISC_R_SUCCESS);
+               }
+               result = rds_hash_add(name->ht, rdataset, NULL);
+               if (result == ISC_R_EXISTS) {
+                       DO_ERROR(DNS_R_FORMERR);
+               }
+
+       skip_rds_check:
                ISC_LIST_APPEND(name->list, rdataset, link);
+
                rdataset = NULL;
        }
 
        if (seen_problem) {
-               return (DNS_R_RECOVERABLE);
+               result = DNS_R_RECOVERABLE;
        }
-       return (ISC_R_SUCCESS);
 
 cleanup:
        if (rdataset != NULL) {
@@ -1117,6 +1187,14 @@ cleanup:
                dns_message_puttempname(msg, &name);
        }
 
+       if (free_ht) {
+               cleanup_name_hashmaps(section);
+       }
+
+       if (name_map != NULL) {
+               isc_ht_destroy(&name_map);
+       }
+
        return (result);
 }
 
@@ -1196,17 +1274,24 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
        dns_name_t *name = NULL;
        dns_name_t *name2 = NULL;
        dns_rdataset_t *rdataset = NULL;
+       dns_rdataset_t *found_rdataset = NULL;
        dns_rdatalist_t *rdatalist = NULL;
-       isc_result_t result;
+       isc_result_t result = ISC_R_SUCCESS;
        dns_rdatatype_t rdtype, covers;
        dns_rdataclass_t rdclass;
        dns_rdata_t *rdata = NULL;
        dns_ttl_t ttl;
        dns_namelist_t *section = &msg->sections[sectionid];
-       bool free_name = false, free_rdataset = false, seen_problem = false;
+       bool free_name = false, seen_problem = false;
+       bool free_ht = false;
        bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
        bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
        bool isedns, issigzero, istsig;
+       isc_ht_t *name_map = NULL;
+
+       if (msg->counts[sectionid] > 1) {
+               isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
+       }
 
        for (count = 0; count < msg->counts[sectionid]; count++) {
                int recstart = source->current;
@@ -1214,7 +1299,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 
                skip_name_search = false;
                skip_type_search = false;
-               free_rdataset = false;
                isedns = false;
                issigzero = false;
                istsig = false;
@@ -1257,8 +1341,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                if (msg->rdclass_set == 0 &&
                    rdtype != dns_rdatatype_opt &&  /* class is UDP SIZE */
                    rdtype != dns_rdatatype_tsig && /* class is ANY */
-                   rdtype != dns_rdatatype_tkey)
-               { /* class is undefined */
+                   rdtype != dns_rdatatype_tkey)   /* class is undefined */
+               {
                        msg->rdclass = rdclass;
                        msg->rdclass_set = 1;
                }
@@ -1456,61 +1540,132 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                                free_name = false;
                        }
                } else {
+                       if (name_map == NULL) {
+                               result = ISC_R_SUCCESS;
+                               goto skip_name_check;
+                       }
+
                        /*
                         * Run through the section, looking to see if this name
                         * is already there.  If it is found, put back the
                         * allocated name since we no longer need it, and set
                         * our name pointer to point to the name we found.
                         */
-                       result = findname(&name2, name, section);
+                       result = name_hash_add(name_map, name, &name2);
 
                        /*
                         * If it is a new name, append to the section.
                         */
-                       if (result == ISC_R_SUCCESS) {
+               skip_name_check:
+                       switch (result) {
+                       case ISC_R_SUCCESS:
+                               ISC_LIST_APPEND(*section, name, link);
+                               break;
+                       case ISC_R_EXISTS:
                                dns_message_puttempname(msg, &name);
                                name = name2;
-                       } else {
-                               ISC_LIST_APPEND(*section, name, link);
+                               name2 = NULL;
+                               break;
+                       default:
+                               UNREACHABLE();
                        }
                        free_name = false;
                }
 
+               rdatalist = newrdatalist(msg);
+               if (rdatalist == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto cleanup;
+               }
+               dns_message_gettemprdataset(msg, &rdataset);
+               if (rdataset == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto cleanup;
+               }
+
+               rdatalist->type = rdtype;
+               rdatalist->covers = covers;
+               rdatalist->rdclass = rdclass;
+               rdatalist->ttl = ttl;
+
+               RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
+                             ISC_R_SUCCESS);
+               dns_rdataset_setownercase(rdataset, name);
+               rdatalist = NULL;
+
                /*
                 * Search name for the particular type and class.
                 * Skip this stage if in update mode or this is a meta-type.
                 */
-               if (preserve_order || msg->opcode == dns_opcode_update ||
-                   skip_type_search)
+               if (isedns || istsig || issigzero) {
+                       /* Skip adding the rdataset to the tables */
+               } else if (preserve_order || msg->opcode == dns_opcode_update ||
+                          skip_type_search)
                {
-                       result = ISC_R_NOTFOUND;
+                       result = ISC_R_SUCCESS;
+
+                       ISC_LIST_APPEND(name->list, rdataset, link);
                } else {
                        /*
                         * If this is a type that can only occur in
                         * the question section, fail.
                         */
                        if (dns_rdatatype_questiononly(rdtype)) {
+                               dns_message_puttemprdataset(msg, &rdataset);
                                DO_ERROR(DNS_R_FORMERR);
                        }
 
-                       rdataset = NULL;
-                       result = dns_message_find(name, rdclass, rdtype, covers,
-                                                 &rdataset);
-               }
+                       if (ISC_LIST_EMPTY(name->list)) {
+                               result = ISC_R_SUCCESS;
+                               goto skip_rds_check;
+                       }
+
+                       if (name->ht == NULL) {
+                               isc_ht_init(&name->ht, msg->mctx, 1);
+                               free_ht = true;
+
+                               INSIST(ISC_LIST_HEAD(name->list) ==
+                                      ISC_LIST_TAIL(name->list));
+
+                               dns_rdataset_t *old_rdataset =
+                                       ISC_LIST_HEAD(name->list);
+
+                               result = rds_hash_add(name->ht, old_rdataset,
+                                                     NULL);
+
+                               INSIST(result == ISC_R_SUCCESS);
+                       }
+                       found_rdataset = NULL;
+                       result = rds_hash_add(name->ht, rdataset,
+                                             &found_rdataset);
+
+                       /*
+                        * If we found an rdataset that matches, we need to
+                        * append this rdata to that set.  If we did not, we
+                        * need to create a new rdatalist, store the important
+                        * bits there, convert it to an rdataset, and link the
+                        * latter to the name. Yuck.  When appending, make
+                        * certain that the type isn't a singleton type, such as
+                        * SOA or CNAME.
+                        *
+                        * Note that this check will be bypassed when preserving
+                        * order, the opcode is an update, or the type search is
+                        * skipped.
+                        */
+               skip_rds_check:
+                       switch (result) {
+                       case ISC_R_EXISTS:
+                               /* Free the rdataset we used as the key */
+                               dns_rdataset_disassociate(rdataset);
+                               isc_mempool_put(msg->rdspool, rdataset);
+                               rdataset = found_rdataset;
+
+                               result = ISC_R_SUCCESS;
+
+                               if (!dns_rdatatype_issingleton(rdtype)) {
+                                       break;
+                               }
 
-               /*
-                * If we found an rdataset that matches, we need to
-                * append this rdata to that set.  If we did not, we need
-                * to create a new rdatalist, store the important bits there,
-                * convert it to an rdataset, and link the latter to the name.
-                * Yuck.  When appending, make certain that the type isn't
-                * a singleton type, such as SOA or CNAME.
-                *
-                * Note that this check will be bypassed when preserving order,
-                * the opcode is an update, or the type search is skipped.
-                */
-               if (result == ISC_R_SUCCESS) {
-                       if (dns_rdatatype_issingleton(rdtype)) {
                                dns_rdata_t *first;
                                dns_rdatalist_fromrdataset(rdataset,
                                                           &rdatalist);
@@ -1519,37 +1674,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                                if (dns_rdata_compare(rdata, first) != 0) {
                                        DO_ERROR(DNS_R_FORMERR);
                                }
-                       }
-               }
-
-               if (result == ISC_R_NOTFOUND) {
-                       rdataset = isc_mempool_get(msg->rdspool);
-                       if (rdataset == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto cleanup;
-                       }
-                       free_rdataset = true;
-
-                       rdatalist = newrdatalist(msg);
-                       if (rdatalist == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto cleanup;
-                       }
-
-                       rdatalist->type = rdtype;
-                       rdatalist->covers = covers;
-                       rdatalist->rdclass = rdclass;
-                       rdatalist->ttl = ttl;
-
-                       dns_rdataset_init(rdataset);
-                       RUNTIME_CHECK(
-                               dns_rdatalist_tordataset(rdatalist, rdataset) ==
-                               ISC_R_SUCCESS);
-                       dns_rdataset_setownercase(rdataset, name);
-
-                       if (!isedns && !istsig && !issigzero) {
+                               break;
+                       case ISC_R_SUCCESS:
                                ISC_LIST_APPEND(name->list, rdataset, link);
-                               free_rdataset = false;
+                               break;
+                       default:
+                               UNREACHABLE();
                        }
                }
 
@@ -1585,7 +1715,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 
                        msg->opt = rdataset;
                        rdataset = NULL;
-                       free_rdataset = false;
                        ercode = (dns_rcode_t)((msg->opt->ttl &
                                                DNS_MESSAGE_EDNSRCODE_MASK) >>
                                               20);
@@ -1597,7 +1726,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        msg->sig0name = name;
                        msg->sigstart = recstart;
                        rdataset = NULL;
-                       free_rdataset = false;
                        free_name = false;
                } else if (istsig) {
                        msg->tsig = rdataset;
@@ -1608,7 +1736,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                         */
                        msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
                        rdataset = NULL;
-                       free_rdataset = false;
                        free_name = false;
                }
 
@@ -1616,13 +1743,11 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        if (free_name) {
                                dns_message_puttempname(msg, &name);
                        }
-                       if (free_rdataset) {
-                               isc_mempool_put(msg->rdspool, rdataset);
-                       }
-                       free_name = free_rdataset = false;
+                       free_name = false;
                }
                INSIST(!free_name);
-               INSIST(!free_rdataset);
+
+               rdataset = NULL;
        }
 
        /*
@@ -1640,16 +1765,20 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
        }
 
        if (seen_problem) {
-               return (DNS_R_RECOVERABLE);
+               result = DNS_R_RECOVERABLE;
        }
-       return (ISC_R_SUCCESS);
 
 cleanup:
        if (free_name) {
                dns_message_puttempname(msg, &name);
        }
-       if (free_rdataset) {
-               isc_mempool_put(msg->rdspool, rdataset);
+
+       if (free_ht) {
+               cleanup_name_hashmaps(section);
+       }
+
+       if (name_map != NULL) {
+               isc_ht_destroy(&name_map);
        }
 
        return (result);
@@ -2446,7 +2575,7 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
                     const dns_name_t *target, dns_rdatatype_t type,
                     dns_rdatatype_t covers, dns_name_t **name,
                     dns_rdataset_t **rdataset) {
-       dns_name_t *foundname;
+       dns_name_t *foundname = NULL;
        isc_result_t result;
 
        /*
@@ -2493,22 +2622,6 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
        return (result);
 }
 
-void
-dns_message_movename(dns_message_t *msg, dns_name_t *name,
-                    dns_section_t fromsection, dns_section_t tosection) {
-       REQUIRE(msg != NULL);
-       REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
-       REQUIRE(name != NULL);
-       REQUIRE(VALID_NAMED_SECTION(fromsection));
-       REQUIRE(VALID_NAMED_SECTION(tosection));
-
-       /*
-        * Unlink the name from the old section
-        */
-       ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
-       ISC_LIST_APPEND(msg->sections[tosection], name, link);
-}
-
 void
 dns_message_addname(dns_message_t *msg, dns_name_t *name,
                    dns_section_t section) {
@@ -2600,6 +2713,10 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
        REQUIRE(!ISC_LINK_LINKED(item, link));
        REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
 
+       if (item->ht != NULL) {
+               isc_ht_destroy(&item->ht);
+       }
+
        /*
         * we need to check this in case dns_name_dup() was used.
         */
index 96f95b34b9a95aef239ad0a438aad0f13cce1658..a1702699f99fd3d795ea055436313fa216385340 100644 (file)
@@ -188,6 +188,7 @@ dns_name_invalidate(dns_name_t *name) {
        name->offsets = NULL;
        name->buffer = NULL;
        ISC_LINK_INIT(name, link);
+       INSIST(name->ht == NULL);
 }
 
 bool