OpenVPN
test_packet_id.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-2026 Sentyron B.V. <openvpn@sentyron.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
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, see <https://www.gnu.org/licenses/>.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include <stdarg.h>
31#include <stddef.h>
32#include <setjmp.h>
33#include <cmocka.h>
34
35#include "packet_id.h"
36#include "reliable.h"
37#include "test_common.h"
38
40{
41 struct
42 {
43 uint32_t buf_id;
44 uint32_t buf_time;
48 struct gc_arena gc;
49};
50
51static int
53{
54 struct test_packet_id_write_data *data = calloc(1, sizeof(struct test_packet_id_write_data));
55
56 if (!data)
57 {
58 return -1;
59 }
60
61 data->test_buf.data = (void *)&data->test_buf_data;
62 data->test_buf.capacity = sizeof(data->test_buf_data);
63 data->gc = gc_new();
64
65 *state = data;
66 return 0;
67}
68
69static int
71{
72 struct test_packet_id_write_data *data = *state;
73 gc_free(&data->gc);
74 free(*state);
75 return 0;
76}
77
78static void
80{
81 struct test_packet_id_write_data *data = *state;
82
83 now = 5010;
84 assert_true(packet_id_write(&data->pis, &data->test_buf, false, false));
85 assert_int_equal(data->pis.id, 1);
86 assert_int_equal(data->test_buf_data.buf_id, htonl(1));
87 assert_int_equal(data->test_buf_data.buf_time, 0);
88}
89
90static void
92{
93 struct test_packet_id_write_data *data = *state;
94
95 now = 5010;
96 assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
97 assert_int_equal(data->pis.id, 1);
98 assert_int_equal(data->pis.time, now);
99 assert_int_equal(data->test_buf_data.buf_id, htonl(1));
100 assert_int_equal(data->test_buf_data.buf_time, htonl((uint32_t)now));
101}
102
103static void
105{
106 struct test_packet_id_write_data *data = *state;
107
108 data->test_buf.offset = sizeof(packet_id_type);
109 now = 5010;
110 assert_true(packet_id_write(&data->pis, &data->test_buf, false, true));
111 assert_int_equal(data->pis.id, 1);
112 assert_int_equal(data->test_buf_data.buf_id, htonl(1));
113 assert_int_equal(data->test_buf_data.buf_time, 0);
114}
115
116static void
118{
119 struct test_packet_id_write_data *data = *state;
120
121 data->test_buf.offset = sizeof(data->test_buf_data);
122 now = 5010;
123 assert_true(packet_id_write(&data->pis, &data->test_buf, true, true));
124 assert_int_equal(data->pis.id, 1);
125 assert_int_equal(data->pis.time, now);
126 assert_int_equal(data->test_buf_data.buf_id, htonl(1));
127 assert_int_equal(data->test_buf_data.buf_time, htonl((uint32_t)now));
128}
129
130static void
132{
133 struct test_packet_id_write_data *data = *state;
134
135 /* maximum 32-bit packet id */
136 data->pis.id = (packet_id_type)(~0);
137 assert_false(packet_id_write(&data->pis, &data->test_buf, false, false));
138}
139
140static void
142{
143 struct test_packet_id_write_data *data = *state;
144
145 /* maximum 32-bit packet id */
146 data->pis.id = (packet_id_type)(~0);
147 data->pis.time = 5006;
148
149 /* Write fails if time did not change */
150 now = 5006;
151 assert_false(packet_id_write(&data->pis, &data->test_buf, true, false));
152
153 /* Write succeeds if time moved forward */
154 now = 5010;
155 assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
156
157 assert_int_equal(data->pis.id, 1);
158 assert_int_equal(data->pis.time, now);
159 assert_int_equal(data->test_buf_data.buf_id, htonl(1));
160 assert_int_equal(data->test_buf_data.buf_time, htonl((uint32_t)now));
161}
162
163static void
165{
166 struct reliable *rel = malloc(sizeof(struct reliable));
167 assert_non_null(rel);
168 reliable_init(rel, 100, 50, 8, false);
169
170 rel->array[5].active = true;
171 rel->array[5].packet_id = 100;
172
173 rel->packet_id = 103;
174
175 assert_int_equal(5, reliable_get_num_output_sequenced_available(rel));
176
177 rel->array[6].active = true;
178 rel->array[6].packet_id = 97;
179 assert_int_equal(2, reliable_get_num_output_sequenced_available(rel));
180
181 /* test ids close to int/unsigned int barrier */
182
183 rel->array[5].active = true;
184 rel->array[5].packet_id = (0x80000000u - 3);
185 rel->array[6].active = false;
186 rel->packet_id = (0x80000000u - 1);
187
188 assert_int_equal(6, reliable_get_num_output_sequenced_available(rel));
189
190 rel->array[5].active = true;
191 rel->array[5].packet_id = (0x80000000u - 3);
192 rel->packet_id = 0x80000001u;
193
194 assert_int_equal(4, reliable_get_num_output_sequenced_available(rel));
195
196
197 /* test wrapping */
198 rel->array[5].active = true;
199 rel->array[5].packet_id = (0xffffffffu - 3);
200 rel->array[6].active = false;
201 rel->packet_id = (0xffffffffu - 1);
202
203 assert_int_equal(6, reliable_get_num_output_sequenced_available(rel));
204
205 rel->array[2].packet_id = 0;
206 rel->array[2].active = true;
207
208 assert_int_equal(6, reliable_get_num_output_sequenced_available(rel));
209
210 rel->packet_id = 3;
211 assert_int_equal(1, reliable_get_num_output_sequenced_available(rel));
212
213 reliable_free(rel);
214}
215
216static void
218{
219 struct test_packet_id_write_data *data = *state;
220
221 struct buffer buf = alloc_buf_gc(128, &data->gc);
222
223 /* test normal writing of packet id to the buffer */
224 assert_true(packet_id_write_epoch(&data->pis, 0x23, &buf));
225
226 assert_int_equal(buf.len, 8);
227 uint8_t expected_header[8] = { 0x00, 0x23, 0, 0, 0, 0, 0, 1 };
228 assert_memory_equal(BPTR(&buf), expected_header, 8);
229
230 /* too small buffer should error out */
231 struct buffer buf_short = alloc_buf_gc(5, &data->gc);
232 assert_false(packet_id_write_epoch(&data->pis, 0xabde, &buf_short));
233
234 /* test a true 48 bit packet id */
235 data->pis.id = 0xfa079ab9d2e8;
236 struct buffer buf_48 = alloc_buf_gc(128, &data->gc);
237 assert_true(packet_id_write_epoch(&data->pis, 0xfffe, &buf_48));
238 uint8_t expected_header_48[8] = { 0xff, 0xfe, 0xfa, 0x07, 0x9a, 0xb9, 0xd2, 0xe9 };
239 assert_memory_equal(BPTR(&buf_48), expected_header_48, 8);
240
241 /* test writing/checking the 48 bit per epoch packet counter
242 * overflow */
243 data->pis.id = 0xfffffffffffe;
244 struct buffer buf_of = alloc_buf_gc(128, &data->gc);
245 assert_true(packet_id_write_epoch(&data->pis, 0xf00f, &buf_of));
246 uint8_t expected_header_of[8] = { 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
247 assert_memory_equal(BPTR(&buf_of), expected_header_of, 8);
248
249 /* This is go over 2^48 - 1 and should error out. */
250 assert_false(packet_id_write_epoch(&data->pis, 0xf00f, &buf_of));
251
252 /* Now read back the packet ids and check if they are the same as what we
253 * have written */
254 struct packet_id_net pin;
255 assert_int_equal(packet_id_read_epoch(&pin, &buf), 0x23);
256 assert_int_equal(pin.id, 1);
257
258 assert_int_equal(packet_id_read_epoch(&pin, &buf_48), 0xfffe);
259 assert_int_equal(pin.id, 0xfa079ab9d2e9);
260
261 assert_int_equal(packet_id_read_epoch(&pin, &buf_of), 0xf00f);
262 assert_int_equal(pin.id, 0xffffffffffff);
263}
264
265static void
267{
268 struct reliable_ack ack = { .len = 4, .packet_id = { 2, 1, 3, 2 } };
269
270 struct reliable_ack mru_ack = { 0 };
271
272 /* Test copying to empty ack structure */
273 copy_acks_to_mru(&ack, &mru_ack, 4);
274 assert_int_equal(mru_ack.len, 3);
275 assert_int_equal(mru_ack.packet_id[0], 2);
276 assert_int_equal(mru_ack.packet_id[1], 1);
277 assert_int_equal(mru_ack.packet_id[2], 3);
278
279 /* Copying again should not change the result */
280 copy_acks_to_mru(&ack, &mru_ack, 4);
281 assert_int_equal(mru_ack.len, 3);
282 assert_int_equal(mru_ack.packet_id[0], 2);
283 assert_int_equal(mru_ack.packet_id[1], 1);
284 assert_int_equal(mru_ack.packet_id[2], 3);
285
286 /* Copying just the first two element should not change the order
287 * as they are still the most recent*/
288 struct reliable_ack mru_ack2 = mru_ack;
289 copy_acks_to_mru(&ack, &mru_ack2, 2);
290 assert_int_equal(mru_ack2.packet_id[0], 2);
291 assert_int_equal(mru_ack2.packet_id[1], 1);
292 assert_int_equal(mru_ack2.packet_id[2], 3);
293
294 /* Adding just two packets shoudl ignore the 42 in array and
295 * reorder the order in the MRU */
296 struct reliable_ack ack2 = { .len = 3, .packet_id = { 3, 2, 42 } };
297 copy_acks_to_mru(&ack2, &mru_ack2, 2);
298 assert_int_equal(mru_ack2.packet_id[0], 3);
299 assert_int_equal(mru_ack2.packet_id[1], 2);
300 assert_int_equal(mru_ack2.packet_id[2], 1);
301
302 /* Copying a zero array into it should also change nothing */
303 struct reliable_ack empty_ack = { .len = 0 };
304 copy_acks_to_mru(&empty_ack, &mru_ack, 0);
305 assert_int_equal(mru_ack.len, 3);
306 assert_int_equal(mru_ack.packet_id[0], 2);
307 assert_int_equal(mru_ack.packet_id[1], 1);
308 assert_int_equal(mru_ack.packet_id[2], 3);
309
310 /* Or should just 0 elements of the ack */
311 copy_acks_to_mru(&ack, &mru_ack, 0);
312 assert_int_equal(mru_ack.len, 3);
313 assert_int_equal(mru_ack.packet_id[0], 2);
314 assert_int_equal(mru_ack.packet_id[1], 1);
315 assert_int_equal(mru_ack.packet_id[2], 3);
316
317 struct reliable_ack ack3 = { .len = 7, .packet_id = { 5, 6, 7, 8, 9, 10, 11 } };
318
319 /* Adding multiple acks tests if the a full array is handled correctly */
320 copy_acks_to_mru(&ack3, &mru_ack, 7);
321
322 struct reliable_ack expected_ack = { .len = 8, .packet_id = { 5, 6, 7, 8, 9, 10, 11, 2 } };
323 assert_int_equal(mru_ack.len, expected_ack.len);
324
325 assert_memory_equal(mru_ack.packet_id, expected_ack.packet_id, sizeof(expected_ack.packet_id));
326}
327
328static void
330{
331 struct reliable rel = { 0 };
332 rel.packet_id = 1;
333
334 assert_true(reliable_pid_in_send_window(&rel, 0));
335
336 /* packet id 1 is outside the window as it is the *next* packet id */
337 assert_false(reliable_pid_in_send_window(&rel, 1));
338
339 /* wrapped around packet id, "-2" */
340 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFFD));
341
342 /* wrapped around packet id, "-10" */
343 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFF6));
344
345 /* wrapped around packet id, "-11": the oldest id still in the window */
346 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFF5));
347
348 /* one further back is outside it */
349 assert_false(reliable_pid_in_send_window(&rel, 0xFFFFFFF4));
350 assert_false(reliable_pid_in_send_window(&rel, 0x80000000));
351
352 rel.packet_id = 0x80000000;
353
354 /* near the signed/usigned integer area */
355 assert_false(reliable_pid_in_send_window(&rel, 0x80000001));
356 assert_true(reliable_pid_in_send_window(&rel, 0x7fffffff));
357 assert_true(reliable_pid_in_send_window(&rel, 0x7ffffff5));
358 assert_true(reliable_pid_in_send_window(&rel, 0x7ffffff4));
359 assert_false(reliable_pid_in_send_window(&rel, 0x7ffffff3));
360
361 rel.packet_id = 0xFFFFFFFD;
362 assert_false(reliable_pid_in_send_window(&rel, 0xFFFFFFFD));
363 assert_false(reliable_pid_in_send_window(&rel, 0));
364 assert_false(reliable_pid_in_send_window(&rel, 1));
365 assert_false(reliable_pid_in_send_window(&rel, 0xFFFFFFFE));
366 assert_false(reliable_pid_in_send_window(&rel, 0xFFFFFFFF));
367 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFF3));
368 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFF2));
369 assert_true(reliable_pid_in_send_window(&rel, 0xFFFFFFF1));
370 assert_false(reliable_pid_in_send_window(&rel, 0xFFFFFFF0));
371
372 rel.packet_id = 500;
373 assert_false(reliable_pid_in_send_window(&rel, 501));
374 assert_true(reliable_pid_in_send_window(&rel, 497));
375 assert_true(reliable_pid_in_send_window(&rel, 500 - (RELIABLE_CAPACITY - 1)));
376 assert_true(reliable_pid_in_send_window(&rel, 500 - RELIABLE_CAPACITY));
377 assert_false(reliable_pid_in_send_window(&rel, 500 - (RELIABLE_CAPACITY + 1)));
378}
379
380
381/* The fix keeps the timeout well below this; the broken code grows past it.
382 * A plain number, so the test builds with or without the fix. */
383#define SANE_TIMEOUT_BOUND (10 * 1000 * 1000)
384
385static struct reliable *
387{
388 struct reliable *rel = malloc(sizeof(struct reliable));
389 assert_non_null(rel);
390 /* reliable_init() zeroes everything, so each test only sets the
391 * fields it actually needs. */
392 reliable_init(rel, 100, 50, 8, false);
393 rel->initial_timeout = 2;
394 return rel;
395}
396
397/*
398 * Each retransmit doubles the timeout. If a peer keeps forcing retransmits,
399 * the broken code doubles it forever: after about 30 rounds it overflows and
400 * turns zero or negative, and then the packet is resent nonstop (the flood).
401 * The fix caps the doubling. This test forces many retransmits and checks the
402 * timeout never overflows or grows without limit.
403 */
404static void
406{
407 (void)state;
408 now = 1000;
409
410 struct reliable *rel = test_reliable_new();
411
412 struct reliable_entry *e = &rel->array[0];
413 e->active = true;
414 e->packet_id = 1;
415 e->timeout = rel->initial_timeout;
416 rel->packet_id = 2;
417
418 for (int i = 0; i < 40; ++i)
419 {
420 /* make the packet due for a fast retransmit */
422
423 int opcode;
424 struct buffer *buf = reliable_send(rel, &opcode);
425 /* our one active packet is the one picked to send */
426 assert_ptr_equal(buf, &e->buf);
427
428 /* a zero or negative timeout would resend with no delay (the flood) */
429 assert_true(e->timeout > 0);
430 /* the timeout must stop growing, not double forever */
431 assert_true(e->timeout <= SANE_TIMEOUT_BOUND);
432 }
433
434 reliable_free(rel);
435}
436
437/*
438 * An ACK should only count if it is for a packet we actually sent. If the
439 * broken code accepts ACKs for packets that were never sent, a peer can force
440 * early retransmits at will (which then feeds the timeout overflow above).
441 * These two cases send such bogus ACKs and check they are ignored.
442 */
443static void
445{
446 (void)state;
447
448 /* Case (a): an ACK for pid 0x40000000, which we never sent (we only sent
449 * 0 and 1). The old "e->packet_id < pid" check treats it as newer and
450 * counts it. It should be ignored. */
451 {
452 struct reliable *rel = test_reliable_new();
453 struct reliable_entry *e = &rel->array[0];
454 e->active = true;
455 e->packet_id = 1;
456 rel->packet_id = 2; /* only pids 0 and 1 were ever sent */
457
458 struct reliable_ack ack = { .len = 1, .packet_id = { 0x40000000 } };
459 reliable_send_purge(rel, &ack);
460
461 /* the bogus ACK must not be counted */
462 assert_int_equal(e->n_acks, 0);
463 /* and must not drop our real packet */
464 assert_true(e->active);
465 reliable_free(rel);
466 }
467
468 /* Case (b): an ACK for pid 0xFFFFFFFF. It is inside the send window, so
469 * it passes the window check, but ids wrap around and 0xFFFFFFFF is really
470 * older than our pid 1. A plain "<" thinks it is newer and counts it; the
471 * wraparound-aware comparison must not. */
472 {
473 struct reliable *rel = test_reliable_new();
474 struct reliable_entry *e = &rel->array[0];
475 e->active = true;
476 e->packet_id = 1;
477 rel->packet_id = 2;
478
479 struct reliable_ack ack = { .len = 1, .packet_id = { 0xFFFFFFFF } };
480 reliable_send_purge(rel, &ack);
481
482 /* the bogus ACK must not be counted */
483 assert_int_equal(e->n_acks, 0);
484 /* and must not drop our real packet */
485 assert_true(e->active);
486 reliable_free(rel);
487 }
488}
489
490/*
491 * Sanity check: a real ACK must still work. Acknowledging a higher packet
492 * should drop that packet and count once towards resending the older one.
493 * The fix must not break this.
494 */
495static void
497{
498 (void)state;
499
500 struct reliable *rel = test_reliable_new();
501
502 struct reliable_entry *e0 = &rel->array[0];
503 e0->active = true;
504 e0->packet_id = 1;
505
506 struct reliable_entry *e1 = &rel->array[1];
507 e1->active = true;
508 e1->packet_id = 2;
509
510 rel->packet_id = 3; /* pids 0,1,2 sent; 1 and 2 still waiting */
511
512 struct reliable_ack ack = { .len = 1, .packet_id = { 2 } };
513 reliable_send_purge(rel, &ack);
514
515 /* packet 2 was acked, so it is dropped */
516 assert_false(e1->active);
517 /* packet 1 is older, so it gets one ACK towards an early resend */
518 assert_int_equal(e0->n_acks, 1);
519 /* packet 1 was not acked, so it stays */
520 assert_true(e0->active);
521
522 reliable_free(rel);
523}
524
525/*
526 * Independent models of the id sets the packet id comparisons accept. The
527 * sweeps below assert reliable.c agrees with them at the anchors swept, so a
528 * change to an accepted id set there fails a test. Each model is tagged
529 * "preserved" or "introduced" against the comparisons that came before. Keep
530 * them standalone: expressing them in terms of reliable.c would make the
531 * sweeps tautologies.
532 */
533
534/* the dropped reliable_pid_min(): "p1 < p2" with the 2^31 horizon,
535 * i.e. ((int32_t)(p1 - p2) < 0) */
536static bool
538{
539 return (packet_id_type)(p1 - p2) >= 0x80000000u;
540}
541
542/* TLS_RELIABLE_N_SEND_BUFFERS and P_CONTROL_V1, from ssl_pkt.h, which this
543 * test binary does not pull in */
544#define CHAR_N_SEND_BUFFERS 6
545#define CHAR_OPCODE_CONTROL_V1 4
546
547/* introduced: the RELIABLE_CAPACITY ids below rel->packet_id.
548 * validate_packet_id_window() stopped one short of that. */
549static bool
551{
552 const packet_id_type dist = (packet_id_type)(rel->packet_id - pid);
553
554 return dist >= 1 && dist <= RELIABLE_CAPACITY;
555}
556
557/* preserved: reliable_pid_in_range2() */
558static bool
560{
561 const packet_id_type base = rel->packet_id;
562 const packet_id_type extent = (packet_id_type)rel->size;
563
564 /* char_anchors and char_anchors_high stay clear of the overflow, where
565 * reliable_pid_in_range2() used a 0x80000000 bias instead */
566 assert_true(base + extent >= base);
567
568 return id < base + extent;
569}
570
571/* preserved: the horizon check, then the slot scan */
572static bool
574{
575 if (ref_pid_min(id, rel->packet_id))
576 {
577 return false;
578 }
579
580 for (int i = 0; i < rel->size; ++i)
581 {
582 if (rel->array[i].active && rel->array[i].packet_id == id)
583 {
584 return false;
585 }
586 }
587
588 return true;
589}
590
591/* The receive path verdict as ssl.c produces it: stored only if both checks
592 * pass, a replay still ACKed, a sequentiality break dropped without an ACK. */
599
600static enum recv_verdict
601recv_filter(const struct reliable *rel, packet_id_type id)
602{
604 {
605 return RECV_DROP;
606 }
607
608 return reliable_not_replay(rel, id) ? RECV_STORE : RECV_ACK_ONLY;
609}
610
611static enum recv_verdict
613{
614 if (!ref_wont_break_sequentiality(rel, id))
615 {
616 return RECV_DROP;
617 }
618
619 return ref_not_replay(rel, id) ? RECV_STORE : RECV_ACK_ONLY;
620}
621
622/* Anchors for rel->packet_id. reliable_wont_break_sequentiality() compares id
623 * against rel->packet_id + rel->size in absolute terms, so its accepted set
624 * depends on where rel->packet_id sits: up to 2^31 that leaves the composite
625 * verdict unchanged, above it it does not, hence the split. Bases past
626 * 0xFFFFFFF3 are excluded, rel->packet_id + rel->size overflowing there. */
627static const packet_id_type char_anchors[] = {
628 0x00000000,
629 0x00000001,
630 0x00000005,
631 0x0000000B,
632 0x0000000C,
633 0x0000000D,
634 0x000001F4,
635 0x7FFFFFF4,
636 0x7FFFFFFF,
637 0x80000000,
638};
639
641 0x80000001,
642 0x8000000C,
643 0xFFFFFFF0,
644 0xFFFFFFF3,
645};
646
647/* offsets applied below and above each anchor */
648static const packet_id_type char_offsets[] = {
649 0,
650 1,
651 2,
652 10,
653 11,
654 12,
655 13,
656 14,
657 100,
658 0x3FFFFFFF,
659 0x40000000,
660 0x7FFFFFFE,
661 0x7FFFFFFF,
662 0x80000000,
663 0x80000001,
664 0x80000002,
665 0xFFFFFFF4,
666 0xFFFFFFFE,
667 0xFFFFFFFF,
668};
669
670static void
671sweep_recv_filter(const packet_id_type *anchors, size_t n_anchors,
672 enum recv_verdict (*oracle)(const struct reliable *, packet_id_type))
673{
674 for (size_t a = 0; a < n_anchors; a++)
675 {
676 for (size_t o = 0; o < SIZE(char_offsets); o++)
677 {
678 /* probe both below and above the anchor */
679 const packet_id_type ids[] = {
680 (packet_id_type)(anchors[a] - char_offsets[o]),
681 (packet_id_type)(anchors[a] + char_offsets[o]),
682 };
683
684 for (size_t i = 0; i < SIZE(ids); i++)
685 {
686 struct reliable rel = { 0 };
688 rel.packet_id = anchors[a];
689
690 assert_int_equal(oracle(&rel, ids[i]), recv_filter(&rel, ids[i]));
691
692 /* with the id already in a receive slot it can only be
693 * acknowledged or dropped, never stored again */
694 rel.array[3].active = true;
695 rel.array[3].packet_id = ids[i];
696
697 assert_int_equal(oracle(&rel, ids[i]), recv_filter(&rel, ids[i]));
698 assert_int_not_equal(RECV_STORE, recv_filter(&rel, ids[i]));
699 }
700 }
701 }
702}
703
704/* Once rel->packet_id + rel->size overflows, the absolute clause makes
705 * reliable_wont_break_sequentiality() permissive; what may be stored is still
706 * the receive window, which wraps with it. */
707static void
709{
710 struct reliable rel = { 0 };
712 rel.packet_id = 0xFFFFFFF8;
713
714 assert_int_equal(RECV_STORE, recv_filter(&rel, 0xFFFFFFF8));
715 assert_int_equal(RECV_STORE, recv_filter(&rel, 0xFFFFFFFF));
716 assert_int_equal(RECV_STORE, recv_filter(&rel, 3));
717
718 /* one past the window, and one behind it: acknowledged, never stored */
719 assert_int_equal(RECV_ACK_ONLY, recv_filter(&rel, 4));
720 assert_int_equal(RECV_ACK_ONLY, recv_filter(&rel, 0xFFFFFFF7));
721}
722
723/* The id the receiver is next waiting for has to be storable at every base,
724 * the packet id wrap included. */
725static void
727{
728 const packet_id_type bases[] = {
729 0,
730 1,
731 500,
732 0x7FFFFFFF,
733 0x80000000,
734 0xFFFFFFF3,
735 0xFFFFFFF4,
736 0xFFFFFFF8,
737 0xFFFFFFFE,
738 0xFFFFFFFF,
739 };
740
741 for (size_t i = 0; i < SIZE(bases); i++)
742 {
743 struct reliable rel = { 0 };
745 rel.packet_id = bases[i];
746
747 assert_true(reliable_wont_break_sequentiality(&rel, rel.packet_id));
748 assert_true(reliable_not_replay(&rel, rel.packet_id));
749 }
750}
751
752/* bases at or below 2^31, where old and new agree; never to change */
753static void
758
759/* Introduced, for the bases above 2^31 only: storing also requires the id to
760 * be inside the receive window. The ids between one further ahead and
761 * rel->packet_id cannot all fit alongside it, so rel->packet_id never reaches
762 * it and the slot is held for the rest of the key state. Still ACKed, like a
763 * replay. */
764static enum recv_verdict
766{
767 const enum recv_verdict verdict = ref_recv_filter(rel, id);
768
769 if (verdict == RECV_STORE
770 && (packet_id_type)(id - rel->packet_id) >= (packet_id_type)rel->size)
771 {
772 return RECV_ACK_ONLY;
773 }
774
775 return verdict;
776}
777
778/* bases above 2^31, where they diverge, kept apart so a change confined
779 * there touches one test */
780static void
785
786static void
787sweep_send_window(const packet_id_type *anchors, size_t n_anchors)
788{
789 for (size_t a = 0; a < n_anchors; a++)
790 {
791 for (size_t o = 0; o < SIZE(char_offsets); o++)
792 {
793 const packet_id_type ids[] = {
794 (packet_id_type)(anchors[a] - char_offsets[o]),
795 (packet_id_type)(anchors[a] + char_offsets[o]),
796 };
797
798 for (size_t i = 0; i < SIZE(ids); i++)
799 {
800 struct reliable rel = { 0 };
802 rel.packet_id = anchors[a];
803
804 assert_int_equal(ref_pid_in_send_window(&rel, ids[i]),
805 reliable_pid_in_send_window(&rel, ids[i]));
806 }
807 }
808 }
809}
810
811/* a pure distance test, so identical at every base */
812static void
818
819/* The window bound in the selection is what stops an entry sitting ahead of
820 * rel->packet_id from being taken for the oldest one: its distance below
821 * rel->packet_id is then nearly the whole id space. array[0] cannot arise
822 * through the API; array[1] is an ordinary outstanding packet. */
823static void
825{
826 now = 1000;
827
828 struct reliable rel = { 0 };
830 rel.initial_timeout = 2;
831 rel.packet_id = 3;
832
833 /* scanned first, and outside the window */
834 rel.array[0].active = true;
835 rel.array[0].packet_id = 0x40000000;
836 rel.array[0].timeout = 2;
837 rel.array[0].next_try = 0;
838
839 /* a genuine outstanding packet, two below rel->packet_id */
840 rel.array[1].active = true;
841 rel.array[1].packet_id = 1;
842 rel.array[1].timeout = 2;
843 rel.array[1].next_try = 0;
844
845 int opcode = 0;
846 assert_ptr_equal(&rel.array[1].buf, reliable_send(&rel, &opcode));
847}
848
849/* reliable_can_send() promises reliable_send() will hand back a buffer, and
850 * its caller asserts on that. The state below cannot arise through the API --
851 * the entry sits outside the send window -- but the two must not be able to
852 * disagree. */
853static void
855{
856 now = 1000;
857
858 struct reliable rel = { 0 };
860 rel.initial_timeout = 2;
861 rel.packet_id = 3;
862
863 rel.array[0].active = true;
864 rel.array[0].packet_id = 0x40000000;
865 rel.array[0].timeout = 2;
866 rel.array[0].next_try = 0;
867
868 int opcode = 0;
869 assert_true(reliable_can_send(&rel));
870 assert_non_null(reliable_send(&rel, &opcode));
871}
872
873/* reliable_send() picks the oldest eligible entry, across the wrap and the
874 * signed midpoint */
875static void
877{
878 now = 1000;
879
880 struct reliable rel = { 0 };
882 rel.initial_timeout = 2;
883 rel.packet_id = 3;
884
885 /* 6, 2 and 1 below rel->packet_id; the first sits exactly on the window
886 * edge, where rel->size still admits it */
887 const packet_id_type wrapped[] = { 0xFFFFFFFD, 1, 2 };
888
889 for (size_t i = 0; i < SIZE(wrapped); i++)
890 {
891 rel.array[i].active = true;
892 rel.array[i].packet_id = wrapped[i];
893 rel.array[i].timeout = 2;
894 rel.array[i].next_try = 0;
895 }
896
897 int opcode = 0;
898 assert_ptr_equal(&rel.array[0].buf, reliable_send(&rel, &opcode));
899
900 /* same across the signed midpoint */
901 struct reliable rel2 = { 0 };
903 rel2.initial_timeout = 2;
904 rel2.packet_id = 0x80000002;
905
906 const packet_id_type midpoint[] = { 0x7FFFFFFF, 0x80000000, 0x80000001 };
907
908 for (size_t i = 0; i < SIZE(midpoint); i++)
909 {
910 rel2.array[i].active = true;
911 rel2.array[i].packet_id = midpoint[i];
912 rel2.array[i].timeout = 2;
913 rel2.array[i].next_try = 0;
914 }
915
916 assert_ptr_equal(&rel2.array[0].buf, reliable_send(&rel2, &opcode));
917}
918
919/* reliable_get_buf_output_sequenced() stops issuing ids once rel->packet_id is
920 * a full window ahead of the oldest unacknowledged one */
921static void
923{
924 struct reliable *rel = test_reliable_new();
925
926 rel->array[0].active = true;
927 rel->array[0].packet_id = 100;
928
929 /* distance 7 < size 8: still allowed */
930 rel->packet_id = 107;
931 assert_non_null(reliable_get_buf_output_sequenced(rel));
932
933 /* distance 8 == size 8: refused */
934 rel->packet_id = 108;
935 assert_null(reliable_get_buf_output_sequenced(rel));
936
937 /* same boundary across the wrap */
938 rel->array[0].packet_id = 0xFFFFFFFC;
939 rel->packet_id = 3;
940 assert_non_null(reliable_get_buf_output_sequenced(rel));
941
942 rel->packet_id = 4;
943 assert_null(reliable_get_buf_output_sequenced(rel));
944
945 reliable_free(rel);
946}
947
948/* Ids at or just ahead of rel->packet_id are accepted */
949static void
951{
952 struct reliable rel = { 0 };
954 rel.packet_id = 10;
955
957 assert_true(rel.array[0].active);
958 assert_int_equal(10, rel.array[0].packet_id);
959
962 assert_true(rel.array[1].active);
963}
964
965/* Ids below rel->packet_id abort. The far-ahead case is left unpinned: callers
966 * cannot produce it, and the bound may legitimately tighten.
967 *
968 * NOTE: expect_assert_failure() does not work with MSVC. It catches the ASSERT
969 * by longjmp()ing out of assert_failed(), and MSVC's longjmp() unwinds the
970 * intervening frames through RtlUnwindEx() instead of just restoring the
971 * registers, which faults. */
972#ifndef _MSC_VER
973static void
975{
976 struct reliable rel = { 0 };
978 rel.packet_id = 10;
979
980 expect_assert_failure(
982 expect_assert_failure(
984}
985#endif /* ifndef _MSC_VER */
986
987
988int
989main(void)
990{
992 const struct CMUnitTest tests[] = {
993 cmocka_unit_test_setup_teardown(test_packet_id_write_short, test_packet_id_write_setup,
995 cmocka_unit_test_setup_teardown(test_packet_id_write_long, test_packet_id_write_setup,
997 cmocka_unit_test_setup_teardown(test_packet_id_write_short_prepend,
999 cmocka_unit_test_setup_teardown(test_packet_id_write_long_prepend,
1001 cmocka_unit_test_setup_teardown(test_packet_id_write_short_wrap, test_packet_id_write_setup,
1003 cmocka_unit_test_setup_teardown(test_packet_id_write_long_wrap, test_packet_id_write_setup,
1005 cmocka_unit_test_setup_teardown(test_packet_id_write_epoch, test_packet_id_write_setup,
1007
1009 cmocka_unit_test(test_copy_acks_to_lru),
1010 cmocka_unit_test(test_packet_id_window),
1011 cmocka_unit_test(test_reliable_backoff_is_bounded),
1013 cmocka_unit_test(test_reliable_purge_legitimate_ack),
1015 cmocka_unit_test(test_recv_window_bounded_at_wrap),
1016 cmocka_unit_test(test_recv_filter_characterization),
1017 cmocka_unit_test(test_recv_filter_high_base),
1018 cmocka_unit_test(test_send_window_characterization),
1019 cmocka_unit_test(test_reliable_send_picks_oldest),
1021 cmocka_unit_test(test_reliable_send_matches_can_send),
1024#ifndef _MSC_VER
1026#endif
1027 };
1028
1029 return cmocka_run_group_tests_name("packet_id tests", tests, NULL, NULL);
1030}
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
#define BPTR(buf)
Return a pointer to the start of the buffer content.
Definition buffer.h:139
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1965
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1949
void reliable_free(struct reliable *rel)
Free allocated memory associated with a reliable structure and the pointer itself.
Definition reliable.c:331
struct buffer * reliable_get_buf_output_sequenced(struct reliable *rel)
Get the buffer of free reliable entry and check whether the outgoing acknowledgment sequence is still...
Definition reliable.c:576
int reliable_get_num_output_sequenced_available(const struct reliable *rel)
Counts the number of free buffers in output that can be potentially used for sending.
Definition reliable.c:569
bool reliable_pid_in_send_window(const struct reliable *rel, packet_id_type pid)
Check whether pid is one of the RELIABLE_CAPACITY ids below rel->packet_id, and so could still be out...
Definition reliable.c:361
#define N_ACK_RETRANSMIT
We retry sending a packet early if this many later packets have been ACKed.
Definition reliable.h:54
void reliable_mark_active_incoming(struct reliable *rel, const struct buffer *buf, packet_id_type pid, int opcode)
Mark the reliable entry associated with the given buffer as active incoming.
Definition reliable.c:755
void reliable_send_purge(struct reliable *rel, const struct reliable_ack *ack)
Remove acknowledged packets from a reliable structure.
Definition reliable.c:369
struct buffer * reliable_send(struct reliable *rel, int *opcode)
Get the next packet to send to the remote peer.
Definition reliable.c:637
bool reliable_can_send(const struct reliable *rel)
Check whether a reliable structure has any active entries ready to be (re)sent.
Definition reliable.c:611
bool reliable_not_replay(const struct reliable *rel, packet_id_type id)
Check that a received packet's ID is not a replay and is inside the receive window.
Definition reliable.c:475
#define RELIABLE_CAPACITY
The maximum number of packets that the reliability layer for one VPN tunnel in one direction can stor...
Definition reliable.h:49
void reliable_init(struct reliable *rel, int buf_size, int offset, int array_size, bool hold)
Initialize a reliable structure.
Definition reliable.c:315
void copy_acks_to_mru(struct reliable_ack *ack, struct reliable_ack *ack_mru, int n)
Copies the first n acks from ack to ack_mru.
Definition reliable.c:171
bool reliable_wont_break_sequentiality(const struct reliable *rel, packet_id_type id)
Check that a received packet's ID can safely be stored in the reliable structure's processing window.
Definition reliable.c:504
#define SIZE(x)
Definition basic.h:29
time_t now
Definition otime.c:33
uint16_t packet_id_read_epoch(struct packet_id_net *pin, struct buffer *buf)
Reads the packet ID containing both the epoch and the per-epoch counter from the buf.
Definition packet_id.c:643
bool packet_id_write_epoch(struct packet_id_send *p, uint16_t epoch, struct buffer *buf)
Writes the packet ID containing both the epoch and the packet id to the buffer specified by buf.
Definition packet_id.c:661
bool packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form, bool prepend)
Write a packet ID to buf, and update the packet ID state.
Definition packet_id.c:373
uint32_t packet_id_type
Definition packet_id.h:45
Reliability Layer module header file.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int capacity
Size in bytes of memory allocated by malloc().
Definition buffer.h:72
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:78
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
int offset
Offset in bytes of the actual content within the allocated memory.
Definition buffer.h:74
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
Data structure for describing the packet id that is received/send to the network.
Definition packet_id.h:191
uint64_t id
Definition packet_id.h:194
uint64_t id
Definition packet_id.h:153
The acknowledgment structure in which packet IDs are stored for later acknowledgment.
Definition reliable.h:75
packet_id_type packet_id[RELIABLE_ACK_SIZE]
Definition reliable.h:77
The structure in which the reliability layer stores a single incoming or outgoing packet.
Definition reliable.h:88
struct buffer buf
Definition reliable.h:97
int opcode
Definition reliable.h:96
time_t next_try
Definition reliable.h:91
size_t n_acks
Definition reliable.h:93
packet_id_type packet_id
Definition reliable.h:92
bool active
Definition reliable.h:89
interval_t timeout
Definition reliable.h:90
The reliability layer storage structure for one VPN tunnel's control channel in one direction.
Definition reliable.h:105
struct reliable_entry array[RELIABLE_CAPACITY]
Definition reliable.h:111
int size
Definition reliable.h:106
packet_id_type packet_id
Packet ID for the next packet to be sent out.
Definition reliable.h:108
interval_t initial_timeout
Definition reliable.h:107
struct packet_id_send pis
struct test_packet_id_write_data::@165330142221073303145237133103267144356214050261 test_buf_data
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:61
recv_verdict
@ RECV_DROP
@ RECV_ACK_ONLY
@ RECV_STORE
static const packet_id_type char_anchors[]
static void test_recv_filter_characterization(void **state)
static bool ref_not_replay(const struct reliable *rel, packet_id_type id)
static void test_reliable_send_matches_can_send(void **state)
static enum recv_verdict ref_recv_filter(const struct reliable *rel, packet_id_type id)
static void test_recv_window_bounded_at_wrap(void **state)
static int test_packet_id_write_setup(void **state)
static void test_packet_id_write_epoch(void **state)
static void test_reliable_send_ignores_entry_ahead(void **state)
static bool ref_pid_min(packet_id_type p1, packet_id_type p2)
static void test_reliable_send_picks_oldest(void **state)
static void test_packet_id_write_long_prepend(void **state)
static void test_packet_id_write_short_wrap(void **state)
static void test_mark_active_incoming_accepts_window(void **state)
static const packet_id_type char_offsets[]
static bool ref_pid_in_send_window(const struct reliable *rel, packet_id_type pid)
static void sweep_recv_filter(const packet_id_type *anchors, size_t n_anchors, enum recv_verdict(*oracle)(const struct reliable *, packet_id_type))
static enum recv_verdict ref_recv_filter_bounded(const struct reliable *rel, packet_id_type id)
static void test_packet_id_write_short_prepend(void **state)
static void test_wont_break_sequentiality_accepts_next_id(void **state)
static void test_packet_id_window(void **state)
static void test_reliable_backoff_is_bounded(void **state)
#define SANE_TIMEOUT_BOUND
static void sweep_send_window(const packet_id_type *anchors, size_t n_anchors)
static void test_reliable_purge_ignores_forged_acks(void **state)
static void test_packet_id_write_long(void **state)
static int test_packet_id_write_teardown(void **state)
#define CHAR_OPCODE_CONTROL_V1
int main(void)
static void test_reliable_purge_legitimate_ack(void **state)
static void test_get_buf_output_sequenced_boundary(void **state)
#define CHAR_N_SEND_BUFFERS
static void test_get_num_output_sequenced_available(void **state)
static struct reliable * test_reliable_new(void)
static void test_copy_acks_to_lru(void **state)
static const packet_id_type char_anchors_high[]
static enum recv_verdict recv_filter(const struct reliable *rel, packet_id_type id)
static void test_recv_filter_high_base(void **state)
static bool ref_wont_break_sequentiality(const struct reliable *rel, packet_id_type id)
static void test_send_window_characterization(void **state)
static void test_mark_active_incoming_rejects_past_ids(void **state)
static void test_packet_id_write_long_wrap(void **state)
static void test_packet_id_write_short(void **state)