902 lines
28 KiB
Diff
902 lines
28 KiB
Diff
|
|
From 608707b4f5b473e416563bfe0d43e26d6dc4a5c6 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
|
||
|
|
Date: Mon, 11 Sep 2023 10:35:28 +0200
|
||
|
|
Subject: [PATCH] Use hashtable when parsing a message
|
||
|
|
|
||
|
|
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.
|
||
|
|
|
||
|
|
Conflict:NA
|
||
|
|
Reference:https://downloads.isc.org/isc/bind/9.18.24/patches/0001-CVE-2023-4408.patch
|
||
|
|
|
||
|
|
(cherry picked from commit b8a96317544c7b310b4f74360825a87b6402ddc2)
|
||
|
|
|
||
|
|
---
|
||
|
|
lib/dns/include/dns/message.h | 38 ----
|
||
|
|
lib/dns/include/dns/name.h | 37 ++--
|
||
|
|
lib/dns/message.c | 374 ++++++++++++++++++++++------------
|
||
|
|
lib/dns/name.c | 1 +
|
||
|
|
lib/isc/ht.c | 55 ++++-
|
||
|
|
5 files changed, 309 insertions(+), 196 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
|
||
|
|
index 940c9b1..f15884a 100644
|
||
|
|
--- a/lib/dns/include/dns/message.h
|
||
|
|
+++ b/lib/dns/include/dns/message.h
|
||
|
|
@@ -856,44 +856,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);
|
||
|
|
diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h
|
||
|
|
index a758c4d..199856a 100644
|
||
|
|
--- a/lib/dns/include/dns/name.h
|
||
|
|
+++ b/lib/dns/include/dns/name.h
|
||
|
|
@@ -68,6 +68,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. */
|
||
|
|
@@ -111,6 +112,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')
|
||
|
|
@@ -166,30 +168,24 @@ 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 \
|
||
|
|
}
|
||
|
|
|
||
|
|
/*%
|
||
|
|
@@ -1330,6 +1326,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) \
|
||
|
|
diff --git a/lib/dns/message.c b/lib/dns/message.c
|
||
|
|
index 761a8e1..8654e92 100644
|
||
|
|
--- a/lib/dns/message.c
|
||
|
|
+++ b/lib/dns/message.c
|
||
|
|
@@ -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/result.h>
|
||
|
|
@@ -493,9 +495,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);
|
||
|
|
@@ -790,6 +794,18 @@ 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) {
|
||
|
|
+ isc_result_t result = isc_ht_find(ht, name->ndata, name->length,
|
||
|
|
+ (void **)foundp);
|
||
|
|
+ if (result == ISC_R_SUCCESS) {
|
||
|
|
+ return (ISC_R_EXISTS);
|
||
|
|
+ }
|
||
|
|
+ result = isc_ht_add(ht, name->ndata, name->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) {
|
||
|
|
@@ -809,29 +825,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
|
||
|
|
@@ -958,6 +971,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) {
|
||
|
|
@@ -967,13 +992,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;
|
||
|
|
@@ -994,13 +1025,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.
|
||
|
|
@@ -1012,19 +1049,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.
|
||
|
|
*/
|
||
|
|
@@ -1054,14 +1097,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.
|
||
|
|
*/
|
||
|
|
@@ -1071,6 +1106,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
goto cleanup;
|
||
|
|
}
|
||
|
|
rdataset = isc_mempool_get(msg->rdspool);
|
||
|
|
+ dns_rdataset_init(rdataset);
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Convert rdatalist to rdataset, and attach the latter to
|
||
|
|
@@ -1078,8 +1114,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;
|
||
|
|
@@ -1087,24 +1121,66 @@ 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,
|
||
|
|
+ ISC_HT_CASE_SENSITIVE);
|
||
|
|
+ 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) {
|
||
|
|
- INSIST(!dns_rdataset_isassociated(rdataset));
|
||
|
|
+ if (dns_rdataset_isassociated(rdataset)) {
|
||
|
|
+ dns_rdataset_disassociate(rdataset);
|
||
|
|
+ }
|
||
|
|
isc_mempool_put(msg->rdspool, rdataset);
|
||
|
|
}
|
||
|
|
if (free_name) {
|
||
|
|
dns_message_puttempname(msg, &name);
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (free_ht) {
|
||
|
|
+ cleanup_name_hashmaps(section);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (name_map != NULL) {
|
||
|
|
+ isc_ht_destroy(&name_map);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return (result);
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1184,17 +1260,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;
|
||
|
|
@@ -1202,10 +1285,10 @@ 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;
|
||
|
|
+ found_rdataset = NULL;
|
||
|
|
|
||
|
|
name = NULL;
|
||
|
|
result = dns_message_gettempname(msg, &name);
|
||
|
|
@@ -1245,8 +1328,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;
|
||
|
|
}
|
||
|
|
@@ -1353,10 +1436,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
* Then put the meta-class back into the finished rdata.
|
||
|
|
*/
|
||
|
|
rdata = newrdata(msg);
|
||
|
|
- if (rdata == NULL) {
|
||
|
|
- result = ISC_R_NOMEMORY;
|
||
|
|
- goto cleanup;
|
||
|
|
- }
|
||
|
|
if (msg->opcode == dns_opcode_update &&
|
||
|
|
update(sectionid, rdclass))
|
||
|
|
{
|
||
|
|
@@ -1445,34 +1524,62 @@ 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);
|
||
|
|
+ rdatalist->type = rdtype;
|
||
|
|
+ rdatalist->covers = covers;
|
||
|
|
+ rdatalist->rdclass = rdclass;
|
||
|
|
+ rdatalist->ttl = ttl;
|
||
|
|
+
|
||
|
|
+ dns_message_gettemprdataset(msg, &rdataset);
|
||
|
|
+ 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
|
||
|
|
@@ -1482,59 +1589,71 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
DO_ERROR(DNS_R_FORMERR);
|
||
|
|
}
|
||
|
|
|
||
|
|
- rdataset = NULL;
|
||
|
|
- result = dns_message_find(name, rdclass, rdtype, covers,
|
||
|
|
- &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.
|
||
|
|
- */
|
||
|
|
- if (result == ISC_R_SUCCESS) {
|
||
|
|
- if (dns_rdatatype_issingleton(rdtype)) {
|
||
|
|
- dns_rdata_t *first;
|
||
|
|
- dns_rdatalist_fromrdataset(rdataset,
|
||
|
|
- &rdatalist);
|
||
|
|
- first = ISC_LIST_HEAD(rdatalist->rdata);
|
||
|
|
- INSIST(first != NULL);
|
||
|
|
- if (dns_rdata_compare(rdata, first) != 0) {
|
||
|
|
- DO_ERROR(DNS_R_FORMERR);
|
||
|
|
- }
|
||
|
|
+ if (ISC_LIST_EMPTY(name->list)) {
|
||
|
|
+ result = ISC_R_SUCCESS;
|
||
|
|
+ goto skip_rds_check;
|
||
|
|
}
|
||
|
|
- }
|
||
|
|
|
||
|
|
- if (result == ISC_R_NOTFOUND) {
|
||
|
|
- rdataset = isc_mempool_get(msg->rdspool);
|
||
|
|
- free_rdataset = true;
|
||
|
|
+ if (name->ht == NULL) {
|
||
|
|
+ isc_ht_init(&name->ht, msg->mctx, 1,
|
||
|
|
+ ISC_HT_CASE_SENSITIVE);
|
||
|
|
+ free_ht = true;
|
||
|
|
|
||
|
|
- rdatalist = newrdatalist(msg);
|
||
|
|
- if (rdatalist == NULL) {
|
||
|
|
- result = ISC_R_NOMEMORY;
|
||
|
|
- goto cleanup;
|
||
|
|
+ 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);
|
||
|
|
|
||
|
|
- rdatalist->type = rdtype;
|
||
|
|
- rdatalist->covers = covers;
|
||
|
|
- rdatalist->rdclass = rdclass;
|
||
|
|
- rdatalist->ttl = ttl;
|
||
|
|
+ /*
|
||
|
|
+ * 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);
|
||
|
|
+ result = ISC_R_SUCCESS;
|
||
|
|
+ rdataset = found_rdataset;
|
||
|
|
|
||
|
|
- dns_rdataset_init(rdataset);
|
||
|
|
- RUNTIME_CHECK(
|
||
|
|
- dns_rdatalist_tordataset(rdatalist, rdataset) ==
|
||
|
|
- ISC_R_SUCCESS);
|
||
|
|
- dns_rdataset_setownercase(rdataset, name);
|
||
|
|
+ if (!dns_rdatatype_issingleton(rdtype)) {
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
- if (!isedns && !istsig && !issigzero) {
|
||
|
|
+ dns_rdatalist_fromrdataset(rdataset,
|
||
|
|
+ &rdatalist);
|
||
|
|
+ dns_rdata_t *first =
|
||
|
|
+ ISC_LIST_HEAD(rdatalist->rdata);
|
||
|
|
+ INSIST(first != NULL);
|
||
|
|
+ if (dns_rdata_compare(rdata, first) != 0) {
|
||
|
|
+ DO_ERROR(DNS_R_FORMERR);
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+ case ISC_R_SUCCESS:
|
||
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
||
|
|
- free_rdataset = false;
|
||
|
|
+ break;
|
||
|
|
+ default:
|
||
|
|
+ UNREACHABLE();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1569,8 +1688,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
dns_rcode_t ercode;
|
||
|
|
|
||
|
|
msg->opt = rdataset;
|
||
|
|
- rdataset = NULL;
|
||
|
|
- free_rdataset = false;
|
||
|
|
ercode = (dns_rcode_t)((msg->opt->ttl &
|
||
|
|
DNS_MESSAGE_EDNSRCODE_MASK) >>
|
||
|
|
20);
|
||
|
|
@@ -1581,8 +1698,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
msg->sig0 = rdataset;
|
||
|
|
msg->sig0name = name;
|
||
|
|
msg->sigstart = recstart;
|
||
|
|
- rdataset = NULL;
|
||
|
|
- free_rdataset = false;
|
||
|
|
free_name = false;
|
||
|
|
} else if (istsig) {
|
||
|
|
msg->tsig = rdataset;
|
||
|
|
@@ -1592,22 +1707,17 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
||
|
|
* Windows doesn't like TSIG names to be compressed.
|
||
|
|
*/
|
||
|
|
msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
|
||
|
|
- rdataset = NULL;
|
||
|
|
- free_rdataset = false;
|
||
|
|
free_name = false;
|
||
|
|
}
|
||
|
|
+ rdataset = NULL;
|
||
|
|
|
||
|
|
if (seen_problem) {
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
@@ -1625,16 +1735,24 @@ 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 (rdataset != NULL && rdataset != found_rdataset) {
|
||
|
|
+ dns_rdataset_disassociate(rdataset);
|
||
|
|
+ isc_mempool_put(msg->rdspool, rdataset);
|
||
|
|
+ }
|
||
|
|
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);
|
||
|
|
@@ -2452,7 +2570,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;
|
||
|
|
|
||
|
|
/*
|
||
|
|
@@ -2499,22 +2617,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) {
|
||
|
|
@@ -2591,6 +2693,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.
|
||
|
|
*/
|
||
|
|
diff --git a/lib/dns/name.c b/lib/dns/name.c
|
||
|
|
index 8a258a2..90044ba 100644
|
||
|
|
--- a/lib/dns/name.c
|
||
|
|
+++ b/lib/dns/name.c
|
||
|
|
@@ -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
|
||
|
|
diff --git a/lib/isc/ht.c b/lib/isc/ht.c
|
||
|
|
index eaf2b3c..e11050f 100644
|
||
|
|
--- a/lib/isc/ht.c
|
||
|
|
+++ b/lib/isc/ht.c
|
||
|
|
@@ -93,11 +93,54 @@ maybe_rehash(isc_ht_t *ht, size_t newcount);
|
||
|
|
static isc_result_t
|
||
|
|
isc__ht_iter_next(isc_ht_iter_t *it);
|
||
|
|
|
||
|
|
+static uint8_t maptolower[] = {
|
||
|
|
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||
|
|
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||
|
|
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
||
|
|
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||
|
|
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||
|
|
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||
|
|
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
|
||
|
|
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||
|
|
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
|
||
|
|
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||
|
|
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
|
||
|
|
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||
|
|
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
|
||
|
|
+ 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||
|
|
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||
|
|
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||
|
|
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
|
||
|
|
+ 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||
|
|
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
|
||
|
|
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||
|
|
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
|
||
|
|
+ 0xfc, 0xfd, 0xfe, 0xff
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+memcasecmp(const void *vs1, const void *vs2, size_t len) {
|
||
|
|
+ uint8_t const *s1 = vs1;
|
||
|
|
+ uint8_t const *s2 = vs2;
|
||
|
|
+ for (size_t i = 0; i < len; i++) {
|
||
|
|
+ uint8_t u1 = s1[i];
|
||
|
|
+ uint8_t u2 = s2[i];
|
||
|
|
+ int U1 = maptolower[u1];
|
||
|
|
+ int U2 = maptolower[u2];
|
||
|
|
+ int diff = U1 - U2;
|
||
|
|
+ if (diff) {
|
||
|
|
+ return diff;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static bool
|
||
|
|
isc__ht_node_match(isc_ht_node_t *node, const uint32_t hashval,
|
||
|
|
- const uint8_t *key, uint32_t keysize) {
|
||
|
|
+ const uint8_t *key, uint32_t keysize, bool case_sensitive) {
|
||
|
|
return (node->hashval == hashval && node->keysize == keysize &&
|
||
|
|
- memcmp(node->key, key, keysize) == 0);
|
||
|
|
+ (case_sensitive ? (memcmp(node->key, key, keysize) == 0)
|
||
|
|
+ : (memcasecmp(node->key, key, keysize) == 0)));
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t
|
||
|
|
@@ -341,7 +384,9 @@ nexttable:
|
||
|
|
for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL;
|
||
|
|
node = node->next)
|
||
|
|
{
|
||
|
|
- if (isc__ht_node_match(node, hashval, key, keysize)) {
|
||
|
|
+ if (isc__ht_node_match(node, hashval, key, keysize,
|
||
|
|
+ ht->case_sensitive))
|
||
|
|
+ {
|
||
|
|
return (node);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@@ -390,7 +435,9 @@ isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
|
||
|
|
for (isc_ht_node_t *node = ht->table[idx][hash]; node != NULL;
|
||
|
|
prev = node, node = node->next)
|
||
|
|
{
|
||
|
|
- if (isc__ht_node_match(node, hashval, key, keysize)) {
|
||
|
|
+ if (isc__ht_node_match(node, hashval, key, keysize,
|
||
|
|
+ ht->case_sensitive))
|
||
|
|
+ {
|
||
|
|
if (prev == NULL) {
|
||
|
|
ht->table[idx][hash] = node->next;
|
||
|
|
} else {
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|