OpenVPN
test_buffer.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) 2016-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
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 <setjmp.h>
31#include <cmocka.h>
32
33#include "buffer.h"
34#include "buffer.c"
35#include "test_common.h"
36
37static void
39{
40 assert_true(strprefix("123456", "123456"));
41 assert_true(strprefix("123456", "123"));
42 assert_true(strprefix("123456", ""));
43 assert_false(strprefix("123456", "456"));
44 assert_false(strprefix("12", "123"));
45}
46
47#define testsep ","
48#define testnosep ""
49#define teststr1 "one"
50#define teststr2 "two"
51#define teststr3 "three"
52
53#define assert_buf_equals_str(buf, str) \
54 assert_int_equal(BLEN(buf), strlen(str)); \
55 assert_memory_equal(BPTR(buf), str, BLEN(buf));
56
57static void
59{
60 struct gc_arena gc = gc_new();
61 struct buffer buf = alloc_buf_gc(16, &gc);
62
63 buf_printf(&buf, "%d", 123);
64 buf_printf(&buf, "%s", "some text, too long to fit");
65 assert_buf_equals_str(&buf, "123some text, t");
66
67 buf_catrunc(&buf, "...");
68 assert_buf_equals_str(&buf, "123some text...");
69
70 buf_catrunc(&buf, "some other text, much too long to fit");
71 assert_buf_equals_str(&buf, "123some text...");
72
73 buf_catrunc(&buf, "something else"); /* exactly right */
74 assert_buf_equals_str(&buf, "1something else");
75
76 buf_catrunc(&buf, "something other"); /* 1 byte too long */
77 assert_buf_equals_str(&buf, "1something else");
78
79 gc_free(&gc);
80}
81
82static void
84{
85 const int input_size = 10;
86 const uint8_t input[] = {
87 0x01, 0x00, 0xff, 0x10, 0xff, 0x00, 0xf0, 0x0f, 0x09, 0x0a
88 };
89 char *output;
90 struct gc_arena gc = gc_new();
91
92 int maxoutput = 0;
93 unsigned int blocksize = 5;
94 char *separator = " ";
95 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
96 assert_string_equal(output, "0100ff10ff 00f00f090a");
97
98 maxoutput = 14;
99 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
100 assert_string_equal(output, "0100[more...]");
101
102 maxoutput = 11;
103 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
104 assert_string_equal(output, "0[more...]");
105
106 maxoutput = 10;
107 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
108 assert_string_equal(output, "0100ff10f");
109
110 maxoutput = 9;
111 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
112 assert_string_equal(output, "0100ff10");
113
114 gc_free(&gc);
115}
116
123
124static int
126{
127 struct test_buffer_list_aggregate_ctx *ctx = calloc(1, sizeof(*ctx));
128 ctx->empty = buffer_list_new();
129
134
138
140 uint8_t data = 0;
141 buffer_list_push_data(ctx->empty_buffers, &data, 0);
142 buffer_list_push_data(ctx->empty_buffers, &data, 0);
143
144 *state = ctx;
145 return 0;
146}
147
148static int
150{
151 struct test_buffer_list_aggregate_ctx *ctx = *state;
152
157 free(ctx);
158 return 0;
159}
160
161static void
163{
164 struct test_buffer_list_aggregate_ctx *ctx = *state;
165
166 /* aggregating an empty buffer list results in an empty buffer list */
168 assert_null(ctx->empty->head);
169}
170
171static void
173{
174 struct test_buffer_list_aggregate_ctx *ctx = *state;
175
176 /* With a max length of 2, no aggregation should take place */
178 assert_int_equal(ctx->one_two_three->size, 3);
179 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
181}
182
183static void
185{
186 struct test_buffer_list_aggregate_ctx *ctx = *state;
187 const char *expected = teststr1 testsep teststr2 testsep;
188
189 /* Aggregate the first two elements
190 * (add 1 to max_len to test if "three" is not sneaked in too)
191 */
192 buffer_list_aggregate_separator(ctx->one_two_three, strlen(expected) + 1,
193 testsep);
194 assert_int_equal(ctx->one_two_three->size, 2);
195 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
197}
198
199static void
201{
202 struct test_buffer_list_aggregate_ctx *ctx = *state;
203
204 /* Aggregate all */
206 assert_int_equal(ctx->one_two_three->size, 1);
207 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
210}
211
212static void
214{
215 struct test_buffer_list_aggregate_ctx *ctx = *state;
216
217 /* Aggregate all */
219 assert_int_equal(ctx->one_two_three->size, 1);
220 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
222}
223
224static void
226{
227 struct test_buffer_list_aggregate_ctx *ctx = *state;
228 struct buffer_list *bl_zerolen = ctx->zero_length_strings;
229
230 /* Aggregate all */
231 buffer_list_aggregate_separator(bl_zerolen, 1<<16, testnosep);
232 assert_int_equal(bl_zerolen->size, 1);
233 struct buffer *buf = buffer_list_peek(bl_zerolen);
234 assert_buf_equals_str(buf, "");
235}
236
237static void
239{
240 struct test_buffer_list_aggregate_ctx *ctx = *state;
241 struct buffer_list *bl_emptybuffers = ctx->empty_buffers;
242
243 /* Aggregate all */
244 buffer_list_aggregate_separator(bl_emptybuffers, 1<<16, testnosep);
245 assert_int_equal(bl_emptybuffers->size, 1);
247 assert_int_equal(BLEN(buf), 0);
248}
249
250static void
252{
253 struct gc_arena gc = gc_new();
254 struct buffer buf = alloc_buf_gc(1024, &gc);
255
256 assert_ptr_equal(gc.list + 1, buf.data);
257 free_buf_gc(&buf, &gc);
259
260 gc_free(&gc);
261}
262
263static void
265{
266 struct gc_arena gc = gc_new();
267 struct buffer buf1 = alloc_buf_gc(1024, &gc);
268 struct buffer buf2 = alloc_buf_gc(1024, &gc);
269 struct buffer buf3 = alloc_buf_gc(1024, &gc);
270
271 struct gc_entry *e;
272
273 e = gc.list;
274
275 assert_ptr_equal(e + 1, buf3.data);
276 assert_ptr_equal(e->next + 1, buf2.data);
277 assert_ptr_equal(e->next->next + 1, buf1.data);
278
279 free_buf_gc(&buf2, &gc);
280
281 assert_non_null(gc.list);
282
283 while (e)
284 {
285 assert_ptr_not_equal(e + 1, buf2.data);
286 e = e->next;
287 }
288
289 gc_free(&gc);
290}
291
292
293static void
295{
296 struct gc_arena gc = gc_new();
297
298 void *p1 = gc_realloc(NULL, 512, &gc);
299 void *p2 = gc_realloc(NULL, 512, &gc);
300
301 assert_ptr_not_equal(p1, p2);
302
303 memset(p1, '1', 512);
304 memset(p2, '2', 512);
305
306 p1 = gc_realloc(p1, 512, &gc);
307
308 /* allocate 512kB to ensure the pointer needs to change */
309 void *p1new = gc_realloc(p1, 512ul * 1024, &gc);
310 assert_ptr_not_equal(p1, p1new);
311
312 void *p2new = gc_realloc(p2, 512ul * 1024, &gc);
313 assert_ptr_not_equal(p2, p2new);
314
315 void *p3 = gc_realloc(NULL, 512, &gc);
316 memset(p3, '3', 512);
317
318
319 gc_free(&gc);
320}
321
322static void
324{
325 char buf[256];
326 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
327 assert_false(string_mod(buf, CC_PRINT, 0, '@'));
328 assert_string_equal(buf, "There is @ a nice 1234 year old tr@ ee!");
329
330 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
331 assert_true(string_mod(buf, CC_ANY, 0, '@'));
332 assert_string_equal(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
333
334 /* 0 as replace removes characters */
335 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
336 assert_false(string_mod(buf, CC_PRINT, 0, '\0'));
337 assert_string_equal(buf, "There is a nice 1234 year old tr ee!");
338
339 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
340 assert_false(string_mod(buf, CC_PRINT, CC_DIGIT, '@'));
341 assert_string_equal(buf, "There is @ a nice @@@@ year old tr@ ee!");
342
343 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
344 assert_false(string_mod(buf, CC_ALPHA, CC_DIGIT, '.'));
345 assert_string_equal(buf, "There.is...a.nice......year.old.tr..ee.");
346
347 strcpy(buf, "There is \x01 a 'nice' \"1234\"\n year old \ntr\x7f ee!");
349 assert_string_equal(buf, "There.is...a.'nice'..1234.\n.year.old.\ntr..ee.");
350
351 strcpy(buf, "There is a \\'nice\\' \"1234\" [*] year old \ntree!");
352 assert_false(string_mod(buf, CC_PRINT, CC_BACKSLASH|CC_ASTERISK, '.'));
353 assert_string_equal(buf, "There is a .'nice.' \"1234\" [.] year old .tree!");
354}
355
356
357static void
359{
360 struct gc_arena gc = gc_new();
361
362 struct buffer buf = alloc_buf_gc(1024, &gc);
363
364 const char test1[] = "There is a nice 1234\x00 year old tree!";
365 buf_write(&buf, test1, sizeof(test1));
366
367 /* allow the null bytes and string but not the ! */
369
370 /* remove final ! and null byte to pass */
371 buf_inc_len(&buf, -2);
373
374 /* Check excluding digits works */
376 gc_free(&gc);
377}
378
379static void
380test_snprintf(void **state)
381{
382 /* we used to have a custom openvpn_snprintf function because some
383 * OS (the comment did not specify which) did not always put the
384 * null byte there. So we unit test this to be sure.
385 *
386 * This probably refers to the MSVC behaviour, see also
387 * https://stackoverflow.com/questions/7706936/is-snprintf-always-null-terminating
388 */
389
390 /* Instead of trying to trick the compiler here, disable the warnings
391 * for this unit test. We know that the results will be truncated
392 * and we want to test that. Not we need the clang as clang-cl (msvc) does
393 * not define __GNUC__ like it does under UNIX(-like) platforms */
394#if defined(__GNUC__) || defined(__clang__)
395/* some clang version do not understand -Wformat-truncation, so ignore the
396 * warning to avoid warnings/errors (-Werror) about unknown pragma/option */
397#if defined(__clang__)
398#pragma clang diagnostic push
399#pragma clang diagnostic ignored "-Wunknown-warning-option"
400#endif
401#pragma GCC diagnostic push
402#pragma GCC diagnostic ignored "-Wformat-truncation"
403#endif
404
405 char buf[10] = { 'a' };
406 int ret = 0;
407
408 ret = snprintf(buf, sizeof(buf), "0123456789abcde");
409 assert_int_equal(ret, 15);
410 assert_int_equal(buf[9], '\0');
411
412 memset(buf, 'b', sizeof(buf));
413 ret = snprintf(buf, sizeof(buf), "- %d - %d -", 77, 88);
414 assert_int_equal(ret, 11);
415 assert_int_equal(buf[9], '\0');
416
417 memset(buf, 'c', sizeof(buf));
418 ret = snprintf(buf, sizeof(buf), "- %8.2f", 77.8899);
419 assert_int_equal(ret, 10);
420 assert_int_equal(buf[9], '\0');
421
422#if defined(__GNUC__) || defined(__clang__)
423#pragma GCC diagnostic pop
424#if defined(__clang__)
425#pragma clang diagnostic pop
426#endif
427#endif
428}
429
430void
431test_buffer_chomp(void **state)
432{
433 struct gc_arena gc = gc_new();
434 struct buffer buf = alloc_buf_gc(1024, &gc);
435
436 const char test1[] = "There is a nice 1234 year old tree!\n\r";
437 buf_write(&buf, test1, sizeof(test1));
438 buf_chomp(&buf);
439 /* Check that our own method agrees */
441 assert_string_equal(BSTR(&buf), "There is a nice 1234 year old tree!");
442
443 struct buffer buf2 = alloc_buf_gc(1024, &gc);
444 const char test2[] = "CR_RESPONSE,MTIx\x0a\x00";
445 buf_write(&buf2, test2, sizeof(test2));
446 buf_chomp(&buf2);
447
448 buf_chomp(&buf2);
449 /* Check that our own method agrees */
451 assert_string_equal(BSTR(&buf2), "CR_RESPONSE,MTIx");
452
453 gc_free(&gc);
454}
455
456int
457main(void)
458{
460 const struct CMUnitTest tests[] = {
461 cmocka_unit_test(test_buffer_strprefix),
462 cmocka_unit_test(test_buffer_printf_catrunc),
463 cmocka_unit_test(test_buffer_format_hex_ex),
464 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_empty,
467 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_noop,
470 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_two,
473 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_all,
476 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_nosep,
479 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_zerolen,
482 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_emptybuffers,
485 cmocka_unit_test(test_buffer_free_gc_one),
486 cmocka_unit_test(test_buffer_free_gc_two),
487 cmocka_unit_test(test_buffer_gc_realloc),
488 cmocka_unit_test(test_character_class),
489 cmocka_unit_test(test_character_string_mod_buf),
490 cmocka_unit_test(test_snprintf),
491 cmocka_unit_test(test_buffer_chomp)
492 };
493
494 return cmocka_run_group_tests_name("buffer", tests, NULL, NULL);
495}
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition buffer.c:1212
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1252
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition buffer.c:190
void buf_catrunc(struct buffer *buf, const char *str)
Definition buffer.c:287
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
void * gc_realloc(void *ptr, size_t size, struct gc_arena *a)
allows to realloc a pointer previously allocated by gc_malloc or gc_realloc
Definition buffer.c:370
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1158
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition buffer.c:1239
bool string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition buffer.c:1073
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1167
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition buffer.c:1041
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition buffer.c:1198
void buf_chomp(struct buffer *buf)
Definition buffer.c:554
#define CC_DOUBLE_QUOTE
double quote
Definition buffer.h:908
#define CC_BLANK
space or tab
Definition buffer.h:896
#define BSTR(buf)
Definition buffer.h:129
#define CC_ANY
any character
Definition buffer.h:883
#define CC_SINGLE_QUOTE
single quote
Definition buffer.h:907
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:590
#define CC_DIGIT
digit isdigit()
Definition buffer.h:890
#define CC_CRLF
carriage return or newline
Definition buffer.h:920
#define CC_ASTERISK
asterisk
Definition buffer.h:916
#define CC_ALPHA
alphabetic isalpha()
Definition buffer.h:887
#define CC_NEWLINE
newline
Definition buffer.h:897
#define CC_SPACE
whitespace isspace()
Definition buffer.h:893
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:668
#define CC_BACKSLASH
backslash
Definition buffer.h:900
#define BLEN(buf)
Definition buffer.h:127
#define CC_NULL
null character \0
Definition buffer.h:884
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:891
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:886
static bool strprefix(const char *str, const char *prefix)
Return true iff str starts with prefix.
Definition buffer.h:977
static struct gc_arena gc_new(void)
Definition buffer.h:1025
struct buffer_entry * head
Definition buffer.h:1122
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:68
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:118
Garbage collection entry for one dynamically allocated block of memory.
Definition buffer.h:88
struct gc_entry * next
Pointer to the next item in the linked list.
Definition buffer.h:89
struct buffer_list * zero_length_strings
struct buffer_list * one_two_three
struct buffer_list * empty
struct buffer_list * empty_buffers
static void test_character_class(void **state)
static void test_buffer_format_hex_ex(void **state)
Definition test_buffer.c:83
static int test_buffer_list_setup(void **state)
static void test_buffer_list_aggregate_separator_all(void **state)
#define assert_buf_equals_str(buf, str)
Definition test_buffer.c:53
static void test_buffer_free_gc_two(void **state)
static void test_snprintf(void **state)
static void test_character_string_mod_buf(void **state)
#define teststr1
Definition test_buffer.c:49
static void test_buffer_list_aggregate_separator_zerolen(void **state)
static void test_buffer_printf_catrunc(void **state)
Definition test_buffer.c:58
void test_buffer_chomp(void **state)
int main(void)
static void test_buffer_list_aggregate_separator_two(void **state)
#define testnosep
Definition test_buffer.c:48
static void test_buffer_list_aggregate_separator_noop(void **state)
static void test_buffer_free_gc_one(void **state)
#define teststr2
Definition test_buffer.c:50
static void test_buffer_list_aggregate_separator_nosep(void **state)
static void test_buffer_gc_realloc(void **state)
static void test_buffer_list_aggregate_separator_empty(void **state)
static int test_buffer_list_teardown(void **state)
static void test_buffer_list_aggregate_separator_emptybuffers(void **state)
static void test_buffer_strprefix(void **state)
Definition test_buffer.c:38
#define teststr3
Definition test_buffer.c:51
#define testsep
Definition test_buffer.c:47
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
struct gc_arena gc
Definition test_ssl.c:155