OpenVPN
list.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29
30#include "integer.h"
31#include "list.h"
32
33#include "crypto.h"
34
35struct hash *
36hash_init(const uint32_t n_buckets,
37 uint64_t (*hash_function)(const void *key, const uint8_t hash_key[HASH_KEY_LEN]),
38 bool (*compare_function)(const void *key1, const void *key2))
39{
40 struct hash *h;
41
42 ASSERT(n_buckets > 0);
43 ALLOC_OBJ_CLEAR(h, struct hash);
45 h->mask = h->n_buckets - 1;
48
49 /* create random hash key */
50 prng_bytes(h->hash_key, sizeof(h->hash_key));
51
53 for (uint32_t i = 0; i < h->n_buckets; ++i)
54 {
55 struct hash_bucket *b = &h->buckets[i];
56 b->list = NULL;
57 }
58 return h;
59}
60
61void
63{
64 for (uint32_t i = 0; i < hash->n_buckets; ++i)
65 {
66 struct hash_bucket *b = &hash->buckets[i];
67 struct hash_element *he = b->list;
68
69 while (he)
70 {
71 struct hash_element *next = he->next;
72 free(he);
73 he = next;
74 }
75 }
76 free(hash->buckets);
77 free(hash);
78}
79
80struct hash_element *
81hash_lookup_fast(struct hash *hash, struct hash_bucket *bucket, const void *key, uint64_t hv)
82{
83 struct hash_element *he;
84 struct hash_element *prev = NULL;
85
86 he = bucket->list;
87
88 while (he)
89 {
90 if (hv == he->hash_value && (*hash->compare_function)(key, he->key))
91 {
92 /* move to head of list */
93 if (prev)
94 {
95 prev->next = he->next;
96 he->next = bucket->list;
97 bucket->list = he;
98 }
99 return he;
100 }
101 prev = he;
102 he = he->next;
103 }
104
105 return NULL;
106}
107
108bool
109hash_remove_fast(struct hash *hash, struct hash_bucket *bucket, const void *key, uint64_t hv)
110{
111 struct hash_element *he;
112 struct hash_element *prev = NULL;
113
114 he = bucket->list;
115
116 while (he)
117 {
118 if (hv == he->hash_value && (*hash->compare_function)(key, he->key))
119 {
120 if (prev)
121 {
122 prev->next = he->next;
123 }
124 else
125 {
126 bucket->list = he->next;
127 }
128 free(he);
129 --hash->n_elements;
130 return true;
131 }
132 prev = he;
133 he = he->next;
134 }
135 return false;
136}
137
138bool
139hash_add(struct hash *hash, const void *key, void *value, bool replace)
140{
141 uint64_t hv;
142 struct hash_bucket *bucket;
143 struct hash_element *he;
144 bool ret = false;
145
146 hv = hash_value(hash, key);
147 bucket = &hash->buckets[hv & hash->mask];
148
149 if ((he = hash_lookup_fast(hash, bucket, key, hv))) /* already exists? */
150 {
151 if (replace)
152 {
153 he->value = value;
154 ret = true;
155 }
156 }
157 else
158 {
159 hash_add_fast(hash, bucket, key, hv, value);
160 ret = true;
161 }
162
163 return ret;
164}
165
166void
168{
169 struct hash_iterator hi;
170 const struct hash_element *he;
171
173 while ((he = hash_iterator_next(&hi)))
174 {
175 if (he->value == value)
176 {
178 }
179 }
181}
182
183static void
184hash_remove_marked(struct hash *hash, struct hash_bucket *bucket)
185{
186 struct hash_element *prev = NULL;
187 struct hash_element *he = bucket->list;
188
189 while (he)
190 {
191 if (!he->key) /* marked? */
192 {
193 struct hash_element *newhe;
194 if (prev)
195 {
196 newhe = prev->next = he->next;
197 }
198 else
199 {
200 newhe = bucket->list = he->next;
201 }
202 free(he);
203 --hash->n_elements;
204 he = newhe;
205 }
206 else
207 {
208 prev = he;
209 he = he->next;
210 }
211 }
212}
213
214void
215hash_iterator_init_range(struct hash *hash, struct hash_iterator *hi, uint32_t start_bucket,
216 uint32_t end_bucket)
217{
218 if (end_bucket > hash->n_buckets)
219 {
220 end_bucket = hash->n_buckets;
221 }
222
223 ASSERT(start_bucket <= end_bucket);
224
225 hi->hash = hash;
226 hi->elem = NULL;
227 hi->bucket = NULL;
228 hi->last = NULL;
229 hi->bucket_marked = false;
230 hi->bucket_index_start = start_bucket;
231 hi->bucket_index_end = end_bucket;
232 hi->bucket_index = hi->bucket_index_start - 1;
233}
234
235void
240
241static inline void
243{
244 hi->bucket = b;
245 hi->last = NULL;
246 hi->bucket_marked = false;
247}
248
249static inline void
251{
252 if (hi->bucket)
253 {
254 if (hi->bucket_marked)
255 {
257 hi->bucket_marked = false;
258 }
259 hi->bucket = NULL;
260 hi->last = NULL;
261 }
262}
263
264static inline void
266{
267 hi->last = hi->elem;
268 hi->elem = hi->elem->next;
269}
270
271void
276
277struct hash_element *
279{
280 struct hash_element *ret = NULL;
281 if (hi->elem)
282 {
283 ret = hi->elem;
285 }
286 else
287 {
288 while (++hi->bucket_index < hi->bucket_index_end)
289 {
290 struct hash_bucket *b;
292 b = &hi->hash->buckets[hi->bucket_index];
293 if (b->list)
294 {
295 hash_iterator_lock(hi, b);
296 hi->elem = b->list;
297 if (hi->elem)
298 {
299 ret = hi->elem;
301 break;
302 }
303 }
304 }
305 }
306 return ret;
307}
308
309void
311{
312 ASSERT(hi->last);
313 hi->last->key = NULL;
314 hi->bucket_marked = true;
315}
#define ALLOC_OBJ_CLEAR(dptr, type)
Allocate and zero-initialise memory for a single object of the given type.
Definition buffer.h:1974
#define ALLOC_ARRAY(dptr, type, n)
Allocate memory for an array of n elements of the given type.
Definition buffer.h:1990
void prng_bytes(uint8_t *output, int len)
Definition crypto.c:1729
Data Channel Cryptography Module.
static size_t adjust_power_of_2(size_t u)
Definition integer.h:205
static void hash_remove_marked(struct hash *hash, struct hash_bucket *bucket)
Definition list.c:184
void hash_iterator_free(struct hash_iterator *hi)
Definition list.c:272
struct hash_element * hash_iterator_next(struct hash_iterator *hi)
Definition list.c:278
void hash_iterator_delete_element(struct hash_iterator *hi)
Definition list.c:310
void hash_iterator_init(struct hash *hash, struct hash_iterator *hi)
Definition list.c:236
struct hash * hash_init(const uint32_t n_buckets, uint64_t(*hash_function)(const void *key, const uint8_t hash_key[HASH_KEY_LEN]), bool(*compare_function)(const void *key1, const void *key2))
Definition list.c:36
static void hash_iterator_lock(struct hash_iterator *hi, struct hash_bucket *b)
Definition list.c:242
static void hash_iterator_unlock(struct hash_iterator *hi)
Definition list.c:250
bool hash_remove_fast(struct hash *hash, struct hash_bucket *bucket, const void *key, uint64_t hv)
Definition list.c:109
void hash_free(struct hash *hash)
Definition list.c:62
struct hash_element * hash_lookup_fast(struct hash *hash, struct hash_bucket *bucket, const void *key, uint64_t hv)
Definition list.c:81
bool hash_add(struct hash *hash, const void *key, void *value, bool replace)
Definition list.c:139
void hash_remove_by_value(struct hash *hash, void *value)
Definition list.c:167
static void hash_iterator_advance(struct hash_iterator *hi)
Definition list.c:265
void hash_iterator_init_range(struct hash *hash, struct hash_iterator *hi, uint32_t start_bucket, uint32_t end_bucket)
Definition list.c:215
#define HASH_KEY_LEN
Definition list.h:53
static void hash_add_fast(struct hash *hash, struct hash_bucket *bucket, const void *key, uint64_t hv, void *value)
Definition list.h:149
static uint64_t hash_value(const struct hash *hash, const void *key)
Definition list.h:107
#define ASSERT(x)
Definition error.h:219
struct hash_element * list
Definition list.h:49
void * value
Definition list.h:41
const void * key
Definition list.h:42
struct hash_element * next
Definition list.h:44
uint64_t hash_value
Definition list.h:43
uint32_t bucket_index_end
Definition list.h:92
bool bucket_marked
Definition list.h:90
struct hash_bucket * bucket
Definition list.h:87
struct hash * hash
Definition list.h:85
uint32_t bucket_index
Definition list.h:86
struct hash_element * elem
Definition list.h:88
uint32_t bucket_index_start
Definition list.h:91
struct hash_element * last
Definition list.h:89
Definition list.h:56
uint32_t mask
Definition list.h:59
struct hash_bucket * buckets
Definition list.h:65
uint64_t(* hash_function)(const void *key, const uint8_t hash_key[HASH_KEY_LEN])
Definition list.h:63
uint32_t n_elements
Definition list.h:58
uint8_t hash_key[HASH_KEY_LEN]
key/iv used for the hash function.
Definition list.h:62
bool(* compare_function)(const void *key1, const void *key2)
Definition list.h:64
uint32_t n_buckets
Definition list.h:57
Container for bidirectional cipher and HMAC key material.
Definition crypto.h:240
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152