From: Mark Andrews Date: Fri, 25 Jul 2003 02:22:26 +0000 (+0000) Subject: 1495. [cleanup] Replace hash functions with universal hash. X-Git-Tag: v9.2.3rc1~24^2 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=1e107b3d7b54de5022c3328423164e533afcc15e;p=thirdparty%2Fbind9.git 1495. [cleanup] Replace hash functions with universal hash. --- diff --git a/CHANGES b/CHANGES index 6e6a510874f..fa2702716df 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +1495. [cleanup] Replace hash functions with universal hash. + 1494. [security] Turn on RSA BLINDING as a precaution. 1493. [placeholder] diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index 0c07831d6a6..567ae9c66a4 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: globals.h,v 1.61 2003/02/26 02:03:58 marka Exp $ */ +/* $Id: globals.h,v 1.62 2003/07/25 02:22:23 marka Exp $ */ #ifndef NAMED_GLOBALS_H #define NAMED_GLOBALS_H 1 diff --git a/bin/named/main.c b/bin/named/main.c index ac7bae91e85..ba97646f5de 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.129 2003/01/16 03:59:23 marka Exp $ */ +/* $Id: main.c,v 1.130 2003/07/25 02:22:23 marka Exp $ */ #include @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include +#include #include #include @@ -493,6 +495,14 @@ create_managers(void) { return (ISC_R_UNEXPECTED); } + result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_hash_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + return (ISC_R_SUCCESS); } @@ -500,6 +510,7 @@ static void destroy_managers(void) { ns_lwresd_shutdown(); + isc_hash_destroy(); isc_entropy_detach(&ns_g_entropy); /* * isc_taskmgr_destroy() will block until all tasks have exited, diff --git a/bin/named/server.c b/bin/named/server.c index 7f06696ff3c..791d8b691a5 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.399 2003/07/17 07:22:21 marka Exp $ */ +/* $Id: server.c,v 1.400 2003/07/25 02:22:23 marka Exp $ */ #include @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2511,6 +2512,8 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), "loading configuration"); + isc_hash_init(); + CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index dc66d5ecaf0..26cb9608cc0 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsupdate.c,v 1.122 2003/07/25 00:01:05 marka Exp $ */ +/* $Id: nsupdate.c,v 1.123 2003/07/25 02:22:23 marka Exp $ */ #include @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -503,6 +504,10 @@ setup_system(void) { result = isc_entropy_create(mctx, &entp); check_result(result, "isc_entropy_create"); + result = isc_hash_create(mctx, entp, DNS_NAME_MAXWIRE); + check_result(result, "isc_hash_create"); + isc_hash_init(); + result = dns_dispatchmgr_create(mctx, entp, &dispatchmgr); check_result(result, "dns_dispatchmgr_create"); @@ -1823,6 +1828,9 @@ cleanup(void) { ddebug("Shutting down timer manager"); isc_timermgr_destroy(&timermgr); + ddebug("Destroying hash context"); + isc_hash_destroy(); + ddebug("Destroying memory context"); if (memdebugging) isc_mem_stats(mctx, stderr); diff --git a/lib/dns/adb.c b/lib/dns/adb.c index d02ee2ecc6b..feebc865ad7 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.204 2003/07/18 04:30:01 marka Exp $ */ +/* $Id: adb.c,v 1.205 2003/07/25 02:22:24 marka Exp $ */ /* * Implementation notes @@ -1586,7 +1586,7 @@ find_name_and_lock(dns_adb_t *adb, dns_name_t *name, dns_adbname_t *adbname; int bucket; - bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS; + bucket = dns_fullname_hash(name, ISC_FALSE) % NBUCKETS; if (*bucketp == DNS_ADB_INVALIDBUCKET) { LOCK(&adb->namelocks[bucket]); diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 810c3970c5a..03d8eb41d2a 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.112 2003/02/26 05:05:15 marka Exp $ */ +/* $Id: dispatch.c,v 1.113 2003/07/25 02:22:24 marka Exp $ */ #include diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 911888b90d9..dca88427cee 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.h,v 1.73 2003/02/26 22:54:29 marka Exp $ */ +/* $Id: adb.h,v 1.74 2003/07/25 02:22:25 marka Exp $ */ #ifndef DNS_ADB_H #define DNS_ADB_H 1 diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index d61d0c697c6..c875f72f0d3 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.h,v 1.102 2002/08/27 04:53:43 marka Exp $ */ +/* $Id: name.h,v 1.103 2003/07/25 02:22:25 marka Exp $ */ #ifndef DNS_NAME_H #define DNS_NAME_H 1 @@ -321,6 +321,22 @@ dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive); * A hash value */ +unsigned int +dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive); +/* + * Provide a hash value for 'name'. Unlike dns_name_hash(), this function + * always takes into account of the entire name to calculate the hash value. + * + * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in + * case will have the same hash value. + * + * Requires: + * 'name' is a valid name + * + * Returns: + * A hash value + */ + unsigned int dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive); /* diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index dc8572b7c46..af43f114af7 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.81 2003/02/26 22:54:29 marka Exp $ */ +/* $Id: view.h,v 1.82 2003/07/25 02:22:25 marka Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 diff --git a/lib/dns/name.c b/lib/dns/name.c index 86a6c452244..f43b79544ec 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -15,13 +15,14 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.c,v 1.139 2003/04/11 07:25:25 marka Exp $ */ +/* $Id: name.c,v 1.140 2003/07/25 02:22:24 marka Exp $ */ #include #include #include +#include #include #include #include @@ -339,6 +340,20 @@ dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) { return (name_hash(name, case_sensitive)); } +unsigned int +dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) { + /* + * Provide a hash value for 'name'. + */ + REQUIRE(VALID_NAME(name)); + + if (name->labels == 0) + return (0); + + return (isc_hash_calc((const unsigned char *)name->ndata, + name->length, case_sensitive)); +} + unsigned int dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) { unsigned char *offsets; diff --git a/lib/dns/view.c b/lib/dns/view.c index 975697723fc..322a55ab746 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -15,10 +15,11 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.115 2003/02/26 22:54:28 marka Exp $ */ +/* $Id: view.c,v 1.116 2003/07/25 02:22:24 marka Exp $ */ #include +#include #include #include /* Required for HP/UX (and others?) */ #include diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index e826ba7bf11..9c539e48342 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.77 2003/06/24 05:10:32 marka Exp $ +# $Id: Makefile.in,v 1.78 2003/07/25 02:22:26 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -52,7 +52,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ OBJS = @ISC_EXTRA_OBJS@ \ assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \ bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \ - heap.@O@ hex.@O@ hmacmd5.@O@ \ + hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ \ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ md5.@O@ \ mem.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ ondestroy.@O@ \ parseint.@O@ quota.@O@ random.@O@ \ diff --git a/lib/isc/hash.c b/lib/isc/hash.c new file mode 100644 index 00000000000..0971b8dff10 --- /dev/null +++ b/lib/isc/hash.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: hash.c,v 1.2 2003/07/25 02:22:26 marka Exp $ */ + +/* + * Some portion of this code was derived from universal hash function + * libraries of Rice University. + */ + +/* "UH Universal Hashing Library" + +Copyright ((c)) 2002, Rice University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Rice University (RICE) nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + +This software is provided by RICE and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall RICE or contributors be liable +for any direct, indirect, incidental, special, exemplary, or +consequential damages (including, but not limited to, procurement of +substitute goods or services; loss of use, data, or profits; or +business interruption) however caused and on any theory of liability, +whether in contract, strict liability, or tort (including negligence +or otherwise) arising in any way out of the use of this software, even +if advised of the possibility of such damage. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h') +#define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC) + +/* + * A large 32-bit prime number that specifies the range of the hash output. + */ +#define PRIME32 0xFFFFFFFB /* 2^32 - 5 */ + +/* + * Types of random seed and hash accumulator. Perhaps they can be system + * dependent. + */ +typedef isc_uint32_t hash_accum_t; +typedef isc_uint16_t hash_random_t; + +struct isc_hash { + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_boolean_t initialized; + isc_refcount_t refcnt; + isc_entropy_t *entropy; /* entropy source */ + unsigned int limit; /* upper limit of key length */ + size_t vectorlen; /* size of the vector below */ + hash_random_t *rndvector; /* random vector for universal hashing */ +}; + +static isc_rwlock_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_hash_t *hash = NULL; + +static unsigned char 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 +}; + +isc_result_t +isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, + unsigned int limit, isc_hash_t **hctxp) +{ + isc_result_t ret; + isc_hash_t *hctx; + size_t vlen; + hash_random_t *rv; + hash_accum_t overflow_limit; + + REQUIRE(mctx != NULL); + REQUIRE(hctxp != NULL && *hctxp == NULL); + + /* + * Overflow check. Since our implementation only does a modulo + * operation at the last stage of hash calculation, the accumulator + * must not overflow. + */ + overflow_limit = + 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8); + if (overflow_limit < (limit + 1) * 0xff) + return (ISC_R_RANGE); + + hctx = isc_mem_get(mctx, sizeof(isc_hash_t)); + if (hctx == NULL) + return (ISC_R_NOMEMORY); + + vlen = sizeof(hash_random_t) * (limit + 1); + rv = isc_mem_get(mctx, vlen); + if (rv == NULL) { + ret = ISC_R_NOMEMORY; + goto errout; + } + + /* + * We need a lock. + */ + if (isc_mutex_init(&hctx->lock) != ISC_R_SUCCESS) { + ret = ISC_R_UNEXPECTED; + goto errout; + } + + /* + * From here down, no failures will/can occur. + */ + hctx->magic = HASH_MAGIC; + hctx->mctx = NULL; + isc_mem_attach(mctx, &hctx->mctx); + hctx->initialized = ISC_FALSE; + isc_refcount_init(&hctx->refcnt, 1); + hctx->entropy = NULL; + hctx->limit = limit; + hctx->vectorlen = vlen; + hctx->rndvector = rv; + + if (entropy != NULL) + isc_entropy_attach(entropy, &hctx->entropy); + + *hctxp = hctx; + return (ISC_R_SUCCESS); + + errout: + isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); + if (rv != NULL) + isc_mem_put(mctx, rv, vlen); + + return (ret); +} + +static void +initialize_lock(void) { + RUNTIME_CHECK(isc_rwlock_init(&createlock, 0, 0) == ISC_R_SUCCESS); +} + +isc_result_t +isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(mctx != NULL); + INSIST(hash == NULL); + + RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS); + + RWLOCK(&createlock, isc_rwlocktype_write); + + if (hash == NULL) + result = isc_hash_ctxcreate(mctx, entropy, limit, &hash); + + RWUNLOCK(&createlock, isc_rwlocktype_write); + + return (result); +} + +void +isc_hash_ctxinit(isc_hash_t *hctx) { + isc_result_t result; + + LOCK(&hctx->lock); + + if (hctx->initialized == ISC_TRUE) + goto out; + + if (hctx->entropy) { + result = isc_entropy_getdata(hctx->entropy, + hctx->rndvector, hctx->vectorlen, + NULL, 0); + INSIST(result == ISC_R_SUCCESS); + } else { + isc_int32_t pr; + unsigned int i, copylen; + unsigned char *p; + + p = (unsigned char *)hctx->rndvector; + for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) { + isc_random_get(&pr); + if (i + sizeof(pr) <= hctx->vectorlen) + copylen = sizeof(pr); + else + copylen = hctx->vectorlen - i; + + memcpy(p, &pr, copylen); + } + INSIST(p == (unsigned char *)hctx->rndvector + + hctx->vectorlen); + } + + hctx->initialized = ISC_TRUE; + + out: + UNLOCK(&hctx->lock); +} + +void +isc_hash_init() { + INSIST(hash != NULL && VALID_HASH(hash)); + + isc_hash_ctxinit(hash); +} + +void +isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) { + REQUIRE(VALID_HASH(hctx)); + REQUIRE(hctxp != NULL && *hctxp == NULL); + + isc_refcount_increment(&hctx->refcnt, NULL); + *hctxp = hctx; +} + +static void +destroy(isc_hash_t **hctxp) { + isc_hash_t *hctx; + isc_mem_t *mctx; + + REQUIRE(hctxp != NULL && *hctxp != NULL); + hctx = *hctxp; + *hctxp = NULL; + + LOCK(&hctx->lock); + + isc_refcount_destroy(&hctx->refcnt); + + mctx = hctx->mctx; + if (hctx->entropy != NULL) + isc_entropy_detach(&hctx->entropy); + if (hctx->rndvector != NULL) + isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen); + + UNLOCK(&hctx->lock); + + DESTROYLOCK(&hctx->lock); + + memset(hctx, 0, sizeof(isc_hash_t)); + isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); + isc_mem_detach(&mctx); +} + +void +isc_hash_ctxdetach(isc_hash_t **hctxp) { + isc_hash_t *hctx; + unsigned int refs; + + REQUIRE(hctxp != NULL && VALID_HASH(*hctxp)); + hctx = *hctxp; + + isc_refcount_decrement(&hctx->refcnt, &refs); + if (refs == 0) + destroy(&hctx); + + *hctxp = NULL; +} + +void +isc_hash_destroy() { + unsigned int refs; + + INSIST(hash != NULL && VALID_HASH(hash)); + + isc_refcount_decrement(&hash->refcnt, &refs); + INSIST(refs == 0); + + destroy(&hash); +} + +static inline unsigned int +hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive) +{ + hash_accum_t partial_sum = 0; + hash_random_t *p = hctx->rndvector; + unsigned int i = 0; + + /* Make it sure that the hash context is initialized. */ + if (hctx->initialized == ISC_FALSE) + isc_hash_ctxinit(hctx); + + if (case_sensitive) { + for (i = 0; i < keylen; i++) + partial_sum += key[i] * (hash_accum_t)p[i]; + } else { + for (i = 0; i < keylen; i++) + partial_sum += maptolower[key[i]] * (hash_accum_t)p[i]; + } + + partial_sum += p[i]; + + return ((unsigned int)(partial_sum % PRIME32)); +} + +unsigned int +isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key, + unsigned int keylen, isc_boolean_t case_sensitive) +{ + REQUIRE(hctx != NULL && VALID_HASH(hctx)); + REQUIRE(keylen <= hctx->limit); + + return (hash_calc(hctx, key, keylen, case_sensitive)); +} + +unsigned int +isc_hash_calc(const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive) +{ + INSIST(hash != NULL && VALID_HASH(hash)); + REQUIRE(keylen <= hash->limit); + + return (hash_calc(hash, key, keylen, case_sensitive)); +} diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h new file mode 100644 index 00000000000..75484ed0eb2 --- /dev/null +++ b/lib/isc/include/isc/hash.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: hash.h,v 1.2 2003/07/25 02:22:26 marka Exp $ */ + +#ifndef ISC_HASH_H +#define ISC_HASH_H 1 + +/***** + ***** Module Info + *****/ + +/* + * Hash + * + * The hash API + * + * Provides an unpredictable hash value for variable length data. + * A hash object contains a random vector (which is hidden from clients + * of this API) to make the actual hash value unpredictable. + * + * The algorithm used in the API guarantees the probability of hash + * collision; in the current implementation, as long as the values stored + * in the random vector are unpredictable, the probability of hash + * collision between arbitrary two different values is at most 1/2^16. + * + * Altough the API is generic about the hash keys, it mainly expects + * DNS names (and sometimes IPv4/v6 addresses) as inputs. It has an + * upper limit of the input length, and may run slow to calculaate the + * has values for large inputs. + * + * This API is designed to be general so that it can provide multiple + * different hash contexts that have different random vectors. However, + * it should be typical to have a single context for an entire system. + * To support such cases, the API also provides a single-context mode. + * + * MP: + * The hash object is almost read-only. Once the internal random vector + * is initialized, no write operation will occur, and there will be no + * need to lock the object to calculate actual hash values. + * + * Reliability: + * In some cases this module uses low-level data copy to initialize the + * random vector. Errors in this part are likely to crash the server or + * corrupt memory. + * + * Resources: + * A buffer, used as a random vector for calculating hash values. + * + * Security: + * This module intends to provide unpredictable hash values in + * adversarial environments in order to avoid denial of service attacks + * to hash buckets. + * Its unpredictability relies on the quality of entropy to build the + * random vector. + * + * Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include + +/*** + *** Functions + ***/ +ISC_LANG_BEGINDECLS + +isc_result_t +isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, unsigned int limit, + isc_hash_t **hctx); +isc_result_t +isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit); +/* + * Create a new hash object. + * + * isc_hash_ctxcreate() creates a different object. + * isc_hash_create() creates a module-internal object to support the + * single-context mode. It should be called only once. + * + * 'entropy' must be NULL or a valid entropy object. If 'entropy' is NULL, + * pseudo random values will be used to build the random vector, which may + * weaken security. + * + * 'limit' specifies the maximum number of hash keys. If it is too large, + * these functions may fail. + */ + +void +isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp); +/* + * Attach to a hash object. + * This function is only necessary for the multiple-context mode. + */ + +void +isc_hash_ctxdetach(isc_hash_t **hctxp); +/* + * Detach from a hash object. + * + * This function is for the multiple-context mode, and takes a valid + * hash object as an argument. + */ + +void +isc_hash_destroy(void); +/* + * This function is for the single-context mode, and is expected to be used + * as a counterpart of isc_hash_create(). + * A valid module-internal hash object must have been created, and this + * function should be called only once. + */ + +void +isc_hash_ctxinit(isc_hash_t *hctx); +void +isc_hash_init(void); +/* + * Initialize a hash object. It fills in the random vector with a proper + * source of entropy, which is typically from the entropy object specified + * at the creation. Thus, it is desirable to call these functions after + * initializing the entropy object with some good entropy sources. + * + * These functions should be called before the first hash calculation. + * + * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash + * object as an argument. + * isc_hash_init() is for the single-context mode. A valid module-internal + * hash object must have been created, and this function should be called only + * once. + */ + +unsigned int +isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key, + unsigned int keylen, isc_boolean_t case_sensitive); +unsigned int +isc_hash_calc(const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive); +/* + * Calculate a hash value. + * + * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash + * object as an argument. + * isc_hash_init() is for the single-context mode. A valid module-internal + * hash object must have been created. + * + * 'key' is the hash key, which is a variable length buffer. + * 'keylen' specifies the key length, which must not be larger than the limit + * specified for the corresponding hash object. + * + * 'case_sensitive' specifies whether the hash key should be treated as + * case_sensitive values. It should typically be ISC_FALSE if the hash key + * is a DNS name. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_HASH_H */ diff --git a/lib/isc/include/isc/sockaddr.h b/lib/isc/include/isc/sockaddr.h index 5257b059de0..8fbd06ac03f 100644 --- a/lib/isc/include/isc/sockaddr.h +++ b/lib/isc/include/isc/sockaddr.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sockaddr.h,v 1.39 2002/04/03 06:38:36 marka Exp $ */ +/* $Id: sockaddr.h,v 1.40 2003/07/25 02:22:26 marka Exp $ */ #ifndef ISC_SOCKADDR_H #define ISC_SOCKADDR_H 1 diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index b30f55ee7fe..2ad31572d7d 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.33 2002/07/19 03:39:44 marka Exp $ */ +/* $Id: types.h,v 1.34 2003/07/25 02:22:26 marka Exp $ */ #ifndef ISC_TYPES_H #define ISC_TYPES_H 1 @@ -52,6 +52,7 @@ typedef struct isc_event isc_event_t; typedef ISC_LIST(isc_event_t) isc_eventlist_t; typedef unsigned int isc_eventtype_t; typedef isc_uint32_t isc_fsaccess_t; +typedef struct isc_hash isc_hash_t; typedef struct isc_interface isc_interface_t; typedef struct isc_interfaceiter isc_interfaceiter_t; typedef struct isc_interval isc_interval_t; diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c index 89754059bb7..9dbc7183628 100644 --- a/lib/isc/sockaddr.c +++ b/lib/isc/sockaddr.c @@ -15,13 +15,14 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sockaddr.c,v 1.56 2003/04/11 07:25:28 marka Exp $ */ +/* $Id: sockaddr.c,v 1.57 2003/07/25 02:22:26 marka Exp $ */ #include #include #include +#include #include #include #include @@ -186,19 +187,17 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) { switch (sockaddr->type.sa.sa_family) { case AF_INET: - h = ntohl(sockaddr->type.sin.sin_addr.s_addr); + s = (const unsigned char *)&sockaddr->type.sin.sin_addr; p = ntohs(sockaddr->type.sin.sin_port); + length = sizeof(sockaddr->type.sin.sin_addr.s_addr); break; case AF_INET6: in6 = &sockaddr->type.sin6.sin6_addr; if (IN6_IS_ADDR_V4MAPPED(in6)) { - h = (in6->s6_addr[12] << 24) | - (in6->s6_addr[13] << 16) | - (in6->s6_addr[14] << 8) | - in6->s6_addr[15]; + s = (const unsigned char *)&in6[12]; + length = sizeof(sockaddr->type.sin.sin_addr.s_addr); } else { - s = (const unsigned char *)&sockaddr-> - type.sin6.sin6_addr; + s = (const unsigned char *)in6; length = sizeof(sockaddr->type.sin6.sin6_addr); } p = ntohs(sockaddr->type.sin6.sin6_port); @@ -214,22 +213,14 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) { length = sockaddr->length; p = 0; } - while (length > 0) { - h = ( h << 4 ) + *s; - if ((g = ( h & 0xf0000000 )) != 0) { - h = h ^ (g >> 24); - h = h ^ g; - } - s++; - length--; - } + + h = isc_hash_calc(s, length, ISC_TRUE); if (!address_only) { - h = h ^ (p << 4); - if ((g = ( h & 0xf0000000 )) != 0) { - h = h ^ (g >> 24); - h = h ^ g; - } + g = isc_hash_calc((const unsigned char *)&p, sizeof(p), + ISC_TRUE); + h = h ^ g; /* XXX: we should concatenate h and p first */ } + return (h); }