| /* |
| * OpenVPN -- An application to securely tunnel IP networks |
| * over a single TCP/UDP port, with support for SSL/TLS-based |
| * session authentication and key exchange, |
| * packet encryption, packet authentication, and |
| * packet compression. |
| * |
| * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #elif defined(_MSC_VER) |
| #include "config-msvc.h" |
| #endif |
| |
| #include "syshead.h" |
| |
| #if P2MP_SERVER |
| |
| #include "integer.h" |
| #include "list.h" |
| #include "misc.h" |
| |
| #include "memdbg.h" |
| |
| struct hash * |
| hash_init(const int n_buckets, |
| const uint32_t iv, |
| uint32_t (*hash_function)(const void *key, uint32_t iv), |
| bool (*compare_function)(const void *key1, const void *key2)) |
| { |
| struct hash *h; |
| int i; |
| |
| ASSERT(n_buckets > 0); |
| ALLOC_OBJ_CLEAR(h, struct hash); |
| h->n_buckets = (int) adjust_power_of_2(n_buckets); |
| h->mask = h->n_buckets - 1; |
| h->hash_function = hash_function; |
| h->compare_function = compare_function; |
| h->iv = iv; |
| ALLOC_ARRAY(h->buckets, struct hash_bucket, h->n_buckets); |
| for (i = 0; i < h->n_buckets; ++i) |
| { |
| struct hash_bucket *b = &h->buckets[i]; |
| b->list = NULL; |
| } |
| return h; |
| } |
| |
| void |
| hash_free(struct hash *hash) |
| { |
| int i; |
| for (i = 0; i < hash->n_buckets; ++i) |
| { |
| struct hash_bucket *b = &hash->buckets[i]; |
| struct hash_element *he = b->list; |
| |
| while (he) |
| { |
| struct hash_element *next = he->next; |
| free(he); |
| he = next; |
| } |
| } |
| free(hash->buckets); |
| free(hash); |
| } |
| |
| struct hash_element * |
| hash_lookup_fast(struct hash *hash, |
| struct hash_bucket *bucket, |
| const void *key, |
| uint32_t hv) |
| { |
| struct hash_element *he; |
| struct hash_element *prev = NULL; |
| |
| he = bucket->list; |
| |
| while (he) |
| { |
| if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) |
| { |
| /* move to head of list */ |
| if (prev) |
| { |
| prev->next = he->next; |
| he->next = bucket->list; |
| bucket->list = he; |
| } |
| return he; |
| } |
| prev = he; |
| he = he->next; |
| } |
| |
| return NULL; |
| } |
| |
| bool |
| hash_remove_fast(struct hash *hash, |
| struct hash_bucket *bucket, |
| const void *key, |
| uint32_t hv) |
| { |
| struct hash_element *he; |
| struct hash_element *prev = NULL; |
| |
| he = bucket->list; |
| |
| while (he) |
| { |
| if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) |
| { |
| if (prev) |
| { |
| prev->next = he->next; |
| } |
| else |
| { |
| bucket->list = he->next; |
| } |
| free(he); |
| --hash->n_elements; |
| return true; |
| } |
| prev = he; |
| he = he->next; |
| } |
| return false; |
| } |
| |
| bool |
| hash_add(struct hash *hash, const void *key, void *value, bool replace) |
| { |
| uint32_t hv; |
| struct hash_bucket *bucket; |
| struct hash_element *he; |
| bool ret = false; |
| |
| hv = hash_value(hash, key); |
| bucket = &hash->buckets[hv & hash->mask]; |
| |
| if ((he = hash_lookup_fast(hash, bucket, key, hv))) /* already exists? */ |
| { |
| if (replace) |
| { |
| he->value = value; |
| ret = true; |
| } |
| } |
| else |
| { |
| hash_add_fast(hash, bucket, key, hv, value); |
| ret = true; |
| } |
| |
| return ret; |
| } |
| |
| void |
| hash_remove_by_value(struct hash *hash, void *value) |
| { |
| struct hash_iterator hi; |
| struct hash_element *he; |
| |
| hash_iterator_init(hash, &hi); |
| while ((he = hash_iterator_next(&hi))) |
| { |
| if (he->value == value) |
| { |
| hash_iterator_delete_element(&hi); |
| } |
| } |
| hash_iterator_free(&hi); |
| } |
| |
| static void |
| hash_remove_marked(struct hash *hash, struct hash_bucket *bucket) |
| { |
| struct hash_element *prev = NULL; |
| struct hash_element *he = bucket->list; |
| |
| while (he) |
| { |
| if (!he->key) /* marked? */ |
| { |
| struct hash_element *newhe; |
| if (prev) |
| { |
| newhe = prev->next = he->next; |
| } |
| else |
| { |
| newhe = bucket->list = he->next; |
| } |
| free(he); |
| --hash->n_elements; |
| he = newhe; |
| } |
| else |
| { |
| prev = he; |
| he = he->next; |
| } |
| } |
| } |
| |
| uint32_t |
| void_ptr_hash_function(const void *key, uint32_t iv) |
| { |
| return hash_func((const void *)&key, sizeof(key), iv); |
| } |
| |
| bool |
| void_ptr_compare_function(const void *key1, const void *key2) |
| { |
| return key1 == key2; |
| } |
| |
| void |
| hash_iterator_init_range(struct hash *hash, |
| struct hash_iterator *hi, |
| int start_bucket, |
| int end_bucket) |
| { |
| if (end_bucket > hash->n_buckets) |
| { |
| end_bucket = hash->n_buckets; |
| } |
| |
| ASSERT(start_bucket >= 0 && start_bucket <= end_bucket); |
| |
| hi->hash = hash; |
| hi->elem = NULL; |
| hi->bucket = NULL; |
| hi->last = NULL; |
| hi->bucket_marked = false; |
| hi->bucket_index_start = start_bucket; |
| hi->bucket_index_end = end_bucket; |
| hi->bucket_index = hi->bucket_index_start - 1; |
| } |
| |
| void |
| hash_iterator_init(struct hash *hash, |
| struct hash_iterator *hi) |
| { |
| hash_iterator_init_range(hash, hi, 0, hash->n_buckets); |
| } |
| |
| static inline void |
| hash_iterator_lock(struct hash_iterator *hi, struct hash_bucket *b) |
| { |
| hi->bucket = b; |
| hi->last = NULL; |
| hi->bucket_marked = false; |
| } |
| |
| static inline void |
| hash_iterator_unlock(struct hash_iterator *hi) |
| { |
| if (hi->bucket) |
| { |
| if (hi->bucket_marked) |
| { |
| hash_remove_marked(hi->hash, hi->bucket); |
| hi->bucket_marked = false; |
| } |
| hi->bucket = NULL; |
| hi->last = NULL; |
| } |
| } |
| |
| static inline void |
| hash_iterator_advance(struct hash_iterator *hi) |
| { |
| hi->last = hi->elem; |
| hi->elem = hi->elem->next; |
| } |
| |
| void |
| hash_iterator_free(struct hash_iterator *hi) |
| { |
| hash_iterator_unlock(hi); |
| } |
| |
| struct hash_element * |
| hash_iterator_next(struct hash_iterator *hi) |
| { |
| struct hash_element *ret = NULL; |
| if (hi->elem) |
| { |
| ret = hi->elem; |
| hash_iterator_advance(hi); |
| } |
| else |
| { |
| while (++hi->bucket_index < hi->bucket_index_end) |
| { |
| struct hash_bucket *b; |
| hash_iterator_unlock(hi); |
| b = &hi->hash->buckets[hi->bucket_index]; |
| if (b->list) |
| { |
| hash_iterator_lock(hi, b); |
| hi->elem = b->list; |
| if (hi->elem) |
| { |
| ret = hi->elem; |
| hash_iterator_advance(hi); |
| break; |
| } |
| } |
| } |
| } |
| return ret; |
| } |
| |
| void |
| hash_iterator_delete_element(struct hash_iterator *hi) |
| { |
| ASSERT(hi->last); |
| hi->last->key = NULL; |
| hi->bucket_marked = true; |
| } |
| |
| |
| #ifdef LIST_TEST |
| |
| /* |
| * Test the hash code by implementing a simple |
| * word frequency algorithm. |
| */ |
| |
| struct word |
| { |
| const char *word; |
| int n; |
| }; |
| |
| static uint32_t |
| word_hash_function(const void *key, uint32_t iv) |
| { |
| const char *str = (const char *) key; |
| const int len = strlen(str); |
| return hash_func((const uint8_t *)str, len, iv); |
| } |
| |
| static bool |
| word_compare_function(const void *key1, const void *key2) |
| { |
| return strcmp((const char *)key1, (const char *)key2) == 0; |
| } |
| |
| static void |
| print_nhash(struct hash *hash) |
| { |
| struct hash_iterator hi; |
| struct hash_element *he; |
| int count = 0; |
| |
| hash_iterator_init(hash, &hi, true); |
| |
| while ((he = hash_iterator_next(&hi))) |
| { |
| printf("%d ", (int) he->value); |
| ++count; |
| } |
| printf("\n"); |
| |
| hash_iterator_free(&hi); |
| ASSERT(count == hash_n_elements(hash)); |
| } |
| |
| static void |
| rmhash(struct hash *hash, const char *word) |
| { |
| hash_remove(hash, word); |
| } |
| |
| void |
| list_test(void) |
| { |
| openvpn_thread_init(); |
| |
| { |
| struct gc_arena gc = gc_new(); |
| struct hash *hash = hash_init(10000, get_random(), word_hash_function, word_compare_function); |
| struct hash *nhash = hash_init(256, get_random(), word_hash_function, word_compare_function); |
| |
| printf("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask); |
| |
| /* parse words from stdin */ |
| while (true) |
| { |
| char buf[256]; |
| char wordbuf[256]; |
| int wbi; |
| int bi; |
| char c; |
| |
| if (!fgets(buf, sizeof(buf), stdin)) |
| { |
| break; |
| } |
| |
| bi = wbi = 0; |
| do |
| { |
| c = buf[bi++]; |
| if (isalnum(c) || c == '_') |
| { |
| ASSERT(wbi < (int) sizeof(wordbuf)); |
| wordbuf[wbi++] = c; |
| } |
| else |
| { |
| if (wbi) |
| { |
| struct word *w; |
| ASSERT(wbi < (int) sizeof(wordbuf)); |
| wordbuf[wbi++] = '\0'; |
| |
| /* word is parsed from stdin */ |
| |
| /* does it already exist in table? */ |
| w = (struct word *) hash_lookup(hash, wordbuf); |
| |
| if (w) |
| { |
| /* yes, increment count */ |
| ++w->n; |
| } |
| else |
| { |
| /* no, make a new object */ |
| ALLOC_OBJ_GC(w, struct word, &gc); |
| w->word = string_alloc(wordbuf, &gc); |
| w->n = 1; |
| ASSERT(hash_add(hash, w->word, w, false)); |
| ASSERT(hash_add(nhash, w->word, (void *) ((random() & 0x0F) + 1), false)); |
| } |
| } |
| wbi = 0; |
| } |
| } while (c); |
| } |
| |
| #if 1 |
| /* remove some words from the table */ |
| { |
| rmhash(hash, "true"); |
| rmhash(hash, "false"); |
| } |
| #endif |
| |
| /* output contents of hash table */ |
| { |
| int base; |
| int inc = 0; |
| int count = 0; |
| |
| for (base = 0; base < hash_n_buckets(hash); base += inc) |
| { |
| struct hash_iterator hi; |
| struct hash_element *he; |
| inc = (get_random() % 3) + 1; |
| hash_iterator_init_range(hash, &hi, true, base, base + inc); |
| |
| while ((he = hash_iterator_next(&hi))) |
| { |
| struct word *w = (struct word *) he->value; |
| printf("%6d '%s'\n", w->n, w->word); |
| ++count; |
| } |
| |
| hash_iterator_free(&hi); |
| } |
| ASSERT(count == hash_n_elements(hash)); |
| } |
| |
| #if 1 |
| /* test hash_remove_by_value function */ |
| { |
| int i; |
| for (i = 1; i <= 16; ++i) |
| { |
| printf("[%d] ***********************************\n", i); |
| print_nhash(nhash); |
| hash_remove_by_value(nhash, (void *) i, true); |
| } |
| printf("FINAL **************************\n"); |
| print_nhash(nhash); |
| } |
| #endif |
| |
| hash_free(hash); |
| hash_free(nhash); |
| gc_free(&gc); |
| } |
| |
| openvpn_thread_cleanup(); |
| } |
| |
| #endif /* ifdef LIST_TEST */ |
| |
| /* |
| * -------------------------------------------------------------------- |
| * hash() -- hash a variable-length key into a 32-bit value |
| * k : the key (the unaligned variable-length array of bytes) |
| * len : the length of the key, counting by bytes |
| * level : can be any 4-byte value |
| * Returns a 32-bit value. Every bit of the key affects every bit of |
| * the return value. Every 1-bit and 2-bit delta achieves avalanche. |
| * About 36+6len instructions. |
| * |
| * The best hash table sizes are powers of 2. There is no need to do |
| * mod a prime (mod is sooo slow!). If you need less than 32 bits, |
| * use a bitmask. For example, if you need only 10 bits, do |
| * h = (h & hashmask(10)); |
| * In which case, the hash table should have hashsize(10) elements. |
| * |
| * If you are hashing n strings (uint8_t **)k, do it like this: |
| * for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); |
| * |
| * By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this |
| * code any way you wish, private, educational, or commercial. It's free. |
| * |
| * See http://burlteburtle.net/bob/hash/evahash.html |
| * Use for hash table lookup, or anything where one collision in 2^32 is |
| * acceptable. Do NOT use for cryptographic purposes. |
| * |
| * -------------------------------------------------------------------- |
| * |
| * mix -- mix 3 32-bit values reversibly. |
| * For every delta with one or two bit set, and the deltas of all three |
| * high bits or all three low bits, whether the original value of a,b,c |
| * is almost all zero or is uniformly distributed, |
| * If mix() is run forward or backward, at least 32 bits in a,b,c |
| * have at least 1/4 probability of changing. |
| * If mix() is run forward, every bit of c will change between 1/3 and |
| * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) |
| * mix() was built out of 36 single-cycle latency instructions in a |
| * structure that could supported 2x parallelism, like so: |
| * a -= b; |
| * a -= c; x = (c>>13); |
| * b -= c; a ^= x; |
| * b -= a; x = (a<<8); |
| * c -= a; b ^= x; |
| * c -= b; x = (b>>13); |
| * ... |
| * Unfortunately, superscalar Pentiums and Sparcs can't take advantage |
| * of that parallelism. They've also turned some of those single-cycle |
| * latency instructions into multi-cycle latency instructions. Still, |
| * this is the fastest good hash I could find. There were about 2^^68 |
| * to choose from. I only looked at a billion or so. |
| * |
| * James Yonan Notes: |
| * |
| * This function is faster than it looks, and appears to be |
| * appropriate for our usage in OpenVPN which is primarily |
| * for hash-table based address lookup (IPv4, IPv6, and Ethernet MAC). |
| * NOTE: This function is never used for cryptographic purposes, only |
| * to produce evenly-distributed indexes into hash tables. |
| * |
| * Benchmark results: 11.39 machine cycles per byte on a P2 266Mhz, |
| * and 12.1 machine cycles per byte on a |
| * 2.2 Ghz P4 when hashing a 6 byte string. |
| * -------------------------------------------------------------------- |
| */ |
| |
| #define mix(a,b,c) \ |
| { \ |
| a -= b; a -= c; a ^= (c>>13); \ |
| b -= c; b -= a; b ^= (a<<8); \ |
| c -= a; c -= b; c ^= (b>>13); \ |
| a -= b; a -= c; a ^= (c>>12); \ |
| b -= c; b -= a; b ^= (a<<16); \ |
| c -= a; c -= b; c ^= (b>>5); \ |
| a -= b; a -= c; a ^= (c>>3); \ |
| b -= c; b -= a; b ^= (a<<10); \ |
| c -= a; c -= b; c ^= (b>>15); \ |
| } |
| |
| uint32_t |
| hash_func(const uint8_t *k, uint32_t length, uint32_t initval) |
| { |
| uint32_t a, b, c, len; |
| |
| /* Set up the internal state */ |
| len = length; |
| a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ |
| c = initval; /* the previous hash value */ |
| |
| /*---------------------------------------- handle most of the key */ |
| while (len >= 12) |
| { |
| a += (k[0] + ((uint32_t) k[1] << 8) |
| + ((uint32_t) k[2] << 16) |
| + ((uint32_t) k[3] << 24)); |
| b += (k[4] + ((uint32_t) k[5] << 8) |
| + ((uint32_t) k[6] << 16) |
| + ((uint32_t) k[7] << 24)); |
| c += (k[8] + ((uint32_t) k[9] << 8) |
| + ((uint32_t) k[10] << 16) |
| + ((uint32_t) k[11] << 24)); |
| mix(a, b, c); |
| k += 12; |
| len -= 12; |
| } |
| |
| /*------------------------------------- handle the last 11 bytes */ |
| c += length; |
| switch (len) /* all the case statements fall through */ |
| { |
| case 11: |
| c += ((uint32_t) k[10] << 24); |
| |
| case 10: |
| c += ((uint32_t) k[9] << 16); |
| |
| case 9: |
| c += ((uint32_t) k[8] << 8); |
| |
| /* the first byte of c is reserved for the length */ |
| case 8: |
| b += ((uint32_t) k[7] << 24); |
| |
| case 7: |
| b += ((uint32_t) k[6] << 16); |
| |
| case 6: |
| b += ((uint32_t) k[5] << 8); |
| |
| case 5: |
| b += k[4]; |
| |
| case 4: |
| a += ((uint32_t) k[3] << 24); |
| |
| case 3: |
| a += ((uint32_t) k[2] << 16); |
| |
| case 2: |
| a += ((uint32_t) k[1] << 8); |
| |
| case 1: |
| a += k[0]; |
| /* case 0: nothing left to add */ |
| } |
| mix(a, b, c); |
| /*-------------------------------------- report the result */ |
| return c; |
| } |
| |
| #else /* if P2MP_SERVER */ |
| static void |
| dummy(void) |
| { |
| } |
| #endif /* P2MP_SERVER */ |