]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1495. [cleanup] Replace hash functions with universal hash.
authorMark Andrews <marka@isc.org>
Fri, 25 Jul 2003 02:22:26 +0000 (02:22 +0000)
committerMark Andrews <marka@isc.org>
Fri, 25 Jul 2003 02:22:26 +0000 (02:22 +0000)
18 files changed:
CHANGES
bin/named/include/named/globals.h
bin/named/main.c
bin/named/server.c
bin/nsupdate/nsupdate.c
lib/dns/adb.c
lib/dns/dispatch.c
lib/dns/include/dns/adb.h
lib/dns/include/dns/name.h
lib/dns/include/dns/view.h
lib/dns/name.c
lib/dns/view.c
lib/isc/Makefile.in
lib/isc/hash.c [new file with mode: 0644]
lib/isc/include/isc/hash.h [new file with mode: 0644]
lib/isc/include/isc/sockaddr.h
lib/isc/include/isc/types.h
lib/isc/sockaddr.c

diff --git a/CHANGES b/CHANGES
index 6e6a510874fd9d29419dd987cbf9a33335125094..fa2702716df935a7de0e65ba3788a29a2455a2f8 100644 (file)
--- 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]
index 0c07831d6a652742ee1697e78ba42f184a542f2a..567ae9c66a4967360ee2a890fe4c8d3ce223d21d 100644 (file)
@@ -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
index ac7bae91e856f78305e67af949aa475062596201..ba97646f5de7304db25a035b778bd1a0b7ea1031 100644 (file)
@@ -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 <config.h>
 
@@ -28,6 +28,7 @@
 #include <isc/dir.h>
 #include <isc/entropy.h>
 #include <isc/file.h>
+#include <isc/hash.h>
 #include <isc/os.h>
 #include <isc/platform.h>
 #include <isc/resource.h>
@@ -39,6 +40,7 @@
 #include <isccc/result.h>
 
 #include <dns/dispatch.h>
+#include <dns/name.h>
 #include <dns/result.h>
 #include <dns/view.h>
 
@@ -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,
index 7f06696ff3c1f02a0db93835478a21bf59bf51c7..791d8b691a5c86ca797c7f2703005b804af978c4 100644 (file)
@@ -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 <config.h>
 
@@ -26,6 +26,7 @@
 #include <isc/dir.h>
 #include <isc/entropy.h>
 #include <isc/file.h>
+#include <isc/hash.h>
 #include <isc/lex.h>
 #include <isc/print.h>
 #include <isc/resource.h>
@@ -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");
 
index dc66d5ecaf0a985e3bc0535e25892658a9c7ebec..26cb9608cc0de4aad724d534f8a919b462caea60 100644 (file)
@@ -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 <config.h>
 
@@ -31,6 +31,7 @@
 #include <isc/commandline.h>
 #include <isc/entropy.h>
 #include <isc/event.h>
+#include <isc/hash.h>
 #include <isc/lex.h>
 #include <isc/mem.h>
 #include <isc/parseint.h>
@@ -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);
index d02ee2ecc6badd16e4b895b3814ee43c0dad354e..feebc865ad7ef0ec0dc6a521acfcefdb4eeb7ea2 100644 (file)
@@ -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]);
index 810c3970c5a2935245549652e4f3cdf8cef263be..03d8eb41d2a06f2e342d5a480b69f25d77065fca 100644 (file)
@@ -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 <config.h>
 
index 911888b90d930051c28044b692fe12fc279e419a..dca88427ceecec6ca915938639d2a36f8312e923 100644 (file)
@@ -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
index d61d0c697c69a17824fc4cc6b46855e4a4592336..c875f72f0d38eec1eb24e8ef8a7b2aba815a9bc0 100644 (file)
@@ -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);
 /*
index dc8572b7c4662bab1f378874923a6e81b58e449e..af43f114af7cf4f3cdc8329a6690c86aae16e04c 100644 (file)
@@ -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
index 86a6c45224498ea074e695a9a2710c82ae267440..f43b79544ecf7ed43271eab399a16e71d8e3edd3 100644 (file)
  * 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 <config.h>
 
 #include <ctype.h>
 
 #include <isc/buffer.h>
+#include <isc/hash.h>
 #include <isc/mem.h>
 #include <isc/print.h>
 #include <isc/string.h>
@@ -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;
index 975697723fcae60db46c458839e2981a4c095425..322a55ab7468b29456b6984ba71a4c3b5ac98b4e 100644 (file)
  * 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 <config.h>
 
+#include <isc/hash.h>
 #include <isc/task.h>
 #include <isc/string.h>                /* Required for HP/UX (and others?) */
 #include <isc/util.h>
index e826ba7bf117037cf8b201ce768765e2b958d52c..9c539e48342a7869f5f6c19090ffa760ab5118cc 100644 (file)
@@ -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 (file)
index 0000000..0971b8d
--- /dev/null
@@ -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 <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#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 (file)
index 0000000..75484ed
--- /dev/null
@@ -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 <isc/types.h>
+
+/***
+ *** 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 */
index 5257b059de01fbe4ed0c4a020ef0d7de0037da6b..8fbd06ac03f4a4555124cbea7bbde8346dad875b 100644 (file)
@@ -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
index b30f55ee7fe9151d5263d7f85ddb12a85aff5784..2ad31572d7ded10db993c31add0040e1a6767421 100644 (file)
@@ -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;
index 89754059bb72de35a47b038b33bd15f9e1c18425..9dbc718362815ffd6a78ff9c507febd1fc6fdaaa 100644 (file)
  * 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 <config.h>
 
 #include <stdio.h>
 
 #include <isc/buffer.h>
+#include <isc/hash.h>
 #include <isc/msgs.h>
 #include <isc/netaddr.h>
 #include <isc/print.h>
@@ -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);
 }