Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/defrag.c
Line
Count
Source
1
/* Copyright (C) 2007-2024 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Endace Technology Limited, Jason Ish <jason.ish@endace.com>
22
 *
23
 * Defragmentation module.
24
 * References:
25
 *   - RFC 815
26
 *   - OpenBSD PF's IP normalization (pf_norm.c)
27
 *
28
 * \todo pool for frag packet storage
29
 * \todo policy bsd-right
30
 * \todo profile hash function
31
 * \todo log anomalies
32
 */
33
34
#include "suricata-common.h"
35
36
#include "queue.h"
37
38
#include "suricata.h"
39
#include "threads.h"
40
#include "conf.h"
41
#include "decode-ipv6.h"
42
#include "util-hashlist.h"
43
#include "util-pool.h"
44
#include "util-time.h"
45
#include "util-print.h"
46
#include "util-debug.h"
47
#include "util-fix_checksum.h"
48
#include "util-random.h"
49
#include "stream-tcp-private.h"
50
#include "stream-tcp-reassemble.h"
51
#include "util-host-os-info.h"
52
#include "util-validate.h"
53
54
#include "defrag.h"
55
#include "defrag-hash.h"
56
#include "defrag-config.h"
57
58
#include "tmqh-packetpool.h"
59
#include "decode.h"
60
61
#ifdef UNITTESTS
62
#include "util-unittest.h"
63
#endif
64
65
22
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
66
11
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
67
68
/**
69
 * Default timeout (in seconds) before a defragmentation tracker will
70
 * be released.
71
 */
72
11
#define TIMEOUT_DEFAULT 60
73
74
/**
75
 * Maximum allowed timeout, 24 hours.
76
 */
77
0
#define TIMEOUT_MAX (60 * 60 * 24)
78
79
/**
80
 * Minimum allowed timeout, 1 second.
81
 */
82
0
#define TIMEOUT_MIN 1
83
84
/** Fragment reassembly policies. */
85
enum defrag_policies {
86
    DEFRAG_POLICY_FIRST = 1,
87
    DEFRAG_POLICY_LAST,
88
    DEFRAG_POLICY_BSD,
89
    DEFRAG_POLICY_BSD_RIGHT,
90
    DEFRAG_POLICY_LINUX,
91
    DEFRAG_POLICY_WINDOWS,
92
    DEFRAG_POLICY_SOLARIS,
93
94
    DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
95
};
96
97
static uint8_t default_policy = DEFRAG_POLICY_BSD;
98
99
/** The global DefragContext so all threads operate from the same
100
 * context. */
101
static DefragContext *defrag_context;
102
103
6.25M
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_INSERT_COLOR
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_REMOVE_COLOR
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_INSERT
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_REMOVE
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
Unexecuted instantiation: IP_FRAGMENTS_RB_FIND
IP_FRAGMENTS_RB_NFIND
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_MINMAX
Line
Count
Source
103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
104
6.25M
105
6.25M
/**
106
6.25M
 * \brief Reset a frag for reuse in a pool.
107
6.25M
 */
108
6.25M
static void
109
6.25M
DefragFragReset(Frag *frag)
110
6.25M
{
111
406k
    if (frag->pkt != NULL)
112
406k
        SCFree(frag->pkt);
113
406k
    memset(frag, 0, sizeof(*frag));
114
406k
}
115
116
/**
117
 * \brief Allocate a new frag for use in a pool.
118
 */
119
static int
120
DefragFragInit(void *data, void *initdata)
121
131k
{
122
131k
    Frag *frag = data;
123
124
131k
    memset(frag, 0, sizeof(*frag));
125
131k
    return 1;
126
131k
}
127
128
/**
129
 * \brief Free all frags associated with a tracker.
130
 */
131
void
132
DefragTrackerFreeFrags(DefragTracker *tracker)
133
242k
{
134
242k
    Frag *frag, *tmp;
135
136
    /* Lock the frag pool as we'll be return items to it. */
137
242k
    SCMutexLock(&defrag_context->frag_pool_lock);
138
139
325k
    RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
140
325k
        RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
141
325k
        DefragFragReset(frag);
142
325k
        PoolReturn(defrag_context->frag_pool, frag);
143
325k
    }
144
145
242k
    SCMutexUnlock(&defrag_context->frag_pool_lock);
146
242k
}
147
148
/**
149
 * \brief Create a new DefragContext.
150
 *
151
 * \retval On success a return an initialized DefragContext, otherwise
152
 *     NULL will be returned.
153
 */
154
static DefragContext *
155
DefragContextNew(void)
156
11
{
157
11
    DefragContext *dc;
158
159
11
    dc = SCCalloc(1, sizeof(*dc));
160
11
    if (unlikely(dc == NULL))
161
0
        return NULL;
162
163
    /* Initialize the pool of trackers. */
164
11
    intmax_t tracker_pool_size;
165
11
    if (!SCConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
166
11
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
167
11
    }
168
169
    /* Initialize the pool of frags. */
170
11
    intmax_t frag_pool_size;
171
11
    if (!SCConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0 ||
172
11
            frag_pool_size > UINT32_MAX) {
173
11
        frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
174
11
    }
175
11
    uint32_t frag_pool_prealloc = (uint32_t)frag_pool_size / 2;
176
11
    dc->frag_pool = PoolInit((uint32_t)frag_pool_size, frag_pool_prealloc, sizeof(Frag), NULL,
177
11
            DefragFragInit, dc, NULL, NULL);
178
11
    if (dc->frag_pool == NULL) {
179
0
        FatalError("Defrag: Failed to initialize fragment pool.");
180
0
    }
181
11
    if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
182
0
        FatalError("Defrag: Failed to initialize frag pool mutex.");
183
0
    }
184
185
    /* Set the default timeout. */
186
11
    intmax_t timeout;
187
11
    if (!SCConfGetInt("defrag.timeout", &timeout)) {
188
11
        dc->timeout = TIMEOUT_DEFAULT;
189
11
    } else {
190
0
        if (timeout < TIMEOUT_MIN) {
191
0
            FatalError("defrag: Timeout less than minimum allowed value.");
192
0
        }
193
0
        else if (timeout > TIMEOUT_MAX) {
194
0
            FatalError("defrag: Timeout greater than maximum allowed value.");
195
0
        }
196
0
        dc->timeout = (uint32_t)timeout;
197
0
    }
198
199
11
    SCLogDebug("Defrag Initialized:");
200
11
    SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
201
11
    SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
202
11
    SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
203
11
    SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
204
11
    SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
205
206
11
    return dc;
207
11
}
208
209
static void
210
DefragContextDestroy(DefragContext *dc)
211
0
{
212
0
    if (dc == NULL)
213
0
        return;
214
215
0
    PoolFree(dc->frag_pool);
216
0
    SCFree(dc);
217
0
}
218
219
/**
220
 * Attempt to re-assemble a packet.
221
 *
222
 * \param tracker The defragmentation tracker to reassemble from.
223
 */
224
static Packet *
225
Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
226
126k
{
227
126k
    Packet *rp = NULL;
228
229
    /* Should not be here unless we have seen the last fragment. */
230
126k
    if (!tracker->seen_last) {
231
0
        return NULL;
232
0
    }
233
234
    /* Check that we have the first fragment and its of a valid size. */
235
126k
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
236
126k
    if (first == NULL) {
237
0
        goto done;
238
126k
    } else if (first->offset != 0) {
239
        /* Still waiting for the first fragment. */
240
71.7k
        goto done;
241
71.7k
    } else if (first->len < sizeof(IPV4Hdr)) {
242
        /* First fragment isn't enough for an IPv6 header. */
243
0
        goto error_remove_tracker;
244
0
    }
245
246
    /* Check that we have all the data. Relies on the fact that
247
     * fragments are inserted in frag_offset order. */
248
55.1k
    Frag *frag = NULL;
249
55.1k
    size_t len = 0;
250
200k
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
251
200k
        if (frag->offset > len) {
252
            /* This fragment starts after the end of the previous
253
             * fragment.  We have a hole. */
254
23.9k
            goto done;
255
23.9k
        }
256
176k
        else {
257
            /* Update the packet length to the largest known data offset. */
258
176k
            len = MAX(len, frag->offset + frag->data_len);
259
176k
        }
260
200k
    }
261
262
31.2k
    const IPV4Hdr *oip4h = PacketGetIPv4(p);
263
264
    /* Allocate a Packet for the reassembled packet.  On failure we
265
     * SCFree all the resources held by this tracker. */
266
31.2k
    rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_RAW_IPPROTO(oip4h));
267
31.2k
    if (rp == NULL) {
268
0
        goto error_remove_tracker;
269
0
    }
270
31.2k
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
271
31.2k
    rp->flags |= PKT_REBUILT_FRAGMENT;
272
31.2k
    rp->datalink = tracker->datalink;
273
274
31.2k
    int fragmentable_offset = 0;
275
31.2k
    uint16_t fragmentable_len = 0;
276
31.2k
    uint16_t hlen = 0;
277
31.2k
    int ip_hdr_offset = 0;
278
279
    /* Assume more frags. */
280
31.2k
    uint16_t prev_offset = 0;
281
31.2k
    bool more_frags = 1;
282
283
70.7k
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
284
70.7k
        SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
285
70.7k
                frag, frag->data_len, frag->offset, frag->pcap_cnt);
286
287
        /* Previous fragment has no more fragments, and this packet
288
         * doesn't overlap. We're done. */
289
70.7k
        if (!more_frags && frag->offset > prev_offset) {
290
162
            break;
291
162
        }
292
293
70.5k
        if (frag->skip)
294
0
            continue;
295
70.5k
        if (frag->ltrim >= frag->data_len)
296
0
            continue;
297
70.5k
        if (frag->offset == 0) {
298
299
31.2k
            if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
300
0
                goto error_remove_tracker;
301
302
31.2k
            hlen = frag->hlen;
303
31.2k
            ip_hdr_offset = tracker->ip_hdr_offset;
304
305
            /* This is the start of the fragmentable portion of the
306
             * first packet.  All fragment offsets are relative to
307
             * this. */
308
31.2k
            fragmentable_offset = tracker->ip_hdr_offset + frag->hlen;
309
31.2k
            fragmentable_len = frag->data_len;
310
31.2k
        }
311
39.3k
        else {
312
39.3k
            int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
313
39.3k
            if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
314
0
                SCLogDebug("Failed re-assemble "
315
0
                           "fragmented packet, exceeds size of packet buffer.");
316
0
                goto error_remove_tracker;
317
0
            }
318
39.3k
            if (PacketCopyDataOffset(rp,
319
39.3k
                    fragmentable_offset + frag->offset + frag->ltrim,
320
39.3k
                    frag->pkt + frag->data_offset + frag->ltrim,
321
39.3k
                    frag->data_len - frag->ltrim) == -1) {
322
0
                goto error_remove_tracker;
323
0
            }
324
39.3k
            if (frag->offset > UINT16_MAX - frag->data_len) {
325
0
                SCLogDebug("Failed re-assemble "
326
0
                           "fragmentable_len exceeds UINT16_MAX");
327
0
                goto error_remove_tracker;
328
0
            }
329
39.3k
            if (frag->offset + frag->data_len > fragmentable_len)
330
39.3k
                fragmentable_len = frag->offset + frag->data_len;
331
39.3k
        }
332
333
        /* Even if this fragment is flagged as having no more
334
         * fragments, still continue. The next fragment may have the
335
         * same offset with data that is preferred.
336
         *
337
         * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
338
         *
339
         * This is due to not all fragments being completely trimmed,
340
         * but relying on the copy ordering. */
341
70.5k
        more_frags = frag->more_frags;
342
70.5k
        prev_offset = frag->offset;
343
70.5k
    }
344
345
31.2k
    SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
346
31.2k
            fragmentable_len);
347
348
31.2k
    const uint32_t packet_len = (uint32_t)hlen + fragmentable_len;
349
31.2k
    if (packet_len > IPV4_MAXPACKET_LEN) {
350
3
        ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
351
3
        goto error_remove_tracker;
352
3
    }
353
354
31.2k
    IPV4Hdr *ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
355
31.2k
    uint16_t old = ip4h->ip_len + ip4h->ip_off;
356
31.2k
    ip4h->ip_len = htons((uint16_t)packet_len);
357
31.2k
    ip4h->ip_off = 0;
358
31.2k
    ip4h->ip_csum = FixChecksum(ip4h->ip_csum, old, ip4h->ip_len + ip4h->ip_off);
359
31.2k
    SET_PKT_LEN(rp, ip_hdr_offset + packet_len);
360
361
31.2k
    tracker->remove = 1;
362
31.2k
    DefragTrackerFreeFrags(tracker);
363
126k
done:
364
126k
    return rp;
365
366
3
error_remove_tracker:
367
3
    tracker->remove = 1;
368
3
    DefragTrackerFreeFrags(tracker);
369
3
    if (rp != NULL)
370
3
        PacketFreeOrRelease(rp);
371
3
    return NULL;
372
31.2k
}
373
374
/**
375
 * Attempt to re-assemble a packet.
376
 *
377
 * \param tracker The defragmentation tracker to reassemble from.
378
 */
379
static Packet *
380
Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
381
46.2k
{
382
46.2k
    Packet *rp = NULL;
383
384
    /* Should not be here unless we have seen the last fragment. */
385
46.2k
    if (!tracker->seen_last)
386
0
        return NULL;
387
388
    /* Check that we have the first fragment and its of a valid size. */
389
46.2k
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
390
46.2k
    if (first == NULL) {
391
0
        goto done;
392
46.2k
    } else if (first->offset != 0) {
393
        /* Still waiting for the first fragment. */
394
7.67k
        goto done;
395
38.5k
    } else if (first->len < sizeof(IPV6Hdr)) {
396
        /* First fragment isn't enough for an IPv6 header. */
397
0
        goto error_remove_tracker;
398
0
    }
399
400
    /* Check that we have all the data. Relies on the fact that
401
     * fragments are inserted if frag_offset order. */
402
38.5k
    size_t len = 0;
403
38.5k
    Frag *frag = NULL;
404
111k
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
405
111k
        if (frag->skip) {
406
0
            continue;
407
0
        }
408
409
111k
        if (frag == first) {
410
0
            if (frag->offset != 0) {
411
0
                goto done;
412
0
            }
413
0
            len = frag->data_len;
414
0
        }
415
111k
        else {
416
111k
            if (frag->offset > len) {
417
                /* This fragment starts after the end of the previous
418
                 * fragment.  We have a hole. */
419
10.2k
                goto done;
420
10.2k
            }
421
101k
            else {
422
101k
                len = MAX(len, frag->offset + frag->data_len);
423
101k
            }
424
111k
        }
425
111k
    }
426
427
28.3k
    const IPV6Hdr *oip6h = PacketGetIPv6(p);
428
429
    /* Allocate a Packet for the reassembled packet.  On failure we
430
     * SCFree all the resources held by this tracker. */
431
28.3k
    rp = PacketDefragPktSetup(
432
28.3k
            p, (const uint8_t *)oip6h, IPV6_GET_RAW_PLEN(oip6h) + sizeof(IPV6Hdr), 0);
433
28.3k
    if (rp == NULL) {
434
0
        goto error_remove_tracker;
435
0
    }
436
28.3k
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
437
28.3k
    rp->flags |= PKT_REBUILT_FRAGMENT;
438
28.3k
    rp->datalink = tracker->datalink;
439
440
28.3k
    uint16_t unfragmentable_len = 0;
441
28.3k
    int fragmentable_offset = 0;
442
28.3k
    uint16_t fragmentable_len = 0;
443
28.3k
    int ip_hdr_offset = 0;
444
28.3k
    uint8_t next_hdr = 0;
445
446
    /* Assume more frags. */
447
28.3k
    uint16_t prev_offset = 0;
448
28.3k
    bool more_frags = 1;
449
450
58.6k
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
451
58.6k
        if (!more_frags && frag->offset > prev_offset) {
452
748
            break;
453
748
        }
454
57.8k
        if (frag->skip)
455
0
            continue;
456
57.8k
        if (frag->data_len - frag->ltrim <= 0)
457
0
            continue;
458
57.8k
        if (frag->offset == 0) {
459
28.3k
            IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
460
28.3k
                frag->frag_hdr_offset);
461
28.3k
            next_hdr = frag_hdr->ip6fh_nxt;
462
463
            /* This is the first packet, we use this packets link and
464
             * IPv6 headers. We also copy in its data, but remove the
465
             * fragmentation header. */
466
28.3k
            if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
467
0
                goto error_remove_tracker;
468
28.3k
            if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
469
28.3k
                frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
470
28.3k
                frag->data_len) == -1)
471
0
                goto error_remove_tracker;
472
28.3k
            ip_hdr_offset = tracker->ip_hdr_offset;
473
474
            /* This is the start of the fragmentable portion of the
475
             * first packet.  All fragment offsets are relative to
476
             * this. */
477
28.3k
            fragmentable_offset = frag->frag_hdr_offset;
478
28.3k
            fragmentable_len = frag->data_len;
479
480
            /* unfragmentable part is the part between the ipv6 header
481
             * and the frag header. */
482
28.3k
            DEBUG_VALIDATE_BUG_ON(fragmentable_offset < ip_hdr_offset + IPV6_HEADER_LEN);
483
28.3k
            DEBUG_VALIDATE_BUG_ON(
484
28.3k
                    fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN > UINT16_MAX);
485
28.3k
            unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN);
486
28.3k
            if (unfragmentable_len >= fragmentable_offset)
487
0
                goto error_remove_tracker;
488
28.3k
        }
489
29.5k
        else {
490
29.5k
            if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
491
29.5k
                frag->pkt + frag->data_offset + frag->ltrim,
492
29.5k
                frag->data_len - frag->ltrim) == -1)
493
0
                goto error_remove_tracker;
494
29.5k
            if (frag->offset + frag->data_len > fragmentable_len)
495
29.4k
                fragmentable_len = frag->offset + frag->data_len;
496
29.5k
        }
497
498
        /* Even if this fragment is flagged as having no more
499
         * fragments, still continue. The next fragment may have the
500
         * same offset with data that is preferred.
501
         *
502
         * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
503
         *
504
         * This is due to not all fragments being completely trimmed,
505
         * but relying on the copy ordering. */
506
57.8k
        more_frags = frag->more_frags;
507
57.8k
        prev_offset = frag->offset;
508
57.8k
    }
509
510
28.3k
    const uint32_t payload_len = (uint32_t)unfragmentable_len + fragmentable_len;
511
28.3k
    if (payload_len > IPV6_MAXPACKET) {
512
3
        ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
513
3
        goto error_remove_tracker;
514
3
    }
515
516
28.3k
    IPV6Hdr *ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + tracker->ip_hdr_offset);
517
28.3k
    ip6h->s_ip6_plen = htons((uint16_t)payload_len);
518
    /* if we have no unfragmentable part, so no ext hdrs before the frag
519
     * header, we need to update the ipv6 headers next header field. This
520
     * points to the frag header, and we will make it point to the layer
521
     * directly after the frag header. */
522
28.3k
    if (unfragmentable_len == 0)
523
2.43k
        ip6h->s_ip6_nxt = next_hdr;
524
28.3k
    SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + payload_len);
525
526
28.3k
    tracker->remove = 1;
527
28.3k
    DefragTrackerFreeFrags(tracker);
528
46.2k
done:
529
46.2k
    return rp;
530
531
3
error_remove_tracker:
532
3
    tracker->remove = 1;
533
3
    DefragTrackerFreeFrags(tracker);
534
3
    if (rp != NULL)
535
3
        PacketFreeOrRelease(rp);
536
3
    return NULL;
537
28.3k
}
538
539
/**
540
 * The RB_TREE compare function for fragments.
541
 *
542
 * When it comes to adding fragments, we want subsequent ones with the
543
 * same offset to be treated as greater than, so we don't have an
544
 * equal return value here.
545
 */
546
2.03M
int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
547
2.03M
    if (a->offset < b->offset) {
548
751k
        return -1;
549
751k
    }
550
1.28M
    return 1;
551
2.03M
}
552
553
/**
554
 * \brief Trim following fragments overlapped by a BSD-preferred fragment.
555
 *
556
 * Only fragments starting after the new one are trimmed. Fully covered
557
 * fragments are removed, partially covered fragments have their left
558
 * trim increased.
559
 */
560
static void DefragBsdTrimFollowing(
561
        DefragTracker *tracker, Frag *next, uint16_t frag_offset, uint16_t frag_end)
562
649k
{
563
821k
    while ((next != NULL) && (frag_end > next->offset)) {
564
172k
        Frag *following = IP_FRAGMENTS_RB_NEXT(next);
565
172k
        if (next->offset <= frag_offset) {
566
            /* Starts at or before the new fragment, its data is preferred. */
567
38.4k
            next = following;
568
38.4k
            continue;
569
38.4k
        }
570
133k
        uint16_t next_ltrim = frag_end - next->offset;
571
133k
        if (next_ltrim >= next->data_len) {
572
79.9k
            RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, next);
573
79.9k
            DefragFragReset(next);
574
79.9k
            SCMutexLock(&defrag_context->frag_pool_lock);
575
79.9k
            PoolReturn(defrag_context->frag_pool, next);
576
79.9k
            SCMutexUnlock(&defrag_context->frag_pool_lock);
577
79.9k
        } else if (next_ltrim > next->ltrim) {
578
12.8k
            next->ltrim = next_ltrim;
579
12.8k
        }
580
133k
        next = following;
581
133k
    }
582
649k
}
583
584
/**
585
 * Insert a new IPv4/IPv6 fragment into a tracker.
586
 *
587
 * \todo Allocate packet buffers from a pool.
588
 */
589
static Packet *
590
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
591
373k
{
592
373k
    Packet *r = NULL;
593
373k
    uint16_t ltrim = 0;
594
595
373k
    bool more_frags;
596
373k
    uint16_t frag_offset;
597
598
    /* IPv4 header length - IPv4 only. */
599
373k
    uint8_t hlen = 0;
600
601
    /* This is the offset of the start of the data in the packet that
602
     * falls after the IP header. */
603
373k
    uint16_t data_offset;
604
605
    /* The length of the (fragmented) data.  This is the length of the
606
     * data that falls after the IP header. */
607
373k
    uint16_t data_len;
608
609
    /* Where the fragment ends. */
610
373k
    uint16_t frag_end;
611
612
    /* Offset in the packet to the IPv6 header. */
613
373k
    uint16_t ip_hdr_offset;
614
615
    /* Offset in the packet to the IPv6 frag header. IPv6 only. */
616
373k
    uint16_t frag_hdr_offset = 0;
617
618
    /* Address family */
619
373k
    int af = tracker->af;
620
621
    /* settings for updating a payload when an ip6 fragment with
622
     * unfragmentable exthdrs are encountered. */
623
373k
    uint32_t ip6_nh_set_offset = 0;
624
373k
    uint8_t ip6_nh_set_value = 0;
625
626
#ifdef DEBUG
627
    uint64_t pcap_cnt = p->pcap_cnt;
628
#endif
629
630
373k
    if (tracker->af == AF_INET) {
631
271k
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
632
271k
        more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
633
271k
        frag_offset = (uint16_t)((uint16_t)IPV4_GET_RAW_FRAGOFFSET(ip4h) << (uint16_t)3);
634
271k
        hlen = IPV4_GET_RAW_HLEN(ip4h);
635
271k
        data_offset = (uint16_t)((uint8_t *)ip4h + hlen - GET_PKT_DATA(p));
636
271k
        data_len = IPV4_GET_RAW_IPLEN(ip4h) - hlen;
637
271k
        frag_end = frag_offset + data_len;
638
271k
        ip_hdr_offset = (uint16_t)((uint8_t *)ip4h - GET_PKT_DATA(p));
639
640
        /* Ignore fragment if the end of packet extends past the
641
         * maximum size of a packet. */
642
271k
        if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
643
628
            ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
644
628
            return NULL;
645
628
        }
646
271k
    }
647
101k
    else if (tracker->af == AF_INET6) {
648
101k
        const IPV6Hdr *ip6h = PacketGetIPv6(p);
649
101k
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
650
101k
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
651
101k
        data_offset = p->l3.vars.ip6.eh.fh_data_offset;
652
101k
        data_len = p->l3.vars.ip6.eh.fh_data_len;
653
101k
        frag_end = frag_offset + data_len;
654
101k
        ip_hdr_offset = (uint16_t)((uint8_t *)ip6h - GET_PKT_DATA(p));
655
101k
        frag_hdr_offset = p->l3.vars.ip6.eh.fh_header_offset;
656
657
101k
        SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
658
101k
                "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
659
101k
                more_frags ? "true" : "false", frag_offset, data_offset,
660
101k
                data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
661
662
        /* handle unfragmentable exthdrs */
663
101k
        if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
664
91.5k
            SCLogDebug("we have exthdrs before fraghdr %u bytes",
665
91.5k
                    (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
666
667
            /* get the offset of the 'next' field in exthdr before the FH,
668
             * relative to the buffer start */
669
670
            /* store offset and FH 'next' value for updating frag buffer below */
671
91.5k
            ip6_nh_set_offset = p->l3.vars.ip6.eh.fh_prev_hdr_offset;
672
91.5k
            ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
673
91.5k
            SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
674
91.5k
        }
675
676
        /* Ignore fragment if the end of packet extends past the
677
         * maximum size of a packet. */
678
101k
        if (frag_offset + data_len > IPV6_MAXPACKET) {
679
607
            ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
680
607
            return NULL;
681
607
        }
682
101k
    }
683
0
    else {
684
0
        DEBUG_VALIDATE_BUG_ON(1);
685
0
        return NULL;
686
0
    }
687
688
    /* Update timeout. */
689
372k
    tracker->timeout = SCTIME_FROM_SECS(SCTIME_SECS(p->ts) + tracker->host_timeout);
690
691
372k
    Frag *prev = NULL, *next = NULL;
692
372k
    bool overlap = false;
693
372k
    ltrim = 0;
694
695
372k
    if (!RB_EMPTY(&tracker->fragment_tree)) {
696
315k
        Frag key = {
697
315k
            .offset = frag_offset - 1,
698
315k
        };
699
315k
        next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
700
315k
        if (next == NULL) {
701
112k
            prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
702
112k
            next = IP_FRAGMENTS_RB_NEXT(prev);
703
203k
        } else {
704
203k
            prev = IP_FRAGMENTS_RB_PREV(next);
705
203k
            if (prev == NULL) {
706
113k
                prev = next;
707
113k
                next = IP_FRAGMENTS_RB_NEXT(prev);
708
113k
            }
709
203k
        }
710
1.13M
        while (prev != NULL) {
711
1.10M
            if (prev->skip) {
712
0
                goto next;
713
0
            }
714
1.10M
            if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
715
260k
                overlap = true;
716
260k
            }
717
718
1.10M
            switch (tracker->policy) {
719
1.10M
            case DEFRAG_POLICY_BSD:
720
1.10M
                if (frag_offset < prev->offset + prev->data_len) {
721
284k
                    if (prev->offset <= frag_offset) {
722
                        /* We prefer the data from the previous
723
                         * fragment, so trim off the data in the new
724
                         * fragment that exists in the previous
725
                         * fragment. */
726
256k
                        uint16_t prev_end = prev->offset + prev->data_len;
727
256k
                        if (prev_end > frag_end) {
728
                            /* Just skip. */
729
                            /* TODO: Set overlap flag. */
730
4.13k
                            goto done;
731
4.13k
                        }
732
252k
                        ltrim = prev_end - frag_offset;
733
734
252k
                        DefragBsdTrimFollowing(tracker, next, frag_offset, frag_end);
735
736
252k
                        goto insert;
737
256k
                    }
738
739
                    /* If the end of this fragment overlaps the start
740
                     * of the previous fragment, then trim up the
741
                     * start of previous fragment so this fragment is
742
                     * used.
743
                     *
744
                     * See:
745
                     * DefragBsdSubsequentOverlapsStartOfOriginal.
746
                     */
747
27.2k
                    if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
748
3.86k
                        uint16_t prev_ltrim = frag_end - prev->offset;
749
3.86k
                        if (prev_ltrim > prev->ltrim) {
750
3.86k
                            prev->ltrim = prev_ltrim;
751
3.86k
                        }
752
3.86k
                    }
753
754
27.2k
                    DefragBsdTrimFollowing(tracker, next, frag_offset, frag_end);
755
756
27.2k
                    goto insert;
757
284k
                }
758
820k
                break;
759
820k
            case DEFRAG_POLICY_LINUX:
760
                /* Check if new fragment overlaps the end of previous
761
                 * fragment, if it does, trim the new fragment.
762
                 *
763
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
764
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
765
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
766
                 */
767
0
                if (prev->offset + prev->ltrim < frag_offset + ltrim &&
768
0
                        prev->offset + prev->data_len > frag_offset + ltrim) {
769
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
770
0
                }
771
772
                /* Check if new fragment overlaps the beginning of
773
                 * previous fragment, if it does, tim the previous
774
                 * fragment.
775
                 *
776
                 * Old:          AAAAAAAA AAAAAAAA
777
                 * New: BBBBBBBB BBBBBBBB BBBBBBBB
778
                 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
779
                 */
780
0
                if (frag_offset + ltrim < prev->offset + prev->ltrim &&
781
0
                        frag_end > prev->offset + prev->ltrim) {
782
0
                    prev->ltrim += frag_end - (prev->offset + prev->ltrim);
783
0
                    goto insert;
784
0
                }
785
786
                /* If the new fragment completely overlaps the
787
                 * previous fragment, mark the previous to be
788
                 * skipped. Re-assembly would succeed without doing
789
                 * this, but this will prevent the bytes from being
790
                 * copied just to be overwritten. */
791
0
                if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
792
0
                        frag_end >= prev->offset + prev->data_len) {
793
0
                    prev->skip = 1;
794
0
                    goto insert;
795
0
                }
796
797
0
                break;
798
0
            case DEFRAG_POLICY_WINDOWS:
799
                /* If new fragment fits inside a previous fragment, drop it. */
800
0
                if (frag_offset + ltrim >= prev->offset + ltrim &&
801
0
                        frag_end <= prev->offset + prev->data_len) {
802
0
                    goto done;
803
0
                }
804
805
                /* If new fragment starts before and ends after
806
                 * previous fragment, drop the previous fragment. */
807
0
                if (frag_offset + ltrim < prev->offset + ltrim &&
808
0
                        frag_end > prev->offset + prev->data_len) {
809
0
                    prev->skip = 1;
810
0
                    goto insert;
811
0
                }
812
813
                /* Check if new fragment overlaps the end of previous
814
                 * fragment, if it does, trim the new fragment.
815
                 *
816
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
817
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
818
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
819
                 */
820
0
                if (frag_offset + ltrim > prev->offset + prev->ltrim &&
821
0
                        frag_offset + ltrim < prev->offset + prev->data_len) {
822
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
823
0
                    goto insert;
824
0
                }
825
826
                /* If new fragment starts at same offset as an
827
                 * existing fragment, but ends after it, trim the new
828
                 * fragment. */
829
0
                if (frag_offset + ltrim == prev->offset + ltrim &&
830
0
                        frag_end > prev->offset + prev->data_len) {
831
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
832
0
                    goto insert;
833
0
                }
834
0
                break;
835
0
            case DEFRAG_POLICY_SOLARIS:
836
0
                if (frag_offset < prev->offset + prev->data_len) {
837
0
                    if (frag_offset >= prev->offset) {
838
0
                        ltrim = prev->offset + prev->data_len - frag_offset;
839
0
                    }
840
0
                    if ((frag_offset < prev->offset) &&
841
0
                        (frag_end >= prev->offset + prev->data_len)) {
842
0
                        prev->skip = 1;
843
0
                    }
844
0
                    goto insert;
845
0
                }
846
0
                break;
847
0
            case DEFRAG_POLICY_FIRST:
848
0
                if ((frag_offset >= prev->offset) &&
849
0
                    (frag_end <= prev->offset + prev->data_len)) {
850
0
                    goto done;
851
0
                }
852
0
                if (frag_offset < prev->offset) {
853
0
                    goto insert;
854
0
                }
855
0
                if (frag_offset < prev->offset + prev->data_len) {
856
0
                    ltrim = prev->offset + prev->data_len - frag_offset;
857
0
                    goto insert;
858
0
                }
859
0
                break;
860
0
            case DEFRAG_POLICY_LAST:
861
0
                if (frag_offset <= prev->offset) {
862
0
                    if (frag_end > prev->offset) {
863
0
                        prev->ltrim = frag_end - prev->offset;
864
0
                    }
865
0
                    goto insert;
866
0
                }
867
0
                break;
868
0
            default:
869
0
                break;
870
1.10M
            }
871
872
820k
        next:
873
820k
            prev = next;
874
820k
            if (next != NULL) {
875
788k
                next = IP_FRAGMENTS_RB_NEXT(next);
876
788k
            }
877
820k
            continue;
878
879
280k
        insert:
880
            /* If existing fragment has been trimmed up completely
881
             * (complete overlap), remove it now instead of holding
882
             * onto it. */
883
280k
            if (prev->skip || prev->ltrim >= prev->data_len) {
884
697
                RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
885
697
                DefragFragReset(prev);
886
697
                SCMutexLock(&defrag_context->frag_pool_lock);
887
697
                PoolReturn(defrag_context->frag_pool, prev);
888
697
                SCMutexUnlock(&defrag_context->frag_pool_lock);
889
697
            }
890
280k
            break;
891
1.10M
        }
892
315k
    }
893
894
367k
    if (ltrim >= data_len) {
895
        /* Full packet has been trimmed due to the overlap policy. Overlap
896
         * already set. */
897
217k
        goto done;
898
217k
    }
899
900
    /* Allocate fragment and insert. */
901
150k
    SCMutexLock(&defrag_context->frag_pool_lock);
902
150k
    Frag *new = PoolGet(defrag_context->frag_pool);
903
150k
    SCMutexUnlock(&defrag_context->frag_pool_lock);
904
150k
    if (new == NULL) {
905
0
        if (af == AF_INET) {
906
0
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
907
0
        } else {
908
0
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
909
0
        }
910
0
        if (tv != NULL && dtv != NULL) {
911
0
            StatsIncr(tv, dtv->counter_defrag_no_frags);
912
0
        }
913
0
        goto error_remove_tracker;
914
0
    }
915
150k
    new->pkt = SCMalloc(GET_PKT_LEN(p));
916
150k
    if (new->pkt == NULL) {
917
0
        SCMutexLock(&defrag_context->frag_pool_lock);
918
0
        PoolReturn(defrag_context->frag_pool, new);
919
0
        SCMutexUnlock(&defrag_context->frag_pool_lock);
920
0
        if (af == AF_INET) {
921
0
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
922
0
        } else {
923
0
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
924
0
        }
925
0
        goto error_remove_tracker;
926
0
    }
927
150k
    memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
928
150k
    new->len = (GET_PKT_LEN(p) - ltrim);
929
    /* in case of unfragmentable exthdrs, update the 'next hdr' field
930
     * in the raw buffer so the reassembled packet will point to the
931
     * correct next header after stripping the frag header */
932
150k
    if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
933
21.0k
        if (new->len > ip6_nh_set_offset) {
934
21.0k
            SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
935
21.0k
                    new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
936
21.0k
            new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
937
21.0k
        }
938
21.0k
    }
939
940
150k
    new->hlen = hlen;
941
150k
    new->offset = frag_offset + ltrim;
942
150k
    new->data_offset = data_offset;
943
150k
    new->data_len = data_len - ltrim;
944
150k
    new->frag_hdr_offset = frag_hdr_offset;
945
150k
    new->more_frags = more_frags;
946
#ifdef DEBUG
947
    new->pcap_cnt = pcap_cnt;
948
#endif
949
150k
    if (new->offset == 0) {
950
48.1k
        tracker->ip_hdr_offset = ip_hdr_offset;
951
48.1k
        tracker->datalink = p->datalink;
952
48.1k
    }
953
954
150k
    IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
955
956
150k
    if (!more_frags) {
957
35.0k
        tracker->seen_last = 1;
958
35.0k
    }
959
960
150k
    if (tracker->seen_last) {
961
40.5k
        if (tracker->af == AF_INET) {
962
29.9k
            r = Defrag4Reassemble(tv, tracker, p);
963
29.9k
            if (r != NULL && tv != NULL && dtv != NULL) {
964
8.56k
                StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
965
8.56k
            }
966
29.9k
        }
967
10.5k
        else if (tracker->af == AF_INET6) {
968
10.5k
            r = Defrag6Reassemble(tv, tracker, p);
969
10.5k
            if (r != NULL && tv != NULL && dtv != NULL) {
970
7.73k
                StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
971
7.73k
            }
972
10.5k
        }
973
40.5k
    }
974
975
976
372k
done:
977
372k
    if (overlap) {
978
260k
        if (af == AF_INET) {
979
190k
            ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
980
190k
        }
981
70.5k
        else {
982
70.5k
            ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
983
70.5k
        }
984
260k
    }
985
372k
    return r;
986
0
error_remove_tracker:
987
0
    tracker->remove = 1;
988
0
    DefragTrackerFreeFrags(tracker);
989
0
    return NULL;
990
150k
}
991
992
/**
993
 * \brief Get the defrag policy based on the destination address of
994
 * the packet.
995
 *
996
 * \param p The packet used to get the destination address.
997
 *
998
 * \retval The defrag policy to use.
999
 */
1000
uint8_t
1001
DefragGetOsPolicy(Packet *p)
1002
226k
{
1003
226k
    int policy = -1;
1004
1005
226k
    if (PacketIsIPv4(p)) {
1006
116k
        policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
1007
116k
    } else if (PacketIsIPv6(p)) {
1008
110k
        policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
1009
110k
    }
1010
1011
226k
    if (policy == -1) {
1012
226k
        return default_policy;
1013
226k
    }
1014
1015
    /* Map the OS policies returned from the configured host info to
1016
     * defrag specific policies. */
1017
0
    switch (policy) {
1018
        /* BSD. */
1019
0
    case OS_POLICY_BSD:
1020
0
    case OS_POLICY_HPUX10:
1021
0
    case OS_POLICY_IRIX:
1022
0
        return DEFRAG_POLICY_BSD;
1023
1024
        /* BSD-Right. */
1025
0
    case OS_POLICY_BSD_RIGHT:
1026
0
        return DEFRAG_POLICY_BSD_RIGHT;
1027
1028
        /* Linux. */
1029
0
    case OS_POLICY_OLD_LINUX:
1030
0
    case OS_POLICY_LINUX:
1031
0
        return DEFRAG_POLICY_LINUX;
1032
1033
        /* First. */
1034
0
    case OS_POLICY_OLD_SOLARIS:
1035
0
    case OS_POLICY_HPUX11:
1036
0
    case OS_POLICY_MACOS:
1037
0
    case OS_POLICY_FIRST:
1038
0
        return DEFRAG_POLICY_FIRST;
1039
1040
        /* Solaris. */
1041
0
    case OS_POLICY_SOLARIS:
1042
0
        return DEFRAG_POLICY_SOLARIS;
1043
1044
        /* Windows. */
1045
0
    case OS_POLICY_WINDOWS:
1046
0
    case OS_POLICY_VISTA:
1047
0
    case OS_POLICY_WINDOWS2K3:
1048
0
        return DEFRAG_POLICY_WINDOWS;
1049
1050
        /* Last. */
1051
0
    case OS_POLICY_LAST:
1052
0
        return DEFRAG_POLICY_LAST;
1053
1054
0
    default:
1055
0
        return default_policy;
1056
0
    }
1057
0
}
1058
1059
/** \internal
1060
 *
1061
 *  \retval NULL or a *LOCKED* tracker */
1062
static DefragTracker *
1063
DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1064
985k
{
1065
985k
    return DefragGetTrackerFromHash(tv, dtv, p);
1066
985k
}
1067
1068
/**
1069
 * \brief Entry point for IPv4 and IPv6 fragments.
1070
 *
1071
 * \param tv ThreadVars for the calling decoder.
1072
 * \param p The packet fragment.
1073
 *
1074
 * \retval A new Packet resembling the re-assembled packet if the most
1075
 *     recent fragment allowed the packet to be re-assembled, otherwise
1076
 *     NULL is returned.
1077
 */
1078
Packet *
1079
Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1080
991k
{
1081
991k
    uint16_t frag_offset;
1082
991k
    uint8_t more_frags;
1083
991k
    DefragTracker *tracker;
1084
991k
    int af;
1085
1086
991k
    if (PacketIsIPv4(p)) {
1087
643k
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
1088
643k
        af = AF_INET;
1089
643k
        more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
1090
643k
        frag_offset = IPV4_GET_RAW_FRAGOFFSET(ip4h);
1091
643k
    } else if (PacketIsIPv6(p)) {
1092
348k
        af = AF_INET6;
1093
348k
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1094
348k
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1095
348k
    } else {
1096
0
        return NULL;
1097
0
    }
1098
1099
991k
    if (frag_offset == 0 && more_frags == 0) {
1100
6.04k
        return NULL;
1101
6.04k
    }
1102
1103
985k
    if (af == AF_INET) {
1104
643k
        StatsIncr(tv, dtv->counter_defrag_ipv4_fragments);
1105
643k
    } else if (af == AF_INET6) {
1106
342k
        StatsIncr(tv, dtv->counter_defrag_ipv6_fragments);
1107
342k
    }
1108
1109
    /* return a locked tracker or NULL */
1110
985k
    tracker = DefragGetTracker(tv, dtv, p);
1111
985k
    if (tracker == NULL) {
1112
0
        if (tv != NULL && dtv != NULL) {
1113
0
            StatsIncr(tv, dtv->counter_defrag_max_hit);
1114
0
        }
1115
0
        return NULL;
1116
0
    }
1117
1118
985k
    Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1119
1120
    /* Capture tracker fields while still holding the lock. ip_hdr_offset is set
1121
     * inside DefragInsertFrag when the first fragment (offset 0) is inserted, so
1122
     * it must be read after that call returns. */
1123
985k
    int tracker_af = tracker->af;
1124
985k
    uint16_t tracker_ip_hdr_offset = tracker->ip_hdr_offset;
1125
1126
    /* Release the tracker lock BEFORE decoding the reassembled packet.
1127
     * This prevents re-entrant Defrag() calls (via tunnel decode) from
1128
     * deadlocking on tracker locks held by other threads. */
1129
985k
    DefragTrackerRelease(tracker);
1130
1131
985k
    if (rp != NULL) {
1132
59.5k
        const uint32_t len = GET_PKT_LEN(rp) - (uint32_t)tracker_ip_hdr_offset;
1133
59.5k
        int decode_rc;
1134
59.5k
        if (tracker_af == AF_INET) {
1135
31.2k
            DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
1136
31.2k
            decode_rc = DecodeIPV4(
1137
31.2k
                    tv, dtv, rp, GET_PKT_DATA(rp) + tracker_ip_hdr_offset, (uint16_t)len);
1138
31.2k
        } else {
1139
28.3k
            decode_rc = DecodeIPV6(tv, dtv, rp, GET_PKT_DATA(rp) + tracker_ip_hdr_offset, len);
1140
28.3k
        }
1141
59.5k
        if (decode_rc != TM_ECODE_OK) {
1142
0
            rp->root = NULL;
1143
0
            TmqhOutputPacketpool(tv, rp);
1144
0
            rp = NULL;
1145
59.5k
        } else {
1146
59.5k
            PacketDefragPktSetupParent(p);
1147
59.5k
        }
1148
59.5k
    }
1149
1150
985k
    return rp;
1151
985k
}
1152
1153
void
1154
DefragInit(void)
1155
11
{
1156
11
    intmax_t tracker_pool_size;
1157
11
    if (!SCConfGetInt("defrag.trackers", &tracker_pool_size)) {
1158
11
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1159
11
    }
1160
1161
    /* Load the defrag-per-host lookup. */
1162
11
    DefragPolicyLoadFromConfig();
1163
1164
    /* Allocate the DefragContext. */
1165
11
    defrag_context = DefragContextNew();
1166
11
    if (defrag_context == NULL) {
1167
0
        FatalError("Failed to allocate memory for the Defrag module.");
1168
0
    }
1169
1170
11
    DefragSetDefaultTimeout(defrag_context->timeout);
1171
11
    DefragInitConfig(false);
1172
11
}
1173
1174
void DefragDestroy(void)
1175
0
{
1176
0
    DefragHashShutdown();
1177
0
    DefragContextDestroy(defrag_context);
1178
0
    defrag_context = NULL;
1179
0
    DefragTreeDestroy();
1180
0
}
1181
1182
#ifdef UNITTESTS
1183
#include "util-unittest-helper.h"
1184
#include "packet.h"
1185
1186
#define IP_MF 0x2000
1187
1188
ThreadVars test_tv = { 0 };
1189
DecodeThreadVars test_dtv = { 0 };
1190
1191
/**
1192
 * Allocate a test packet.  Nothing to fancy, just a simple IP packet
1193
 * with some payload of no particular protocol.
1194
 */
1195
static Packet *BuildIpv4TestPacket(
1196
        uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
1197
{
1198
    Packet *p = NULL;
1199
    int hlen = 20;
1200
    int ttl = 64;
1201
    uint8_t *pcontent;
1202
    IPV4Hdr ip4h;
1203
1204
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1205
    if (unlikely(p == NULL))
1206
        return NULL;
1207
1208
    PacketInit(p);
1209
1210
    struct timeval tval;
1211
    gettimeofday(&tval, NULL);
1212
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1213
    //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1214
    ip4h.ip_verhl = 4 << 4;
1215
    ip4h.ip_verhl |= hlen >> 2;
1216
    ip4h.ip_len = htons(hlen + content_len);
1217
    ip4h.ip_id = htons(id);
1218
    if (mf)
1219
        ip4h.ip_off = htons(IP_MF | off);
1220
    else
1221
        ip4h.ip_off = htons(off);
1222
    ip4h.ip_ttl = ttl;
1223
    ip4h.ip_proto = proto;
1224
1225
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1226
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1227
1228
    /* copy content_len crap, we need full length */
1229
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1230
    IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1231
    SET_IPV4_SRC_ADDR(ip4p, &p->src);
1232
    SET_IPV4_DST_ADDR(ip4p, &p->dst);
1233
1234
    pcontent = SCCalloc(1, content_len);
1235
    if (unlikely(pcontent == NULL))
1236
        return NULL;
1237
    memset(pcontent, content, content_len);
1238
    PacketCopyDataOffset(p, hlen, pcontent, content_len);
1239
    SET_PKT_LEN(p, hlen + content_len);
1240
    SCFree(pcontent);
1241
1242
    ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1243
1244
    /* Self test. */
1245
    FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1246
    FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1247
    FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1248
    FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1249
    FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1250
    FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1251
    FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1252
    FAIL_IF(IPV4_GET_RAW_IPPROTO(ip4p) != proto);
1253
1254
    return p;
1255
}
1256
1257
/**
1258
 * Allocate a test packet, much like BuildIpv4TestPacket, but with
1259
 * the full content provided by the caller.
1260
 */
1261
static int BuildIpv4TestPacketWithContent(Packet **packet, uint8_t proto, uint16_t id, uint16_t off,
1262
        int mf, const uint8_t *content, int content_len)
1263
{
1264
    Packet *p = NULL;
1265
    int hlen = 20;
1266
    int ttl = 64;
1267
    IPV4Hdr ip4h;
1268
1269
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1270
    FAIL_IF_NULL(p);
1271
1272
    PacketInit(p);
1273
1274
    struct timeval tval;
1275
    gettimeofday(&tval, NULL);
1276
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1277
    ip4h.ip_verhl = 4 << 4;
1278
    ip4h.ip_verhl |= hlen >> 2;
1279
    ip4h.ip_len = htons(hlen + content_len);
1280
    ip4h.ip_id = htons(id);
1281
    if (mf)
1282
        ip4h.ip_off = htons(IP_MF | off);
1283
    else
1284
        ip4h.ip_off = htons(off);
1285
    ip4h.ip_ttl = ttl;
1286
    ip4h.ip_proto = proto;
1287
1288
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1289
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1290
1291
    /* copy content_len crap, we need full length */
1292
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1293
    IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1294
    SET_IPV4_SRC_ADDR(ip4p, &p->src);
1295
    SET_IPV4_DST_ADDR(ip4p, &p->dst);
1296
1297
    PacketCopyDataOffset(p, hlen, content, content_len);
1298
    SET_PKT_LEN(p, hlen + content_len);
1299
1300
    ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1301
1302
    /* Self test. */
1303
    FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1304
    FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1305
    FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1306
    FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1307
    FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1308
    FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1309
    FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1310
    FAIL_IF(IPV4_GET_RAW_IPPROTO(ip4p) != proto);
1311
1312
    *packet = p;
1313
    PASS;
1314
}
1315
1316
static Packet *BuildIpv6TestPacket(
1317
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
1318
{
1319
    Packet *p = NULL;
1320
    uint8_t *pcontent;
1321
    IPV6Hdr ip6h;
1322
1323
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1324
    if (unlikely(p == NULL))
1325
        return NULL;
1326
1327
    PacketInit(p);
1328
1329
    struct timeval tval;
1330
    gettimeofday(&tval, NULL);
1331
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1332
1333
    ip6h.s_ip6_nxt = 44;
1334
    ip6h.s_ip6_hlim = 2;
1335
1336
    /* Source and dest address - very bogus addresses. */
1337
    ip6h.s_ip6_src[0] = 0x01010101;
1338
    ip6h.s_ip6_src[1] = 0x01010101;
1339
    ip6h.s_ip6_src[2] = 0x01010101;
1340
    ip6h.s_ip6_src[3] = 0x01010101;
1341
    ip6h.s_ip6_dst[0] = 0x02020202;
1342
    ip6h.s_ip6_dst[1] = 0x02020202;
1343
    ip6h.s_ip6_dst[2] = 0x02020202;
1344
    ip6h.s_ip6_dst[3] = 0x02020202;
1345
1346
    /* copy content_len crap, we need full length */
1347
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1348
1349
    IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1350
    IPV6_SET_RAW_VER(ip6p, 6);
1351
    /* Fragmentation header. */
1352
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1353
    fh->ip6fh_nxt = proto;
1354
    fh->ip6fh_ident = htonl(id);
1355
    fh->ip6fh_offlg = htons((off << 3) | mf);
1356
1357
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1358
1359
    pcontent = SCCalloc(1, content_len);
1360
    if (unlikely(pcontent == NULL))
1361
        return NULL;
1362
    memset(pcontent, content, content_len);
1363
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1364
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1365
    SCFree(pcontent);
1366
1367
    ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1368
1369
    SET_IPV6_SRC_ADDR(ip6p, &p->src);
1370
    SET_IPV6_DST_ADDR(ip6p, &p->dst);
1371
1372
    /* Self test. */
1373
    if (IPV6_GET_RAW_VER(ip6p) != 6)
1374
        goto error;
1375
    if (IPV6_GET_RAW_NH(ip6p) != 44)
1376
        goto error;
1377
    if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1378
        goto error;
1379
1380
    return p;
1381
error:
1382
    if (p != NULL)
1383
        SCFree(p);
1384
    return NULL;
1385
}
1386
1387
static Packet *BuildIpv6TestPacketWithContent(
1388
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1389
{
1390
    Packet *p = NULL;
1391
    IPV6Hdr ip6h;
1392
1393
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1394
    if (unlikely(p == NULL))
1395
        return NULL;
1396
1397
    PacketInit(p);
1398
1399
    struct timeval tval;
1400
    gettimeofday(&tval, NULL);
1401
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1402
1403
    ip6h.s_ip6_nxt = 44;
1404
    ip6h.s_ip6_hlim = 2;
1405
1406
    /* Source and dest address - very bogus addresses. */
1407
    ip6h.s_ip6_src[0] = 0x01010101;
1408
    ip6h.s_ip6_src[1] = 0x01010101;
1409
    ip6h.s_ip6_src[2] = 0x01010101;
1410
    ip6h.s_ip6_src[3] = 0x01010101;
1411
    ip6h.s_ip6_dst[0] = 0x02020202;
1412
    ip6h.s_ip6_dst[1] = 0x02020202;
1413
    ip6h.s_ip6_dst[2] = 0x02020202;
1414
    ip6h.s_ip6_dst[3] = 0x02020202;
1415
1416
    /* copy content_len crap, we need full length */
1417
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1418
1419
    IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1420
    IPV6_SET_RAW_VER(ip6p, 6);
1421
    /* Fragmentation header. */
1422
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1423
    fh->ip6fh_nxt = proto;
1424
    fh->ip6fh_ident = htonl(id);
1425
    fh->ip6fh_offlg = htons((off << 3) | mf);
1426
1427
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1428
1429
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
1430
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1431
1432
    ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1433
1434
    SET_IPV6_SRC_ADDR(ip6p, &p->src);
1435
    SET_IPV6_DST_ADDR(ip6p, &p->dst);
1436
1437
    /* Self test. */
1438
    if (IPV6_GET_RAW_VER(ip6p) != 6)
1439
        goto error;
1440
    if (IPV6_GET_RAW_NH(ip6p) != 44)
1441
        goto error;
1442
    if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1443
        goto error;
1444
1445
    return p;
1446
error:
1447
    if (p != NULL)
1448
        SCFree(p);
1449
    return NULL;
1450
}
1451
1452
/**
1453
 * Test the simplest possible re-assembly scenario.  All packet in
1454
 * order and no overlaps.
1455
 */
1456
static int DefragInOrderSimpleTest(void)
1457
{
1458
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1459
    Packet *reassembled = NULL;
1460
    int id = 12;
1461
1462
    DefragInit();
1463
1464
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1465
    FAIL_IF_NULL(p1);
1466
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1467
    FAIL_IF_NULL(p2);
1468
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1469
    FAIL_IF_NULL(p3);
1470
1471
    FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1472
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1473
1474
    reassembled = Defrag(&test_tv, &test_dtv, p3);
1475
    FAIL_IF_NULL(reassembled);
1476
1477
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1478
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1479
1480
    /* 20 bytes in we should find 8 bytes of A. */
1481
    for (int i = 20; i < 20 + 8; i++) {
1482
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1483
    }
1484
1485
    /* 28 bytes in we should find 8 bytes of B. */
1486
    for (int i = 28; i < 28 + 8; i++) {
1487
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1488
    }
1489
1490
    /* And 36 bytes in we should find 3 bytes of C. */
1491
    for (int i = 36; i < 36 + 3; i++) {
1492
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1493
    }
1494
1495
    SCFree(p1);
1496
    SCFree(p2);
1497
    SCFree(p3);
1498
    SCFree(reassembled);
1499
1500
    DefragDestroy();
1501
    PASS;
1502
}
1503
1504
/**
1505
 * Simple fragmented packet in reverse order.
1506
 */
1507
static int DefragReverseSimpleTest(void)
1508
{
1509
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1510
    Packet *reassembled = NULL;
1511
    int id = 12;
1512
1513
    DefragInit();
1514
1515
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1516
    FAIL_IF_NULL(p1);
1517
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1518
    FAIL_IF_NULL(p2);
1519
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1520
    FAIL_IF_NULL(p3);
1521
1522
    FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1523
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1524
    reassembled = Defrag(&test_tv, &test_dtv, p1);
1525
    FAIL_IF_NULL(reassembled);
1526
1527
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1528
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1529
1530
    /* 20 bytes in we should find 8 bytes of A. */
1531
    for (int i = 20; i < 20 + 8; i++) {
1532
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1533
    }
1534
1535
    /* 28 bytes in we should find 8 bytes of B. */
1536
    for (int i = 28; i < 28 + 8; i++) {
1537
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1538
    }
1539
1540
    /* And 36 bytes in we should find 3 bytes of C. */
1541
    for (int i = 36; i < 36 + 3; i++) {
1542
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1543
    }
1544
1545
    SCFree(p1);
1546
    SCFree(p2);
1547
    SCFree(p3);
1548
    SCFree(reassembled);
1549
1550
    DefragDestroy();
1551
    PASS;
1552
}
1553
1554
/**
1555
 * Test the simplest possible re-assembly scenario.  All packet in
1556
 * order and no overlaps.
1557
 */
1558
static int DefragInOrderSimpleIpv6Test(void)
1559
{
1560
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1561
    Packet *reassembled = NULL;
1562
    int id = 12;
1563
1564
    DefragInit();
1565
1566
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1567
    FAIL_IF_NULL(p1);
1568
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1569
    FAIL_IF_NULL(p2);
1570
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1571
    FAIL_IF_NULL(p3);
1572
1573
    FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1574
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1575
    reassembled = Defrag(&test_tv, &test_dtv, p3);
1576
    FAIL_IF_NULL(reassembled);
1577
1578
    const IPV6Hdr *ip6h = PacketGetIPv6(reassembled);
1579
    FAIL_IF(IPV6_GET_RAW_PLEN(ip6h) != 19);
1580
1581
    /* 40 bytes in we should find 8 bytes of A. */
1582
    for (int i = 40; i < 40 + 8; i++) {
1583
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1584
    }
1585
1586
    /* 28 bytes in we should find 8 bytes of B. */
1587
    for (int i = 48; i < 48 + 8; i++) {
1588
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1589
    }
1590
1591
    /* And 36 bytes in we should find 3 bytes of C. */
1592
    for (int i = 56; i < 56 + 3; i++) {
1593
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1594
    }
1595
1596
    SCFree(p1);
1597
    SCFree(p2);
1598
    SCFree(p3);
1599
    SCFree(reassembled);
1600
1601
    DefragDestroy();
1602
    PASS;
1603
}
1604
1605
static int DefragReverseSimpleIpv6Test(void)
1606
{
1607
    DefragContext *dc = NULL;
1608
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1609
    Packet *reassembled = NULL;
1610
    int id = 12;
1611
1612
    DefragInit();
1613
1614
    dc = DefragContextNew();
1615
    FAIL_IF_NULL(dc);
1616
1617
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1618
    FAIL_IF_NULL(p1);
1619
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1620
    FAIL_IF_NULL(p2);
1621
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1622
    FAIL_IF_NULL(p3);
1623
1624
    FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1625
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1626
    reassembled = Defrag(&test_tv, &test_dtv, p1);
1627
    FAIL_IF_NULL(reassembled);
1628
1629
    /* 40 bytes in we should find 8 bytes of A. */
1630
    for (int i = 40; i < 40 + 8; i++) {
1631
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1632
    }
1633
1634
    /* 28 bytes in we should find 8 bytes of B. */
1635
    for (int i = 48; i < 48 + 8; i++) {
1636
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1637
    }
1638
1639
    /* And 36 bytes in we should find 3 bytes of C. */
1640
    for (int i = 56; i < 56 + 3; i++) {
1641
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1642
    }
1643
1644
    DefragContextDestroy(dc);
1645
    SCFree(p1);
1646
    SCFree(p2);
1647
    SCFree(p3);
1648
    SCFree(reassembled);
1649
1650
    DefragDestroy();
1651
    PASS;
1652
}
1653
1654
static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
1655
{
1656
    int i;
1657
1658
    DefragInit();
1659
1660
    /*
1661
     * Build the packets.
1662
     */
1663
1664
    int id = 1;
1665
    Packet *packets[17];
1666
    memset(packets, 0x00, sizeof(packets));
1667
1668
    /*
1669
     * Original fragments.
1670
     */
1671
1672
    /* <1> A*24 at 0. */
1673
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1674
1675
    /* <2> B*16 at 32. */
1676
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1677
1678
    /* <3> C*24 at 48. */
1679
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1680
1681
    /* <3_1> D*8 at 80. */
1682
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1683
1684
    /* <3_2> E*16 at 104. */
1685
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1686
1687
    /* <3_3> F*24 at 120. */
1688
    packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1689
1690
    /* <3_4> G*16 at 144. */
1691
    packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1692
1693
    /* <3_5> H*16 at 160. */
1694
    packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1695
1696
    /* <3_6> I*8 at 176. */
1697
    packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1698
1699
    /*
1700
     * Overlapping subsequent fragments.
1701
     */
1702
1703
    /* <4> J*32 at 8. */
1704
    packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1705
1706
    /* <5> K*24 at 48. */
1707
    packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1708
1709
    /* <6> L*24 at 72. */
1710
    packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1711
1712
    /* <7> M*24 at 96. */
1713
    packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1714
1715
    /* <8> N*8 at 128. */
1716
    packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1717
1718
    /* <9> O*8 at 152. */
1719
    packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1720
1721
    /* <10> P*8 at 160. */
1722
    packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1723
1724
    /* <11> Q*16 at 176. */
1725
    packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1726
1727
    default_policy = policy;
1728
1729
    /* Send all but the last. */
1730
    for (i = 0; i < 9; i++) {
1731
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1732
        FAIL_IF_NOT_NULL(tp);
1733
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP));
1734
    }
1735
    int overlap = 0;
1736
    for (; i < 16; i++) {
1737
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1738
        FAIL_IF_NOT_NULL(tp);
1739
        if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1740
            overlap++;
1741
        }
1742
    }
1743
    FAIL_IF_NOT(overlap);
1744
1745
    /* And now the last one. */
1746
    Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1747
    FAIL_IF_NULL(reassembled);
1748
1749
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1750
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 20 + 192);
1751
    FAIL_IF(expected_len != 192);
1752
1753
    if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
1754
        printf("Expected:\n");
1755
        PrintRawDataFp(stdout, expected, expected_len);
1756
        printf("Got:\n");
1757
        PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
1758
        FAIL;
1759
    }
1760
    SCFree(reassembled);
1761
1762
    /* Make sure all frags were returned back to the pool. */
1763
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1764
1765
    for (i = 0; i < 17; i++) {
1766
        SCFree(packets[i]);
1767
    }
1768
    DefragDestroy();
1769
    PASS;
1770
}
1771
1772
static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
1773
{
1774
    int i;
1775
1776
    DefragInit();
1777
1778
    /*
1779
     * Build the packets.
1780
     */
1781
1782
    int id = 1;
1783
    Packet *packets[17];
1784
    memset(packets, 0x00, sizeof(packets));
1785
1786
    /*
1787
     * Original fragments.
1788
     */
1789
1790
    /* <1> A*24 at 0. */
1791
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1792
1793
    /* <2> B*16 at 32. */
1794
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1795
1796
    /* <3> C*24 at 48. */
1797
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1798
1799
    /* <3_1> D*8 at 80. */
1800
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1801
1802
    /* <3_2> E*16 at 104. */
1803
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1804
1805
    /* <3_3> F*24 at 120. */
1806
    packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1807
1808
    /* <3_4> G*16 at 144. */
1809
    packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1810
1811
    /* <3_5> H*16 at 160. */
1812
    packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1813
1814
    /* <3_6> I*8 at 176. */
1815
    packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1816
1817
    /*
1818
     * Overlapping subsequent fragments.
1819
     */
1820
1821
    /* <4> J*32 at 8. */
1822
    packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1823
1824
    /* <5> K*24 at 48. */
1825
    packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1826
1827
    /* <6> L*24 at 72. */
1828
    packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1829
1830
    /* <7> M*24 at 96. */
1831
    packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1832
1833
    /* <8> N*8 at 128. */
1834
    packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1835
1836
    /* <9> O*8 at 152. */
1837
    packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1838
1839
    /* <10> P*8 at 160. */
1840
    packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1841
1842
    /* <11> Q*16 at 176. */
1843
    packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1844
1845
    default_policy = policy;
1846
1847
    /* Send all but the last. */
1848
    for (i = 0; i < 9; i++) {
1849
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1850
        FAIL_IF_NOT_NULL(tp);
1851
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP));
1852
    }
1853
    int overlap = 0;
1854
    for (; i < 16; i++) {
1855
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1856
        FAIL_IF_NOT_NULL(tp);
1857
        if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1858
            overlap++;
1859
        }
1860
    }
1861
    FAIL_IF_NOT(overlap);
1862
1863
    /* And now the last one. */
1864
    Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1865
    FAIL_IF_NULL(reassembled);
1866
    FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1867
1868
    FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(reassembled)) != 192);
1869
1870
    SCFree(reassembled);
1871
1872
    /* Make sure all frags were returned to the pool. */
1873
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1874
1875
    for (i = 0; i < 17; i++) {
1876
        SCFree(packets[i]);
1877
    }
1878
    DefragDestroy();
1879
    PASS;
1880
}
1881
1882
/* Define data that matches the naming "Target-Based Fragmentation
1883
 * Reassembly".
1884
 *
1885
 * For example, the data refers to a fragment of data as <1>, or <3_6>
1886
 * and uses these to diagram the input fragments and the resulting
1887
 * policies. We build test cases for the papers scenario but assign
1888
 * specific values to each segment.
1889
 */
1890
#define D_1   'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
1891
#define D_2   'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
1892
#define D_3   'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
1893
#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
1894
#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
1895
#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
1896
#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
1897
#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
1898
#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
1899
#define D_4   'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
1900
#define D_5   'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
1901
#define D_6   'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
1902
#define D_7   'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
1903
#define D_8   'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
1904
#define D_9   'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
1905
#define D_10  'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
1906
#define D_11  'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
1907
1908
static int
1909
DefragSturgesNovakBsdTest(void)
1910
{
1911
    /* Expected data. */
1912
    uint8_t expected[] = {
1913
        D_1,
1914
        D_1,
1915
        D_1,
1916
        D_4,
1917
        D_4,
1918
        D_2,
1919
        D_3,
1920
        D_3,
1921
        D_3,
1922
        D_6,
1923
        D_6,
1924
        D_6,
1925
        D_7,
1926
        D_7,
1927
        D_7,
1928
        D_3_3,
1929
        D_3_3,
1930
        D_3_3,
1931
        D_3_4,
1932
        D_3_4,
1933
        D_3_5,
1934
        D_3_5,
1935
        D_3_6,
1936
        D_11,
1937
    };
1938
1939
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1940
                    sizeof(expected)));
1941
    PASS;
1942
}
1943
1944
static int DefragSturgesNovakBsdIpv6Test(void)
1945
{
1946
    /* Expected data. */
1947
    uint8_t expected[] = {
1948
        D_1,
1949
        D_1,
1950
        D_1,
1951
        D_4,
1952
        D_4,
1953
        D_2,
1954
        D_3,
1955
        D_3,
1956
        D_3,
1957
        D_6,
1958
        D_6,
1959
        D_6,
1960
        D_7,
1961
        D_7,
1962
        D_7,
1963
        D_3_3,
1964
        D_3_3,
1965
        D_3_3,
1966
        D_3_4,
1967
        D_3_4,
1968
        D_3_5,
1969
        D_3_5,
1970
        D_3_6,
1971
        D_11,
1972
    };
1973
1974
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
1975
    PASS;
1976
}
1977
1978
static int DefragSturgesNovakLinuxIpv4Test(void)
1979
{
1980
    /* Expected data. */
1981
    uint8_t expected[] = {
1982
        D_1,
1983
        D_1,
1984
        D_1,
1985
        D_4,
1986
        D_4,
1987
        D_2,
1988
        D_5,
1989
        D_5,
1990
        D_5,
1991
        D_6,
1992
        D_6,
1993
        D_6,
1994
        D_7,
1995
        D_7,
1996
        D_7,
1997
        D_3_3,
1998
        D_3_3,
1999
        D_3_3,
2000
        D_3_4,
2001
        D_3_4,
2002
        D_10,
2003
        D_3_5,
2004
        D_11,
2005
        D_11,
2006
    };
2007
2008
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
2009
                    sizeof(expected)));
2010
    PASS;
2011
}
2012
2013
static int DefragSturgesNovakLinuxIpv6Test(void)
2014
{
2015
    /* Expected data. */
2016
    uint8_t expected[] = {
2017
        D_1,
2018
        D_1,
2019
        D_1,
2020
        D_4,
2021
        D_4,
2022
        D_2,
2023
        D_5,
2024
        D_5,
2025
        D_5,
2026
        D_6,
2027
        D_6,
2028
        D_6,
2029
        D_7,
2030
        D_7,
2031
        D_7,
2032
        D_3_3,
2033
        D_3_3,
2034
        D_3_3,
2035
        D_3_4,
2036
        D_3_4,
2037
        D_10,
2038
        D_3_5,
2039
        D_11,
2040
        D_11,
2041
    };
2042
2043
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
2044
    PASS;
2045
}
2046
2047
static int DefragSturgesNovakWindowsIpv4Test(void)
2048
{
2049
    /* Expected data. */
2050
    uint8_t expected[] = {
2051
        D_1,
2052
        D_1,
2053
        D_1,
2054
        D_4,
2055
        D_2,
2056
        D_2,
2057
        D_3,
2058
        D_3,
2059
        D_3,
2060
        D_6,
2061
        D_6,
2062
        D_6,
2063
        D_7,
2064
        D_3_2,
2065
        D_3_2,
2066
        D_3_3,
2067
        D_3_3,
2068
        D_3_3,
2069
        D_3_4,
2070
        D_3_4,
2071
        D_3_5,
2072
        D_3_5,
2073
        D_3_6,
2074
        D_11,
2075
    };
2076
2077
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
2078
                    sizeof(expected)));
2079
    PASS;
2080
}
2081
2082
static int DefragSturgesNovakWindowsIpv6Test(void)
2083
{
2084
    /* Expected data. */
2085
    uint8_t expected[] = {
2086
        D_1,
2087
        D_1,
2088
        D_1,
2089
        D_4,
2090
        D_2,
2091
        D_2,
2092
        D_3,
2093
        D_3,
2094
        D_3,
2095
        D_6,
2096
        D_6,
2097
        D_6,
2098
        D_7,
2099
        D_3_2,
2100
        D_3_2,
2101
        D_3_3,
2102
        D_3_3,
2103
        D_3_3,
2104
        D_3_4,
2105
        D_3_4,
2106
        D_3_5,
2107
        D_3_5,
2108
        D_3_6,
2109
        D_11,
2110
    };
2111
2112
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
2113
    PASS;
2114
}
2115
2116
static int DefragSturgesNovakSolarisTest(void)
2117
{
2118
    /* Expected data. */
2119
    uint8_t expected[] = {
2120
        D_1,
2121
        D_1,
2122
        D_1,
2123
        D_4,
2124
        D_2,
2125
        D_2,
2126
        D_3,
2127
        D_3,
2128
        D_3,
2129
        D_6,
2130
        D_6,
2131
        D_6,
2132
        D_7,
2133
        D_7,
2134
        D_7,
2135
        D_3_3,
2136
        D_3_3,
2137
        D_3_3,
2138
        D_3_4,
2139
        D_3_4,
2140
        D_3_5,
2141
        D_3_5,
2142
        D_3_6,
2143
        D_11,
2144
    };
2145
2146
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
2147
                    sizeof(expected)));
2148
    PASS;
2149
}
2150
2151
static int DefragSturgesNovakSolarisIpv6Test(void)
2152
{
2153
    /* Expected data. */
2154
    uint8_t expected[] = {
2155
        D_1,
2156
        D_1,
2157
        D_1,
2158
        D_4,
2159
        D_2,
2160
        D_2,
2161
        D_3,
2162
        D_3,
2163
        D_3,
2164
        D_6,
2165
        D_6,
2166
        D_6,
2167
        D_7,
2168
        D_7,
2169
        D_7,
2170
        D_3_3,
2171
        D_3_3,
2172
        D_3_3,
2173
        D_3_4,
2174
        D_3_4,
2175
        D_3_5,
2176
        D_3_5,
2177
        D_3_6,
2178
        D_11,
2179
    };
2180
2181
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
2182
    PASS;
2183
}
2184
2185
static int DefragSturgesNovakFirstTest(void)
2186
{
2187
    /* Expected data. */
2188
    uint8_t expected[] = {
2189
        D_1,
2190
        D_1,
2191
        D_1,
2192
        D_4,
2193
        D_2,
2194
        D_2,
2195
        D_3,
2196
        D_3,
2197
        D_3,
2198
        D_6,
2199
        D_3_1,
2200
        D_6,
2201
        D_7,
2202
        D_3_2,
2203
        D_3_2,
2204
        D_3_3,
2205
        D_3_3,
2206
        D_3_3,
2207
        D_3_4,
2208
        D_3_4,
2209
        D_3_5,
2210
        D_3_5,
2211
        D_3_6,
2212
        D_11,
2213
    };
2214
2215
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2216
                    sizeof(expected)));
2217
    PASS;
2218
}
2219
2220
static int DefragSturgesNovakFirstIpv6Test(void)
2221
{
2222
    /* Expected data. */
2223
    uint8_t expected[] = {
2224
        D_1,
2225
        D_1,
2226
        D_1,
2227
        D_4,
2228
        D_2,
2229
        D_2,
2230
        D_3,
2231
        D_3,
2232
        D_3,
2233
        D_6,
2234
        D_3_1,
2235
        D_6,
2236
        D_7,
2237
        D_3_2,
2238
        D_3_2,
2239
        D_3_3,
2240
        D_3_3,
2241
        D_3_3,
2242
        D_3_4,
2243
        D_3_4,
2244
        D_3_5,
2245
        D_3_5,
2246
        D_3_6,
2247
        D_11,
2248
    };
2249
2250
    return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
2251
}
2252
2253
static int
2254
DefragSturgesNovakLastTest(void)
2255
{
2256
    /* Expected data. */
2257
    uint8_t expected[] = {
2258
        D_1,
2259
        D_4,
2260
        D_4,
2261
        D_4,
2262
        D_4,
2263
        D_2,
2264
        D_5,
2265
        D_5,
2266
        D_5,
2267
        D_6,
2268
        D_6,
2269
        D_6,
2270
        D_7,
2271
        D_7,
2272
        D_7,
2273
        D_3_3,
2274
        D_8,
2275
        D_3_3,
2276
        D_3_4,
2277
        D_9,
2278
        D_10,
2279
        D_3_5,
2280
        D_11,
2281
        D_11,
2282
    };
2283
2284
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2285
                    sizeof(expected)));
2286
    PASS;
2287
}
2288
2289
static int DefragSturgesNovakLastIpv6Test(void)
2290
{
2291
    /* Expected data. */
2292
    uint8_t expected[] = {
2293
        D_1,
2294
        D_4,
2295
        D_4,
2296
        D_4,
2297
        D_4,
2298
        D_2,
2299
        D_5,
2300
        D_5,
2301
        D_5,
2302
        D_6,
2303
        D_6,
2304
        D_6,
2305
        D_7,
2306
        D_7,
2307
        D_7,
2308
        D_3_3,
2309
        D_8,
2310
        D_3_3,
2311
        D_3_4,
2312
        D_9,
2313
        D_10,
2314
        D_3_5,
2315
        D_11,
2316
        D_11,
2317
    };
2318
2319
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
2320
    PASS;
2321
}
2322
2323
static int DefragTimeoutTest(void)
2324
{
2325
    int i;
2326
2327
    /* Setup a small number of trackers. */
2328
    FAIL_IF_NOT(SCConfSet("defrag.trackers", "16"));
2329
2330
    DefragInit();
2331
2332
    /* Load in 16 packets. */
2333
    for (i = 0; i < 16; i++) {
2334
        Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
2335
        FAIL_IF_NULL(p);
2336
2337
        Packet *tp = Defrag(&test_tv, &test_dtv, p);
2338
        SCFree(p);
2339
        FAIL_IF_NOT_NULL(tp);
2340
    }
2341
2342
    /* Build a new packet but push the timestamp out by our timeout.
2343
     * This should force our previous fragments to be timed out. */
2344
    Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2345
    FAIL_IF_NULL(p);
2346
2347
    p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2348
    Packet *tp = Defrag(&test_tv, &test_dtv, p);
2349
    FAIL_IF_NOT_NULL(tp);
2350
2351
    DefragTracker *tracker = DefragLookupTrackerFromHash(p);
2352
    FAIL_IF_NULL(tracker);
2353
2354
    FAIL_IF(tracker->id != 99);
2355
2356
    SCMutexUnlock(&tracker->lock);
2357
    SCFree(p);
2358
2359
    DefragDestroy();
2360
    PASS;
2361
}
2362
2363
/**
2364
 * QA found that if you send a packet where more frags is 0, offset is
2365
 * > 0 and there is no data in the packet that the re-assembler will
2366
 * fail.  The fix was simple, but this unit test is just to make sure
2367
 * its not introduced.
2368
 */
2369
static int DefragNoDataIpv4Test(void)
2370
{
2371
    DefragContext *dc = NULL;
2372
    Packet *p = NULL;
2373
    int id = 12;
2374
2375
    DefragInit();
2376
2377
    dc = DefragContextNew();
2378
    FAIL_IF_NULL(dc);
2379
2380
    /* This packet has an offset > 0, more frags set to 0 and no data. */
2381
    p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2382
    FAIL_IF_NULL(p);
2383
2384
    /* We do not expect a packet returned. */
2385
    FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2386
2387
    /* The fragment should have been ignored so no fragments should
2388
     * have been allocated from the pool. */
2389
    FAIL_IF(dc->frag_pool->outstanding != 0);
2390
2391
    DefragContextDestroy(dc);
2392
    SCFree(p);
2393
2394
    DefragDestroy();
2395
    PASS;
2396
}
2397
2398
static int DefragTooLargeIpv4Test(void)
2399
{
2400
    DefragContext *dc = NULL;
2401
    Packet *p = NULL;
2402
2403
    DefragInit();
2404
2405
    dc = DefragContextNew();
2406
    FAIL_IF_NULL(dc);
2407
2408
    /* Create a fragment that would extend past the max allowable size
2409
     * for an IPv4 packet. */
2410
    p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2411
    FAIL_IF_NULL(p);
2412
2413
    /* We do not expect a packet returned. */
2414
    FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2415
2416
    /* We do expect an event. */
2417
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE));
2418
2419
    /* The fragment should have been ignored so no fragments should have
2420
     * been allocated from the pool. */
2421
    FAIL_IF(dc->frag_pool->outstanding != 0);
2422
2423
    DefragContextDestroy(dc);
2424
    SCFree(p);
2425
2426
    DefragDestroy();
2427
    PASS;
2428
}
2429
2430
/**
2431
 * Test that fragments in different VLANs that would otherwise be
2432
 * re-assembled, are not re-assembled.  Just use simple in-order
2433
 * fragments.
2434
 */
2435
static int DefragVlanTest(void)
2436
{
2437
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2438
2439
    DefragInit();
2440
2441
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2442
    FAIL_IF_NULL(p1);
2443
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2444
    FAIL_IF_NULL(p2);
2445
2446
    /* With no VLAN IDs set, packets should re-assemble. */
2447
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2448
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2449
    SCFree(r);
2450
2451
    /* With mismatched VLANs, packets should not re-assemble. */
2452
    p1->vlan_id[0] = 1;
2453
    p2->vlan_id[0] = 2;
2454
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2455
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2456
2457
    SCFree(p1);
2458
    SCFree(p2);
2459
    DefragDestroy();
2460
2461
    PASS;
2462
}
2463
2464
/**
2465
 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2466
 */
2467
static int DefragVlanQinQTest(void)
2468
{
2469
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2470
2471
    DefragInit();
2472
2473
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2474
    FAIL_IF_NULL(p1);
2475
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2476
    FAIL_IF_NULL(p2);
2477
2478
    /* With no VLAN IDs set, packets should re-assemble. */
2479
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2480
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2481
    SCFree(r);
2482
2483
    /* With mismatched VLANs, packets should not re-assemble. */
2484
    p1->vlan_id[0] = 1;
2485
    p2->vlan_id[0] = 1;
2486
    p1->vlan_id[1] = 1;
2487
    p2->vlan_id[1] = 2;
2488
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2489
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2490
2491
    SCFree(p1);
2492
    SCFree(p2);
2493
    DefragDestroy();
2494
2495
    PASS;
2496
}
2497
2498
/**
2499
 * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2500
 */
2501
static int DefragVlanQinQinQTest(void)
2502
{
2503
    Packet *r = NULL;
2504
2505
    DefragInit();
2506
2507
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2508
    FAIL_IF_NULL(p1);
2509
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2510
    FAIL_IF_NULL(p2);
2511
2512
    /* With no VLAN IDs set, packets should re-assemble. */
2513
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2514
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2515
    SCFree(r);
2516
2517
    /* With mismatched VLANs, packets should not re-assemble. */
2518
    p1->vlan_id[0] = 1;
2519
    p2->vlan_id[0] = 1;
2520
    p1->vlan_id[1] = 2;
2521
    p2->vlan_id[1] = 2;
2522
    p1->vlan_id[2] = 3;
2523
    p2->vlan_id[2] = 4;
2524
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2525
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2526
2527
    PacketFree(p1);
2528
    PacketFree(p2);
2529
    DefragDestroy();
2530
2531
    PASS;
2532
}
2533
static int DefragTrackerReuseTest(void)
2534
{
2535
    int id = 1;
2536
    Packet *p1 = NULL;
2537
    DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2538
2539
    DefragInit();
2540
2541
    /* Build a packet, its not a fragment but shouldn't matter for
2542
     * this test. */
2543
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2544
    FAIL_IF_NULL(p1);
2545
2546
    /* Get a tracker. It shouldn't look like its already in use. */
2547
    tracker1 = DefragGetTracker(&test_tv, &test_dtv, p1);
2548
    FAIL_IF_NULL(tracker1);
2549
    FAIL_IF(tracker1->seen_last);
2550
    FAIL_IF(tracker1->remove);
2551
    DefragTrackerRelease(tracker1);
2552
2553
    /* Get a tracker again, it should be the same one. */
2554
    tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2555
    FAIL_IF_NULL(tracker2);
2556
    FAIL_IF(tracker2 != tracker1);
2557
    DefragTrackerRelease(tracker1);
2558
2559
    /* Now mark the tracker for removal. It should not be returned
2560
     * when we get a tracker for a packet that may have the same
2561
     * attributes. */
2562
    tracker1->remove = 1;
2563
2564
    tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2565
    FAIL_IF_NULL(tracker2);
2566
    /* DefragGetTracker will have returned tracker1 to the stack,
2567
     * the set up a new tracker. Since it pops the stack, it got
2568
     * tracker1. */
2569
    FAIL_IF(tracker2 != tracker1);
2570
    FAIL_IF(tracker2->remove);
2571
2572
    SCFree(p1);
2573
    DefragDestroy();
2574
    PASS;
2575
}
2576
2577
/**
2578
 * IPV4: Test the case where you have a packet fragmented in 3 parts
2579
 * and send like:
2580
 * - Offset: 2; MF: 1
2581
 * - Offset: 0; MF: 1
2582
 * - Offset: 1; MF: 0
2583
 *
2584
 * Only the fragments with offset 0 and 1 should be reassembled.
2585
 */
2586
static int DefragMfIpv4Test(void)
2587
{
2588
    int ip_id = 9;
2589
    Packet *p = NULL;
2590
2591
    DefragInit();
2592
2593
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2594
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2595
    Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2596
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2597
2598
    p = Defrag(&test_tv, &test_dtv, p1);
2599
    FAIL_IF_NOT_NULL(p);
2600
2601
    p = Defrag(&test_tv, &test_dtv, p2);
2602
    FAIL_IF_NOT_NULL(p);
2603
2604
    /* This should return a packet as MF=0. */
2605
    p = Defrag(&test_tv, &test_dtv, p3);
2606
    FAIL_IF_NULL(p);
2607
2608
    /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2609
     * fragments should be in the re-assembled packet. */
2610
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(p)) != 36);
2611
2612
    /* Verify the payload of the IPv4 packet. */
2613
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2614
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
2615
2616
    SCFree(p1);
2617
    SCFree(p2);
2618
    SCFree(p3);
2619
    SCFree(p);
2620
    DefragDestroy();
2621
    PASS;
2622
}
2623
2624
/**
2625
 * IPV6: Test the case where you have a packet fragmented in 3 parts
2626
 * and send like:
2627
 * - Offset: 2; MF: 1
2628
 * - Offset: 0; MF: 1
2629
 * - Offset: 1; MF: 0
2630
 *
2631
 * Only the fragments with offset 0 and 1 should be reassembled.
2632
 */
2633
static int DefragMfIpv6Test(void)
2634
{
2635
    int ip_id = 9;
2636
    Packet *p = NULL;
2637
2638
    DefragInit();
2639
2640
    Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2641
    Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2642
    Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2643
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2644
2645
    p = Defrag(&test_tv, &test_dtv, p1);
2646
    FAIL_IF_NOT_NULL(p);
2647
2648
    p = Defrag(&test_tv, &test_dtv, p2);
2649
    FAIL_IF_NOT_NULL(p);
2650
2651
    /* This should return a packet as MF=0. */
2652
    p = Defrag(&test_tv, &test_dtv, p3);
2653
    FAIL_IF_NULL(p);
2654
2655
    /* For IPv6 the expected length is just the length of the payload
2656
     * of 2 fragments, so 16. */
2657
    FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(p)) != 16);
2658
2659
    /* Verify the payload of the IPv4 packet. */
2660
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2661
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
2662
2663
    SCFree(p1);
2664
    SCFree(p2);
2665
    SCFree(p3);
2666
    SCFree(p);
2667
    DefragDestroy();
2668
    PASS;
2669
}
2670
2671
/**
2672
 * \brief Test that fragments that match other than the proto don't
2673
 * actually get matched.
2674
 */
2675
static int DefragTestBadProto(void)
2676
{
2677
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2678
    int id = 12;
2679
2680
    DefragInit();
2681
2682
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2683
    FAIL_IF_NULL(p1);
2684
    p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2685
    FAIL_IF_NULL(p2);
2686
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2687
    FAIL_IF_NULL(p3);
2688
2689
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p1));
2690
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p2));
2691
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p3));
2692
2693
    SCFree(p1);
2694
    SCFree(p2);
2695
    SCFree(p3);
2696
2697
    DefragDestroy();
2698
    PASS;
2699
}
2700
2701
/**
2702
 * \test Test a report Linux overlap issue that doesn't appear to be
2703
 *     covered by the Sturges/Novak tests above.
2704
 */
2705
static int DefragTestJeremyLinux(void)
2706
{
2707
2708
    uint8_t expected[] = "AAAAAAAA"
2709
                         "AAAAAAAA"
2710
                         "AAAAAAAA"
2711
                         "CCCCCCCC"
2712
                         "CCCCCCCC"
2713
                         "CCCCCCCC"
2714
                         "CCCCCCCC"
2715
                         "CCCCCCCC"
2716
                         "CCCCCCCC"
2717
                         "BBBBBBBB"
2718
                         "BBBBBBBB"
2719
                         "DDDDDDDD"
2720
                         "DDDDDD";
2721
2722
    DefragInit();
2723
    default_policy = DEFRAG_POLICY_LINUX;
2724
2725
    int id = 1;
2726
    Packet *packets[4];
2727
    int i = 0;
2728
2729
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2730
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2731
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2732
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2733
2734
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2735
    FAIL_IF_NOT_NULL(r);
2736
2737
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2738
    FAIL_IF_NOT_NULL(r);
2739
2740
    r = Defrag(&test_tv, &test_dtv, packets[2]);
2741
    FAIL_IF_NOT_NULL(r);
2742
2743
    r = Defrag(&test_tv, &test_dtv, packets[3]);
2744
    FAIL_IF_NULL(r);
2745
2746
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2747
2748
    for (i = 0; i < 4; i++) {
2749
        SCFree(packets[i]);
2750
    }
2751
    SCFree(r);
2752
2753
    DefragDestroy();
2754
    PASS;
2755
}
2756
2757
/**
2758
 * | 0        | 8        | 16       | 24       | 32       |
2759
 * |----------|----------|----------|----------|----------|
2760
 * |                                  AAAAAAAA | AAAAAAAA |
2761
 * |          | BBBBBBBB | BBBBBBBB |          |          |
2762
 * |          |          | CCCCCCCC | CCCCCCCC |          |
2763
 * | DDDDDDDD |          |          |          |          |
2764
 *
2765
 * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
2766
 */
2767
static int DefragBsdFragmentAfterNoMfIpv4Test(void)
2768
{
2769
    DefragInit();
2770
    default_policy = DEFRAG_POLICY_BSD;
2771
    Packet *packets[4];
2772
2773
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2774
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2775
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2776
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2777
2778
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2779
    FAIL_IF_NOT_NULL(r);
2780
2781
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2782
    FAIL_IF_NOT_NULL(r);
2783
2784
    r = Defrag(&test_tv, &test_dtv, packets[2]);
2785
    FAIL_IF_NOT_NULL(r);
2786
2787
    r = Defrag(&test_tv, &test_dtv, packets[3]);
2788
    FAIL_IF_NULL(r);
2789
2790
    // clang-format off
2791
    uint8_t expected[] = {
2792
  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2793
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2794
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2795
  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2796
  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2797
    };
2798
    // clang-format on
2799
2800
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2801
        printf("Expected:\n");
2802
        PrintRawDataFp(stdout, expected, sizeof(expected));
2803
        printf("Got:\n");
2804
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2805
        FAIL;
2806
    }
2807
2808
    DefragDestroy();
2809
    PASS;
2810
}
2811
2812
static int DefragBsdFragmentAfterNoMfIpv6Test(void)
2813
{
2814
    DefragInit();
2815
    default_policy = DEFRAG_POLICY_BSD;
2816
    Packet *packets[4];
2817
2818
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2819
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2820
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2821
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2822
2823
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2824
    FAIL_IF_NOT_NULL(r);
2825
2826
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2827
    FAIL_IF_NOT_NULL(r);
2828
2829
    r = Defrag(&test_tv, &test_dtv, packets[2]);
2830
    FAIL_IF_NOT_NULL(r);
2831
2832
    r = Defrag(&test_tv, &test_dtv, packets[3]);
2833
    FAIL_IF_NULL(r);
2834
2835
    // clang-format off
2836
    uint8_t expected[] = {
2837
  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2838
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2839
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2840
  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2841
  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2842
    };
2843
    // clang-format on
2844
2845
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
2846
        printf("Expected:\n");
2847
        PrintRawDataFp(stdout, expected, sizeof(expected));
2848
        printf("Got:\n");
2849
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2850
        FAIL;
2851
    }
2852
2853
    DefragDestroy();
2854
    PASS;
2855
}
2856
2857
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
2858
{
2859
    DefragInit();
2860
    default_policy = DEFRAG_POLICY_BSD;
2861
    Packet *packets[4];
2862
2863
    /* Packet 1: off=16, mf=1 */
2864
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2865
            &packets[0], IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
2866
2867
    /* Packet 2: off=8, mf=1 */
2868
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2869
            &packets[1], IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16));
2870
2871
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2872
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2873
            &packets[2], IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
2874
2875
    /* Packet 4: off=8, mf=1 */
2876
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2877
            &packets[3], IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
2878
2879
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2880
    FAIL_IF_NOT_NULL(r);
2881
2882
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2883
    FAIL_IF_NOT_NULL(r);
2884
2885
    r = Defrag(&test_tv, &test_dtv, packets[2]);
2886
    FAIL_IF_NOT_NULL(r);
2887
2888
    r = Defrag(&test_tv, &test_dtv, packets[3]);
2889
    FAIL_IF_NULL(r);
2890
2891
    // clang-format off
2892
    const uint8_t expected[] = {
2893
  // AACCBBDD
2894
  // AACCDDBB
2895
  // AABBDDCC
2896
  // DDCCBBAA
2897
  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2898
  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2899
  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2900
  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2901
    };
2902
    // clang-format on
2903
2904
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
2905
2906
    DefragDestroy();
2907
    PASS;
2908
}
2909
2910
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
2911
{
2912
    DefragInit();
2913
    default_policy = DEFRAG_POLICY_BSD;
2914
    Packet *packets[4];
2915
2916
    /* Packet 1: off=16, mf=1 */
2917
    packets[0] = BuildIpv6TestPacketWithContent(
2918
            IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
2919
2920
    /* Packet 2: off=8, mf=1 */
2921
    packets[1] = BuildIpv6TestPacketWithContent(
2922
            IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
2923
2924
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2925
    packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
2926
2927
    /* Packet 4: off=8, mf=1 */
2928
    packets[3] =
2929
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
2930
2931
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2932
    FAIL_IF_NOT_NULL(r);
2933
2934
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2935
    FAIL_IF_NOT_NULL(r);
2936
2937
    r = Defrag(&test_tv, &test_dtv, packets[2]);
2938
    FAIL_IF_NOT_NULL(r);
2939
2940
    r = Defrag(&test_tv, &test_dtv, packets[3]);
2941
    FAIL_IF_NULL(r);
2942
2943
    // clang-format off
2944
    const uint8_t expected[] = {
2945
  // AACCBBDD
2946
  // AACCDDBB
2947
  // AABBDDCC
2948
  // DDCCBBAA
2949
  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2950
  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2951
  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2952
  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2953
    };
2954
    // clang-format on
2955
2956
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
2957
2958
    DefragDestroy();
2959
    PASS;
2960
}
2961
2962
/**
2963
 * #### Input
2964
 *
2965
 * | 96 (0)   | 104 (8)  | 112 (16) | 120 (24) |
2966
 * |----------|----------|----------|----------|
2967
 * |          | EEEEEEEE | EEEEEEEE | EEEEEEEE |
2968
 * | MMMMMMMM | MMMMMMMM | MMMMMMMM |          |
2969
 *
2970
 * #### Expected Output
2971
 *
2972
 * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
2973
 */
2974
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
2975
{
2976
    DefragInit();
2977
    default_policy = DEFRAG_POLICY_BSD;
2978
    Packet *packets[2];
2979
2980
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2981
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2982
2983
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2984
    FAIL_IF_NOT_NULL(r);
2985
2986
    r = Defrag(&test_tv, &test_dtv, packets[1]);
2987
    FAIL_IF_NULL(r);
2988
2989
    // clang-format off
2990
    const uint8_t expected[] = {
2991
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2992
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2993
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2994
  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
2995
    };
2996
    // clang-format on
2997
2998
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2999
        printf("Expected:\n");
3000
        PrintRawDataFp(stdout, expected, sizeof(expected));
3001
        printf("Got:\n");
3002
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3003
        FAIL;
3004
    }
3005
3006
    PASS;
3007
}
3008
3009
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
3010
{
3011
    DefragInit();
3012
    default_policy = DEFRAG_POLICY_BSD;
3013
    Packet *packets[2];
3014
3015
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
3016
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
3017
3018
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3019
    FAIL_IF_NOT_NULL(r);
3020
3021
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3022
    FAIL_IF_NULL(r);
3023
3024
    // clang-format off
3025
    const uint8_t expected[] = {
3026
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3027
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3028
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3029
  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3030
    };
3031
    // clang-format on
3032
3033
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3034
        printf("Expected:\n");
3035
        PrintRawDataFp(stdout, expected, sizeof(expected));
3036
        printf("Got:\n");
3037
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3038
        FAIL;
3039
    }
3040
3041
    PASS;
3042
}
3043
3044
/**
3045
 * Reassembly should fail.
3046
 *
3047
 * |0       |8       |16      |24      |32      |40      |48      |
3048
 * |========|========|========|========|========|========|========|
3049
 * |        |        |AABBCCDD|AABBDDCC|        |        |        |
3050
 * |        |        |        |        |        |AACCBBDD|        |
3051
 * |        |AACCDDBB|AADDBBCC|        |        |        |        |
3052
 * |ZZZZZZZZ|        |        |        |        |        |        |
3053
 * |        |        |        |        |        |        |DDCCBBAA|
3054
 */
3055
static int DefragBsdMissingFragmentIpv4Test(void)
3056
{
3057
    DefragInit();
3058
    default_policy = DEFRAG_POLICY_BSD;
3059
    Packet *packets[5];
3060
3061
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3062
            &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
3063
3064
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3065
            &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8));
3066
3067
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3068
            &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16));
3069
3070
    /* ICMP header. */
3071
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3072
            &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
3073
3074
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3075
            &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
3076
3077
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3078
    FAIL_IF_NOT_NULL(r);
3079
3080
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3081
    FAIL_IF_NOT_NULL(r);
3082
3083
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3084
    FAIL_IF_NOT_NULL(r);
3085
3086
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3087
    FAIL_IF_NOT_NULL(r);
3088
3089
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3090
    FAIL_IF_NOT_NULL(r);
3091
3092
#if 0
3093
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3094
#endif
3095
3096
    for (int i = 0; i < 5; i++) {
3097
        SCFree(packets[i]);
3098
    }
3099
3100
    DefragDestroy();
3101
3102
    PASS;
3103
}
3104
3105
static int DefragBsdMissingFragmentIpv6Test(void)
3106
{
3107
    DefragInit();
3108
    default_policy = DEFRAG_POLICY_BSD;
3109
    Packet *packets[5];
3110
3111
    packets[0] = BuildIpv6TestPacketWithContent(
3112
            IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
3113
3114
    packets[1] =
3115
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
3116
3117
    packets[2] = BuildIpv6TestPacketWithContent(
3118
            IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
3119
3120
    /* ICMP header. */
3121
    packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
3122
3123
    packets[4] =
3124
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
3125
3126
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3127
    FAIL_IF_NOT_NULL(r);
3128
3129
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3130
    FAIL_IF_NOT_NULL(r);
3131
3132
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3133
    FAIL_IF_NOT_NULL(r);
3134
3135
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3136
    FAIL_IF_NOT_NULL(r);
3137
3138
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3139
    FAIL_IF_NOT_NULL(r);
3140
3141
#if 0
3142
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3143
#endif
3144
3145
    for (int i = 0; i < 5; i++) {
3146
        SCFree(packets[i]);
3147
    }
3148
    DefragDestroy();
3149
    PASS;
3150
}
3151
3152
/**
3153
 * \test A BSD-preferred fragment that starts within an earlier fragment
3154
 *     and fully covers a later fragment. A subsequent fragment then
3155
 *     overlaps the end of the preferred fragment and must be trimmed.
3156
 *
3157
 *     Arrival:
3158
 *       A: 0..16
3159
 *       B: 24..40
3160
 *       C: 48..56 (last)
3161
 *       D: 8..40  (stored as 16..40, fully covers B)
3162
 *       E: 32..48 (must be trimmed to 40..48)
3163
 *
3164
 *     Expected: A*16 D*24 E*8 C*8
3165
 */
3166
static int DefragBsdOverlapAfterCoveredStartsInsidePrevIpv4Test(void)
3167
{
3168
    DefragInit();
3169
    default_policy = DEFRAG_POLICY_BSD;
3170
    Packet *packets[5];
3171
3172
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 54, 0, 1, 'A', 16);
3173
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 54, 24 >> 3, 1, 'B', 16);
3174
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 54, 48 >> 3, 0, 'C', 8);
3175
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 54, 8 >> 3, 1, 'D', 32);
3176
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, 54, 32 >> 3, 1, 'E', 16);
3177
3178
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[0]);
3179
    FAIL_IF_NOT_NULL(rp);
3180
3181
    rp = Defrag(&test_tv, &test_dtv, packets[1]);
3182
    FAIL_IF_NOT_NULL(rp);
3183
3184
    rp = Defrag(&test_tv, &test_dtv, packets[2]);
3185
    FAIL_IF_NOT_NULL(rp);
3186
3187
    rp = Defrag(&test_tv, &test_dtv, packets[3]);
3188
    FAIL_IF_NOT_NULL(rp);
3189
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[3], IPV4_FRAG_OVERLAP));
3190
3191
    rp = Defrag(&test_tv, &test_dtv, packets[4]);
3192
    FAIL_IF_NULL(rp);
3193
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV4_FRAG_OVERLAP));
3194
3195
    // clang-format off
3196
    const uint8_t expected[] = {
3197
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3198
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3199
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3200
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3201
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3202
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3203
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3204
    };
3205
    // clang-format on
3206
3207
    FAIL_IF(GET_PKT_LEN(rp) != 20 + sizeof(expected));
3208
    if (memcmp(expected, GET_PKT_DATA(rp) + 20, sizeof(expected)) != 0) {
3209
        printf("Expected:\n");
3210
        PrintRawDataFp(stdout, expected, sizeof(expected));
3211
        printf("Got:\n");
3212
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 20, GET_PKT_LEN(rp) - 20);
3213
        FAIL;
3214
    }
3215
3216
    /* Make sure all frags were returned back to the pool. */
3217
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3218
3219
    for (int i = 0; i < 5; i++) {
3220
        PacketFree(packets[i]);
3221
    }
3222
    PacketFree(rp);
3223
    DefragDestroy();
3224
    PASS;
3225
}
3226
3227
/** IPv6 variant of DefragBsdOverlapAfterCoveredStartsInsidePrevIpv4Test. */
3228
static int DefragBsdOverlapAfterCoveredStartsInsidePrevIpv6Test(void)
3229
{
3230
    DefragInit();
3231
    default_policy = DEFRAG_POLICY_BSD;
3232
    Packet *packets[5];
3233
3234
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 54, 0, 1, 'A', 16);
3235
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 54, 24 >> 3, 1, 'B', 16);
3236
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 54, 48 >> 3, 0, 'C', 8);
3237
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 54, 8 >> 3, 1, 'D', 32);
3238
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMP, 54, 32 >> 3, 1, 'E', 16);
3239
3240
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[0]);
3241
    FAIL_IF_NOT_NULL(rp);
3242
3243
    rp = Defrag(&test_tv, &test_dtv, packets[1]);
3244
    FAIL_IF_NOT_NULL(rp);
3245
3246
    rp = Defrag(&test_tv, &test_dtv, packets[2]);
3247
    FAIL_IF_NOT_NULL(rp);
3248
3249
    rp = Defrag(&test_tv, &test_dtv, packets[3]);
3250
    FAIL_IF_NOT_NULL(rp);
3251
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[3], IPV6_FRAG_OVERLAP));
3252
3253
    rp = Defrag(&test_tv, &test_dtv, packets[4]);
3254
    FAIL_IF_NULL(rp);
3255
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV6_FRAG_OVERLAP));
3256
3257
    // clang-format off
3258
    const uint8_t expected[] = {
3259
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3260
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3261
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3262
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3263
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3264
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3265
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3266
    };
3267
    // clang-format on
3268
3269
    FAIL_IF(GET_PKT_LEN(rp) != 40 + sizeof(expected));
3270
    if (memcmp(expected, GET_PKT_DATA(rp) + 40, sizeof(expected)) != 0) {
3271
        printf("Expected:\n");
3272
        PrintRawDataFp(stdout, expected, sizeof(expected));
3273
        printf("Got:\n");
3274
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 40, GET_PKT_LEN(rp) - 40);
3275
        FAIL;
3276
    }
3277
3278
    /* Make sure all frags were returned back to the pool. */
3279
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3280
3281
    for (int i = 0; i < 5; i++) {
3282
        PacketFree(packets[i]);
3283
    }
3284
    PacketFree(rp);
3285
    DefragDestroy();
3286
    PASS;
3287
}
3288
3289
/**
3290
 * \test A BSD-preferred fragment that starts before an earlier fragment
3291
 *     and fully covers a later fragment. A subsequent fragment then
3292
 *     overlaps the end of the preferred fragment and must be trimmed.
3293
 *
3294
 *     Arrival:
3295
 *       A: 0..16
3296
 *       B: 24..32
3297
 *       C: 40..56
3298
 *       D: 64..72 (last)
3299
 *       E: 16..56 (fully covers B and C)
3300
 *       F: 48..64 (must be trimmed to 56..64)
3301
 *
3302
 *     Expected: A*16 E*40 F*8 D*8
3303
 */
3304
static int DefragBsdOverlapAfterCoveredStartsBeforeIpv4Test(void)
3305
{
3306
    DefragInit();
3307
    default_policy = DEFRAG_POLICY_BSD;
3308
    Packet *packets[6];
3309
3310
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 0, 1, 'A', 16);
3311
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 24 >> 3, 1, 'B', 8);
3312
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 40 >> 3, 1, 'C', 16);
3313
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 64 >> 3, 0, 'D', 8);
3314
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 16 >> 3, 1, 'E', 40);
3315
    packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, 55, 48 >> 3, 1, 'F', 16);
3316
3317
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[0]);
3318
    FAIL_IF_NOT_NULL(rp);
3319
3320
    rp = Defrag(&test_tv, &test_dtv, packets[1]);
3321
    FAIL_IF_NOT_NULL(rp);
3322
3323
    rp = Defrag(&test_tv, &test_dtv, packets[2]);
3324
    FAIL_IF_NOT_NULL(rp);
3325
3326
    rp = Defrag(&test_tv, &test_dtv, packets[3]);
3327
    FAIL_IF_NOT_NULL(rp);
3328
3329
    rp = Defrag(&test_tv, &test_dtv, packets[4]);
3330
    FAIL_IF_NOT_NULL(rp);
3331
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV4_FRAG_OVERLAP));
3332
3333
    rp = Defrag(&test_tv, &test_dtv, packets[5]);
3334
    FAIL_IF_NULL(rp);
3335
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[5], IPV4_FRAG_OVERLAP));
3336
3337
    // clang-format off
3338
    const uint8_t expected[] = {
3339
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3340
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3341
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3342
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3343
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3344
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3345
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3346
        'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
3347
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3348
    };
3349
    // clang-format on
3350
3351
    FAIL_IF(GET_PKT_LEN(rp) != 20 + sizeof(expected));
3352
    if (memcmp(expected, GET_PKT_DATA(rp) + 20, sizeof(expected)) != 0) {
3353
        printf("Expected:\n");
3354
        PrintRawDataFp(stdout, expected, sizeof(expected));
3355
        printf("Got:\n");
3356
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 20, GET_PKT_LEN(rp) - 20);
3357
        FAIL;
3358
    }
3359
3360
    /* Make sure all frags were returned back to the pool. */
3361
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3362
3363
    for (int i = 0; i < 6; i++) {
3364
        PacketFree(packets[i]);
3365
    }
3366
    PacketFree(rp);
3367
    DefragDestroy();
3368
    PASS;
3369
}
3370
3371
/** IPv6 variant of DefragBsdOverlapAfterCoveredStartsBeforeIpv4Test. */
3372
static int DefragBsdOverlapAfterCoveredStartsBeforeIpv6Test(void)
3373
{
3374
    DefragInit();
3375
    default_policy = DEFRAG_POLICY_BSD;
3376
    Packet *packets[6];
3377
3378
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 0, 1, 'A', 16);
3379
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 24 >> 3, 1, 'B', 8);
3380
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 40 >> 3, 1, 'C', 16);
3381
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 64 >> 3, 0, 'D', 8);
3382
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 16 >> 3, 1, 'E', 40);
3383
    packets[5] = BuildIpv6TestPacket(IPPROTO_ICMP, 55, 48 >> 3, 1, 'F', 16);
3384
3385
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[0]);
3386
    FAIL_IF_NOT_NULL(rp);
3387
3388
    rp = Defrag(&test_tv, &test_dtv, packets[1]);
3389
    FAIL_IF_NOT_NULL(rp);
3390
3391
    rp = Defrag(&test_tv, &test_dtv, packets[2]);
3392
    FAIL_IF_NOT_NULL(rp);
3393
3394
    rp = Defrag(&test_tv, &test_dtv, packets[3]);
3395
    FAIL_IF_NOT_NULL(rp);
3396
3397
    rp = Defrag(&test_tv, &test_dtv, packets[4]);
3398
    FAIL_IF_NOT_NULL(rp);
3399
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV6_FRAG_OVERLAP));
3400
3401
    rp = Defrag(&test_tv, &test_dtv, packets[5]);
3402
    FAIL_IF_NULL(rp);
3403
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[5], IPV6_FRAG_OVERLAP));
3404
3405
    // clang-format off
3406
    const uint8_t expected[] = {
3407
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3408
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3409
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3410
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3411
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3412
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3413
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3414
        'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
3415
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3416
    };
3417
    // clang-format on
3418
3419
    FAIL_IF(GET_PKT_LEN(rp) != 40 + sizeof(expected));
3420
    if (memcmp(expected, GET_PKT_DATA(rp) + 40, sizeof(expected)) != 0) {
3421
        printf("Expected:\n");
3422
        PrintRawDataFp(stdout, expected, sizeof(expected));
3423
        printf("Got:\n");
3424
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 40, GET_PKT_LEN(rp) - 40);
3425
        FAIL;
3426
    }
3427
3428
    /* Make sure all frags were returned back to the pool. */
3429
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3430
3431
    for (int i = 0; i < 6; i++) {
3432
        PacketFree(packets[i]);
3433
    }
3434
    PacketFree(rp);
3435
    DefragDestroy();
3436
    PASS;
3437
}
3438
3439
/**
3440
 * \test A BSD fragment must only trim the fragments that start after
3441
 *     it. E follows D in the fragment tree, but D starts before E and
3442
 *     must be left alone.
3443
 *
3444
 *     Arrival:
3445
 *       A: 0..32
3446
 *       B: 16..56 (stored as 32..56)
3447
 *       C: 24..40 (stored as 32..40, trims B to 40..56)
3448
 *       D: 0..40  (stored as 32..40, fully covers C)
3449
 *       E: 40..56 (fully covered by B, must not trim D)
3450
 *       F: 56..64 (last)
3451
 *
3452
 *     Expected: A*32 D*8 B*16 F*8
3453
 */
3454
static int DefragBsdFollowingStartsBeforeNewIpv4Test(void)
3455
{
3456
    DefragInit();
3457
    default_policy = DEFRAG_POLICY_BSD;
3458
    Packet *packets[6];
3459
3460
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 0, 1, 'A', 32);
3461
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 16 >> 3, 1, 'B', 40);
3462
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 24 >> 3, 1, 'C', 16);
3463
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 0, 1, 'D', 40);
3464
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 40 >> 3, 1, 'E', 16);
3465
    packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, 56, 56 >> 3, 0, 'F', 8);
3466
3467
    for (int i = 0; i < 5; i++) {
3468
        Packet *rp = Defrag(&test_tv, &test_dtv, packets[i]);
3469
        FAIL_IF_NOT_NULL(rp);
3470
    }
3471
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV4_FRAG_OVERLAP));
3472
3473
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[5]);
3474
    FAIL_IF_NULL(rp);
3475
3476
    // clang-format off
3477
    const uint8_t expected[] = {
3478
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3479
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3480
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3481
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3482
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3483
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3484
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3485
        'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
3486
    };
3487
    // clang-format on
3488
3489
    FAIL_IF(GET_PKT_LEN(rp) != 20 + sizeof(expected));
3490
    if (memcmp(expected, GET_PKT_DATA(rp) + 20, sizeof(expected)) != 0) {
3491
        printf("Expected:\n");
3492
        PrintRawDataFp(stdout, expected, sizeof(expected));
3493
        printf("Got:\n");
3494
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 20, GET_PKT_LEN(rp) - 20);
3495
        FAIL;
3496
    }
3497
3498
    /* Make sure all frags were returned back to the pool. */
3499
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3500
3501
    for (int i = 0; i < 6; i++) {
3502
        PacketFree(packets[i]);
3503
    }
3504
    PacketFree(rp);
3505
    DefragDestroy();
3506
    PASS;
3507
}
3508
3509
/** IPv6 variant of DefragBsdFollowingStartsBeforeNewIpv4Test. */
3510
static int DefragBsdFollowingStartsBeforeNewIpv6Test(void)
3511
{
3512
    DefragInit();
3513
    default_policy = DEFRAG_POLICY_BSD;
3514
    Packet *packets[6];
3515
3516
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 0, 1, 'A', 32);
3517
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 16 >> 3, 1, 'B', 40);
3518
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 24 >> 3, 1, 'C', 16);
3519
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 0, 1, 'D', 40);
3520
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 40 >> 3, 1, 'E', 16);
3521
    packets[5] = BuildIpv6TestPacket(IPPROTO_ICMP, 56, 56 >> 3, 0, 'F', 8);
3522
3523
    for (int i = 0; i < 5; i++) {
3524
        Packet *rp = Defrag(&test_tv, &test_dtv, packets[i]);
3525
        FAIL_IF_NOT_NULL(rp);
3526
    }
3527
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(packets[4], IPV6_FRAG_OVERLAP));
3528
3529
    Packet *rp = Defrag(&test_tv, &test_dtv, packets[5]);
3530
    FAIL_IF_NULL(rp);
3531
3532
    // clang-format off
3533
    const uint8_t expected[] = {
3534
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3535
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3536
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3537
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3538
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3539
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3540
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3541
        'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F',
3542
    };
3543
    // clang-format on
3544
3545
    FAIL_IF(GET_PKT_LEN(rp) != 40 + sizeof(expected));
3546
    if (memcmp(expected, GET_PKT_DATA(rp) + 40, sizeof(expected)) != 0) {
3547
        printf("Expected:\n");
3548
        PrintRawDataFp(stdout, expected, sizeof(expected));
3549
        printf("Got:\n");
3550
        PrintRawDataFp(stdout, GET_PKT_DATA(rp) + 40, GET_PKT_LEN(rp) - 40);
3551
        FAIL;
3552
    }
3553
3554
    /* Make sure all frags were returned back to the pool. */
3555
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
3556
3557
    for (int i = 0; i < 6; i++) {
3558
        PacketFree(packets[i]);
3559
    }
3560
    PacketFree(rp);
3561
    DefragDestroy();
3562
    PASS;
3563
}
3564
3565
/**
3566
 * \test A later BSD overlap must not lower the left trim already set on the
3567
 *     next fragment.
3568
 *
3569
 * 'B' (16..48) starts before 'A' (24..56) and trims it to 48..56. 'C' (0..40)
3570
 * then starts before 'B' and must not lower the trim of 'A' back to 40, or
3571
 * 'A' overwrites the 40..48 bytes preferred from 'B'.
3572
 *
3573
 * |0       |8       |16      |24      |32      |40      |48      |56      |
3574
 * |========|========|========|========|========|========|========|========|
3575
 * |        |        |        |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|        |
3576
 * |        |        |BBBBBBBB|BBBBBBBB|BBBBBBBB|BBBBBBBB|        |        |
3577
 * |CCCCCCCC|CCCCCCCC|CCCCCCCC|CCCCCCCC|CCCCCCCC|        |        |        |
3578
 * |        |        |        |        |        |        |        |DDDDDDDD|
3579
 *
3580
 * |CCCCCCCC|CCCCCCCC|CCCCCCCC|CCCCCCCC|CCCCCCCC|BBBBBBBB|AAAAAAAA|DDDDDDDD|
3581
 */
3582
static int DefragBsdNextLtrimNotLoweredIpv4Test(void)
3583
{
3584
    DefragInit();
3585
    default_policy = DEFRAG_POLICY_BSD;
3586
    Packet *packets[4];
3587
3588
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 53, 24 >> 3, 1, 'A', 32);
3589
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 53, 16 >> 3, 1, 'B', 32);
3590
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 53, 0, 1, 'C', 40);
3591
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 53, 56 >> 3, 0, 'D', 8);
3592
3593
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3594
    FAIL_IF_NOT_NULL(r);
3595
3596
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3597
    FAIL_IF_NOT_NULL(r);
3598
3599
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3600
    FAIL_IF_NOT_NULL(r);
3601
3602
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3603
    FAIL_IF_NULL(r);
3604
3605
    // clang-format off
3606
    const uint8_t expected[] = {
3607
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3608
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3609
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3610
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3611
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3612
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3613
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3614
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3615
    };
3616
    // clang-format on
3617
3618
    FAIL_IF(GET_PKT_LEN(r) != 20 + sizeof(expected));
3619
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
3620
        printf("Expected:\n");
3621
        PrintRawDataFp(stdout, expected, sizeof(expected));
3622
        printf("Got:\n");
3623
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3624
        FAIL;
3625
    }
3626
3627
    for (int i = 0; i < 4; i++) {
3628
        PacketFree(packets[i]);
3629
    }
3630
    PacketFree(r);
3631
    DefragDestroy();
3632
    PASS;
3633
}
3634
3635
/** IPv6 variant of DefragBsdNextLtrimNotLoweredIpv4Test. */
3636
static int DefragBsdNextLtrimNotLoweredIpv6Test(void)
3637
{
3638
    DefragInit();
3639
    default_policy = DEFRAG_POLICY_BSD;
3640
    Packet *packets[4];
3641
3642
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 53, 24 >> 3, 1, 'A', 32);
3643
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 53, 16 >> 3, 1, 'B', 32);
3644
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 53, 0, 1, 'C', 40);
3645
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 53, 56 >> 3, 0, 'D', 8);
3646
3647
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3648
    FAIL_IF_NOT_NULL(r);
3649
3650
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3651
    FAIL_IF_NOT_NULL(r);
3652
3653
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3654
    FAIL_IF_NOT_NULL(r);
3655
3656
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3657
    FAIL_IF_NULL(r);
3658
3659
    // clang-format off
3660
    const uint8_t expected[] = {
3661
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3662
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3663
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3664
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3665
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
3666
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
3667
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3668
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3669
    };
3670
    // clang-format on
3671
3672
    FAIL_IF(GET_PKT_LEN(r) != 40 + sizeof(expected));
3673
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3674
        printf("Expected:\n");
3675
        PrintRawDataFp(stdout, expected, sizeof(expected));
3676
        printf("Got:\n");
3677
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3678
        FAIL;
3679
    }
3680
3681
    for (int i = 0; i < 4; i++) {
3682
        PacketFree(packets[i]);
3683
    }
3684
    PacketFree(r);
3685
    DefragDestroy();
3686
    PASS;
3687
}
3688
3689
/**
3690
 * \test A BSD-preferred fragment that starts within an earlier fragment trims
3691
 *     all of the following fragments it overlaps.
3692
 *
3693
 * 'D' (8..48) starts inside 'A' (0..16), so 'A' is preferred for 8..16. 'D'
3694
 * starts before both 'B' (16..32) and 'C' (32..48), so it is preferred over
3695
 * both of them, not just the immediate right-hand neighbour 'B'.
3696
 *
3697
 * |0       |8       |16      |24      |32      |40      |48      |
3698
 * |========|========|========|========|========|========|========|
3699
 * |AAAAAAAA|AAAAAAAA|        |        |        |        |        |
3700
 * |        |        |BBBBBBBB|BBBBBBBB|        |        |        |
3701
 * |        |        |        |        |CCCCCCCC|CCCCCCCC|        |
3702
 * |        |DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|        |
3703
 * |        |        |        |        |        |        |EEEEEEEE|
3704
 *
3705
 * |AAAAAAAA|AAAAAAAA|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|EEEEEEEE|
3706
 */
3707
static int DefragBsdTrimAllOverlappedStartsInsidePrevIpv4Test(void)
3708
{
3709
    DefragInit();
3710
    default_policy = DEFRAG_POLICY_BSD;
3711
    Packet *packets[5];
3712
3713
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 50, 0, 1, 'A', 16);
3714
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 50, 16 >> 3, 1, 'B', 16);
3715
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 50, 32 >> 3, 1, 'C', 16);
3716
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 50, 8 >> 3, 1, 'D', 40);
3717
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, 50, 48 >> 3, 0, 'E', 8);
3718
3719
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3720
    FAIL_IF_NOT_NULL(r);
3721
3722
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3723
    FAIL_IF_NOT_NULL(r);
3724
3725
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3726
    FAIL_IF_NOT_NULL(r);
3727
3728
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3729
    FAIL_IF_NOT_NULL(r);
3730
3731
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3732
    FAIL_IF_NULL(r);
3733
3734
    // clang-format off
3735
    const uint8_t expected[] = {
3736
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3737
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3738
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3739
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3740
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3741
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3742
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3743
    };
3744
    // clang-format on
3745
3746
    FAIL_IF(GET_PKT_LEN(r) != 20 + sizeof(expected));
3747
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
3748
        printf("Expected:\n");
3749
        PrintRawDataFp(stdout, expected, sizeof(expected));
3750
        printf("Got:\n");
3751
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3752
        FAIL;
3753
    }
3754
3755
    for (int i = 0; i < 5; i++) {
3756
        PacketFree(packets[i]);
3757
    }
3758
    PacketFree(r);
3759
    DefragDestroy();
3760
    PASS;
3761
}
3762
3763
/** IPv6 variant of DefragBsdTrimAllOverlappedStartsInsidePrevIpv4Test. */
3764
static int DefragBsdTrimAllOverlappedStartsInsidePrevIpv6Test(void)
3765
{
3766
    DefragInit();
3767
    default_policy = DEFRAG_POLICY_BSD;
3768
    Packet *packets[5];
3769
3770
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 50, 0, 1, 'A', 16);
3771
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 50, 16 >> 3, 1, 'B', 16);
3772
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 50, 32 >> 3, 1, 'C', 16);
3773
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 50, 8 >> 3, 1, 'D', 40);
3774
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMP, 50, 48 >> 3, 0, 'E', 8);
3775
3776
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3777
    FAIL_IF_NOT_NULL(r);
3778
3779
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3780
    FAIL_IF_NOT_NULL(r);
3781
3782
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3783
    FAIL_IF_NOT_NULL(r);
3784
3785
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3786
    FAIL_IF_NOT_NULL(r);
3787
3788
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3789
    FAIL_IF_NULL(r);
3790
3791
    // clang-format off
3792
    const uint8_t expected[] = {
3793
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3794
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
3795
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3796
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3797
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3798
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3799
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3800
    };
3801
    // clang-format on
3802
3803
    FAIL_IF(GET_PKT_LEN(r) != 40 + sizeof(expected));
3804
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3805
        printf("Expected:\n");
3806
        PrintRawDataFp(stdout, expected, sizeof(expected));
3807
        printf("Got:\n");
3808
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3809
        FAIL;
3810
    }
3811
3812
    for (int i = 0; i < 5; i++) {
3813
        PacketFree(packets[i]);
3814
    }
3815
    PacketFree(r);
3816
    DefragDestroy();
3817
    PASS;
3818
}
3819
3820
/**
3821
 * \test A BSD-preferred fragment that starts before the first stored fragment
3822
 *     trims all of the following fragments it overlaps.
3823
 *
3824
 * 'D' (0..56) starts before 'A' (8..24), 'B' (24..40) and 'C' (40..56), so it
3825
 * is preferred over all of them, not just 'A' and the immediate right-hand
3826
 * neighbour 'B'.
3827
 *
3828
 * |0       |8       |16      |24      |32      |40      |48      |56      |
3829
 * |========|========|========|========|========|========|========|========|
3830
 * |        |AAAAAAAA|AAAAAAAA|        |        |        |        |        |
3831
 * |        |        |        |BBBBBBBB|BBBBBBBB|        |        |        |
3832
 * |        |        |        |        |        |CCCCCCCC|CCCCCCCC|        |
3833
 * |DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|        |
3834
 * |        |        |        |        |        |        |        |EEEEEEEE|
3835
 *
3836
 * |DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|DDDDDDDD|EEEEEEEE|
3837
 */
3838
static int DefragBsdTrimAllOverlappedStartsBeforeIpv4Test(void)
3839
{
3840
    DefragInit();
3841
    default_policy = DEFRAG_POLICY_BSD;
3842
    Packet *packets[5];
3843
3844
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 51, 8 >> 3, 1, 'A', 16);
3845
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 51, 24 >> 3, 1, 'B', 16);
3846
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 51, 40 >> 3, 1, 'C', 16);
3847
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 51, 0, 1, 'D', 56);
3848
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, 51, 56 >> 3, 0, 'E', 8);
3849
3850
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3851
    FAIL_IF_NOT_NULL(r);
3852
3853
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3854
    FAIL_IF_NOT_NULL(r);
3855
3856
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3857
    FAIL_IF_NOT_NULL(r);
3858
3859
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3860
    FAIL_IF_NOT_NULL(r);
3861
3862
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3863
    FAIL_IF_NULL(r);
3864
3865
    // clang-format off
3866
    const uint8_t expected[] = {
3867
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3868
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3869
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3870
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3871
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3872
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3873
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3874
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3875
    };
3876
    // clang-format on
3877
3878
    FAIL_IF(GET_PKT_LEN(r) != 20 + sizeof(expected));
3879
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
3880
        printf("Expected:\n");
3881
        PrintRawDataFp(stdout, expected, sizeof(expected));
3882
        printf("Got:\n");
3883
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3884
        FAIL;
3885
    }
3886
3887
    for (int i = 0; i < 5; i++) {
3888
        PacketFree(packets[i]);
3889
    }
3890
    PacketFree(r);
3891
    DefragDestroy();
3892
    PASS;
3893
}
3894
3895
/** IPv6 variant of DefragBsdTrimAllOverlappedStartsBeforeIpv4Test. */
3896
static int DefragBsdTrimAllOverlappedStartsBeforeIpv6Test(void)
3897
{
3898
    DefragInit();
3899
    default_policy = DEFRAG_POLICY_BSD;
3900
    Packet *packets[5];
3901
3902
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 51, 8 >> 3, 1, 'A', 16);
3903
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 51, 24 >> 3, 1, 'B', 16);
3904
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 51, 40 >> 3, 1, 'C', 16);
3905
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 51, 0, 1, 'D', 56);
3906
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMP, 51, 56 >> 3, 0, 'E', 8);
3907
3908
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3909
    FAIL_IF_NOT_NULL(r);
3910
3911
    r = Defrag(&test_tv, &test_dtv, packets[1]);
3912
    FAIL_IF_NOT_NULL(r);
3913
3914
    r = Defrag(&test_tv, &test_dtv, packets[2]);
3915
    FAIL_IF_NOT_NULL(r);
3916
3917
    r = Defrag(&test_tv, &test_dtv, packets[3]);
3918
    FAIL_IF_NOT_NULL(r);
3919
3920
    r = Defrag(&test_tv, &test_dtv, packets[4]);
3921
    FAIL_IF_NULL(r);
3922
3923
    // clang-format off
3924
    const uint8_t expected[] = {
3925
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3926
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3927
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3928
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3929
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3930
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3931
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
3932
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3933
    };
3934
    // clang-format on
3935
3936
    FAIL_IF(GET_PKT_LEN(r) != 40 + sizeof(expected));
3937
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3938
        printf("Expected:\n");
3939
        PrintRawDataFp(stdout, expected, sizeof(expected));
3940
        printf("Got:\n");
3941
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3942
        FAIL;
3943
    }
3944
3945
    for (int i = 0; i < 5; i++) {
3946
        PacketFree(packets[i]);
3947
    }
3948
    PacketFree(r);
3949
3950
    DefragDestroy();
3951
3952
    PASS;
3953
}
3954
3955
#endif /* UNITTESTS */
3956
3957
void DefragRegisterTests(void)
3958
0
{
3959
#ifdef UNITTESTS
3960
    UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
3961
    UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
3962
    UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
3963
    UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
3964
            DefragSturgesNovakLinuxIpv4Test);
3965
    UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
3966
                   DefragSturgesNovakWindowsIpv4Test);
3967
    UtRegisterTest("DefragSturgesNovakSolarisTest",
3968
                   DefragSturgesNovakSolarisTest);
3969
    UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
3970
    UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
3971
3972
    UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
3973
    UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
3974
3975
    UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
3976
    UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
3977
    UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
3978
    UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
3979
    UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
3980
    UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
3981
    UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
3982
    UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
3983
3984
    UtRegisterTest("DefragVlanTest", DefragVlanTest);
3985
    UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
3986
    UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
3987
    UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
3988
    UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
3989
    UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
3990
    UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
3991
    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
3992
3993
    UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
3994
3995
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
3996
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
3997
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
3998
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
3999
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
4000
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
4001
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2",
4002
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
4003
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
4004
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
4005
    UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
4006
    UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
4007
    UtRegisterTest("DefragBsdOverlapAfterCoveredStartsInsidePrevIpv4Test",
4008
            DefragBsdOverlapAfterCoveredStartsInsidePrevIpv4Test);
4009
    UtRegisterTest("DefragBsdOverlapAfterCoveredStartsInsidePrevIpv6Test",
4010
            DefragBsdOverlapAfterCoveredStartsInsidePrevIpv6Test);
4011
    UtRegisterTest("DefragBsdOverlapAfterCoveredStartsBeforeIpv4Test",
4012
            DefragBsdOverlapAfterCoveredStartsBeforeIpv4Test);
4013
    UtRegisterTest("DefragBsdOverlapAfterCoveredStartsBeforeIpv6Test",
4014
            DefragBsdOverlapAfterCoveredStartsBeforeIpv6Test);
4015
    UtRegisterTest(
4016
            "DefragBsdFollowingStartsBeforeNewIpv4Test", DefragBsdFollowingStartsBeforeNewIpv4Test);
4017
    UtRegisterTest(
4018
            "DefragBsdFollowingStartsBeforeNewIpv6Test", DefragBsdFollowingStartsBeforeNewIpv6Test);
4019
    UtRegisterTest("DefragBsdNextLtrimNotLoweredIpv4Test", DefragBsdNextLtrimNotLoweredIpv4Test);
4020
    UtRegisterTest("DefragBsdNextLtrimNotLoweredIpv6Test", DefragBsdNextLtrimNotLoweredIpv6Test);
4021
    UtRegisterTest("DefragBsdTrimAllOverlappedStartsInsidePrevIpv4Test",
4022
            DefragBsdTrimAllOverlappedStartsInsidePrevIpv4Test);
4023
    UtRegisterTest("DefragBsdTrimAllOverlappedStartsInsidePrevIpv6Test",
4024
            DefragBsdTrimAllOverlappedStartsInsidePrevIpv6Test);
4025
    UtRegisterTest("DefragBsdTrimAllOverlappedStartsBeforeIpv4Test",
4026
            DefragBsdTrimAllOverlappedStartsBeforeIpv4Test);
4027
    UtRegisterTest("DefragBsdTrimAllOverlappedStartsBeforeIpv6Test",
4028
            DefragBsdTrimAllOverlappedStartsBeforeIpv6Test);
4029
#endif /* UNITTESTS */
4030
0
}