OpenVPN
test_misc.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single 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) 2021-2024 Arne Schwabe <arne@rfc2549.org>
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, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <string.h>
34#include <setjmp.h>
35#include <cmocka.h>
36
37#include "ssl_util.h"
38#include "options_util.h"
39#include "test_common.h"
40#include "list.h"
41#include "mock_msg.h"
42
43static void
45{
46 struct gc_arena gc = gc_new();
47
48 const char *input = "V4,dev-type tun,link-mtu 1457,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
49
50 const char *output = options_string_compat_lzo(input, &gc);
51
52 assert_string_equal(output, "V4,dev-type tun,link-mtu 1458,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server,comp-lzo");
53
54 /* This string is has a much too small link-mtu so we should fail on it" */
55 input = "V4,dev-type tun,link-mtu 2,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
56
57 output = options_string_compat_lzo(input, &gc);
58
59 assert_string_equal(input, output);
60
61 /* not matching at all */
62 input = "V4,dev-type tun";
63 output = options_string_compat_lzo(input, &gc);
64
65 assert_string_equal(input, output);
66
67
68 input = "V4,dev-type tun,link-mtu 999,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
69 output = options_string_compat_lzo(input, &gc);
70
71 /* 999 -> 1000, 3 to 4 chars */
72 assert_string_equal(output, "V4,dev-type tun,link-mtu 1000,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server,comp-lzo");
73
74 gc_free(&gc);
75}
76
77static void
79{
80 struct options o;
81
82 const char *teststr = "TEMP:There are no flags here [really not]";
83
84 const char *msg = parse_auth_failed_temp(&o, teststr + strlen("TEMP"));
85 assert_string_equal(msg, "There are no flags here [really not]");
86}
87
88static void
90{
91 struct options o;
92
93 const char *teststr = "[backoff 42,advance no]";
94
95 const char *msg = parse_auth_failed_temp(&o, teststr);
96 assert_string_equal(msg, "");
97 assert_int_equal(o.server_backoff_time, 42);
98 assert_int_equal(o.no_advance, true);
99}
100
101static void
103{
104 struct options o;
105
106 const char *teststr = "[advance remote,backoff 77]:go round and round";
107
108 const char *msg = parse_auth_failed_temp(&o, teststr);
109 assert_string_equal(msg, "go round and round");
110 assert_int_equal(o.server_backoff_time, 77);
111}
112
113
114
115struct word
116{
117 const char *word;
118 int n;
119};
120
121
122static uint32_t
123word_hash_function(const void *key, uint32_t iv)
124{
125 const char *str = (const char *) key;
126 const int len = strlen(str);
127 return hash_func((const uint8_t *)str, len, iv);
128}
129
130static bool
131word_compare_function(const void *key1, const void *key2)
132{
133 return strcmp((const char *)key1, (const char *)key2) == 0;
134}
135
136static unsigned long
138{
139 /* rand() is not very random, but it's C99 and this is just for testing */
140 return rand();
141}
142
143static struct hash_element *
145{
146 struct hash_iterator hi;
147 struct hash_element *he;
148 struct hash_element *ret = NULL;
150
151 while ((he = hash_iterator_next(&hi)))
152 {
153 if (he->value == value)
154 {
155 ret = he;
156 }
157 }
159 return ret;
160}
161
162static void
163test_list(void **state)
164{
165
166/*
167 * Test the hash code by implementing a simple
168 * word frequency algorithm.
169 */
170
171 struct gc_arena gc = gc_new();
174
175 printf("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask);
176
177 char wordfile[PATH_MAX] = { 0 };
178 openvpn_test_get_srcdir_dir(wordfile, PATH_MAX, "/../../../COPYRIGHT.GPL" );
179
180 FILE *words = fopen(wordfile, "r");
181 assert_non_null(words);
182
183 int wordcount = 0;
184
185 /* parse words from file */
186 while (true)
187 {
188 char buf[256];
189 char wordbuf[256];
190
191 if (!fgets(buf, sizeof(buf), words))
192 {
193 break;
194 }
195
196 char c = 0;
197 int bi = 0, wbi = 0;
198
199 do
200 {
201 c = buf[bi++];
202 if (isalnum(c) || c == '_')
203 {
204 assert_true(wbi < (int) sizeof(wordbuf));
205 wordbuf[wbi++] = c;
206 }
207 else
208 {
209 if (wbi)
210 {
211 wordcount++;
212
213 ASSERT(wbi < (int) sizeof(wordbuf));
214 wordbuf[wbi++] = '\0';
215
216 /* word is parsed from stdin */
217
218 /* does it already exist in table? */
219 struct word *w = (struct word *) hash_lookup(hash, wordbuf);
220
221 if (w)
222 {
223 assert_string_equal(w->word, wordbuf);
224 /* yes, increment count */
225 ++w->n;
226 }
227 else
228 {
229 /* no, make a new object */
230 ALLOC_OBJ_GC(w, struct word, &gc);
231 w->word = string_alloc(wordbuf, &gc);
232 w->n = 1;
233 assert_true(hash_add(hash, w->word, w, false));
234 assert_true(hash_add(nhash, w->word, (void *) ((ptr_type )(random() & 0x0F) + 1), false));
235 }
236 }
237 wbi = 0;
238 }
239 }
240 while (c);
241 }
242
243 assert_int_equal(wordcount, 2978);
244
245 /* remove some words from the table */
246 {
247 assert_true(hash_remove(hash, "DEFECTIVE"));
248 assert_false(hash_remove(hash, "false"));
249 }
250
251 /* output contents of hash table */
252 {
253 ptr_type inc = 0;
254 int count = 0;
255
256 for (ptr_type base = 0; base < hash_n_buckets(hash); base += inc)
257 {
258 struct hash_iterator hi;
259 struct hash_element *he;
260 inc = (get_random() % 3) + 1;
261 hash_iterator_init_range(hash, &hi, base, base + inc);
262
263 while ((he = hash_iterator_next(&hi)))
264 {
265 struct word *w = (struct word *) he->value;
266 /*printf("%6d '%s'\n", w->n, w->word); */
267 ++count;
268 /* check a few words to match prior results */
269 if (!strcmp(w->word, "is"))
270 {
271 assert_int_equal(w->n, 49);
272 }
273 else if (!strcmp(w->word, "redistribute"))
274 {
275 assert_int_equal(w->n, 5);
276 }
277 else if (!strcmp(w->word, "circumstances"))
278 {
279 assert_int_equal(w->n, 1);
280 }
281 else if (!strcmp(w->word, "so"))
282 {
283 assert_int_equal(w->n, 8);
284 }
285 else if (!strcmp(w->word, "BECAUSE"))
286 {
287 assert_int_equal(w->n, 1);
288 }
289 }
290
292 }
293 assert_int_equal(count, hash_n_elements(hash));
294 }
295
296 /* test hash_remove_by_value function */
297 {
298 for (ptr_type i = 1; i <= 16; ++i)
299 {
300 struct hash_element *item = hash_lookup_by_value(nhash, (void *) i);
301 hash_remove_by_value(nhash, (void *) i);
302 /* check item got removed if it was present before */
303 if (item)
304 {
305 assert_null(hash_lookup_by_value(nhash, (void *) i));
306 }
307 }
308 }
309
311 hash_free(nhash);
312 gc_free(&gc);
313}
314
315static void
317{
318 assert_true(valid_integer("1234", true));
319 assert_true(valid_integer("1234", false));
320 assert_true(valid_integer("0", false));
321 assert_true(valid_integer("0", true));
322 assert_true(valid_integer("-777", false));
323 assert_false(valid_integer("-777", true));
324
325 assert_false(valid_integer("-777foo", false));
326 assert_false(valid_integer("-777foo", true));
327
328 assert_false(valid_integer("foo777", true));
329 assert_false(valid_integer("foo777", false));
330
331 /* 2**31 + 5 , just outside of signed int range */
332 assert_false(valid_integer("2147483653", true));
333 assert_false(valid_integer("2147483653", false));
334 assert_false(valid_integer("-2147483653", true));
335 assert_false(valid_integer("-2147483653", false));
336
337
338 int msglevel = D_LOW;
339 int saved_log_level = mock_get_debug_level();
341
342 /* check happy path */
343 assert_int_equal(positive_atoi("1234", msglevel), 1234);
344 assert_int_equal(positive_atoi("0", msglevel), 0);
345
346 assert_int_equal(atoi_warn("1234", msglevel), 1234);
347 assert_int_equal(atoi_warn("0", msglevel), 0);
348 assert_int_equal(atoi_warn("-1194", msglevel), -1194);
349
351 assert_int_equal(positive_atoi("-1234", msglevel), 0);
352 assert_string_equal(mock_msg_buf, "Cannot parse argument '-1234' as non-negative integer");
353
354 /* 2**31 + 5 , just outside of signed int range */
356 assert_int_equal(positive_atoi("2147483653", msglevel), 0);
357 assert_string_equal(mock_msg_buf, "Cannot parse argument '2147483653' as non-negative integer");
358
360 assert_int_equal(atoi_warn("2147483653", msglevel), 0);
361 assert_string_equal(mock_msg_buf, "Cannot parse argument '2147483653' as integer");
362
364 assert_int_equal(positive_atoi("foo77", msglevel), 0);
365 assert_string_equal(mock_msg_buf, "Cannot parse argument 'foo77' as non-negative integer");
366
368 assert_int_equal(positive_atoi("77foo", msglevel), 0);
369 assert_string_equal(mock_msg_buf, "Cannot parse argument '77foo' as non-negative integer");
370
372 assert_int_equal(atoi_warn("foo77", msglevel), 0);
373 assert_string_equal(mock_msg_buf, "Cannot parse argument 'foo77' as integer");
374
376 assert_int_equal(atoi_warn("77foo", msglevel), 0);
377 assert_string_equal(mock_msg_buf, "Cannot parse argument '77foo' as integer");
378
379 mock_set_debug_level(saved_log_level);
380}
381
382const struct CMUnitTest misc_tests[] = {
383 cmocka_unit_test(test_compat_lzo_string),
384 cmocka_unit_test(test_auth_fail_temp_no_flags),
385 cmocka_unit_test(test_auth_fail_temp_flags),
386 cmocka_unit_test(test_auth_fail_temp_flags_msg),
387 cmocka_unit_test(test_list),
388 cmocka_unit_test(test_atoi_variants)
389};
390
391int
392main(void)
393{
395 return cmocka_run_group_tests(misc_tests, NULL, NULL);
396}
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition buffer.h:1092
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
static const char *const key1
Definition cert_data.h:56
unsigned long ptr_type
Definition common.h:58
#define D_LOW
Definition errlevel.h:97
void hash_iterator_free(struct hash_iterator *hi)
Definition list.c:283
struct hash_element * hash_iterator_next(struct hash_iterator *hi)
Definition list.c:289
void hash_iterator_init(struct hash *hash, struct hash_iterator *hi)
Definition list.c:246
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))
Definition list.c:38
void hash_iterator_init_range(struct hash *hash, struct hash_iterator *hi, int start_bucket, int end_bucket)
Definition list.c:223
uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval)
Definition list.c:408
void hash_free(struct hash *hash)
Definition list.c:63
bool hash_add(struct hash *hash, const void *key, void *value, bool replace)
Definition list.c:147
void hash_remove_by_value(struct hash *hash, void *value)
Definition list.c:175
static bool hash_remove(struct hash *hash, const void *key)
Definition list.h:176
static void * hash_lookup(struct hash *hash, const void *key)
Definition list.h:140
static int hash_n_elements(const struct hash *hash)
Definition list.h:122
static int hash_n_buckets(const struct hash *hash)
Definition list.h:128
int mock_get_debug_level(void)
Definition mock_msg.c:57
char mock_msg_buf[MOCK_MSG_BUF]
Definition mock_msg.c:47
void mock_set_debug_level(int level)
Mock debug level defaults to 0, which gives clean(-ish) test reports.
Definition mock_msg.c:51
#define CLEAR(x)
Definition basic.h:33
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
int positive_atoi(const char *str, int msglevel)
Converts a str to a positive number if the string represents a postive integer number.
int atoi_warn(const char *str, int msglevel)
Converts a str to an integer if the string can be represented as an integer number.
const char * parse_auth_failed_temp(struct options *o, const char *reason)
bool valid_integer(const char *str, bool positive)
Checks if the string is a valid integer by checking if it can be converted to an integer.
const char * options_string_compat_lzo(const char *options, struct gc_arena *gc)
Takes a locally produced OCC string for TLS server mode and modifies as if the option comp-lzo was en...
Definition ssl_util.c:78
SSL utility functions.
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
void * value
Definition list.h:45
Definition list.h:57
int n_buckets
Definition list.h:58
int mask
Definition list.h:60
Container for bidirectional cipher and HMAC key material.
Definition crypto.h:239
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
int server_backoff_time
Definition options.h:304
bool no_advance
Definition options.h:293
int n
Definition test_misc.c:118
const char * word
Definition test_misc.c:117
#define random
Definition syshead.h:44
static void openvpn_unit_test_setup(void)
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition test_common.h:36
void openvpn_test_get_srcdir_dir(char *buf, size_t bufsize, const char *filename)
Helper function to get a file path from the unit test directory to open it or pass its path to anothe...
Definition test_common.h:54
static void test_atoi_variants(void **state)
Definition test_misc.c:316
static void test_auth_fail_temp_flags(void **state)
Definition test_misc.c:89
static void test_compat_lzo_string(void **state)
Definition test_misc.c:44
int main(void)
Definition test_misc.c:392
static uint32_t word_hash_function(const void *key, uint32_t iv)
Definition test_misc.c:123
static void test_list(void **state)
Definition test_misc.c:163
static void test_auth_fail_temp_no_flags(void **state)
Definition test_misc.c:78
const struct CMUnitTest misc_tests[]
Definition test_misc.c:382
static unsigned long get_random(void)
Definition test_misc.c:137
static bool word_compare_function(const void *key1, const void *key2)
Definition test_misc.c:131
static struct hash_element * hash_lookup_by_value(struct hash *hash, void *value)
Definition test_misc.c:144
static void test_auth_fail_temp_flags_msg(void **state)
Definition test_misc.c:102
struct gc_arena gc
Definition test_ssl.c:155