diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 23:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 23:51:28 +0000 |
commit | 754c7de1e91eeb28c6d3766900ead0c3e44fdb85 (patch) | |
tree | 51433c0e38731dc9ecd342555a56f876980b1834 /lib | |
parent | Adding debian version 1:9.16.44-1~deb11u1. (diff) | |
download | bind9-754c7de1e91eeb28c6d3766900ead0c3e44fdb85.tar.xz bind9-754c7de1e91eeb28c6d3766900ead0c3e44fdb85.zip |
Merging upstream version 1:9.16.48.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib')
53 files changed, 1169 insertions, 604 deletions
diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 3a78a17..ee64543 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -1457,6 +1457,10 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, (void)cfg_map_get(options, "cookie-algorithm", &obj); if (obj != NULL) { ccalg = cfg_obj_asstring(obj); + if (strcasecmp(ccalg, "aes") == 0) { + cfg_obj_log(obj, logctx, ISC_LOG_WARNING, + "cookie-algorithm 'aes' is deprecated"); + } } obj = NULL; diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 87f0f8b..6f98fec 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -442,8 +442,8 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); * These are currently used on simple unsigned ints, so they are * not really associated with any particular type. */ -#define WANT_INET(x) (((x)&DNS_ADBFIND_INET) != 0) -#define WANT_INET6(x) (((x)&DNS_ADBFIND_INET6) != 0) +#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) +#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) @@ -452,11 +452,11 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); * glue, and compare this to the appropriate bits set in o, to see if * this is ok. */ -#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o)&DNS_ADBFIND_GLUEOK) != 0)) -#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o)&DNS_ADBFIND_HINTOK) != 0)) +#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0)) +#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0)) #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o)) #define STARTATZONE_MATCHES(nf, o) \ - (((nf)->flags & NAME_STARTATZONE) == ((o)&DNS_ADBFIND_STARTATZONE)) + (((nf)->flags & NAME_STARTATZONE) == ((o) & DNS_ADBFIND_STARTATZONE)) #define ENTER_LEVEL ISC_LOG_DEBUG(50) #define EXIT_LEVEL ENTER_LEVEL diff --git a/lib/dns/catz.c b/lib/dns/catz.c index 2c00d6e..0275a4f 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -423,9 +423,9 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) { dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE); - isc_ht_init(&toadd, target->catzs->mctx, 16); + isc_ht_init(&toadd, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); - isc_ht_init(&tomod, target->catzs->mctx, 16); + isc_ht_init(&tomod, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); isc_ht_iter_create(newzone->entries, &iter1); @@ -610,7 +610,7 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, isc_refcount_init(&new_zones->refs, 1); - isc_ht_init(&new_zones->zones, mctx, 4); + isc_ht_init(&new_zones->zones, mctx, 4, ISC_HT_CASE_SENSITIVE); isc_mem_attach(mctx, &new_zones->mctx); new_zones->zmm = zmm; @@ -662,7 +662,7 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, dns_name_init(&new_zone->name, NULL); dns_name_dup(name, catzs->mctx, &new_zone->name); - isc_ht_init(&new_zone->entries, catzs->mctx, 16); + isc_ht_init(&new_zone->entries, catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); new_zone->updatetimer = NULL; result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL, diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index d49beb2..df5a358 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -164,7 +164,8 @@ computeid(dst_key_t *key); static isc_result_t frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, dns_rdataclass_t rdclass, - isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); + isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, + dst_key_t **keyp); static isc_result_t algorithm_status(unsigned int alg); @@ -780,6 +781,13 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { isc_result_t dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) { + return (dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp)); +} + +isc_result_t +dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, + dst_key_t **keyp) { uint8_t alg, proto; uint32_t flags, extflags; dst_key_t *key = NULL; @@ -810,7 +818,7 @@ dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, } result = frombuffer(name, alg, flags, proto, rdclass, source, mctx, - &key); + no_rdata, &key); if (result != ISC_R_SUCCESS) { return (result); } @@ -831,7 +839,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, REQUIRE(dst_initialized); result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx, - &key); + false, &key); if (result != ISC_R_SUCCESS) { return (result); } @@ -2337,7 +2345,8 @@ computeid(dst_key_t *key) { static isc_result_t frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, dns_rdataclass_t rdclass, - isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) { + isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, + dst_key_t **keyp) { dst_key_t *key; isc_result_t ret; @@ -2362,10 +2371,12 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, return (DST_R_UNSUPPORTEDALG); } - ret = key->func->fromdns(key, source); - if (ret != ISC_R_SUCCESS) { - dst_key_free(&key); - return (ret); + if (!no_rdata) { + ret = key->func->fromdns(key, source); + if (ret != ISC_R_SUCCESS) { + dst_key_free(&key); + return (ret); + } } } diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 8214021..ea45742 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -542,7 +542,7 @@ dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, * *\li 'cctx' be valid. * - *\li 'buffer' is a valid buffer. + *\li 'buffer' is a valid buffer with length less than 65536. * * Side Effects: * @@ -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); diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index 683f71d..2e1c5f8 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -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) \ diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h index 4a6b078..6cfd40f 100644 --- a/lib/dns/include/dns/rbt.h +++ b/lib/dns/include/dns/rbt.h @@ -140,6 +140,12 @@ struct dns_rbtnode { */ ISC_LINK(dns_rbtnode_t) deadlink; + /*% + * This linked list is used to store nodes from which tree pruning can + * be started. + */ + ISC_LINK(dns_rbtnode_t) prunelink; + /*@{*/ /*! * These values are used in the RBT DB implementation. The appropriate diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index fd1697e..4be0969 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -492,7 +492,7 @@ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[]; /*%< * Conversion macros among dns_rdatatype_t, attributes and isc_statscounter_t. */ -#define DNS_RDATASTATSTYPE_BASE(type) ((dns_rdatatype_t)((type)&0xFFFF)) +#define DNS_RDATASTATSTYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) #define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16) #define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b)) diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h index b435cd6..c5d7a31 100644 --- a/lib/dns/include/dns/validator.h +++ b/lib/dns/include/dns/validator.h @@ -149,6 +149,7 @@ struct dns_validator { unsigned int depth; unsigned int authcount; unsigned int authfail; + bool failed; isc_stdtime_t start; }; diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 3185e9f..3e3cfe6 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -471,6 +471,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory); */ isc_result_t +dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, + dst_key_t **keyp); +isc_result_t dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); /*%< diff --git a/lib/dns/mapapi b/lib/dns/mapapi index 1b502d3..a46e190 100644 --- a/lib/dns/mapapi +++ b/lib/dns/mapapi @@ -13,4 +13,4 @@ # Whenever releasing a new major release of BIND9, set this value # back to 1.0 when releasing the first alpha. Map files are *never* # compatible across major releases. -MAPAPI=3.0 +MAPAPI=4.0 diff --git a/lib/dns/master.c b/lib/dns/master.c index fc56107..024fbd5 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -88,7 +88,7 @@ #define DNS_MASTER_LHS 2048 #define DNS_MASTER_RHS MINTSIZ -#define CHECKNAMESFAIL(x) (((x)&DNS_MASTER_CHECKNAMESFAIL) != 0) +#define CHECKNAMESFAIL(x) (((x) & DNS_MASTER_CHECKNAMESFAIL) != 0) typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t; diff --git a/lib/dns/message.c b/lib/dns/message.c index 09645c2..22aa552 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/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); @@ -799,6 +803,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) { dns_name_t *curr; @@ -817,29 +833,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 +979,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 +1000,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 +1033,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 +1057,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. */ @@ -1063,14 +1106,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, } /* - * 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. */ rdatalist = newrdatalist(msg); @@ -1083,6 +1118,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,32 +1127,71 @@ 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; - } + RUNTIME_CHECK(result == ISC_R_SUCCESS); 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); } @@ -1196,17 +1271,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,10 +1296,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); @@ -1257,8 +1339,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; } @@ -1365,10 +1447,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)) { @@ -1456,34 +1534,71 @@ 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 @@ -1493,63 +1608,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); - if (rdataset == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup; - } - 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(); } } @@ -1584,8 +1707,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); @@ -1596,8 +1717,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; @@ -1607,22 +1726,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); } /* @@ -1640,16 +1754,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); @@ -1789,6 +1911,7 @@ dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(buffer != NULL); + REQUIRE(isc_buffer_length(buffer) < 65536); REQUIRE(msg->buffer == NULL); REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); @@ -2445,7 +2568,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 +2616,6 @@ dns_message_findname(dns_message_t *msg, dns_section_t section, } 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) { REQUIRE(msg != NULL); @@ -2599,6 +2706,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 96f95b3..a170269 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/dns/ncache.c b/lib/dns/ncache.c index 9247ac1..941574d 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -754,7 +754,7 @@ dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, raw += 2; sigregion.base = raw; dns_rdata_reset(&rdata); - dns_rdata_fromregion(&rdata, rdataset->rdclass, rdataset->type, + dns_rdata_fromregion(&rdata, ncacherdataset->rdclass, type, &sigregion); (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); rdataset->covers = rrsig.covered; diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c index 7f68580..b9702eb 100644 --- a/lib/dns/nsec3.c +++ b/lib/dns/nsec3.c @@ -48,10 +48,10 @@ goto failure; \ } while (0) -#define OPTOUT(x) (((x)&DNS_NSEC3FLAG_OPTOUT) != 0) -#define CREATE(x) (((x)&DNS_NSEC3FLAG_CREATE) != 0) -#define INITIAL(x) (((x)&DNS_NSEC3FLAG_INITIAL) != 0) -#define REMOVE(x) (((x)&DNS_NSEC3FLAG_REMOVE) != 0) +#define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0) +#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) +#define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0) +#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) isc_result_t dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 1f2a2e0..09412c5 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -895,9 +895,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { #if !defined(OPENSSL_NO_ENGINE) ENGINE *ep = NULL; const BIGNUM *ex = NULL; + const char *engine = NULL; #endif /* if !defined(OPENSSL_NO_ENGINE) */ isc_mem_t *mctx = key->mctx; - const char *engine = NULL, *label = NULL; + const char *label = NULL; EVP_PKEY *pkey = NULL; BIGNUM *n = NULL, *e = NULL, *d = NULL; BIGNUM *p = NULL, *q = NULL; @@ -930,9 +931,11 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { +#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 case TAG_RSA_ENGINE: engine = (char *)priv.elements[i].data; break; +#endif case TAG_RSA_LABEL: label = (char *)priv.elements[i].data; break; diff --git a/lib/dns/private.c b/lib/dns/private.c index 56573b3..4157e82 100644 --- a/lib/dns/private.c +++ b/lib/dns/private.c @@ -39,10 +39,10 @@ * been requested to be built otherwise a NSEC chain needs to be built. */ -#define REMOVE(x) (((x)&DNS_NSEC3FLAG_REMOVE) != 0) -#define CREATE(x) (((x)&DNS_NSEC3FLAG_CREATE) != 0) -#define INITIAL(x) (((x)&DNS_NSEC3FLAG_INITIAL) != 0) -#define NONSEC(x) (((x)&DNS_NSEC3FLAG_NONSEC) != 0) +#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) +#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) +#define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0) +#define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0) #define CHECK(x) \ do { \ diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index d5d18b8..780a950 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -2307,6 +2307,7 @@ create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep) { HASHVAL(node) = 0; ISC_LINK_INIT(node, deadlink); + ISC_LINK_INIT(node, prunelink); LOCKNUM(node) = 0; WILD(node) = 0; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index ee06c51..723d169 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -116,7 +116,7 @@ struct rbtdb_file_header { typedef uint32_t rbtdb_serial_t; typedef uint32_t rbtdb_rdatatype_t; -#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type)&0xFFFF)) +#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) #define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16)) #define RBTDB_RDATATYPE_VALUE(base, ext) \ ((rbtdb_rdatatype_t)(((uint32_t)ext) << 16) | \ @@ -521,6 +521,10 @@ struct dns_rbtdb { */ rbtnodelist_t *deadnodes; + /* List of nodes from which recursive tree pruning can be started from. + * Locked by tree_lock. */ + rbtnodelist_t prunenodes; + /* * Heaps. These are used for TTL based expiry in a cache, * or for zone resigning in a zone DB. hmctx is the memory @@ -1067,6 +1071,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { unsigned int i; isc_result_t result; char buf[DNS_NAME_FORMATSIZE]; + dns_rbtnode_t *node = NULL; dns_rbt_t **treep; isc_time_t start; @@ -1092,8 +1097,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { * the overhead of unlinking all nodes here should be negligible. */ for (i = 0; i < rbtdb->node_lock_count; i++) { - dns_rbtnode_t *node; - node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); while (node != NULL) { ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink); @@ -1101,6 +1104,12 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { } } + node = ISC_LIST_HEAD(rbtdb->prunenodes); + while (node != NULL) { + ISC_LIST_UNLINK(rbtdb->prunenodes, node, prunelink); + node = ISC_LIST_HEAD(rbtdb->prunenodes); + } + if (event == NULL) { rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; } @@ -1935,19 +1944,32 @@ is_leaf(dns_rbtnode_t *node) { node->left == NULL && node->right == NULL); } +/*% + * The tree lock must be held when this function is called as it reads and + * updates rbtdb->prunenodes. + */ static void send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, isc_rwlocktype_t locktype) { - isc_event_t *ev; - dns_db_t *db; + bool pruning_queued = (ISC_LIST_HEAD(rbtdb->prunenodes) != NULL); + + INSIST(locktype == isc_rwlocktype_write); - ev = isc_event_allocate(rbtdb->common.mctx, NULL, DNS_EVENT_RBTPRUNE, - prune_tree, node, sizeof(isc_event_t)); new_reference(rbtdb, node, locktype); - db = NULL; - attach((dns_db_t *)rbtdb, &db); - ev->ev_sender = db; - isc_task_send(rbtdb->task, &ev); + INSIST(!ISC_LINK_LINKED(node, prunelink)); + ISC_LIST_APPEND(rbtdb->prunenodes, node, prunelink); + + if (!pruning_queued) { + isc_event_t *ev = NULL; + dns_db_t *db = NULL; + + attach((dns_db_t *)rbtdb, &db); + + ev = isc_event_allocate(rbtdb->common.mctx, NULL, + DNS_EVENT_RBTPRUNE, prune_tree, db, + sizeof(isc_event_t)); + isc_task_send(rbtdb->task, &ev); + } } /*% @@ -2222,17 +2244,26 @@ restore_locks: } /* - * Prune the tree by recursively cleaning-up single leaves. In the worst - * case, the number of iteration is the number of tree levels, which is at - * most the maximum number of domain name labels, i.e, 127. In practice, this - * should be much smaller (only a few times), and even the worst case would be - * acceptable for a single event. + * Prune the tree by recursively cleaning up single leaves. Go through all + * nodes stored in the rbtdb->prunenodes list; for each of them, in the worst + * case, it will be necessary to traverse a number of tree levels equal to the + * maximum legal number of domain name labels (127); in practice, the number of + * tree levels to traverse will virtually always be much smaller (a few levels + * at most). While holding the tree lock throughout this entire operation is + * less than ideal, so is splitting the latter up by queueing a separate + * prune_tree() run for each node to start pruning from (as queueing requires + * allocating memory and can therefore potentially be exploited to exhaust + * available memory). Also note that actually freeing up the memory used by + * RBTDB nodes (which is what this function does) is essential to keeping cache + * memory use in check, so since the tree lock needs to be acquired anyway, + * freeing as many nodes as possible before the tree lock gets released is + * prudent. */ static void prune_tree(isc_task_t *task, isc_event_t *event) { - dns_rbtdb_t *rbtdb = event->ev_sender; - dns_rbtnode_t *node = event->ev_arg; - dns_rbtnode_t *parent; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)event->ev_arg; + dns_rbtnode_t *node = NULL; + dns_rbtnode_t *parent = NULL; unsigned int locknum; UNUSED(task); @@ -2240,44 +2271,60 @@ prune_tree(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - locknum = node->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); - do { - parent = node->parent; - decrement_reference(rbtdb, node, 0, isc_rwlocktype_write, - isc_rwlocktype_write, true); - if (parent != NULL && parent->down == NULL) { - /* - * node was the only down child of the parent and has - * just been removed. We'll then need to examine the - * parent. Keep the lock if possible; otherwise, - * release the old lock and acquire one for the parent. - */ - if (parent->locknum != locknum) { - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); - locknum = parent->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + while ((node = ISC_LIST_HEAD(rbtdb->prunenodes)) != NULL) { + locknum = node->locknum; + NODE_LOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + do { + if (ISC_LINK_LINKED(node, prunelink)) { + ISC_LIST_UNLINK(rbtdb->prunenodes, node, + prunelink); } - /* - * We need to gain a reference to the node before - * decrementing it in the next iteration. - */ - if (ISC_LINK_LINKED(parent, deadlink)) { - ISC_LIST_UNLINK(rbtdb->deadnodes[locknum], + parent = node->parent; + decrement_reference(rbtdb, node, 0, + isc_rwlocktype_write, + isc_rwlocktype_write, true); + + if (parent != NULL && parent->down == NULL) { + /* + * node was the only down child of the parent + * and has just been removed. We'll then need + * to examine the parent. Keep the lock if + * possible; otherwise, release the old lock and + * acquire one for the parent. + */ + if (parent->locknum != locknum) { + NODE_UNLOCK( + &rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + locknum = parent->locknum; + NODE_LOCK( + &rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + } + + /* + * We need to gain a reference to the node + * before decrementing it in the next iteration. + */ + if (ISC_LINK_LINKED(parent, deadlink)) { + ISC_LIST_UNLINK( + rbtdb->deadnodes[locknum], parent, deadlink); + } + new_reference(rbtdb, parent, + isc_rwlocktype_write); + } else { + parent = NULL; } - new_reference(rbtdb, parent, isc_rwlocktype_write); - } else { - parent = NULL; - } - node = parent; - } while (node != NULL); - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + node = parent; + } while (node != NULL); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + } RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); detach((dns_db_t **)&rbtdb); @@ -8735,6 +8782,8 @@ dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, ISC_LIST_INIT(rbtdb->deadnodes[i]); } + ISC_LIST_INIT(rbtdb->prunenodes); + rbtdb->active = rbtdb->node_lock_count; for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { @@ -10070,7 +10119,7 @@ rehash_bits(rbtdb_version_t *version, size_t newcount) { uint32_t newbits = oldbits; while (newcount >= HASHSIZE(newbits) && - newbits <= RBTDB_GLUE_TABLE_MAX_BITS) + newbits < RBTDB_GLUE_TABLE_MAX_BITS) { newbits += 1; } diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index a283831..3b49819 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -2057,7 +2057,7 @@ decvalue(char value) { * isascii() is valid for full range of int values, no need to * mask or cast. */ - if (!isascii(value)) { + if (!isascii((unsigned char)value)) { return (-1); } if ((s = strchr(decdigits, value)) == NULL) { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index a97aaa8..0952624 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -10634,8 +10634,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, * Since we have a pool of tasks we bind them to task queues * to spread the load evenly */ - result = isc_task_create_bound(taskmgr, 0, - &res->buckets[i].task, i); + result = isc_task_create_bound( + taskmgr, 0, &res->buckets[i].task, ISC_NM_TASK_SLOW(i)); if (result != ISC_R_SUCCESS) { isc_mutex_destroy(&res->buckets[i].lock); goto cleanup_buckets; diff --git a/lib/dns/result.c b/lib/dns/result.c index 9921291..f07c2f1 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -405,7 +405,7 @@ dns_result_torcode(isc_result_t result) { * Rcodes can't be bigger than 12 bits, which is why we * AND with 0xFFF instead of 0xFFFF. */ - return ((dns_rcode_t)((result)&0xFFF)); + return ((dns_rcode_t)((result) & 0xFFF)); } /* diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c index 69e2667..84f841a 100644 --- a/lib/dns/rootns.c +++ b/lib/dns/rootns.c @@ -34,6 +34,9 @@ #include <dns/rootns.h> #include <dns/view.h> +/* + * Also update 'upcoming' when updating 'root_ns'. + */ static char root_ns[] = ";\n" "; Internet Root Nameservers\n" @@ -54,8 +57,8 @@ static char root_ns[] = ". 518400 IN NS M.ROOT-SERVERS.NET.\n" "A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n" "A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n" - "B.ROOT-SERVERS.NET. 3600000 IN A 199.9.14.201\n" - "B.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:200::b\n" + "B.ROOT-SERVERS.NET. 3600000 IN A 170.247.170.2\n" + "B.ROOT-SERVERS.NET. 3600000 IN AAAA 2801:1b8:10::b\n" "C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n" "C.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2::c\n" "D.ROOT-SERVERS.NET. 3600000 IN A 199.7.91.13\n" @@ -79,6 +82,24 @@ static char root_ns[] = "M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n" "M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n"; +static unsigned char b_data[] = "\001b\014root-servers\003net"; +static unsigned char b_offsets[] = { 0, 2, 15, 19 }; + +static struct upcoming { + const dns_name_t name; + dns_rdatatype_t type; + isc_stdtime_t time; +} upcoming[] = { { + .name = DNS_NAME_INITABSOLUTE(b_data, b_offsets), + .type = dns_rdatatype_a, + .time = 1701086400 /* November 27 2023, 12:00 UTC */ + }, + { + .name = DNS_NAME_INITABSOLUTE(b_data, b_offsets), + .type = dns_rdatatype_aaaa, + .time = 1701086400 /* November 27 2023, 12:00 UTC */ + } }; + static isc_result_t in_rootns(dns_rdataset_t *rootns, dns_name_t *name) { isc_result_t result; @@ -337,6 +358,18 @@ inrrset(dns_rdataset_t *rrset, dns_rdata_t *rdata) { return (false); } +static bool +changing(const dns_name_t *name, dns_rdatatype_t type, isc_stdtime_t now) { + for (size_t i = 0; i < ARRAY_SIZE(upcoming); i++) { + if (upcoming[i].time > now && upcoming[i].type == type && + dns_name_equal(&upcoming[i].name, name)) + { + return (true); + } + } + return (false); +} + /* * Check that the address RRsets match. * @@ -368,7 +401,9 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, while (result == ISC_R_SUCCESS) { dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); - if (!inrrset(&hintrrset, &rdata)) { + if (!inrrset(&hintrrset, &rdata) && + !changing(name, dns_rdatatype_a, now)) + { report(view, name, true, &rdata); } result = dns_rdataset_next(&rootrrset); @@ -377,7 +412,9 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, while (result == ISC_R_SUCCESS) { dns_rdata_reset(&rdata); dns_rdataset_current(&hintrrset, &rdata); - if (!inrrset(&rootrrset, &rdata)) { + if (!inrrset(&rootrrset, &rdata) && + !changing(name, dns_rdatatype_a, now)) + { report(view, name, false, &rdata); } result = dns_rdataset_next(&hintrrset); @@ -416,7 +453,9 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, while (result == ISC_R_SUCCESS) { dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); - if (!inrrset(&hintrrset, &rdata)) { + if (!inrrset(&hintrrset, &rdata) && + !changing(name, dns_rdatatype_aaaa, now)) + { report(view, name, true, &rdata); } dns_rdata_reset(&rdata); @@ -426,7 +465,9 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, while (result == ISC_R_SUCCESS) { dns_rdata_reset(&rdata); dns_rdataset_current(&hintrrset, &rdata); - if (!inrrset(&rootrrset, &rdata)) { + if (!inrrset(&rootrrset, &rdata) && + !changing(name, dns_rdatatype_aaaa, now)) + { report(view, name, false, &rdata); } dns_rdata_reset(&rdata); diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 20db72f..fdc9759 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -1544,7 +1544,7 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { * simplifies update_from_db */ - isc_ht_init(&zone->nodes, rpzs->mctx, 1); + isc_ht_init(&zone->nodes, rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE); dns_name_init(&zone->origin, NULL); dns_name_init(&zone->client_ip, NULL); @@ -1722,7 +1722,8 @@ setup_update(dns_rpz_zone_t *rpz) { ISC_LOG_DEBUG(1), "rpz: %s: using hashtable size %d", domain, hashsize); - isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize); + isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize, + ISC_HT_CASE_SENSITIVE); result = dns_db_createiterator(rpz->updb, DNS_DB_NONSEC3, &rpz->updbit); if (result != ISC_R_SUCCESS) { diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index e102d09..8f4c3b9 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -1744,8 +1744,9 @@ isc_result_t dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name, const dns_name_t *algorithm, dns_tsig_keyring_t *ring) { dns_tsigkey_t *key; - isc_stdtime_t now; isc_result_t result; + isc_rwlocktype_t locktype = isc_rwlocktype_read; + isc_stdtime_t now; REQUIRE(tsigkey != NULL); REQUIRE(*tsigkey == NULL); @@ -1757,25 +1758,30 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name, RWUNLOCK(&ring->lock, isc_rwlocktype_write); isc_stdtime_get(&now); - RWLOCK(&ring->lock, isc_rwlocktype_read); + +again: + RWLOCK(&ring->lock, locktype); key = NULL; result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key); if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) { - RWUNLOCK(&ring->lock, isc_rwlocktype_read); + RWUNLOCK(&ring->lock, locktype); return (ISC_R_NOTFOUND); } if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) { - RWUNLOCK(&ring->lock, isc_rwlocktype_read); + RWUNLOCK(&ring->lock, locktype); return (ISC_R_NOTFOUND); } if (key->inception != key->expire && isc_serial_lt(key->expire, now)) { /* * The key has expired. */ - RWUNLOCK(&ring->lock, isc_rwlocktype_read); - RWLOCK(&ring->lock, isc_rwlocktype_write); + if (locktype == isc_rwlocktype_read) { + RWUNLOCK(&ring->lock, locktype); + locktype = isc_rwlocktype_write; + goto again; + } remove_fromring(key); - RWUNLOCK(&ring->lock, isc_rwlocktype_write); + RWUNLOCK(&ring->lock, locktype); return (ISC_R_NOTFOUND); } #if 0 @@ -1790,7 +1796,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name, } #endif /* if 0 */ isc_refcount_increment(&key->refs); - RWUNLOCK(&ring->lock, isc_rwlocktype_read); + RWUNLOCK(&ring->lock, locktype); adjust_lru(key); *tsigkey = key; return (ISC_R_SUCCESS); diff --git a/lib/dns/update.c b/lib/dns/update.c index 9d71238..5fc9605 100644 --- a/lib/dns/update.c +++ b/lib/dns/update.c @@ -1090,8 +1090,8 @@ static isc_result_t add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, - isc_stdtime_t inception, isc_stdtime_t expire, bool check_ksk, - bool keyset_kskonly) { + isc_stdtime_t now, isc_stdtime_t inception, isc_stdtime_t expire, + bool check_ksk, bool keyset_kskonly) { isc_result_t result; dns_dbnode_t *node = NULL; dns_kasp_t *kasp = dns_zone_getkasp(zone); @@ -1224,7 +1224,7 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, continue; } else if (zsk && !dst_key_is_signing(keys[i], DST_BOOL_ZSK, - inception, &when)) + now, &when)) { /* * This key is not active for zone-signing. @@ -1382,8 +1382,9 @@ static isc_result_t add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, bool cut, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, - isc_stdtime_t inception, isc_stdtime_t expire, bool check_ksk, - bool keyset_kskonly, unsigned int *sigs) { + isc_stdtime_t now, isc_stdtime_t inception, + isc_stdtime_t expire, bool check_ksk, bool keyset_kskonly, + unsigned int *sigs) { isc_result_t result; dns_dbnode_t *node; dns_rdatasetiter_t *iter; @@ -1433,7 +1434,7 @@ add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, continue; } result = add_sigs(log, zone, db, ver, name, type, diff, keys, - nkeys, inception, expire, check_ksk, + nkeys, now, inception, expire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { goto cleanup_iterator; @@ -1482,7 +1483,7 @@ struct dns_update_state { dns_diff_t work; dst_key_t *zone_keys[DNS_MAXZONEKEYS]; unsigned int nkeys; - isc_stdtime_t inception, expire, soaexpire, keyexpire; + isc_stdtime_t now, inception, expire, soaexpire, keyexpire; dns_ttl_t nsecttl; bool check_ksk, keyset_kskonly, build_nsec3; enum { @@ -1528,7 +1529,6 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, dns_difftuple_t *t, *next; bool flag, build_nsec; unsigned int i; - isc_stdtime_t now; dns_rdata_soa_t soa; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t rdataset; @@ -1565,16 +1565,17 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, goto failure; } - isc_stdtime_get(&now); - state->inception = now - 3600; /* Allow for some clock skew. */ - state->expire = now + + isc_stdtime_get(&state->now); + state->inception = state->now - 3600; /* Allow for some clock + skew. */ + state->expire = state->now + dns__jitter_expire(zone, sigvalidityinterval); - state->soaexpire = now + sigvalidityinterval; + state->soaexpire = state->now + sigvalidityinterval; state->keyexpire = dns_zone_getkeyvalidityinterval(zone); if (state->keyexpire == 0) { state->keyexpire = state->expire; } else { - state->keyexpire += now; + state->keyexpire += state->now; } /* @@ -1690,8 +1691,8 @@ next_state: log, zone, db, newver, name, type, &state->sig_diff, state->zone_keys, state->nkeys, - state->inception, exp, - state->check_ksk, + state->now, state->inception, + exp, state->check_ksk, state->keyset_kskonly)); sigs++; } @@ -1893,9 +1894,10 @@ next_state: CHECK(add_exposed_sigs( log, zone, db, newver, name, cut, &state->sig_diff, state->zone_keys, - state->nkeys, state->inception, - state->expire, state->check_ksk, - state->keyset_kskonly, &sigs)); + state->nkeys, state->now, + state->inception, state->expire, + state->check_ksk, state->keyset_kskonly, + &sigs)); } unlink: ISC_LIST_UNLINK(state->affected.tuples, t, link); @@ -1971,8 +1973,8 @@ next_state: dns_rdatatype_nsec, &state->sig_diff, state->zone_keys, state->nkeys, - state->inception, state->expire, - state->check_ksk, + state->now, state->inception, + state->expire, state->check_ksk, state->keyset_kskonly)); sigs++; } else { @@ -2100,9 +2102,10 @@ next_state: CHECK(add_exposed_sigs( log, zone, db, newver, name, cut, &state->sig_diff, state->zone_keys, - state->nkeys, state->inception, - state->expire, state->check_ksk, - state->keyset_kskonly, &sigs)); + state->nkeys, state->now, + state->inception, state->expire, + state->check_ksk, state->keyset_kskonly, + &sigs)); CHECK(dns_nsec3_addnsec3sx( db, newver, name, state->nsecttl, unsecure, privatetype, @@ -2146,8 +2149,8 @@ next_state: dns_rdatatype_nsec3, &state->sig_diff, state->zone_keys, state->nkeys, - state->inception, state->expire, - state->check_ksk, + state->now, state->inception, + state->expire, state->check_ksk, state->keyset_kskonly)); sigs++; } else { diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 6cf717f..243b19f 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -1104,8 +1104,8 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, * 'rdataset'. If found, build a dst_key_t for it and point val->key at * it. * - * If val->key is already non-NULL, locate it in the rdataset and then - * search past it for the *next* key that could have signed 'siginfo', then + * If val->key is already non-NULL, start searching from the next position in + * 'rdataset' to find the *next* key that could have signed 'siginfo', then * set val->key to that. * * Returns ISC_R_SUCCESS if a possible matching key has been found, @@ -1118,59 +1118,59 @@ select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) { isc_buffer_t b; dns_rdata_t rdata = DNS_RDATA_INIT; dst_key_t *oldkey = val->key; - bool foundold; + bool no_rdata = false; if (oldkey == NULL) { - foundold = true; + result = dns_rdataset_first(rdataset); } else { - foundold = false; + dst_key_free(&oldkey); val->key = NULL; + result = dns_rdataset_next(rdataset); } - - result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) { - goto failure; + goto done; } + do { dns_rdataset_current(rdataset, &rdata); isc_buffer_init(&b, rdata.data, rdata.length); isc_buffer_add(&b, rdata.length); INSIST(val->key == NULL); - result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b, - val->view->mctx, &val->key); + result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b, + val->view->mctx, no_rdata, + &val->key); if (result == ISC_R_SUCCESS) { if (siginfo->algorithm == (dns_secalg_t)dst_key_alg(val->key) && siginfo->keyid == (dns_keytag_t)dst_key_id(val->key) && + (dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) == + 0 && dst_key_iszonekey(val->key)) { - if (foundold) { - /* - * This is the key we're looking for. - */ - return (ISC_R_SUCCESS); - } else if (dst_key_compare(oldkey, val->key)) { - foundold = true; - dst_key_free(&oldkey); + if (no_rdata) { + /* Retry with full key */ + dns_rdata_reset(&rdata); + dst_key_free(&val->key); + no_rdata = false; + continue; } + /* This is the key we're looking for. */ + goto done; } dst_key_free(&val->key); } dns_rdata_reset(&rdata); result = dns_rdataset_next(rdataset); + no_rdata = true; } while (result == ISC_R_SUCCESS); +done: if (result == ISC_R_NOMORE) { result = ISC_R_NOTFOUND; } -failure: - if (oldkey != NULL) { - dst_key_free(&oldkey); - } - return (result); } @@ -1589,20 +1589,9 @@ validate_answer(dns_validator_t *val, bool resume) { continue; } - do { - isc_result_t tresult; - vresult = verify(val, val->key, &rdata, - val->siginfo->keyid); - if (vresult == ISC_R_SUCCESS) { - break; - } - - tresult = select_signing_key(val, val->keyset); - if (tresult != ISC_R_SUCCESS) { - break; - } - } while (1); + vresult = verify(val, val->key, &rdata, val->siginfo->keyid); if (vresult != ISC_R_SUCCESS) { + val->failed = true; validator_log(val, ISC_LOG_DEBUG(3), "failed to verify rdataset"); } else { @@ -1639,9 +1628,13 @@ validate_answer(dns_validator_t *val, bool resume) { } else { validator_log(val, ISC_LOG_DEBUG(3), "verify failure: %s", - isc_result_totext(result)); + isc_result_totext(vresult)); resume = false; } + if (val->failed) { + result = ISC_R_NOMORE; + break; + } } if (result != ISC_R_NOMORE) { validator_log(val, ISC_LOG_DEBUG(3), diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index 5c0ba7c..610d3ed 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -535,7 +535,6 @@ dns_message_clonebuffer dns_message_create dns_message_currentname dns_message_detach -dns_message_find dns_message_findname dns_message_findtype dns_message_firstname @@ -554,7 +553,6 @@ dns_message_gettsigkey dns_message_headertotext dns_message_logfmtpacket dns_message_logpacket -dns_message_movename dns_message_nextname dns_message_parse dns_message_peekheader @@ -1467,6 +1465,7 @@ dst_key_format dst_key_free dst_key_frombuffer dst_key_fromdns +dst_key_fromdns_ex dst_key_fromfile dst_key_fromgssapi dst_key_fromlabel diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 73da12e..ea02456 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -125,7 +125,7 @@ */ #define RANGE(a, min, max) (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max))) -#define NSEC3REMOVE(x) (((x)&DNS_NSEC3FLAG_REMOVE) != 0) +#define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) /*% * Key flags @@ -7034,8 +7034,9 @@ failure: static isc_result_t add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, - unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, - isc_stdtime_t expire, bool check_ksk, bool keyset_kskonly) { + unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t now, + isc_stdtime_t inception, isc_stdtime_t expire, bool check_ksk, + bool keyset_kskonly) { isc_result_t result; dns_dbnode_t *node = NULL; dns_stats_t *dnssecsignstats; @@ -7227,7 +7228,7 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone, continue; } } else if (!dst_key_is_signing(keys[i], DST_BOOL_ZSK, - inception, &when)) + now, &when)) { /* * This key is not active for zone-signing. @@ -7446,7 +7447,7 @@ zone_resigninc(dns_zone_t *zone) { */ result = add_sigs(db, version, name, zone, covers, zonediff.diff, zone_keys, nkeys, zone->mctx, - inception, + now, inception, resign > (now - 300) ? expire : fullexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { @@ -7509,7 +7510,7 @@ zone_resigninc(dns_zone_t *zone) { * termination is sensible. */ result = add_sigs(db, version, &zone->origin, zone, dns_rdatatype_soa, - zonediff.diff, zone_keys, nkeys, zone->mctx, + zonediff.diff, zone_keys, nkeys, zone->mctx, now, inception, soaexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, @@ -7745,10 +7746,11 @@ failure: static isc_result_t sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name, dns_dbnode_t *node, dns_dbversion_t *version, bool build_nsec3, - bool build_nsec, dst_key_t *key, isc_stdtime_t inception, - isc_stdtime_t expire, dns_ttl_t nsecttl, bool is_ksk, bool is_zsk, - bool keyset_kskonly, bool is_bottom_of_zone, dns_diff_t *diff, - int32_t *signatures, isc_mem_t *mctx) { + bool build_nsec, dst_key_t *key, isc_stdtime_t now, + isc_stdtime_t inception, isc_stdtime_t expire, dns_ttl_t nsecttl, + bool is_ksk, bool is_zsk, bool keyset_kskonly, + bool is_bottom_of_zone, dns_diff_t *diff, int32_t *signatures, + isc_mem_t *mctx) { isc_result_t result; dns_rdatasetiter_t *iterator = NULL; dns_rdataset_t rdataset; @@ -7843,8 +7845,8 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name, } } else if (!is_zsk) { goto next_rdataset; - } else if (is_zsk && !dst_key_is_signing(key, DST_BOOL_ZSK, - inception, &when)) + } else if (is_zsk && + !dst_key_is_signing(key, DST_BOOL_ZSK, now, &when)) { /* Only applies to dnssec-policy. */ if (dns_zone_getkasp(zone) != NULL) { @@ -8447,8 +8449,8 @@ dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, } result = add_sigs(db, version, &tuple->name, zone, tuple->rdata.type, zonediff->diff, zone_keys, - nkeys, zone->mctx, inception, exp, check_ksk, - keyset_kskonly); + nkeys, zone->mctx, now, inception, exp, + check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "dns__zone_updatesigs:add_sigs -> %s", @@ -9222,7 +9224,7 @@ skip_removals: } result = add_sigs(db, version, &zone->origin, zone, dns_rdatatype_soa, - zonediff.diff, zone_keys, nkeys, zone->mctx, + zonediff.diff, zone_keys, nkeys, zone->mctx, now, inception, soaexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, @@ -9843,8 +9845,8 @@ zone_sign(dns_zone_t *zone) { CHECK(sign_a_node( db, zone, name, node, version, build_nsec3, - build_nsec, zone_keys[i], inception, expire, - zone_nsecttl(zone), is_ksk, is_zsk, + build_nsec, zone_keys[i], now, inception, + expire, zone_nsecttl(zone), is_ksk, is_zsk, (both && keyset_kskonly), is_bottom_of_zone, zonediff.diff, &signatures, zone->mctx)); /* @@ -9979,7 +9981,7 @@ zone_sign(dns_zone_t *zone) { * termination is sensible. */ result = add_sigs(db, version, &zone->origin, zone, dns_rdatatype_soa, - zonediff.diff, zone_keys, nkeys, zone->mctx, + zonediff.diff, zone_keys, nkeys, zone->mctx, now, inception, soaexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_sign:add_sigs -> %s", @@ -17612,6 +17614,12 @@ again: DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); } + + /* + * Set loadtime. + */ + zone->loadtime = now; + if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) { char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; if (zone->tsigkey != NULL) { @@ -20405,7 +20413,7 @@ tickle_apex_rrset(dns_rdatatype_t rrtype, dns_zone_t *zone, dns_db_t *db, return (result); } result = add_sigs(db, ver, &zone->origin, zone, rrtype, - zonediff->diff, keys, nkeys, zone->mctx, + zonediff->diff, keys, nkeys, zone->mctx, now, inception, keyexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { diff --git a/lib/isc/ht.c b/lib/isc/ht.c index 07a36b4..e11050f 100644 --- a/lib/isc/ht.c +++ b/lib/isc/ht.c @@ -27,51 +27,274 @@ typedef struct isc_ht_node isc_ht_node_t; #define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b') #define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC) +#define HT_NO_BITS 0 +#define HT_MIN_BITS 1 +#define HT_MAX_BITS 32 +#define HT_OVERCOMMIT 3 + +#define HT_NEXTTABLE(idx) ((idx == 0) ? 1 : 0) +#define TRY_NEXTTABLE(idx, ht) (idx == ht->hindex && rehashing_in_progress(ht)) + +#define GOLDEN_RATIO_32 0x61C88647 + +#define HASHSIZE(bits) (UINT64_C(1) << (bits)) + struct isc_ht_node { void *value; isc_ht_node_t *next; + uint32_t hashval; size_t keysize; - unsigned char key[FLEXIBLE_ARRAY_MEMBER]; + unsigned char key[]; }; struct isc_ht { unsigned int magic; isc_mem_t *mctx; - size_t size; - size_t mask; - unsigned int count; - isc_ht_node_t **table; + size_t count; + bool case_sensitive; + size_t size[2]; + uint8_t hashbits[2]; + isc_ht_node_t **table[2]; + uint8_t hindex; + uint32_t hiter; /* rehashing iterator */ }; struct isc_ht_iter { isc_ht_t *ht; size_t i; + uint8_t hindex; isc_ht_node_t *cur; }; +static isc_ht_node_t * +isc__ht_find(const isc_ht_t *ht, const unsigned char *key, + const uint32_t keysize, const uint32_t hashval, const uint8_t idx); +static void +isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, + const uint32_t hashval, const uint8_t idx, void *value); +static isc_result_t +isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, + const uint32_t hashval, const uint8_t idx); + +static uint32_t +rehash_bits(isc_ht_t *ht, size_t newcount); + +static void +hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits); +static void +hashtable_free(isc_ht_t *ht, const uint8_t idx); +static void +hashtable_rehash(isc_ht_t *ht, uint32_t newbits); +static void +hashtable_rehash_one(isc_ht_t *ht); +static void +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, bool case_sensitive) { + return (node->hashval == hashval && node->keysize == keysize && + (case_sensitive ? (memcmp(node->key, key, keysize) == 0) + : (memcasecmp(node->key, key, keysize) == 0))); +} + +static uint32_t +hash_32(uint32_t val, unsigned int bits) { + REQUIRE(bits <= HT_MAX_BITS); + /* High bits are more random. */ + return (val * GOLDEN_RATIO_32 >> (32 - bits)); +} + +static bool +rehashing_in_progress(const isc_ht_t *ht) { + return (ht->table[HT_NEXTTABLE(ht->hindex)] != NULL); +} + +static bool +hashtable_is_overcommited(isc_ht_t *ht) { + return (ht->count >= (ht->size[ht->hindex] * HT_OVERCOMMIT)); +} + +static uint32_t +rehash_bits(isc_ht_t *ht, size_t newcount) { + uint32_t newbits = ht->hashbits[ht->hindex]; + + while (newcount >= HASHSIZE(newbits) && newbits <= HT_MAX_BITS) { + newbits += 1; + } + + return (newbits); +} + +/* + * Rebuild the hashtable to reduce the load factor + */ +static void +hashtable_rehash(isc_ht_t *ht, uint32_t newbits) { + uint8_t oldindex = ht->hindex; + uint32_t oldbits = ht->hashbits[oldindex]; + uint8_t newindex = HT_NEXTTABLE(oldindex); + + REQUIRE(ht->hashbits[oldindex] >= HT_MIN_BITS); + REQUIRE(ht->hashbits[oldindex] <= HT_MAX_BITS); + REQUIRE(ht->table[oldindex] != NULL); + + REQUIRE(newbits <= HT_MAX_BITS); + REQUIRE(ht->hashbits[newindex] == HT_NO_BITS); + REQUIRE(ht->table[newindex] == NULL); + + REQUIRE(newbits > oldbits); + + hashtable_new(ht, newindex, newbits); + + ht->hindex = newindex; + + hashtable_rehash_one(ht); +} + +static void +hashtable_rehash_one(isc_ht_t *ht) { + isc_ht_node_t **newtable = ht->table[ht->hindex]; + uint32_t oldsize = ht->size[HT_NEXTTABLE(ht->hindex)]; + isc_ht_node_t **oldtable = ht->table[HT_NEXTTABLE(ht->hindex)]; + isc_ht_node_t *node = NULL; + isc_ht_node_t *nextnode; + + /* Find first non-empty node */ + while (ht->hiter < oldsize && oldtable[ht->hiter] == NULL) { + ht->hiter++; + } + + /* Rehashing complete */ + if (ht->hiter == oldsize) { + hashtable_free(ht, HT_NEXTTABLE(ht->hindex)); + ht->hiter = 0; + return; + } + + /* Move the first non-empty node from old hashtable to new hashtable */ + for (node = oldtable[ht->hiter]; node != NULL; node = nextnode) { + uint32_t hash = hash_32(node->hashval, + ht->hashbits[ht->hindex]); + nextnode = node->next; + node->next = newtable[hash]; + newtable[hash] = node; + } + + oldtable[ht->hiter] = NULL; + + ht->hiter++; +} + +static void +maybe_rehash(isc_ht_t *ht, size_t newcount) { + uint32_t newbits = rehash_bits(ht, newcount); + + if (ht->hashbits[ht->hindex] < newbits && newbits <= HT_MAX_BITS) { + hashtable_rehash(ht, newbits); + } +} + +static void +hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits) { + size_t size; + REQUIRE(ht->hashbits[idx] == HT_NO_BITS); + REQUIRE(ht->table[idx] == NULL); + REQUIRE(bits >= HT_MIN_BITS); + REQUIRE(bits <= HT_MAX_BITS); + + ht->hashbits[idx] = bits; + ht->size[idx] = HASHSIZE(ht->hashbits[idx]); + + size = ht->size[idx] * sizeof(isc_ht_node_t *); + + ht->table[idx] = isc_mem_get(ht->mctx, size); + memset(ht->table[idx], 0, size); +} + +static void +hashtable_free(isc_ht_t *ht, const uint8_t idx) { + size_t size = ht->size[idx] * sizeof(isc_ht_node_t *); + + for (size_t i = 0; i < ht->size[idx]; i++) { + isc_ht_node_t *node = ht->table[idx][i]; + while (node != NULL) { + isc_ht_node_t *next = node->next; + ht->count--; + isc_mem_put(ht->mctx, node, + sizeof(*node) + node->keysize); + node = next; + } + } + + isc_mem_put(ht->mctx, ht->table[idx], size); + ht->hashbits[idx] = HT_NO_BITS; + ht->table[idx] = NULL; +} + void -isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { +isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits, + unsigned int options) { isc_ht_t *ht = NULL; - size_t i; + bool case_sensitive = ((options & ISC_HT_CASE_INSENSITIVE) == 0); REQUIRE(htp != NULL && *htp == NULL); REQUIRE(mctx != NULL); - REQUIRE(bits >= 1 && bits <= (sizeof(size_t) * 8 - 1)); + REQUIRE(bits >= 1 && bits <= HT_MAX_BITS); - ht = isc_mem_get(mctx, sizeof(struct isc_ht)); + ht = isc_mem_get(mctx, sizeof(*ht)); + *ht = (isc_ht_t){ + .case_sensitive = case_sensitive, + }; - ht->mctx = NULL; isc_mem_attach(mctx, &ht->mctx); - ht->size = ((size_t)1 << bits); - ht->mask = ((size_t)1 << bits) - 1; - ht->count = 0; - - ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t *)); - - for (i = 0; i < ht->size; i++) { - ht->table[i] = NULL; - } + hashtable_new(ht, 0, bits); ht->magic = ISC_HT_MAGIC; @@ -81,128 +304,186 @@ isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { void isc_ht_destroy(isc_ht_t **htp) { isc_ht_t *ht; - size_t i; REQUIRE(htp != NULL); + REQUIRE(ISC_HT_VALID(*htp)); ht = *htp; *htp = NULL; - - REQUIRE(ISC_HT_VALID(ht)); - ht->magic = 0; - for (i = 0; i < ht->size; i++) { - isc_ht_node_t *node = ht->table[i]; - while (node != NULL) { - isc_ht_node_t *next = node->next; - ht->count--; - isc_mem_put(ht->mctx, node, - offsetof(isc_ht_node_t, key) + - node->keysize); - node = next; + for (size_t i = 0; i <= 1; i++) { + if (ht->table[i] != NULL) { + hashtable_free(ht, i); } } INSIST(ht->count == 0); - isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t *)); - isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht)); + isc_mem_putanddetach(&ht->mctx, ht, sizeof(*ht)); } -isc_result_t -isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize, - void *value) { +static void +isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, + const uint32_t hashval, const uint8_t idx, void *value) { isc_ht_node_t *node; uint32_t hash; + hash = hash_32(hashval, ht->hashbits[idx]); + + node = isc_mem_get(ht->mctx, sizeof(*node) + keysize); + *node = (isc_ht_node_t){ + .keysize = keysize, + .hashval = hashval, + .next = ht->table[idx][hash], + .value = value, + }; + + memmove(node->key, key, keysize); + + ht->count++; + ht->table[idx][hash] = node; +} + +isc_result_t +isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, + void *value) { + uint32_t hashval; + REQUIRE(ISC_HT_VALID(ht)); REQUIRE(key != NULL && keysize > 0); - hash = isc_hash_function(key, keysize, true); - node = ht->table[hash & ht->mask]; - while (node != NULL) { - if (keysize == node->keysize && - memcmp(key, node->key, keysize) == 0) - { - return (ISC_R_EXISTS); - } - node = node->next; + if (rehashing_in_progress(ht)) { + /* Rehash in progress */ + hashtable_rehash_one(ht); + } else if (hashtable_is_overcommited(ht)) { + /* Rehash requested */ + maybe_rehash(ht, ht->count); } - node = isc_mem_get(ht->mctx, offsetof(isc_ht_node_t, key) + keysize); + hashval = isc_hash32(key, keysize, ht->case_sensitive); - memmove(node->key, key, keysize); - node->keysize = keysize; - node->next = ht->table[hash & ht->mask]; - node->value = value; + if (isc__ht_find(ht, key, keysize, hashval, ht->hindex) != NULL) { + return (ISC_R_EXISTS); + } + + isc__ht_add(ht, key, keysize, hashval, ht->hindex, value); - ht->count++; - ht->table[hash & ht->mask] = node; return (ISC_R_SUCCESS); } +static isc_ht_node_t * +isc__ht_find(const isc_ht_t *ht, const unsigned char *key, + const uint32_t keysize, const uint32_t hashval, + const uint8_t idx) { + uint32_t hash; + uint8_t findex = idx; + +nexttable: + hash = hash_32(hashval, ht->hashbits[findex]); + for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL; + node = node->next) + { + if (isc__ht_node_match(node, hashval, key, keysize, + ht->case_sensitive)) + { + return (node); + } + } + if (TRY_NEXTTABLE(findex, ht)) { + /* + * Rehashing in progress, check the other table + */ + findex = HT_NEXTTABLE(findex); + goto nexttable; + } + + return (NULL); +} + isc_result_t -isc_ht_find(const isc_ht_t *ht, const unsigned char *key, uint32_t keysize, - void **valuep) { +isc_ht_find(const isc_ht_t *ht, const unsigned char *key, + const uint32_t keysize, void **valuep) { + uint32_t hashval; isc_ht_node_t *node; - uint32_t hash; REQUIRE(ISC_HT_VALID(ht)); REQUIRE(key != NULL && keysize > 0); REQUIRE(valuep == NULL || *valuep == NULL); - hash = isc_hash_function(key, keysize, true); - node = ht->table[hash & ht->mask]; - while (node != NULL) { - if (keysize == node->keysize && - memcmp(key, node->key, keysize) == 0) - { - if (valuep != NULL) { - *valuep = node->value; - } - return (ISC_R_SUCCESS); - } - node = node->next; + hashval = isc_hash32(key, keysize, ht->case_sensitive); + + node = isc__ht_find(ht, key, keysize, hashval, ht->hindex); + if (node == NULL) { + return (ISC_R_NOTFOUND); } - return (ISC_R_NOTFOUND); + if (valuep != NULL) { + *valuep = node->value; + } + return (ISC_R_SUCCESS); } -isc_result_t -isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) { - isc_ht_node_t *node, *prev; +static isc_result_t +isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, + const uint32_t hashval, const uint8_t idx) { + isc_ht_node_t *prev = NULL; uint32_t hash; - REQUIRE(ISC_HT_VALID(ht)); - REQUIRE(key != NULL && keysize > 0); + hash = hash_32(hashval, ht->hashbits[idx]); - prev = NULL; - hash = isc_hash_function(key, keysize, true); - node = ht->table[hash & ht->mask]; - while (node != NULL) { - if (keysize == node->keysize && - memcmp(key, node->key, keysize) == 0) + 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, + ht->case_sensitive)) { if (prev == NULL) { - ht->table[hash & ht->mask] = node->next; + ht->table[idx][hash] = node->next; } else { prev->next = node->next; } isc_mem_put(ht->mctx, node, - offsetof(isc_ht_node_t, key) + - node->keysize); + sizeof(*node) + node->keysize); ht->count--; return (ISC_R_SUCCESS); } - - prev = node; - node = node->next; } + return (ISC_R_NOTFOUND); } +isc_result_t +isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize) { + uint32_t hashval; + uint8_t hindex; + isc_result_t result; + + REQUIRE(ISC_HT_VALID(ht)); + REQUIRE(key != NULL && keysize > 0); + + if (rehashing_in_progress(ht)) { + /* Rehash in progress */ + hashtable_rehash_one(ht); + } + + hindex = ht->hindex; + hashval = isc_hash32(key, keysize, ht->case_sensitive); +nexttable: + result = isc__ht_delete(ht, key, keysize, hashval, hindex); + + if (result == ISC_R_NOTFOUND && TRY_NEXTTABLE(hindex, ht)) { + /* + * Rehashing in progress, check the other table + */ + hindex = HT_NEXTTABLE(hindex); + goto nexttable; + } + + return (result); +} + void isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { isc_ht_iter_t *it; @@ -211,10 +492,10 @@ isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { REQUIRE(itp != NULL && *itp == NULL); it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t)); - - it->ht = ht; - it->i = 0; - it->cur = NULL; + *it = (isc_ht_iter_t){ + .ht = ht, + .hindex = ht->hindex, + }; *itp = it; } @@ -229,25 +510,46 @@ isc_ht_iter_destroy(isc_ht_iter_t **itp) { it = *itp; *itp = NULL; ht = it->ht; - isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t)); + isc_mem_put(ht->mctx, it, sizeof(*it)); } isc_result_t isc_ht_iter_first(isc_ht_iter_t *it) { + isc_ht_t *ht; + REQUIRE(it != NULL); + ht = it->ht; + + it->hindex = ht->hindex; it->i = 0; - while (it->i < it->ht->size && it->ht->table[it->i] == NULL) { + + return (isc__ht_iter_next(it)); +} + +static isc_result_t +isc__ht_iter_next(isc_ht_iter_t *it) { + isc_ht_t *ht = it->ht; + + while (it->i < ht->size[it->hindex] && + ht->table[it->hindex][it->i] == NULL) + { it->i++; } - if (it->i == it->ht->size) { - return (ISC_R_NOMORE); + if (it->i < ht->size[it->hindex]) { + it->cur = ht->table[it->hindex][it->i]; + + return (ISC_R_SUCCESS); } - it->cur = it->ht->table[it->i]; + if (TRY_NEXTTABLE(it->hindex, ht)) { + it->hindex = HT_NEXTTABLE(it->hindex); + it->i = 0; + return (isc__ht_iter_next(it)); + } - return (ISC_R_SUCCESS); + return (ISC_R_NOMORE); } isc_result_t @@ -256,60 +558,36 @@ isc_ht_iter_next(isc_ht_iter_t *it) { REQUIRE(it->cur != NULL); it->cur = it->cur->next; - if (it->cur == NULL) { - do { - it->i++; - } while (it->i < it->ht->size && it->ht->table[it->i] == NULL); - if (it->i >= it->ht->size) { - return (ISC_R_NOMORE); - } - it->cur = it->ht->table[it->i]; + + if (it->cur != NULL) { + return (ISC_R_SUCCESS); } - return (ISC_R_SUCCESS); + it->i++; + + return (isc__ht_iter_next(it)); } isc_result_t isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) { isc_result_t result = ISC_R_SUCCESS; - isc_ht_node_t *to_delete = NULL; - isc_ht_node_t *prev = NULL; - isc_ht_node_t *node = NULL; - uint32_t hash; + isc_ht_node_t *dnode = NULL; + uint8_t dindex; isc_ht_t *ht; + isc_result_t dresult; + REQUIRE(it != NULL); REQUIRE(it->cur != NULL); - to_delete = it->cur; - ht = it->ht; - it->cur = it->cur->next; - if (it->cur == NULL) { - do { - it->i++; - } while (it->i < ht->size && ht->table[it->i] == NULL); - if (it->i >= ht->size) { - result = ISC_R_NOMORE; - } else { - it->cur = ht->table[it->i]; - } - } + ht = it->ht; + dnode = it->cur; + dindex = it->hindex; - hash = isc_hash_function(to_delete->key, to_delete->keysize, true); - node = ht->table[hash & ht->mask]; - while (node != to_delete) { - prev = node; - node = node->next; - INSIST(node != NULL); - } + result = isc_ht_iter_next(it); - if (prev == NULL) { - ht->table[hash & ht->mask] = node->next; - } else { - prev->next = node->next; - } - isc_mem_put(ht->mctx, node, - offsetof(isc_ht_node_t, key) + node->keysize); - ht->count--; + dresult = isc__ht_delete(ht, dnode->key, dnode->keysize, dnode->hashval, + dindex); + INSIST(dresult == ISC_R_SUCCESS); return (result); } @@ -334,8 +612,8 @@ isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, *keysize = it->cur->keysize; } -unsigned int -isc_ht_count(isc_ht_t *ht) { +size_t +isc_ht_count(const isc_ht_t *ht) { REQUIRE(ISC_HT_VALID(ht)); return (ht->count); diff --git a/lib/isc/include/isc/endian.h b/lib/isc/include/isc/endian.h index e598a7b..9b4f635 100644 --- a/lib/isc/include/isc/endian.h +++ b/lib/isc/include/isc/endian.h @@ -110,29 +110,29 @@ #include <inttypes.h> #ifndef bswap_16 -#define bswap_16(x) \ - ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | \ - (((uint16_t)(x)&0x00ff) << 8))) +#define bswap_16(x) \ + ((uint16_t)((((uint16_t)(x) & 0xff00) >> 8) | \ + (((uint16_t)(x) & 0x00ff) << 8))) #endif /* !bswap_16 */ #ifndef bswap_32 -#define bswap_32(x) \ - ((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | \ - (((uint32_t)(x)&0x00ff0000) >> 8) | \ - (((uint32_t)(x)&0x0000ff00) << 8) | \ - (((uint32_t)(x)&0x000000ff) << 24))) +#define bswap_32(x) \ + ((uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | \ + (((uint32_t)(x) & 0x00ff0000) >> 8) | \ + (((uint32_t)(x) & 0x0000ff00) << 8) | \ + (((uint32_t)(x) & 0x000000ff) << 24))) #endif /* !bswap_32 */ #ifndef bswap_64 -#define bswap_64(x) \ - ((uint64_t)((((uint64_t)(x)&0xff00000000000000ULL) >> 56) | \ - (((uint64_t)(x)&0x00ff000000000000ULL) >> 40) | \ - (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24) | \ - (((uint64_t)(x)&0x000000ff00000000ULL) >> 8) | \ - (((uint64_t)(x)&0x00000000ff000000ULL) << 8) | \ - (((uint64_t)(x)&0x0000000000ff0000ULL) << 24) | \ - (((uint64_t)(x)&0x000000000000ff00ULL) << 40) | \ - (((uint64_t)(x)&0x00000000000000ffULL) << 56))) +#define bswap_64(x) \ + ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ + (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) #endif /* !bswap_64 */ #ifndef htobe16 diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h index f1386bb..163fbef 100644 --- a/lib/isc/include/isc/ht.h +++ b/lib/isc/include/isc/ht.h @@ -13,8 +13,7 @@ /* ! \file */ -#ifndef ISC_HT_H -#define ISC_HT_H 1 +#pragma once #include <inttypes.h> #include <string.h> @@ -25,9 +24,15 @@ typedef struct isc_ht isc_ht_t; typedef struct isc_ht_iter isc_ht_iter_t; +enum { ISC_HT_CASE_SENSITIVE = 0x00, ISC_HT_CASE_INSENSITIVE = 0x01 }; + /*% * Initialize hashtable at *htp, using memory context and size of (1<<bits) * + * If 'options' contains ISC_HT_CASE_INSENSITIVE, then upper- and lower-case + * letters in key values will generate the same hash values; this can be used + * when the key for a hash table is a DNS name. + * * Requires: *\li 'htp' is not NULL and '*htp' is NULL. *\li 'mctx' is a valid memory context. @@ -35,7 +40,8 @@ typedef struct isc_ht_iter isc_ht_iter_t; * */ void -isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits); +isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits, + unsigned int options); /*% * Destroy hashtable, freeing everything @@ -52,6 +58,7 @@ isc_ht_destroy(isc_ht_t **htp); * * Requires: *\li 'ht' is a valid hashtable + *\li write-lock * * Returns: *\li #ISC_R_NOMEMORY -- not enough memory to create pool @@ -59,7 +66,7 @@ isc_ht_destroy(isc_ht_t **htp); *\li #ISC_R_SUCCESS -- all is well. */ isc_result_t -isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize, +isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, void *value); /*% @@ -70,27 +77,29 @@ isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize, * * Requires: * \li 'ht' is a valid hashtable + * \li read-lock * * Returns: * \li #ISC_R_SUCCESS -- success * \li #ISC_R_NOTFOUND -- key not found */ isc_result_t -isc_ht_find(const isc_ht_t *ht, const unsigned char *key, uint32_t keysize, - void **valuep); +isc_ht_find(const isc_ht_t *ht, const unsigned char *key, + const uint32_t keysize, void **valuep); /*% * Delete node from hashtable * * Requires: *\li ht is a valid hashtable + *\li write-lock * * Returns: *\li #ISC_R_NOTFOUND -- key not found *\li #ISC_R_SUCCESS -- all is well */ isc_result_t -isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize); +isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize); /*% * Create an iterator for the hashtable; point '*itp' to it. @@ -178,6 +187,5 @@ isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize); * Requires: *\li 'ht' is a valid hashtable */ -unsigned int -isc_ht_count(isc_ht_t *ht); -#endif /* ifndef ISC_HT_H */ +size_t +isc_ht_count(const isc_ht_t *ht); diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index f1747be..efeb5f3 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -479,6 +479,9 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, * 'cb'. */ +#define ISC_NM_TASK_SLOW_OFFSET -2 +#define ISC_NM_TASK_SLOW(i) (ISC_NM_TASK_SLOW_OFFSET - 1 - i) + void isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid); /*%< diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h index 7c004e9..93b0aae 100644 --- a/lib/isc/include/isc/radix.h +++ b/lib/isc/include/isc/radix.h @@ -193,7 +193,7 @@ isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func); */ #define RADIX_MAXBITS 128 -#define RADIX_NBIT(x) (0x80 >> ((x)&0x7f)) +#define RADIX_NBIT(x) (0x80 >> ((x) & 0x7f)) #define RADIX_NBYTE(x) ((x) >> 3) #define RADIX_WALK(Xhead, Xnode) \ diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h index a3a5079..61c5d7b 100644 --- a/lib/isc/include/isc/resultclass.h +++ b/lib/isc/include/isc/resultclass.h @@ -29,7 +29,7 @@ #define ISC_RESULTCLASS_TONUM(rclass) ((rclass) >> 16) #define ISC_RESULTCLASS_SIZE 65536 #define ISC_RESULTCLASS_INCLASS(rclass, result) \ - ((rclass) == ((result)&0xFFFF0000)) + ((rclass) == ((result) & 0xFFFF0000)) #define ISC_RESULTCLASS_ISC ISC_RESULTCLASS_FROMNUM(0) #define ISC_RESULTCLASS_DNS ISC_RESULTCLASS_FROMNUM(1) diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c index 39aaae6..62ce195 100644 --- a/lib/isc/netaddr.c +++ b/lib/isc/netaddr.c @@ -436,7 +436,7 @@ isc_netaddr_issitelocal(const isc_netaddr_t *na) { } #define ISC_IPADDR_ISNETZERO(i) \ - (((uint32_t)(i)&ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000)) + (((uint32_t)(i) & ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000)) bool isc_netaddr_isnetzero(const isc_netaddr_t *na) { diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 05fde1a..c3a1762 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -655,6 +655,7 @@ struct isc_nm { isc_refcount_t references; isc_mem_t *mctx; int nworkers; + int nlisteners; isc_mutex_t lock; isc_condition_t wkstatecond; isc_condition_t wkpausecond; diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 6f42ec9..7bff1cc 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -231,12 +231,12 @@ isc__nm_winsock_destroy(void) { #endif /* WIN32 */ static void -isc__nm_threadpool_initialize(uint32_t workers) { +isc__nm_threadpool_initialize(uint32_t nworkers) { char buf[11]; int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf, &(size_t){ sizeof(buf) }); if (r == UV_ENOENT) { - snprintf(buf, sizeof(buf), "%" PRIu32, workers); + snprintf(buf, sizeof(buf), "%" PRIu32, nworkers); uv_os_setenv("UV_THREADPOOL_SIZE", buf); } } @@ -254,11 +254,11 @@ isc__nm_threadpool_initialize(uint32_t workers) { #endif void -isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { +isc__netmgr_create(isc_mem_t *mctx, uint32_t nworkers, isc_nm_t **netmgrp) { isc_nm_t *mgr = NULL; char name[32]; - REQUIRE(workers > 0); + REQUIRE(nworkers > 0); #ifdef MAXIMAL_UV_VERSION if (uv_version() > MAXIMAL_UV_VERSION) { @@ -282,10 +282,13 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { isc__nm_winsock_initialize(); #endif /* WIN32 */ - isc__nm_threadpool_initialize(workers); + isc__nm_threadpool_initialize(nworkers); mgr = isc_mem_get(mctx, sizeof(*mgr)); - *mgr = (isc_nm_t){ .nworkers = workers }; + *mgr = (isc_nm_t){ + .nworkers = nworkers * 2, + .nlisteners = nworkers, + }; isc_mem_attach(mctx, &mgr->mctx); isc_mutex_init(&mgr->lock); @@ -316,11 +319,12 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { atomic_init(&mgr->keepalive, 30000); atomic_init(&mgr->advertised, 30000); - isc_barrier_init(&mgr->pausing, workers); - isc_barrier_init(&mgr->resuming, workers); + isc_barrier_init(&mgr->pausing, mgr->nworkers); + isc_barrier_init(&mgr->resuming, mgr->nworkers); - mgr->workers = isc_mem_get(mctx, workers * sizeof(isc__networker_t)); - for (size_t i = 0; i < workers; i++) { + mgr->workers = isc_mem_get(mctx, + mgr->nworkers * sizeof(isc__networker_t)); + for (int i = 0; i < mgr->nworkers; i++) { isc__networker_t *worker = &mgr->workers[i]; int r; @@ -354,7 +358,7 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { mgr->workers_running++; isc_thread_create(nm_thread, &mgr->workers[i], &worker->thread); - snprintf(name, sizeof(name), "isc-net-%04zu", i); + snprintf(name, sizeof(name), "isc-net-%04d", i); isc_thread_setname(worker->thread, name); } @@ -840,9 +844,15 @@ isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) { isc__networker_t *worker = NULL; if (threadid == -1) { - tid = (int)isc_random_uniform(nm->nworkers); + tid = (int)isc_random_uniform(nm->nlisteners); + } else if (threadid == ISC_NM_TASK_SLOW_OFFSET) { + tid = nm->nlisteners + + (int)isc_random_uniform(nm->nworkers - nm->nlisteners); + } else if (threadid < ISC_NM_TASK_SLOW_OFFSET) { + tid = nm->nlisteners + (ISC_NM_TASK_SLOW(threadid) % + (nm->nworkers - nm->nlisteners)); } else { - tid = threadid % nm->nworkers; + tid = threadid % nm->nlisteners; } worker = &nm->workers[tid]; diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 821d6c4..1666318 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -323,7 +323,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc__nm_connectcb(sock, req, result, false); } else { isc__nmsocket_clearcb(sock); - sock->tid = isc_random_uniform(mgr->nworkers); + sock->tid = isc_random_uniform(mgr->nlisteners); isc__nm_connectcb(sock, req, result, true); } atomic_store(&sock->closed, true); @@ -341,7 +341,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc__nm_put_netievent_tcpconnect(mgr, ievent); } else { atomic_init(&sock->active, false); - sock->tid = isc_random_uniform(mgr->nworkers); + sock->tid = isc_random_uniform(mgr->nlisteners); isc__nm_enqueue_ievent(&mgr->workers[sock->tid], (isc__netievent_t *)ievent); } @@ -445,7 +445,7 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface, #if defined(WIN32) sock->nchildren = 1; #else - sock->nchildren = mgr->nworkers; + sock->nchildren = mgr->nlisteners; #endif children_size = sock->nchildren * sizeof(sock->children[0]); sock->children = isc_mem_get(mgr->mctx, children_size); diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index bd593eb..037d74c 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -303,7 +303,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc__nm_put_netievent_tcpdnsconnect(mgr, ievent); } else { atomic_init(&sock->active, false); - sock->tid = isc_random_uniform(mgr->nworkers); + sock->tid = isc_random_uniform(mgr->nlisteners); isc__nm_enqueue_ievent(&mgr->workers[sock->tid], (isc__netievent_t *)ievent); } @@ -410,7 +410,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface, #if defined(WIN32) sock->nchildren = 1; #else - sock->nchildren = mgr->nworkers; + sock->nchildren = mgr->nlisteners; #endif children_size = sock->nchildren * sizeof(sock->children[0]); sock->children = isc_mem_get(mgr->mctx, children_size); diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 00f9d40..bc59fca 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -136,7 +136,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb, uv_os_sock_t fd = -1; /* - * We are creating mgr->nworkers duplicated sockets, one + * We are creating mgr->nlisteners duplicated sockets, one * socket for each worker thread. */ sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t)); @@ -146,7 +146,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb, #if defined(WIN32) sock->nchildren = 1; #else - sock->nchildren = mgr->nworkers; + sock->nchildren = mgr->nlisteners; #endif children_size = sock->nchildren * sizeof(sock->children[0]); @@ -847,7 +847,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc__nm_put_netievent_udpconnect(mgr, event); } else { atomic_init(&sock->active, false); - sock->tid = isc_random_uniform(mgr->nworkers); + sock->tid = isc_random_uniform(mgr->nlisteners); isc__nm_enqueue_ievent(&mgr->workers[sock->tid], (isc__netievent_t *)event); } diff --git a/lib/isc/netmgr/uv-compat.h b/lib/isc/netmgr/uv-compat.h index 3a10387..eea8744 100644 --- a/lib/isc/netmgr/uv-compat.h +++ b/lib/isc/netmgr/uv-compat.h @@ -72,7 +72,7 @@ uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb); #endif #if UV_VERSION_HEX < UV_VERSION(1, 34, 0) -#define uv_sleep(msec) usleep(msec * 1000) +#define uv_sleep(msec) usleep((msec) * 1000) #endif /* UV_VERSION_HEX < UV_VERSION(1, 34, 0) */ #if UV_VERSION_HEX < UV_VERSION(1, 27, 0) diff --git a/lib/isc/tests/ht_test.c b/lib/isc/tests/ht_test.c index 30cc615..cc824c3 100644 --- a/lib/isc/tests/ht_test.c +++ b/lib/isc/tests/ht_test.c @@ -61,7 +61,7 @@ test_ht_full(int bits, uintptr_t count) { isc_result_t result; uintptr_t i; - isc_ht_init(&ht, test_mctx, bits); + isc_ht_init(&ht, test_mctx, bits, ISC_HT_CASE_SENSITIVE); assert_non_null(ht); for (i = 1; i < count; i++) { @@ -206,7 +206,7 @@ test_ht_iterator() { unsigned char key[16]; size_t tksize; - isc_ht_init(&ht, test_mctx, 16); + isc_ht_init(&ht, test_mctx, 16, ISC_HT_CASE_SENSITIVE); assert_non_null(ht); for (i = 1; i <= count; i++) { /* @@ -333,9 +333,62 @@ isc_ht_iterator_test(void **state) { test_ht_iterator(); } +static void +isc_ht_case(void **state) { + UNUSED(state); + + isc_ht_t *ht = NULL; + void *f = NULL; + isc_result_t result = ISC_R_UNSET; + + unsigned char lower[16] = { "test case" }; + unsigned char same[16] = { "test case" }; + unsigned char upper[16] = { "TEST CASE" }; + unsigned char mixed[16] = { "tEsT CaSe" }; + + isc_ht_init(&ht, test_mctx, 8, ISC_HT_CASE_SENSITIVE); + assert_non_null(ht); + + result = isc_ht_add(ht, lower, 16, (void *)lower); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_ht_add(ht, same, 16, (void *)same); + assert_int_equal(result, ISC_R_EXISTS); + + result = isc_ht_add(ht, upper, 16, (void *)upper); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_ht_find(ht, mixed, 16, &f); + assert_int_equal(result, ISC_R_NOTFOUND); + assert_null(f); + + isc_ht_destroy(&ht); + assert_null(ht); + + isc_ht_init(&ht, test_mctx, 8, ISC_HT_CASE_INSENSITIVE); + assert_non_null(ht); + + result = isc_ht_add(ht, lower, 16, (void *)lower); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_ht_add(ht, same, 16, (void *)same); + assert_int_equal(result, ISC_R_EXISTS); + + result = isc_ht_add(ht, upper, 16, (void *)upper); + assert_int_equal(result, ISC_R_EXISTS); + + result = isc_ht_find(ht, mixed, 16, &f); + assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, &lower); + + isc_ht_destroy(&ht); + assert_null(ht); +} + int main(void) { const struct CMUnitTest tests[] = { + cmocka_unit_test(isc_ht_case), cmocka_unit_test(isc_ht_20), cmocka_unit_test(isc_ht_8), cmocka_unit_test(isc_ht_1), diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h index ead9c7f..9401ef7 100644 --- a/lib/isc/unix/include/isc/net.h +++ b/lib/isc/unix/include/isc/net.h @@ -194,10 +194,10 @@ /*% Is IP address multicast? */ #define ISC_IPADDR_ISMULTICAST(i) \ - (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xe0000000)) + (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xe0000000)) #define ISC_IPADDR_ISEXPERIMENTAL(i) \ - (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xf0000000)) + (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xf0000000)) /*** *** Functions. diff --git a/lib/isc/url.c b/lib/isc/url.c index cccb712..320a863 100644 --- a/lib/isc/url.c +++ b/lib/isc/url.c @@ -44,7 +44,7 @@ #ifndef BIT_AT #define BIT_AT(a, i) \ (!!((unsigned int)(a)[(unsigned int)(i) >> 3] & \ - (1 << ((unsigned int)(i)&7)))) + (1 << ((unsigned int)(i) & 7)))) #endif #if HTTP_PARSER_STRICT @@ -201,7 +201,8 @@ typedef enum { #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) #define IS_HOST_CHAR(c) (isalnum((unsigned char)c) || (c) == '.' || (c) == '-') #else -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80)) +#define IS_URL_CHAR(c) \ + (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) #define IS_HOST_CHAR(c) \ (isalnum((unsigned char)c) || (c) == '.' || (c) == '-' || (c) == '_') #endif diff --git a/lib/isc/win32/file.c b/lib/isc/win32/file.c index 32f6a19..7da57fc 100644 --- a/lib/isc/win32/file.c +++ b/lib/isc/win32/file.c @@ -569,10 +569,14 @@ isc_file_isabsolute(const char *filename) { if ((filename[0] == '\\') && (filename[1] == '\\')) { return (true); } - if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\') { + if (isalpha((unsigned char)filename[0]) && filename[1] == ':' && + filename[2] == '\\') + { return (true); } - if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') { + if (isalpha((unsigned char)filename[0]) && filename[1] == ':' && + filename[2] == '/') + { return (true); } return (false); diff --git a/lib/isc/win32/fsaccess.c b/lib/isc/win32/fsaccess.c index 909f9e5..eb1ab54 100644 --- a/lib/isc/win32/fsaccess.c +++ b/lib/isc/win32/fsaccess.c @@ -70,7 +70,7 @@ is_ntfs(const char *file) { * Look for c:\path\... style, c:/path/... or \\computer\shar\path... * the UNC style file specs */ - if (isalpha(filename[0]) && filename[1] == ':' && + if (isalpha((unsigned char)filename[0]) && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/')) { /* Copy 'c:\' or 'c:/' and NUL terminate. */ diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h index 391614e..3f17223 100644 --- a/lib/isc/win32/include/isc/net.h +++ b/lib/isc/win32/include/isc/net.h @@ -123,10 +123,10 @@ typedef uint16_t in_port_t; #define ISC__IPADDR(x) ((uint32_t)htonl((uint32_t)(x))) #define ISC_IPADDR_ISMULTICAST(i) \ - (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xe0000000)) + (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xe0000000)) #define ISC_IPADDR_ISEXPERIMENTAL(i) \ - (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xf0000000)) + (((uint32_t)(i) & ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xf0000000)) /* * Fix the FD_SET and FD_CLR Macros to properly cast diff --git a/lib/isc/win32/include/isc/stat.h b/lib/isc/win32/include/isc/stat.h index 63577f9..bc0ec04 100644 --- a/lib/isc/win32/include/isc/stat.h +++ b/lib/isc/win32/include/isc/stat.h @@ -49,10 +49,10 @@ typedef unsigned short mode_t; #endif /* ifndef S_IFREG */ #ifndef S_ISDIR -#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* ifndef S_ISDIR */ #ifndef S_ISREG -#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* ifndef S_ISREG */ #endif /* ISC_STAT_H */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 4503b8d..1290c30 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -196,7 +196,7 @@ client_trace(ns_client_t *client, int level, const char *message) { #define DNS_GETDB_IGNOREACL 0x08U #define DNS_GETDB_STALEFIRST 0X0CU -#define PENDINGOK(x) (((x)&DNS_DBFIND_PENDINGOK) != 0) +#define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0) #define SFCACHE_CDFLAG 0x1 @@ -455,10 +455,10 @@ static void query_addnxrrsetnsec(query_ctx_t *qctx); static isc_result_t -query_nxdomain(query_ctx_t *qctx, bool empty_wild); +query_nxdomain(query_ctx_t *qctx, isc_result_t result); static isc_result_t -query_redirect(query_ctx_t *qctx); +query_redirect(query_ctx_t *qctx, isc_result_t result); static isc_result_t query_ncache(query_ctx_t *qctx, isc_result_t result); @@ -6095,6 +6095,13 @@ query_lookup_stale(ns_client_t *client) { query_ctx_t qctx; qctx_init(client, NULL, client->query.qtype, &qctx); + if (DNS64(client)) { + qctx.qtype = qctx.type = dns_rdatatype_a; + qctx.dns64 = true; + } + if (DNS64EXCLUDE(client)) { + qctx.dns64_exclude = true; + } dns_db_attach(client->view->cachedb, &qctx.db); client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK; client->query.dboptions |= DNS_DBFIND_STALETIMEOUT; @@ -7345,8 +7352,7 @@ query_usestale(query_ctx_t *qctx, isc_result_t result) { * result from the search. */ static isc_result_t -query_gotanswer(query_ctx_t *qctx, isc_result_t res) { - isc_result_t result = res; +query_gotanswer(query_ctx_t *qctx, isc_result_t result) { char errmsg[256]; CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); @@ -7416,16 +7422,16 @@ root_key_sentinel: return (query_nodata(qctx, DNS_R_NXRRSET)); case DNS_R_EMPTYWILD: - return (query_nxdomain(qctx, true)); + return (query_nxdomain(qctx, DNS_R_EMPTYWILD)); case DNS_R_NXDOMAIN: - return (query_nxdomain(qctx, false)); + return (query_nxdomain(qctx, DNS_R_NXDOMAIN)); case DNS_R_COVERINGNSEC: return (query_coveringnsec(qctx)); case DNS_R_NCACHENXDOMAIN: - result = query_redirect(qctx); + result = query_redirect(qctx, result); if (result != ISC_R_COMPLETE) { return (result); } @@ -9243,10 +9249,10 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { * Handle NXDOMAIN and empty wildcard responses. */ static isc_result_t -query_nxdomain(query_ctx_t *qctx, bool empty_wild) { +query_nxdomain(query_ctx_t *qctx, isc_result_t result) { dns_section_t section; uint32_t ttl; - isc_result_t result; + bool empty_wild = (result == DNS_R_EMPTYWILD); CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain"); @@ -9255,7 +9261,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { INSIST(qctx->is_zone || REDIRECT(qctx->client)); if (!empty_wild) { - result = query_redirect(qctx); + result = query_redirect(qctx, result); if (result != ISC_R_COMPLETE) { return (result); } @@ -9343,7 +9349,7 @@ cleanup: * redirecting, so query processing should continue past it. */ static isc_result_t -query_redirect(query_ctx_t *qctx) { +query_redirect(query_ctx_t *qctx, isc_result_t saved_result) { isc_result_t result; CCTRACE(ISC_LOG_DEBUG(3), "query_redirect"); @@ -9384,7 +9390,7 @@ query_redirect(query_ctx_t *qctx) { SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset); SAVE(qctx->client->query.redirect.sigrdataset, qctx->sigrdataset); - qctx->client->query.redirect.result = DNS_R_NCACHENXDOMAIN; + qctx->client->query.redirect.result = saved_result; dns_name_copynf(qctx->fname, qctx->client->query.redirect.fname); qctx->client->query.redirect.authoritative = @@ -10005,7 +10011,7 @@ query_coveringnsec(query_ctx_t *qctx) { * We now have the proof that we have an NXDOMAIN. Apply * NXDOMAIN redirection if configured. */ - result = query_redirect(qctx); + result = query_redirect(qctx, DNS_R_COVERINGNSEC); if (result != ISC_R_COMPLETE) { redirected = true; goto cleanup; diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index df15408..939803b 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -627,7 +627,7 @@ attach_query_msg_to_client(ns_client_t *client, const char *qnamestr, dns_rdatatype_t qtype, unsigned int qflags) { dns_rdataset_t *qrdataset = NULL; dns_message_t *message = NULL; - unsigned char query[65536]; + unsigned char query[65535]; dns_name_t *qname = NULL; isc_buffer_t querybuf; dns_compress_t cctx; diff --git a/lib/ns/xfrout.c b/lib/ns/xfrout.c index f0c52f2..271b462 100644 --- a/lib/ns/xfrout.c +++ b/lib/ns/xfrout.c @@ -1281,7 +1281,7 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, * Note that although 65535-byte RRs are allowed in principle, they * cannot be zone-transferred (at least not if uncompressible), * because the message and RR headers would push the size of the - * TCP message over the 65536 byte limit. + * TCP message over the 65535 byte limit. */ mem = isc_mem_get(mctx, len); isc_buffer_init(&xfr->buf, mem, len); |