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 
42 static void
44 {
45  struct gc_arena gc = gc_new();
46 
47  const char *input = "V4,dev-type tun,link-mtu 1457,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
48 
49  const char *output = options_string_compat_lzo(input, &gc);
50 
51  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");
52 
53  /* This string is has a much too small link-mtu so we should fail on it" */
54  input = "V4,dev-type tun,link-mtu 2,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
55 
56  output = options_string_compat_lzo(input, &gc);
57 
58  assert_string_equal(input, output);
59 
60  /* not matching at all */
61  input = "V4,dev-type tun";
62  output = options_string_compat_lzo(input, &gc);
63 
64  assert_string_equal(input, output);
65 
66 
67  input = "V4,dev-type tun,link-mtu 999,tun-mtu 1400,proto UDPv4,auth SHA1,keysize 128,key-method 2,tls-server";
68  output = options_string_compat_lzo(input, &gc);
69 
70  /* 999 -> 1000, 3 to 4 chars */
71  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");
72 
73  gc_free(&gc);
74 }
75 
76 static void
78 {
79  struct options o;
80 
81  const char *teststr = "TEMP:There are no flags here [really not]";
82 
83  const char *msg = parse_auth_failed_temp(&o, teststr + strlen("TEMP"));
84  assert_string_equal(msg, "There are no flags here [really not]");
85 }
86 
87 static void
89 {
90  struct options o;
91 
92  const char *teststr = "[backoff 42,advance no]";
93 
94  const char *msg = parse_auth_failed_temp(&o, teststr);
95  assert_string_equal(msg, "");
96  assert_int_equal(o.server_backoff_time, 42);
97  assert_int_equal(o.no_advance, true);
98 }
99 
100 static void
102 {
103  struct options o;
104 
105  const char *teststr = "[advance remote,backoff 77]:go round and round";
106 
107  const char *msg = parse_auth_failed_temp(&o, teststr);
108  assert_string_equal(msg, "go round and round");
109  assert_int_equal(o.server_backoff_time, 77);
110 }
111 
112 
113 
114 struct word
115 {
116  const char *word;
117  int n;
118 };
119 
120 
121 static uint32_t
122 word_hash_function(const void *key, uint32_t iv)
123 {
124  const char *str = (const char *) key;
125  const int len = strlen(str);
126  return hash_func((const uint8_t *)str, len, iv);
127 }
128 
129 static bool
130 word_compare_function(const void *key1, const void *key2)
131 {
132  return strcmp((const char *)key1, (const char *)key2) == 0;
133 }
134 
135 static unsigned long
137 {
138  /* rand() is not very random, but it's C99 and this is just for testing */
139  return rand();
140 }
141 
142 static struct hash_element *
144 {
145  struct hash_iterator hi;
146  struct hash_element *he;
147  struct hash_element *ret = NULL;
148  hash_iterator_init(hash, &hi);
149 
150  while ((he = hash_iterator_next(&hi)))
151  {
152  if (he->value == value)
153  {
154  ret = he;
155  }
156  }
157  hash_iterator_free(&hi);
158  return ret;
159 }
160 
161 static void
162 test_list(void **state)
163 {
164 
165 /*
166  * Test the hash code by implementing a simple
167  * word frequency algorithm.
168  */
169 
170  struct gc_arena gc = gc_new();
173 
174  printf("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask);
175 
176  char wordfile[PATH_MAX] = { 0 };
177  openvpn_test_get_srcdir_dir(wordfile, PATH_MAX, "/../../../COPYRIGHT.GPL" );
178 
179  FILE *words = fopen(wordfile, "r");
180  assert_non_null(words);
181 
182  int wordcount = 0;
183 
184  /* parse words from file */
185  while (true)
186  {
187  char buf[256];
188  char wordbuf[256];
189 
190  if (!fgets(buf, sizeof(buf), words))
191  {
192  break;
193  }
194 
195  char c = 0;
196  int bi = 0, wbi = 0;
197 
198  do
199  {
200  c = buf[bi++];
201  if (isalnum(c) || c == '_')
202  {
203  assert_true(wbi < (int) sizeof(wordbuf));
204  wordbuf[wbi++] = c;
205  }
206  else
207  {
208  if (wbi)
209  {
210  wordcount++;
211 
212  ASSERT(wbi < (int) sizeof(wordbuf));
213  wordbuf[wbi++] = '\0';
214 
215  /* word is parsed from stdin */
216 
217  /* does it already exist in table? */
218  struct word *w = (struct word *) hash_lookup(hash, wordbuf);
219 
220  if (w)
221  {
222  assert_string_equal(w->word, wordbuf);
223  /* yes, increment count */
224  ++w->n;
225  }
226  else
227  {
228  /* no, make a new object */
229  ALLOC_OBJ_GC(w, struct word, &gc);
230  w->word = string_alloc(wordbuf, &gc);
231  w->n = 1;
232  assert_true(hash_add(hash, w->word, w, false));
233  assert_true(hash_add(nhash, w->word, (void *) ((ptr_type )(random() & 0x0F) + 1), false));
234  }
235  }
236  wbi = 0;
237  }
238  }
239  while (c);
240  }
241 
242  assert_int_equal(wordcount, 2978);
243 
244  /* remove some words from the table */
245  {
246  assert_true(hash_remove(hash, "DEFECTIVE"));
247  assert_false(hash_remove(hash, "false"));
248  }
249 
250  /* output contents of hash table */
251  {
252  ptr_type inc = 0;
253  int count = 0;
254 
255  for (ptr_type base = 0; base < hash_n_buckets(hash); base += inc)
256  {
257  struct hash_iterator hi;
258  struct hash_element *he;
259  inc = (get_random() % 3) + 1;
260  hash_iterator_init_range(hash, &hi, base, base + inc);
261 
262  while ((he = hash_iterator_next(&hi)))
263  {
264  struct word *w = (struct word *) he->value;
265  /*printf("%6d '%s'\n", w->n, w->word); */
266  ++count;
267  /* check a few words to match prior results */
268  if (!strcmp(w->word, "is"))
269  {
270  assert_int_equal(w->n, 49);
271  }
272  else if (!strcmp(w->word, "redistribute"))
273  {
274  assert_int_equal(w->n, 5);
275  }
276  else if (!strcmp(w->word, "circumstances"))
277  {
278  assert_int_equal(w->n, 1);
279  }
280  else if (!strcmp(w->word, "so"))
281  {
282  assert_int_equal(w->n, 8);
283  }
284  else if (!strcmp(w->word, "BECAUSE"))
285  {
286  assert_int_equal(w->n, 1);
287  }
288  }
289 
290  hash_iterator_free(&hi);
291  }
292  assert_int_equal(count, hash_n_elements(hash));
293  }
294 
295  /* test hash_remove_by_value function */
296  {
297  for (ptr_type i = 1; i <= 16; ++i)
298  {
299  struct hash_element *item = hash_lookup_by_value(nhash, (void *) i);
300  hash_remove_by_value(nhash, (void *) i);
301  /* check item got removed if it was present before */
302  if (item)
303  {
304  assert_null(hash_lookup_by_value(nhash, (void *) i));
305  }
306  }
307  }
308 
309  hash_free(hash);
310  hash_free(nhash);
311  gc_free(&gc);
312 }
313 
314 
315 const struct CMUnitTest misc_tests[] = {
316  cmocka_unit_test(test_compat_lzo_string),
317  cmocka_unit_test(test_auth_fail_temp_no_flags),
318  cmocka_unit_test(test_auth_fail_temp_flags),
319  cmocka_unit_test(test_auth_fail_temp_flags_msg),
320  cmocka_unit_test(test_list)
321 };
322 
323 int
324 main(void)
325 {
327  return cmocka_run_group_tests(misc_tests, NULL, NULL);
328 }
hash_n_elements
static int hash_n_elements(const struct hash *hash)
Definition: list.h:122
hash_init
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
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1030
hash_iterator
Definition: list.h:88
hash
Definition: list.h:56
test_common.h
test_auth_fail_temp_flags
static void test_auth_fail_temp_flags(void **state)
Definition: test_misc.c:88
test_list
static void test_list(void **state)
Definition: test_misc.c:162
key1
static const char *const key1
Definition: cert_data.h:56
main
int main(void)
Definition: test_misc.c:324
hash_add
bool hash_add(struct hash *hash, const void *key, void *value, bool replace)
Definition: list.c:147
hash_element::value
void * value
Definition: list.h:45
hash_remove
static bool hash_remove(struct hash *hash, const void *key)
Definition: list.h:176
hash_lookup
static void * hash_lookup(struct hash *hash, const void *key)
Definition: list.h:140
parse_auth_failed_temp
const char * parse_auth_failed_temp(struct options *o, const char *reason)
Definition: options_util.c:34
key
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:149
hash_remove_by_value
void hash_remove_by_value(struct hash *hash, void *value)
Definition: list.c:175
hash_iterator_free
void hash_iterator_free(struct hash_iterator *hi)
Definition: list.c:283
misc_tests
const struct CMUnitTest misc_tests[]
Definition: test_misc.c:315
test_auth_fail_temp_flags_msg
static void test_auth_fail_temp_flags_msg(void **state)
Definition: test_misc.c:101
options_util.h
ssl_util.h
word::n
int n
Definition: test_misc.c:117
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:667
ASSERT
#define ASSERT(x)
Definition: error.h:195
word_hash_function
static uint32_t word_hash_function(const void *key, uint32_t iv)
Definition: test_misc.c:122
hash_iterator_next
struct hash_element * hash_iterator_next(struct hash_iterator *hi)
Definition: list.c:289
get_random
static unsigned long get_random(void)
Definition: test_misc.c:136
hash_lookup_by_value
static struct hash_element * hash_lookup_by_value(struct hash *hash, void *value)
Definition: test_misc.c:143
options
Definition: options.h:236
options::no_advance
bool no_advance
Definition: options.h:280
hash::mask
int mask
Definition: list.h:60
word_compare_function
static bool word_compare_function(const void *key1, const void *key2)
Definition: test_misc.c:130
syshead.h
hash_iterator_init
void hash_iterator_init(struct hash *hash, struct hash_iterator *hi)
Definition: list.c:246
word::word
const char * word
Definition: test_misc.c:116
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
openvpn_unit_test_setup
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
test_compat_lzo_string
static void test_compat_lzo_string(void **state)
Definition: test_misc.c:43
hash_free
void hash_free(struct hash *hash)
Definition: list.c:63
ptr_type
unsigned long ptr_type
Definition: common.h:58
test_auth_fail_temp_no_flags
static void test_auth_fail_temp_no_flags(void **state)
Definition: test_misc.c:77
hash_element
Definition: list.h:43
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1038
options_string_compat_lzo
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
config.h
key2
Container for bidirectional cipher and HMAC key material.
Definition: crypto.h:179
word
Definition: test_misc.c:114
hash::n_buckets
int n_buckets
Definition: list.h:58
hash_n_buckets
static int hash_n_buckets(const struct hash *hash)
Definition: list.h:128
list.h
random
#define random
Definition: syshead.h:44
options::server_backoff_time
int server_backoff_time
Definition: options.h:291
msg
#define msg(flags,...)
Definition: error.h:144
hash_func
uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval)
Definition: list.c:408
openvpn_test_get_srcdir_dir
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
hash_iterator_init_range
void hash_iterator_init_range(struct hash *hash, struct hash_iterator *hi, int start_bucket, int end_bucket)
Definition: list.c:223
ALLOC_OBJ_GC
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition: buffer.h:1097