Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/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-queue.h"
57
#include "defrag-config.h"
58
59
#include "tmqh-packetpool.h"
60
#include "decode.h"
61
62
#ifdef UNITTESTS
63
#include "util-unittest.h"
64
#endif
65
66
104
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
67
33
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
68
69
/**
70
 * Default timeout (in seconds) before a defragmentation tracker will
71
 * be released.
72
 */
73
33
#define TIMEOUT_DEFAULT 60
74
75
/**
76
 * Maximum allowed timeout, 24 hours.
77
 */
78
0
#define TIMEOUT_MAX (60 * 60 * 24)
79
80
/**
81
 * Minimum allowed timeout, 1 second.
82
 */
83
0
#define TIMEOUT_MIN 1
84
85
/** Fragment reassembly policies. */
86
enum defrag_policies {
87
    DEFRAG_POLICY_FIRST = 1,
88
    DEFRAG_POLICY_LAST,
89
    DEFRAG_POLICY_BSD,
90
    DEFRAG_POLICY_BSD_RIGHT,
91
    DEFRAG_POLICY_LINUX,
92
    DEFRAG_POLICY_WINDOWS,
93
    DEFRAG_POLICY_SOLARIS,
94
95
    DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
96
};
97
98
static uint8_t default_policy = DEFRAG_POLICY_BSD;
99
100
/** The global DefragContext so all threads operate from the same
101
 * context. */
102
static DefragContext *defrag_context;
103
104
4.35M
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_INSERT_COLOR
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_REMOVE_COLOR
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_INSERT
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_REMOVE
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
Unexecuted instantiation: IP_FRAGMENTS_RB_FIND
IP_FRAGMENTS_RB_NFIND
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
IP_FRAGMENTS_RB_MINMAX
Line
Count
Source
104
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
105
4.35M
106
4.35M
/**
107
4.35M
 * \brief Reset a frag for reuse in a pool.
108
4.35M
 */
109
4.35M
static void
110
4.35M
DefragFragReset(Frag *frag)
111
4.35M
{
112
154k
    if (frag->pkt != NULL)
113
154k
        SCFree(frag->pkt);
114
154k
    memset(frag, 0, sizeof(*frag));
115
154k
}
116
117
/**
118
 * \brief Allocate a new frag for use in a pool.
119
 */
120
static int
121
DefragFragInit(void *data, void *initdata)
122
2.33M
{
123
2.33M
    Frag *frag = data;
124
125
2.33M
    memset(frag, 0, sizeof(*frag));
126
2.33M
    return 1;
127
2.33M
}
128
129
/**
130
 * \brief Free all frags associated with a tracker.
131
 */
132
void
133
DefragTrackerFreeFrags(DefragTracker *tracker)
134
42.7k
{
135
42.7k
    Frag *frag, *tmp;
136
137
    /* Lock the frag pool as we'll be return items to it. */
138
42.7k
    SCMutexLock(&defrag_context->frag_pool_lock);
139
140
145k
    RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
141
145k
        RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
142
145k
        DefragFragReset(frag);
143
145k
        PoolReturn(defrag_context->frag_pool, frag);
144
145k
    }
145
146
42.7k
    SCMutexUnlock(&defrag_context->frag_pool_lock);
147
42.7k
}
148
149
/**
150
 * \brief Create a new DefragContext.
151
 *
152
 * \retval On success a return an initialized DefragContext, otherwise
153
 *     NULL will be returned.
154
 */
155
static DefragContext *
156
DefragContextNew(void)
157
33
{
158
33
    DefragContext *dc;
159
160
33
    dc = SCCalloc(1, sizeof(*dc));
161
33
    if (unlikely(dc == NULL))
162
0
        return NULL;
163
164
    /* Initialize the pool of trackers. */
165
33
    intmax_t tracker_pool_size;
166
33
    if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
167
33
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
168
33
    }
169
170
    /* Initialize the pool of frags. */
171
33
    intmax_t frag_pool_size;
172
33
    if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
173
33
        frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
174
33
    }
175
33
    intmax_t frag_pool_prealloc = frag_pool_size / 2;
176
33
    dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
177
33
        sizeof(Frag),
178
33
        NULL, DefragFragInit, dc, NULL, NULL);
179
33
    if (dc->frag_pool == NULL) {
180
0
        FatalError("Defrag: Failed to initialize fragment pool.");
181
0
    }
182
33
    if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
183
0
        FatalError("Defrag: Failed to initialize frag pool mutex.");
184
0
    }
185
186
    /* Set the default timeout. */
187
33
    intmax_t timeout;
188
33
    if (!ConfGetInt("defrag.timeout", &timeout)) {
189
33
        dc->timeout = TIMEOUT_DEFAULT;
190
33
    }
191
0
    else {
192
0
        if (timeout < TIMEOUT_MIN) {
193
0
            FatalError("defrag: Timeout less than minimum allowed value.");
194
0
        }
195
0
        else if (timeout > TIMEOUT_MAX) {
196
0
            FatalError("defrag: Timeout greater than maximum allowed value.");
197
0
        }
198
0
        dc->timeout = timeout;
199
0
    }
200
201
33
    SCLogDebug("Defrag Initialized:");
202
33
    SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
203
33
    SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
204
33
    SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
205
33
    SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
206
33
    SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
207
208
33
    return dc;
209
33
}
210
211
static void
212
DefragContextDestroy(DefragContext *dc)
213
0
{
214
0
    if (dc == NULL)
215
0
        return;
216
217
0
    PoolFree(dc->frag_pool);
218
0
    SCFree(dc);
219
0
}
220
221
/**
222
 * Attempt to re-assemble a packet.
223
 *
224
 * \param tracker The defragmentation tracker to reassemble from.
225
 */
226
static Packet *
227
Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
228
148k
{
229
148k
    Packet *rp = NULL;
230
231
    /* Should not be here unless we have seen the last fragment. */
232
148k
    if (!tracker->seen_last) {
233
0
        return NULL;
234
0
    }
235
236
    /* Check that we have the first fragment and its of a valid size. */
237
148k
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
238
148k
    if (first == NULL) {
239
0
        goto done;
240
148k
    } else if (first->offset != 0) {
241
        /* Still waiting for the first fragment. */
242
113k
        goto done;
243
113k
    } else if (first->len < sizeof(IPV4Hdr)) {
244
        /* First fragment isn't enough for an IPv6 header. */
245
0
        goto error_remove_tracker;
246
0
    }
247
248
    /* Check that we have all the data. Relies on the fact that
249
     * fragments are inserted in frag_offset order. */
250
34.9k
    Frag *frag = NULL;
251
34.9k
    size_t len = 0;
252
20.5M
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
253
20.5M
        if (frag->offset > len) {
254
            /* This fragment starts after the end of the previous
255
             * fragment.  We have a hole. */
256
26.1k
            goto done;
257
26.1k
        }
258
20.5M
        else {
259
            /* Update the packet length to the largest known data offset. */
260
20.5M
            len = MAX(len, frag->offset + frag->data_len);
261
20.5M
        }
262
20.5M
    }
263
264
    /* Allocate a Packet for the reassembled packet.  On failure we
265
     * SCFree all the resources held by this tracker. */
266
8.77k
    rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
267
8.77k
    if (rp == NULL) {
268
0
        goto error_remove_tracker;
269
0
    }
270
8.77k
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
271
8.77k
    rp->flags |= PKT_REBUILT_FRAGMENT;
272
8.77k
    rp->datalink = tracker->datalink;
273
274
8.77k
    int fragmentable_offset = 0;
275
8.77k
    uint16_t fragmentable_len = 0;
276
8.77k
    uint16_t hlen = 0;
277
8.77k
    int ip_hdr_offset = 0;
278
279
    /* Assume more frags. */
280
8.77k
    uint16_t prev_offset = 0;
281
8.77k
    bool more_frags = 1;
282
283
25.4k
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
284
25.4k
        SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
285
25.4k
                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
25.4k
        if (!more_frags && frag->offset > prev_offset) {
290
252
            break;
291
252
        }
292
293
25.2k
        if (frag->skip)
294
0
            continue;
295
25.2k
        if (frag->ltrim >= frag->data_len)
296
522
            continue;
297
24.6k
        if (frag->offset == 0) {
298
299
8.77k
            if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
300
0
                goto error_remove_tracker;
301
302
8.77k
            hlen = frag->hlen;
303
8.77k
            ip_hdr_offset = frag->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
8.77k
            fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
309
8.77k
            fragmentable_len = frag->data_len;
310
8.77k
        }
311
15.9k
        else {
312
15.9k
            int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
313
15.9k
            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
15.9k
            if (PacketCopyDataOffset(rp,
319
15.9k
                    fragmentable_offset + frag->offset + frag->ltrim,
320
15.9k
                    frag->pkt + frag->data_offset + frag->ltrim,
321
15.9k
                    frag->data_len - frag->ltrim) == -1) {
322
0
                goto error_remove_tracker;
323
0
            }
324
15.9k
            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
15.9k
            if (frag->offset + frag->data_len > fragmentable_len)
330
13.1k
                fragmentable_len = frag->offset + frag->data_len;
331
15.9k
        }
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
24.6k
        more_frags = frag->more_frags;
342
24.6k
        prev_offset = frag->offset;
343
24.6k
    }
344
345
8.77k
    SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
346
8.77k
            fragmentable_len);
347
348
8.77k
    rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
349
8.77k
    uint16_t old = rp->ip4h->ip_len + rp->ip4h->ip_off;
350
8.77k
    DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len);
351
8.77k
    rp->ip4h->ip_len = htons(fragmentable_len + hlen);
352
8.77k
    rp->ip4h->ip_off = 0;
353
8.77k
    rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
354
8.77k
        old, rp->ip4h->ip_len + rp->ip4h->ip_off);
355
8.77k
    SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
356
357
8.77k
    tracker->remove = 1;
358
8.77k
    DefragTrackerFreeFrags(tracker);
359
148k
done:
360
148k
    return rp;
361
362
0
error_remove_tracker:
363
0
    tracker->remove = 1;
364
0
    DefragTrackerFreeFrags(tracker);
365
0
    if (rp != NULL)
366
0
        PacketFreeOrRelease(rp);
367
0
    return NULL;
368
8.77k
}
369
370
/**
371
 * Attempt to re-assemble a packet.
372
 *
373
 * \param tracker The defragmentation tracker to reassemble from.
374
 */
375
static Packet *
376
Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
377
22.3k
{
378
22.3k
    Packet *rp = NULL;
379
380
    /* Should not be here unless we have seen the last fragment. */
381
22.3k
    if (!tracker->seen_last)
382
0
        return NULL;
383
384
    /* Check that we have the first fragment and its of a valid size. */
385
22.3k
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
386
22.3k
    if (first == NULL) {
387
0
        goto done;
388
22.3k
    } else if (first->offset != 0) {
389
        /* Still waiting for the first fragment. */
390
3.37k
        goto done;
391
18.9k
    } else if (first->len < sizeof(IPV6Hdr)) {
392
        /* First fragment isn't enough for an IPv6 header. */
393
0
        goto error_remove_tracker;
394
0
    }
395
396
    /* Check that we have all the data. Relies on the fact that
397
     * fragments are inserted if frag_offset order. */
398
18.9k
    size_t len = 0;
399
18.9k
    Frag *frag = NULL;
400
30.1M
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
401
30.1M
        if (frag->skip) {
402
0
            continue;
403
0
        }
404
405
30.1M
        if (frag == first) {
406
0
            if (frag->offset != 0) {
407
0
                goto done;
408
0
            }
409
0
            len = frag->data_len;
410
0
        }
411
30.1M
        else {
412
30.1M
            if (frag->offset > len) {
413
                /* This fragment starts after the end of the previous
414
                 * fragment.  We have a hole. */
415
15.3k
                goto done;
416
15.3k
            }
417
30.1M
            else {
418
30.1M
                len = MAX(len, frag->offset + frag->data_len);
419
30.1M
            }
420
30.1M
        }
421
30.1M
    }
422
423
    /* Allocate a Packet for the reassembled packet.  On failure we
424
     * SCFree all the resources held by this tracker. */
425
3.60k
    rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
426
3.60k
            IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
427
3.60k
    if (rp == NULL) {
428
0
        goto error_remove_tracker;
429
0
    }
430
3.60k
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
431
3.60k
    rp->flags |= PKT_REBUILT_FRAGMENT;
432
3.60k
    rp->datalink = tracker->datalink;
433
434
3.60k
    uint16_t unfragmentable_len = 0;
435
3.60k
    int fragmentable_offset = 0;
436
3.60k
    uint16_t fragmentable_len = 0;
437
3.60k
    int ip_hdr_offset = 0;
438
3.60k
    uint8_t next_hdr = 0;
439
440
    /* Assume more frags. */
441
3.60k
    uint16_t prev_offset = 0;
442
3.60k
    bool more_frags = 1;
443
444
12.1k
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
445
12.1k
        if (!more_frags && frag->offset > prev_offset) {
446
555
            break;
447
555
        }
448
11.5k
        if (frag->skip)
449
0
            continue;
450
11.5k
        if (frag->data_len - frag->ltrim <= 0)
451
1.90k
            continue;
452
9.65k
        if (frag->offset == 0) {
453
3.60k
            IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
454
3.60k
                frag->frag_hdr_offset);
455
3.60k
            next_hdr = frag_hdr->ip6fh_nxt;
456
457
            /* This is the first packet, we use this packets link and
458
             * IPv6 headers. We also copy in its data, but remove the
459
             * fragmentation header. */
460
3.60k
            if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
461
0
                goto error_remove_tracker;
462
3.60k
            if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
463
3.60k
                frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
464
3.60k
                frag->data_len) == -1)
465
0
                goto error_remove_tracker;
466
3.60k
            ip_hdr_offset = frag->ip_hdr_offset;
467
468
            /* This is the start of the fragmentable portion of the
469
             * first packet.  All fragment offsets are relative to
470
             * this. */
471
3.60k
            fragmentable_offset = frag->frag_hdr_offset;
472
3.60k
            fragmentable_len = frag->data_len;
473
474
            /* unfragmentable part is the part between the ipv6 header
475
             * and the frag header. */
476
3.60k
            DEBUG_VALIDATE_BUG_ON(fragmentable_offset < ip_hdr_offset + IPV6_HEADER_LEN);
477
3.60k
            DEBUG_VALIDATE_BUG_ON(
478
3.60k
                    fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN > UINT16_MAX);
479
3.60k
            unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN);
480
3.60k
            if (unfragmentable_len >= fragmentable_offset)
481
0
                goto error_remove_tracker;
482
3.60k
        }
483
6.05k
        else {
484
6.05k
            if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
485
6.05k
                frag->pkt + frag->data_offset + frag->ltrim,
486
6.05k
                frag->data_len - frag->ltrim) == -1)
487
0
                goto error_remove_tracker;
488
6.05k
            if (frag->offset + frag->data_len > fragmentable_len)
489
5.89k
                fragmentable_len = frag->offset + frag->data_len;
490
6.05k
        }
491
492
        /* Even if this fragment is flagged as having no more
493
         * fragments, still continue. The next fragment may have the
494
         * same offset with data that is preferred.
495
         *
496
         * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
497
         *
498
         * This is due to not all fragments being completely trimmed,
499
         * but relying on the copy ordering. */
500
9.65k
        more_frags = frag->more_frags;
501
9.65k
        prev_offset = frag->offset;
502
9.65k
    }
503
504
3.60k
    rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
505
3.60k
    DEBUG_VALIDATE_BUG_ON(unfragmentable_len > UINT16_MAX - fragmentable_len);
506
3.60k
    rp->ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
507
    /* if we have no unfragmentable part, so no ext hdrs before the frag
508
     * header, we need to update the ipv6 headers next header field. This
509
     * points to the frag header, and we will make it point to the layer
510
     * directly after the frag header. */
511
3.60k
    if (unfragmentable_len == 0)
512
2.21k
        rp->ip6h->s_ip6_nxt = next_hdr;
513
3.60k
    SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
514
3.60k
            unfragmentable_len + fragmentable_len);
515
516
3.60k
    tracker->remove = 1;
517
3.60k
    DefragTrackerFreeFrags(tracker);
518
22.3k
done:
519
22.3k
    return rp;
520
521
0
error_remove_tracker:
522
0
    tracker->remove = 1;
523
0
    DefragTrackerFreeFrags(tracker);
524
0
    if (rp != NULL)
525
0
        PacketFreeOrRelease(rp);
526
0
    return NULL;
527
3.60k
}
528
529
/**
530
 * The RB_TREE compare function for fragments.
531
 *
532
 * When it comes to adding fragments, we want subsequent ones with the
533
 * same offset to be treated as greater than, so we don't have an
534
 * equal return value here.
535
 */
536
3.67M
int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
537
3.67M
    if (a->offset < b->offset) {
538
1.11M
        return -1;
539
1.11M
    }
540
2.55M
    return 1;
541
3.67M
}
542
543
/**
544
 * Insert a new IPv4/IPv6 fragment into a tracker.
545
 *
546
 * \todo Allocate packet buffers from a pool.
547
 */
548
static Packet *
549
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
550
308k
{
551
308k
    Packet *r = NULL;
552
308k
    uint16_t ltrim = 0;
553
554
308k
    uint8_t more_frags;
555
308k
    uint16_t frag_offset;
556
557
    /* IPv4 header length - IPv4 only. */
558
308k
    uint8_t hlen = 0;
559
560
    /* This is the offset of the start of the data in the packet that
561
     * falls after the IP header. */
562
308k
    uint16_t data_offset;
563
564
    /* The length of the (fragmented) data.  This is the length of the
565
     * data that falls after the IP header. */
566
308k
    uint16_t data_len;
567
568
    /* Where the fragment ends. */
569
308k
    uint16_t frag_end;
570
571
    /* Offset in the packet to the IPv6 header. */
572
308k
    uint16_t ip_hdr_offset;
573
574
    /* Offset in the packet to the IPv6 frag header. IPv6 only. */
575
308k
    uint16_t frag_hdr_offset = 0;
576
577
    /* Address family */
578
308k
    int af = tracker->af;
579
580
    /* settings for updating a payload when an ip6 fragment with
581
     * unfragmentable exthdrs are encountered. */
582
308k
    uint32_t ip6_nh_set_offset = 0;
583
308k
    uint8_t ip6_nh_set_value = 0;
584
585
#ifdef DEBUG
586
    uint64_t pcap_cnt = p->pcap_cnt;
587
#endif
588
589
308k
    if (tracker->af == AF_INET) {
590
129k
        more_frags = IPV4_GET_MF(p);
591
129k
        frag_offset = (uint16_t)(IPV4_GET_IPOFFSET(p) << 3);
592
129k
        hlen = IPV4_GET_HLEN(p);
593
129k
        data_offset = (uint16_t)((uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p));
594
129k
        data_len = IPV4_GET_IPLEN(p) - hlen;
595
129k
        frag_end = frag_offset + data_len;
596
129k
        ip_hdr_offset = (uint16_t)((uint8_t *)p->ip4h - GET_PKT_DATA(p));
597
598
        /* Ignore fragment if the end of packet extends past the
599
         * maximum size of a packet. */
600
129k
        if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
601
6.61k
            ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
602
6.61k
            return NULL;
603
6.61k
        }
604
129k
    }
605
179k
    else if (tracker->af == AF_INET6) {
606
179k
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
607
179k
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
608
179k
        data_offset = p->ip6eh.fh_data_offset;
609
179k
        data_len = p->ip6eh.fh_data_len;
610
179k
        frag_end = frag_offset + data_len;
611
179k
        ip_hdr_offset = (uint16_t)((uint8_t *)p->ip6h - GET_PKT_DATA(p));
612
179k
        frag_hdr_offset = p->ip6eh.fh_header_offset;
613
614
179k
        SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
615
179k
                "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
616
179k
                more_frags ? "true" : "false", frag_offset, data_offset,
617
179k
                data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
618
619
        /* handle unfragmentable exthdrs */
620
179k
        if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
621
169k
            SCLogDebug("we have exthdrs before fraghdr %u bytes",
622
169k
                    (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
623
624
            /* get the offset of the 'next' field in exthdr before the FH,
625
             * relative to the buffer start */
626
627
            /* store offset and FH 'next' value for updating frag buffer below */
628
169k
            ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset;
629
169k
            ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
630
169k
            SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
631
169k
        }
632
633
        /* Ignore fragment if the end of packet extends past the
634
         * maximum size of a packet. */
635
179k
        if (frag_offset + data_len > IPV6_MAXPACKET) {
636
1.03k
            ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
637
1.03k
            return NULL;
638
1.03k
        }
639
179k
    }
640
0
    else {
641
0
        DEBUG_VALIDATE_BUG_ON(1);
642
0
        return NULL;
643
0
    }
644
645
    /* Update timeout. */
646
300k
    tracker->timeout = SCTIME_FROM_SECS(SCTIME_SECS(p->ts) + tracker->host_timeout);
647
648
300k
    Frag *prev = NULL, *next = NULL;
649
300k
    bool overlap = false;
650
300k
    ltrim = 0;
651
652
300k
    if (!RB_EMPTY(&tracker->fragment_tree)) {
653
263k
        Frag key = {
654
263k
            .offset = frag_offset - 1,
655
263k
        };
656
263k
        next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
657
263k
        if (next == NULL) {
658
144k
            prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
659
144k
            next = IP_FRAGMENTS_RB_NEXT(prev);
660
144k
        } else {
661
119k
            prev = IP_FRAGMENTS_RB_PREV(next);
662
119k
            if (prev == NULL) {
663
64.5k
                prev = next;
664
64.5k
                next = IP_FRAGMENTS_RB_NEXT(prev);
665
64.5k
            }
666
119k
        }
667
833k
        while (prev != NULL) {
668
830k
            if (prev->skip) {
669
0
                goto next;
670
0
            }
671
830k
            if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
672
260k
                overlap = true;
673
260k
            }
674
675
830k
            switch (tracker->policy) {
676
830k
            case DEFRAG_POLICY_BSD:
677
830k
                if (frag_offset < prev->offset + prev->data_len) {
678
260k
                    if (prev->offset <= frag_offset) {
679
                        /* We prefer the data from the previous
680
                         * fragment, so trim off the data in the new
681
                         * fragment that exists in the previous
682
                         * fragment. */
683
258k
                        uint16_t prev_end = prev->offset + prev->data_len;
684
258k
                        if (prev_end > frag_end) {
685
                            /* Just skip. */
686
                            /* TODO: Set overlap flag. */
687
3.45k
                            goto done;
688
3.45k
                        }
689
254k
                        ltrim = prev_end - frag_offset;
690
691
254k
                        if ((next != NULL) && (frag_end > next->offset)) {
692
45.0k
                            next->ltrim = frag_end - next->offset;
693
45.0k
                        }
694
695
254k
                        goto insert;
696
258k
                    }
697
698
                    /* If the end of this fragment overlaps the start
699
                     * of the previous fragment, then trim up the
700
                     * start of previous fragment so this fragment is
701
                     * used.
702
                     *
703
                     * See:
704
                     * DefragBsdSubsequentOverlapsStartOfOriginal.
705
                     */
706
2.74k
                    if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
707
1.12k
                        uint16_t prev_ltrim = frag_end - prev->offset;
708
1.12k
                        if (prev_ltrim > prev->ltrim) {
709
1.12k
                            prev->ltrim = prev_ltrim;
710
1.12k
                        }
711
1.12k
                    }
712
713
2.74k
                    if ((next != NULL) && (frag_end > next->offset)) {
714
1.19k
                        next->ltrim = frag_end - next->offset;
715
1.19k
                    }
716
717
2.74k
                    goto insert;
718
260k
                }
719
569k
                break;
720
569k
            case DEFRAG_POLICY_LINUX:
721
                /* Check if new fragment overlaps the end of previous
722
                 * fragment, if it does, trim the new fragment.
723
                 *
724
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
725
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
726
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
727
                 */
728
0
                if (prev->offset + prev->ltrim < frag_offset + ltrim &&
729
0
                        prev->offset + prev->data_len > frag_offset + ltrim) {
730
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
731
0
                }
732
733
                /* Check if new fragment overlaps the beginning of
734
                 * previous fragment, if it does, tim the previous
735
                 * fragment.
736
                 *
737
                 * Old:          AAAAAAAA AAAAAAAA
738
                 * New: BBBBBBBB BBBBBBBB BBBBBBBB
739
                 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
740
                 */
741
0
                if (frag_offset + ltrim < prev->offset + prev->ltrim &&
742
0
                        frag_end > prev->offset + prev->ltrim) {
743
0
                    prev->ltrim += frag_end - (prev->offset + prev->ltrim);
744
0
                    goto insert;
745
0
                }
746
747
                /* If the new fragment completely overlaps the
748
                 * previous fragment, mark the previous to be
749
                 * skipped. Re-assembly would succeed without doing
750
                 * this, but this will prevent the bytes from being
751
                 * copied just to be overwritten. */
752
0
                if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
753
0
                        frag_end >= prev->offset + prev->data_len) {
754
0
                    prev->skip = 1;
755
0
                    goto insert;
756
0
                }
757
758
0
                break;
759
0
            case DEFRAG_POLICY_WINDOWS:
760
                /* If new fragment fits inside a previous fragment, drop it. */
761
0
                if (frag_offset + ltrim >= prev->offset + ltrim &&
762
0
                        frag_end <= prev->offset + prev->data_len) {
763
0
                    goto done;
764
0
                }
765
766
                /* If new fragment starts before and ends after
767
                 * previous fragment, drop the previous fragment. */
768
0
                if (frag_offset + ltrim < prev->offset + ltrim &&
769
0
                        frag_end > prev->offset + prev->data_len) {
770
0
                    prev->skip = 1;
771
0
                    goto insert;
772
0
                }
773
774
                /* Check if new fragment overlaps the end of previous
775
                 * fragment, if it does, trim the new fragment.
776
                 *
777
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
778
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
779
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
780
                 */
781
0
                if (frag_offset + ltrim > prev->offset + prev->ltrim &&
782
0
                        frag_offset + ltrim < prev->offset + prev->data_len) {
783
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
784
0
                    goto insert;
785
0
                }
786
787
                /* If new fragment starts at same offset as an
788
                 * existing fragment, but ends after it, trim the new
789
                 * fragment. */
790
0
                if (frag_offset + ltrim == prev->offset + ltrim &&
791
0
                        frag_end > prev->offset + prev->data_len) {
792
0
                    ltrim += prev->offset + prev->data_len - frag_offset;
793
0
                    goto insert;
794
0
                }
795
0
                break;
796
0
            case DEFRAG_POLICY_SOLARIS:
797
0
                if (frag_offset < prev->offset + prev->data_len) {
798
0
                    if (frag_offset >= prev->offset) {
799
0
                        ltrim = prev->offset + prev->data_len - frag_offset;
800
0
                    }
801
0
                    if ((frag_offset < prev->offset) &&
802
0
                        (frag_end >= prev->offset + prev->data_len)) {
803
0
                        prev->skip = 1;
804
0
                    }
805
0
                    goto insert;
806
0
                }
807
0
                break;
808
0
            case DEFRAG_POLICY_FIRST:
809
0
                if ((frag_offset >= prev->offset) &&
810
0
                    (frag_end <= prev->offset + prev->data_len)) {
811
0
                    goto done;
812
0
                }
813
0
                if (frag_offset < prev->offset) {
814
0
                    goto insert;
815
0
                }
816
0
                if (frag_offset < prev->offset + prev->data_len) {
817
0
                    ltrim = prev->offset + prev->data_len - frag_offset;
818
0
                    goto insert;
819
0
                }
820
0
                break;
821
0
            case DEFRAG_POLICY_LAST:
822
0
                if (frag_offset <= prev->offset) {
823
0
                    if (frag_end > prev->offset) {
824
0
                        prev->ltrim = frag_end - prev->offset;
825
0
                    }
826
0
                    goto insert;
827
0
                }
828
0
                break;
829
0
            default:
830
0
                break;
831
830k
            }
832
833
569k
        next:
834
569k
            prev = next;
835
569k
            if (next != NULL) {
836
567k
                next = IP_FRAGMENTS_RB_NEXT(next);
837
567k
            }
838
569k
            continue;
839
840
257k
        insert:
841
            /* If existing fragment has been trimmed up completely
842
             * (complete overlap), remove it now instead of holding
843
             * onto it. */
844
257k
            if (prev->skip || prev->ltrim >= prev->data_len) {
845
2.31k
                RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
846
2.31k
                DefragFragReset(prev);
847
2.31k
                SCMutexLock(&defrag_context->frag_pool_lock);
848
2.31k
                PoolReturn(defrag_context->frag_pool, prev);
849
2.31k
                SCMutexUnlock(&defrag_context->frag_pool_lock);
850
2.31k
            }
851
257k
            break;
852
830k
        }
853
263k
    }
854
855
297k
    if (ltrim >= data_len) {
856
        /* Full packet has been trimmed due to the overlap policy. Overlap
857
         * already set. */
858
235k
        goto done;
859
235k
    }
860
861
    /* Allocate fragment and insert. */
862
62.4k
    SCMutexLock(&defrag_context->frag_pool_lock);
863
62.4k
    Frag *new = PoolGet(defrag_context->frag_pool);
864
62.4k
    SCMutexUnlock(&defrag_context->frag_pool_lock);
865
62.4k
    if (new == NULL) {
866
0
        if (af == AF_INET) {
867
0
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
868
0
        } else {
869
0
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
870
0
        }
871
0
        goto done;
872
0
    }
873
62.4k
    new->pkt = SCMalloc(GET_PKT_LEN(p));
874
62.4k
    if (new->pkt == NULL) {
875
0
        SCMutexLock(&defrag_context->frag_pool_lock);
876
0
        PoolReturn(defrag_context->frag_pool, new);
877
0
        SCMutexUnlock(&defrag_context->frag_pool_lock);
878
0
        if (af == AF_INET) {
879
0
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
880
0
        } else {
881
0
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
882
0
        }
883
0
        goto done;
884
0
    }
885
62.4k
    memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
886
62.4k
    new->len = (GET_PKT_LEN(p) - ltrim);
887
    /* in case of unfragmentable exthdrs, update the 'next hdr' field
888
     * in the raw buffer so the reassembled packet will point to the
889
     * correct next header after stripping the frag header */
890
62.4k
    if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
891
13.9k
        if (new->len > ip6_nh_set_offset) {
892
13.9k
            SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
893
13.9k
                    new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
894
13.9k
            new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
895
13.9k
        }
896
13.9k
    }
897
898
62.4k
    new->hlen = hlen;
899
62.4k
    new->offset = frag_offset + ltrim;
900
62.4k
    new->data_offset = data_offset;
901
62.4k
    new->data_len = data_len - ltrim;
902
62.4k
    new->ip_hdr_offset = ip_hdr_offset;
903
62.4k
    new->frag_hdr_offset = frag_hdr_offset;
904
62.4k
    new->more_frags = more_frags;
905
#ifdef DEBUG
906
    new->pcap_cnt = pcap_cnt;
907
#endif
908
62.4k
    if (frag_offset == 0) {
909
20.7k
        tracker->datalink = p->datalink;
910
20.7k
    }
911
912
62.4k
    IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
913
914
62.4k
    if (!more_frags) {
915
33.6k
        tracker->seen_last = 1;
916
33.6k
    }
917
918
62.4k
    if (tracker->seen_last) {
919
43.2k
        if (tracker->af == AF_INET) {
920
29.6k
            r = Defrag4Reassemble(tv, tracker, p);
921
29.6k
            if (r != NULL && tv != NULL && dtv != NULL) {
922
824
                StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
923
824
                if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
924
824
                               IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
925
926
0
                    UNSET_TUNNEL_PKT(r);
927
0
                    r->root = NULL;
928
0
                    TmqhOutputPacketpool(tv, r);
929
0
                    r = NULL;
930
824
                } else {
931
824
                    PacketDefragPktSetupParent(p);
932
824
                }
933
824
            }
934
29.6k
        }
935
13.5k
        else if (tracker->af == AF_INET6) {
936
13.5k
            r = Defrag6Reassemble(tv, tracker, p);
937
13.5k
            if (r != NULL && tv != NULL && dtv != NULL) {
938
1.03k
                StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
939
1.03k
                if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
940
1.03k
                               IPV6_GET_PLEN(r) + IPV6_HEADER_LEN)
941
1.03k
                               != TM_ECODE_OK) {
942
943
0
                    UNSET_TUNNEL_PKT(r);
944
0
                    r->root = NULL;
945
0
                    TmqhOutputPacketpool(tv, r);
946
0
                    r = NULL;
947
1.03k
                } else {
948
1.03k
                    PacketDefragPktSetupParent(p);
949
1.03k
                }
950
1.03k
            }
951
13.5k
        }
952
43.2k
    }
953
954
955
300k
done:
956
300k
    if (overlap) {
957
260k
        if (af == AF_INET) {
958
113k
            ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
959
113k
        }
960
146k
        else {
961
146k
            ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
962
146k
        }
963
260k
    }
964
300k
    return r;
965
62.4k
}
966
967
/**
968
 * \brief Get the defrag policy based on the destination address of
969
 * the packet.
970
 *
971
 * \param p The packet used to get the destination address.
972
 *
973
 * \retval The defrag policy to use.
974
 */
975
uint8_t
976
DefragGetOsPolicy(Packet *p)
977
20.8k
{
978
20.8k
    int policy = -1;
979
980
20.8k
    if (PKT_IS_IPV4(p)) {
981
5.00k
        policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
982
5.00k
    }
983
15.8k
    else if (PKT_IS_IPV6(p)) {
984
15.8k
        policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
985
15.8k
    }
986
987
20.8k
    if (policy == -1) {
988
20.8k
        return default_policy;
989
20.8k
    }
990
991
    /* Map the OS policies returned from the configured host info to
992
     * defrag specific policies. */
993
0
    switch (policy) {
994
        /* BSD. */
995
0
    case OS_POLICY_BSD:
996
0
    case OS_POLICY_HPUX10:
997
0
    case OS_POLICY_IRIX:
998
0
        return DEFRAG_POLICY_BSD;
999
1000
        /* BSD-Right. */
1001
0
    case OS_POLICY_BSD_RIGHT:
1002
0
        return DEFRAG_POLICY_BSD_RIGHT;
1003
1004
        /* Linux. */
1005
0
    case OS_POLICY_OLD_LINUX:
1006
0
    case OS_POLICY_LINUX:
1007
0
        return DEFRAG_POLICY_LINUX;
1008
1009
        /* First. */
1010
0
    case OS_POLICY_OLD_SOLARIS:
1011
0
    case OS_POLICY_HPUX11:
1012
0
    case OS_POLICY_MACOS:
1013
0
    case OS_POLICY_FIRST:
1014
0
        return DEFRAG_POLICY_FIRST;
1015
1016
        /* Solaris. */
1017
0
    case OS_POLICY_SOLARIS:
1018
0
        return DEFRAG_POLICY_SOLARIS;
1019
1020
        /* Windows. */
1021
0
    case OS_POLICY_WINDOWS:
1022
0
    case OS_POLICY_VISTA:
1023
0
    case OS_POLICY_WINDOWS2K3:
1024
0
        return DEFRAG_POLICY_WINDOWS;
1025
1026
        /* Last. */
1027
0
    case OS_POLICY_LAST:
1028
0
        return DEFRAG_POLICY_LAST;
1029
1030
0
    default:
1031
0
        return default_policy;
1032
0
    }
1033
0
}
1034
1035
/** \internal
1036
 *
1037
 *  \retval NULL or a *LOCKED* tracker */
1038
static DefragTracker *
1039
DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1040
698k
{
1041
698k
    return DefragGetTrackerFromHash(tv, dtv, p);
1042
698k
}
1043
1044
/**
1045
 * \brief Entry point for IPv4 and IPv6 fragments.
1046
 *
1047
 * \param tv ThreadVars for the calling decoder.
1048
 * \param p The packet fragment.
1049
 *
1050
 * \retval A new Packet resembling the re-assembled packet if the most
1051
 *     recent fragment allowed the packet to be re-assembled, otherwise
1052
 *     NULL is returned.
1053
 */
1054
Packet *
1055
Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1056
318k
{
1057
318k
    uint16_t frag_offset;
1058
318k
    uint8_t more_frags;
1059
318k
    DefragTracker *tracker;
1060
318k
    int af;
1061
1062
318k
    if (PKT_IS_IPV4(p)) {
1063
129k
        af = AF_INET;
1064
129k
        more_frags = IPV4_GET_MF(p);
1065
129k
        frag_offset = IPV4_GET_IPOFFSET(p);
1066
129k
    }
1067
189k
    else if (PKT_IS_IPV6(p)) {
1068
189k
        af = AF_INET6;
1069
189k
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1070
189k
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1071
189k
    }
1072
0
    else {
1073
0
        return NULL;
1074
0
    }
1075
1076
318k
    if (frag_offset == 0 && more_frags == 0) {
1077
10.0k
        return NULL;
1078
10.0k
    }
1079
1080
308k
    if (tv != NULL && dtv != NULL) {
1081
308k
        if (af == AF_INET) {
1082
129k
            StatsIncr(tv, dtv->counter_defrag_ipv4_fragments);
1083
129k
        }
1084
179k
        else if (af == AF_INET6) {
1085
179k
            StatsIncr(tv, dtv->counter_defrag_ipv6_fragments);
1086
179k
        }
1087
308k
    }
1088
1089
    /* return a locked tracker or NULL */
1090
308k
    tracker = DefragGetTracker(tv, dtv, p);
1091
308k
    if (tracker == NULL) {
1092
0
        if (tv != NULL && dtv != NULL) {
1093
0
            StatsIncr(tv, dtv->counter_defrag_max_hit);
1094
0
        }
1095
0
        return NULL;
1096
0
    }
1097
1098
308k
    Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1099
308k
    DefragTrackerRelease(tracker);
1100
1101
308k
    return rp;
1102
308k
}
1103
1104
void
1105
DefragInit(void)
1106
71
{
1107
71
    intmax_t tracker_pool_size;
1108
71
    if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1109
71
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1110
71
    }
1111
1112
    /* Load the defrag-per-host lookup. */
1113
71
    DefragPolicyLoadFromConfig();
1114
1115
    /* Allocate the DefragContext. */
1116
71
    defrag_context = DefragContextNew();
1117
71
    if (defrag_context == NULL) {
1118
0
        FatalError("Failed to allocate memory for the Defrag module.");
1119
0
    }
1120
1121
71
    DefragSetDefaultTimeout(defrag_context->timeout);
1122
71
    DefragInitConfig(false);
1123
71
}
1124
1125
void DefragDestroy(void)
1126
0
{
1127
0
    DefragHashShutdown();
1128
0
    DefragContextDestroy(defrag_context);
1129
0
    defrag_context = NULL;
1130
0
    DefragTreeDestroy();
1131
0
}
1132
1133
#ifdef UNITTESTS
1134
#include "util-unittest-helper.h"
1135
#include "packet.h"
1136
1137
#define IP_MF 0x2000
1138
1139
/**
1140
 * Allocate a test packet.  Nothing to fancy, just a simple IP packet
1141
 * with some payload of no particular protocol.
1142
 */
1143
static Packet *BuildIpv4TestPacket(
1144
        uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
1145
{
1146
    Packet *p = NULL;
1147
    int hlen = 20;
1148
    int ttl = 64;
1149
    uint8_t *pcontent;
1150
    IPV4Hdr ip4h;
1151
1152
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1153
    if (unlikely(p == NULL))
1154
        return NULL;
1155
1156
    PacketInit(p);
1157
1158
    struct timeval tval;
1159
    gettimeofday(&tval, NULL);
1160
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1161
    //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1162
    ip4h.ip_verhl = 4 << 4;
1163
    ip4h.ip_verhl |= hlen >> 2;
1164
    ip4h.ip_len = htons(hlen + content_len);
1165
    ip4h.ip_id = htons(id);
1166
    if (mf)
1167
        ip4h.ip_off = htons(IP_MF | off);
1168
    else
1169
        ip4h.ip_off = htons(off);
1170
    ip4h.ip_ttl = ttl;
1171
    ip4h.ip_proto = proto;
1172
1173
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1174
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1175
1176
    /* copy content_len crap, we need full length */
1177
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1178
    p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1179
    SET_IPV4_SRC_ADDR(p, &p->src);
1180
    SET_IPV4_DST_ADDR(p, &p->dst);
1181
1182
    pcontent = SCCalloc(1, content_len);
1183
    if (unlikely(pcontent == NULL))
1184
        return NULL;
1185
    memset(pcontent, content, content_len);
1186
    PacketCopyDataOffset(p, hlen, pcontent, content_len);
1187
    SET_PKT_LEN(p, hlen + content_len);
1188
    SCFree(pcontent);
1189
1190
    p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1191
1192
    /* Self test. */
1193
    if (IPV4_GET_VER(p) != 4)
1194
        goto error;
1195
    if (IPV4_GET_HLEN(p) != hlen)
1196
        goto error;
1197
    if (IPV4_GET_IPLEN(p) != hlen + content_len)
1198
        goto error;
1199
    if (IPV4_GET_IPID(p) != id)
1200
        goto error;
1201
    if (IPV4_GET_IPOFFSET(p) != off)
1202
        goto error;
1203
    if (IPV4_GET_MF(p) != mf)
1204
        goto error;
1205
    if (IPV4_GET_IPTTL(p) != ttl)
1206
        goto error;
1207
    if (IPV4_GET_IPPROTO(p) != proto)
1208
        goto error;
1209
1210
    return p;
1211
error:
1212
    if (p != NULL)
1213
        SCFree(p);
1214
    return NULL;
1215
}
1216
1217
/**
1218
 * Allocate a test packet, much like BuildIpv4TestPacket, but with
1219
 * the full content provided by the caller.
1220
 */
1221
static Packet *BuildIpv4TestPacketWithContent(
1222
        uint8_t proto, uint16_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1223
{
1224
    Packet *p = NULL;
1225
    int hlen = 20;
1226
    int ttl = 64;
1227
    IPV4Hdr ip4h;
1228
1229
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1230
    if (unlikely(p == NULL))
1231
        return NULL;
1232
1233
    PacketInit(p);
1234
1235
    struct timeval tval;
1236
    gettimeofday(&tval, NULL);
1237
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1238
    ip4h.ip_verhl = 4 << 4;
1239
    ip4h.ip_verhl |= hlen >> 2;
1240
    ip4h.ip_len = htons(hlen + content_len);
1241
    ip4h.ip_id = htons(id);
1242
    if (mf)
1243
        ip4h.ip_off = htons(IP_MF | off);
1244
    else
1245
        ip4h.ip_off = htons(off);
1246
    ip4h.ip_ttl = ttl;
1247
    ip4h.ip_proto = proto;
1248
1249
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1250
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1251
1252
    /* copy content_len crap, we need full length */
1253
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1254
    p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1255
    SET_IPV4_SRC_ADDR(p, &p->src);
1256
    SET_IPV4_DST_ADDR(p, &p->dst);
1257
1258
    PacketCopyDataOffset(p, hlen, content, content_len);
1259
    SET_PKT_LEN(p, hlen + content_len);
1260
1261
    p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1262
1263
    /* Self test. */
1264
    if (IPV4_GET_VER(p) != 4)
1265
        goto error;
1266
    if (IPV4_GET_HLEN(p) != hlen)
1267
        goto error;
1268
    if (IPV4_GET_IPLEN(p) != hlen + content_len)
1269
        goto error;
1270
    if (IPV4_GET_IPID(p) != id)
1271
        goto error;
1272
    if (IPV4_GET_IPOFFSET(p) != off)
1273
        goto error;
1274
    if (IPV4_GET_MF(p) != mf)
1275
        goto error;
1276
    if (IPV4_GET_IPTTL(p) != ttl)
1277
        goto error;
1278
    if (IPV4_GET_IPPROTO(p) != proto)
1279
        goto error;
1280
1281
    return p;
1282
error:
1283
    if (p != NULL)
1284
        SCFree(p);
1285
    return NULL;
1286
}
1287
1288
static Packet *BuildIpv6TestPacket(
1289
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
1290
{
1291
    Packet *p = NULL;
1292
    uint8_t *pcontent;
1293
    IPV6Hdr ip6h;
1294
1295
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1296
    if (unlikely(p == NULL))
1297
        return NULL;
1298
1299
    PacketInit(p);
1300
1301
    struct timeval tval;
1302
    gettimeofday(&tval, NULL);
1303
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1304
1305
    ip6h.s_ip6_nxt = 44;
1306
    ip6h.s_ip6_hlim = 2;
1307
1308
    /* Source and dest address - very bogus addresses. */
1309
    ip6h.s_ip6_src[0] = 0x01010101;
1310
    ip6h.s_ip6_src[1] = 0x01010101;
1311
    ip6h.s_ip6_src[2] = 0x01010101;
1312
    ip6h.s_ip6_src[3] = 0x01010101;
1313
    ip6h.s_ip6_dst[0] = 0x02020202;
1314
    ip6h.s_ip6_dst[1] = 0x02020202;
1315
    ip6h.s_ip6_dst[2] = 0x02020202;
1316
    ip6h.s_ip6_dst[3] = 0x02020202;
1317
1318
    /* copy content_len crap, we need full length */
1319
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1320
1321
    p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1322
    IPV6_SET_RAW_VER(p->ip6h, 6);
1323
    /* Fragmentation header. */
1324
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1325
    fh->ip6fh_nxt = proto;
1326
    fh->ip6fh_ident = htonl(id);
1327
    fh->ip6fh_offlg = htons((off << 3) | mf);
1328
1329
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1330
1331
    pcontent = SCCalloc(1, content_len);
1332
    if (unlikely(pcontent == NULL))
1333
        return NULL;
1334
    memset(pcontent, content, content_len);
1335
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1336
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1337
    SCFree(pcontent);
1338
1339
    p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1340
1341
    SET_IPV6_SRC_ADDR(p, &p->src);
1342
    SET_IPV6_DST_ADDR(p, &p->dst);
1343
1344
    /* Self test. */
1345
    if (IPV6_GET_VER(p) != 6)
1346
        goto error;
1347
    if (IPV6_GET_NH(p) != 44)
1348
        goto error;
1349
    if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1350
        goto error;
1351
1352
    return p;
1353
error:
1354
    if (p != NULL)
1355
        SCFree(p);
1356
    return NULL;
1357
}
1358
1359
static Packet *BuildIpv6TestPacketWithContent(
1360
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1361
{
1362
    Packet *p = NULL;
1363
    IPV6Hdr ip6h;
1364
1365
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
1366
    if (unlikely(p == NULL))
1367
        return NULL;
1368
1369
    PacketInit(p);
1370
1371
    struct timeval tval;
1372
    gettimeofday(&tval, NULL);
1373
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
1374
1375
    ip6h.s_ip6_nxt = 44;
1376
    ip6h.s_ip6_hlim = 2;
1377
1378
    /* Source and dest address - very bogus addresses. */
1379
    ip6h.s_ip6_src[0] = 0x01010101;
1380
    ip6h.s_ip6_src[1] = 0x01010101;
1381
    ip6h.s_ip6_src[2] = 0x01010101;
1382
    ip6h.s_ip6_src[3] = 0x01010101;
1383
    ip6h.s_ip6_dst[0] = 0x02020202;
1384
    ip6h.s_ip6_dst[1] = 0x02020202;
1385
    ip6h.s_ip6_dst[2] = 0x02020202;
1386
    ip6h.s_ip6_dst[3] = 0x02020202;
1387
1388
    /* copy content_len crap, we need full length */
1389
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1390
1391
    p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1392
    IPV6_SET_RAW_VER(p->ip6h, 6);
1393
    /* Fragmentation header. */
1394
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1395
    fh->ip6fh_nxt = proto;
1396
    fh->ip6fh_ident = htonl(id);
1397
    fh->ip6fh_offlg = htons((off << 3) | mf);
1398
1399
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1400
1401
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
1402
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1403
1404
    p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1405
1406
    SET_IPV6_SRC_ADDR(p, &p->src);
1407
    SET_IPV6_DST_ADDR(p, &p->dst);
1408
1409
    /* Self test. */
1410
    if (IPV6_GET_VER(p) != 6)
1411
        goto error;
1412
    if (IPV6_GET_NH(p) != 44)
1413
        goto error;
1414
    if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1415
        goto error;
1416
1417
    return p;
1418
error:
1419
    if (p != NULL)
1420
        SCFree(p);
1421
    return NULL;
1422
}
1423
1424
/**
1425
 * Test the simplest possible re-assembly scenario.  All packet in
1426
 * order and no overlaps.
1427
 */
1428
static int DefragInOrderSimpleTest(void)
1429
{
1430
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1431
    Packet *reassembled = NULL;
1432
    int id = 12;
1433
    int i;
1434
1435
    DefragInit();
1436
1437
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1438
    FAIL_IF_NULL(p1);
1439
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1440
    FAIL_IF_NULL(p2);
1441
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1442
    FAIL_IF_NULL(p3);
1443
1444
    FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1445
    FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1446
1447
    reassembled = Defrag(NULL, NULL, p3);
1448
    FAIL_IF_NULL(reassembled);
1449
1450
    FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1451
    FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1452
1453
    /* 20 bytes in we should find 8 bytes of A. */
1454
    for (i = 20; i < 20 + 8; i++) {
1455
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1456
    }
1457
1458
    /* 28 bytes in we should find 8 bytes of B. */
1459
    for (i = 28; i < 28 + 8; i++) {
1460
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1461
    }
1462
1463
    /* And 36 bytes in we should find 3 bytes of C. */
1464
    for (i = 36; i < 36 + 3; i++) {
1465
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1466
    }
1467
1468
    SCFree(p1);
1469
    SCFree(p2);
1470
    SCFree(p3);
1471
    SCFree(reassembled);
1472
1473
    DefragDestroy();
1474
    PASS;
1475
}
1476
1477
/**
1478
 * Simple fragmented packet in reverse order.
1479
 */
1480
static int DefragReverseSimpleTest(void)
1481
{
1482
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1483
    Packet *reassembled = NULL;
1484
    int id = 12;
1485
    int i;
1486
1487
    DefragInit();
1488
1489
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1490
    FAIL_IF_NULL(p1);
1491
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1492
    FAIL_IF_NULL(p2);
1493
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1494
    FAIL_IF_NULL(p3);
1495
1496
    FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1497
    FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1498
1499
    reassembled = Defrag(NULL, NULL, p1);
1500
    FAIL_IF_NULL(reassembled);
1501
1502
    FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1503
    FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1504
1505
    /* 20 bytes in we should find 8 bytes of A. */
1506
    for (i = 20; i < 20 + 8; i++) {
1507
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1508
    }
1509
1510
    /* 28 bytes in we should find 8 bytes of B. */
1511
    for (i = 28; i < 28 + 8; i++) {
1512
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1513
    }
1514
1515
    /* And 36 bytes in we should find 3 bytes of C. */
1516
    for (i = 36; i < 36 + 3; i++) {
1517
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1518
    }
1519
1520
    SCFree(p1);
1521
    SCFree(p2);
1522
    SCFree(p3);
1523
    SCFree(reassembled);
1524
1525
    DefragDestroy();
1526
    PASS;
1527
}
1528
1529
/**
1530
 * Test the simplest possible re-assembly scenario.  All packet in
1531
 * order and no overlaps.
1532
 */
1533
static int DefragInOrderSimpleIpv6Test(void)
1534
{
1535
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1536
    Packet *reassembled = NULL;
1537
    int id = 12;
1538
    int i;
1539
1540
    DefragInit();
1541
1542
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1543
    FAIL_IF_NULL(p1);
1544
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1545
    FAIL_IF_NULL(p2);
1546
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1547
    FAIL_IF_NULL(p3);
1548
1549
    FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1550
    FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1551
    reassembled = Defrag(NULL, NULL, p3);
1552
    FAIL_IF_NULL(reassembled);
1553
1554
    FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1555
1556
    /* 40 bytes in we should find 8 bytes of A. */
1557
    for (i = 40; i < 40 + 8; i++) {
1558
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1559
    }
1560
1561
    /* 28 bytes in we should find 8 bytes of B. */
1562
    for (i = 48; i < 48 + 8; i++) {
1563
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1564
    }
1565
1566
    /* And 36 bytes in we should find 3 bytes of C. */
1567
    for (i = 56; i < 56 + 3; i++) {
1568
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1569
    }
1570
1571
    SCFree(p1);
1572
    SCFree(p2);
1573
    SCFree(p3);
1574
    SCFree(reassembled);
1575
1576
    DefragDestroy();
1577
    PASS;
1578
}
1579
1580
static int DefragReverseSimpleIpv6Test(void)
1581
{
1582
    DefragContext *dc = NULL;
1583
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1584
    Packet *reassembled = NULL;
1585
    int id = 12;
1586
    int i;
1587
1588
    DefragInit();
1589
1590
    dc = DefragContextNew();
1591
    FAIL_IF_NULL(dc);
1592
1593
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1594
    FAIL_IF_NULL(p1);
1595
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1596
    FAIL_IF_NULL(p2);
1597
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1598
    FAIL_IF_NULL(p3);
1599
1600
    FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1601
    FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1602
    reassembled = Defrag(NULL, NULL, p1);
1603
    FAIL_IF_NULL(reassembled);
1604
1605
    /* 40 bytes in we should find 8 bytes of A. */
1606
    for (i = 40; i < 40 + 8; i++) {
1607
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1608
    }
1609
1610
    /* 28 bytes in we should find 8 bytes of B. */
1611
    for (i = 48; i < 48 + 8; i++) {
1612
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1613
    }
1614
1615
    /* And 36 bytes in we should find 3 bytes of C. */
1616
    for (i = 56; i < 56 + 3; i++) {
1617
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1618
    }
1619
1620
    DefragContextDestroy(dc);
1621
    SCFree(p1);
1622
    SCFree(p2);
1623
    SCFree(p3);
1624
    SCFree(reassembled);
1625
1626
    DefragDestroy();
1627
    PASS;
1628
}
1629
1630
static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
1631
{
1632
    int i;
1633
1634
    DefragInit();
1635
1636
    /*
1637
     * Build the packets.
1638
     */
1639
1640
    int id = 1;
1641
    Packet *packets[17];
1642
    memset(packets, 0x00, sizeof(packets));
1643
1644
    /*
1645
     * Original fragments.
1646
     */
1647
1648
    /* <1> A*24 at 0. */
1649
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1650
1651
    /* <2> B*16 at 32. */
1652
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1653
1654
    /* <3> C*24 at 48. */
1655
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1656
1657
    /* <3_1> D*8 at 80. */
1658
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1659
1660
    /* <3_2> E*16 at 104. */
1661
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1662
1663
    /* <3_3> F*24 at 120. */
1664
    packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1665
1666
    /* <3_4> G*16 at 144. */
1667
    packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1668
1669
    /* <3_5> H*16 at 160. */
1670
    packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1671
1672
    /* <3_6> I*8 at 176. */
1673
    packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1674
1675
    /*
1676
     * Overlapping subsequent fragments.
1677
     */
1678
1679
    /* <4> J*32 at 8. */
1680
    packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1681
1682
    /* <5> K*24 at 48. */
1683
    packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1684
1685
    /* <6> L*24 at 72. */
1686
    packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1687
1688
    /* <7> M*24 at 96. */
1689
    packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1690
1691
    /* <8> N*8 at 128. */
1692
    packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1693
1694
    /* <9> O*8 at 152. */
1695
    packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1696
1697
    /* <10> P*8 at 160. */
1698
    packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1699
1700
    /* <11> Q*16 at 176. */
1701
    packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1702
1703
    default_policy = policy;
1704
1705
    /* Send all but the last. */
1706
    for (i = 0; i < 9; i++) {
1707
        Packet *tp = Defrag(NULL, NULL, packets[i]);
1708
        FAIL_IF_NOT_NULL(tp);
1709
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP));
1710
    }
1711
    int overlap = 0;
1712
    for (; i < 16; i++) {
1713
        Packet *tp = Defrag(NULL, NULL, packets[i]);
1714
        FAIL_IF_NOT_NULL(tp);
1715
        if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1716
            overlap++;
1717
        }
1718
    }
1719
    FAIL_IF_NOT(overlap);
1720
1721
    /* And now the last one. */
1722
    Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1723
    FAIL_IF_NULL(reassembled);
1724
1725
    FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1726
    FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1727
    FAIL_IF(expected_len != 192);
1728
1729
    if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
1730
        printf("Expected:\n");
1731
        PrintRawDataFp(stdout, expected, expected_len);
1732
        printf("Got:\n");
1733
        PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
1734
        FAIL;
1735
    }
1736
    SCFree(reassembled);
1737
1738
    /* Make sure all frags were returned back to the pool. */
1739
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1740
1741
    for (i = 0; i < 17; i++) {
1742
        SCFree(packets[i]);
1743
    }
1744
    DefragDestroy();
1745
    PASS;
1746
}
1747
1748
static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
1749
{
1750
    int i;
1751
1752
    DefragInit();
1753
1754
    /*
1755
     * Build the packets.
1756
     */
1757
1758
    int id = 1;
1759
    Packet *packets[17];
1760
    memset(packets, 0x00, sizeof(packets));
1761
1762
    /*
1763
     * Original fragments.
1764
     */
1765
1766
    /* <1> A*24 at 0. */
1767
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1768
1769
    /* <2> B*16 at 32. */
1770
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1771
1772
    /* <3> C*24 at 48. */
1773
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1774
1775
    /* <3_1> D*8 at 80. */
1776
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1777
1778
    /* <3_2> E*16 at 104. */
1779
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1780
1781
    /* <3_3> F*24 at 120. */
1782
    packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1783
1784
    /* <3_4> G*16 at 144. */
1785
    packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1786
1787
    /* <3_5> H*16 at 160. */
1788
    packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1789
1790
    /* <3_6> I*8 at 176. */
1791
    packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1792
1793
    /*
1794
     * Overlapping subsequent fragments.
1795
     */
1796
1797
    /* <4> J*32 at 8. */
1798
    packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1799
1800
    /* <5> K*24 at 48. */
1801
    packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1802
1803
    /* <6> L*24 at 72. */
1804
    packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1805
1806
    /* <7> M*24 at 96. */
1807
    packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1808
1809
    /* <8> N*8 at 128. */
1810
    packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1811
1812
    /* <9> O*8 at 152. */
1813
    packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1814
1815
    /* <10> P*8 at 160. */
1816
    packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1817
1818
    /* <11> Q*16 at 176. */
1819
    packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1820
1821
    default_policy = policy;
1822
1823
    /* Send all but the last. */
1824
    for (i = 0; i < 9; i++) {
1825
        Packet *tp = Defrag(NULL, NULL, packets[i]);
1826
        FAIL_IF_NOT_NULL(tp);
1827
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP));
1828
    }
1829
    int overlap = 0;
1830
    for (; i < 16; i++) {
1831
        Packet *tp = Defrag(NULL, NULL, packets[i]);
1832
        FAIL_IF_NOT_NULL(tp);
1833
        if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1834
            overlap++;
1835
        }
1836
    }
1837
    FAIL_IF_NOT(overlap);
1838
1839
    /* And now the last one. */
1840
    Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1841
    FAIL_IF_NULL(reassembled);
1842
    FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1843
1844
    FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1845
1846
    SCFree(reassembled);
1847
1848
    /* Make sure all frags were returned to the pool. */
1849
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1850
1851
    for (i = 0; i < 17; i++) {
1852
        SCFree(packets[i]);
1853
    }
1854
    DefragDestroy();
1855
    PASS;
1856
}
1857
1858
/* Define data that matches the naming "Target-Based Fragmentation
1859
 * Reassembly".
1860
 *
1861
 * For example, the data refers to a fragment of data as <1>, or <3_6>
1862
 * and uses these to diagram the input fragments and the resulting
1863
 * policies. We build test cases for the papers scenario but assign
1864
 * specific values to each segment.
1865
 */
1866
#define D_1   'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
1867
#define D_2   'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
1868
#define D_3   'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
1869
#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
1870
#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
1871
#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
1872
#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
1873
#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
1874
#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
1875
#define D_4   'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
1876
#define D_5   'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
1877
#define D_6   'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
1878
#define D_7   'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
1879
#define D_8   'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
1880
#define D_9   'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
1881
#define D_10  'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
1882
#define D_11  'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
1883
1884
static int
1885
DefragSturgesNovakBsdTest(void)
1886
{
1887
    /* Expected data. */
1888
    uint8_t expected[] = {
1889
        D_1,
1890
        D_1,
1891
        D_1,
1892
        D_4,
1893
        D_4,
1894
        D_2,
1895
        D_3,
1896
        D_3,
1897
        D_3,
1898
        D_6,
1899
        D_6,
1900
        D_6,
1901
        D_7,
1902
        D_7,
1903
        D_7,
1904
        D_3_3,
1905
        D_3_3,
1906
        D_3_3,
1907
        D_3_4,
1908
        D_3_4,
1909
        D_3_5,
1910
        D_3_5,
1911
        D_3_6,
1912
        D_11,
1913
    };
1914
1915
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1916
                    sizeof(expected)));
1917
    PASS;
1918
}
1919
1920
static int DefragSturgesNovakBsdIpv6Test(void)
1921
{
1922
    /* Expected data. */
1923
    uint8_t expected[] = {
1924
        D_1,
1925
        D_1,
1926
        D_1,
1927
        D_4,
1928
        D_4,
1929
        D_2,
1930
        D_3,
1931
        D_3,
1932
        D_3,
1933
        D_6,
1934
        D_6,
1935
        D_6,
1936
        D_7,
1937
        D_7,
1938
        D_7,
1939
        D_3_3,
1940
        D_3_3,
1941
        D_3_3,
1942
        D_3_4,
1943
        D_3_4,
1944
        D_3_5,
1945
        D_3_5,
1946
        D_3_6,
1947
        D_11,
1948
    };
1949
1950
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
1951
    PASS;
1952
}
1953
1954
static int DefragSturgesNovakLinuxIpv4Test(void)
1955
{
1956
    /* Expected data. */
1957
    uint8_t expected[] = {
1958
        D_1,
1959
        D_1,
1960
        D_1,
1961
        D_4,
1962
        D_4,
1963
        D_2,
1964
        D_5,
1965
        D_5,
1966
        D_5,
1967
        D_6,
1968
        D_6,
1969
        D_6,
1970
        D_7,
1971
        D_7,
1972
        D_7,
1973
        D_3_3,
1974
        D_3_3,
1975
        D_3_3,
1976
        D_3_4,
1977
        D_3_4,
1978
        D_10,
1979
        D_3_5,
1980
        D_11,
1981
        D_11,
1982
    };
1983
1984
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1985
                    sizeof(expected)));
1986
    PASS;
1987
}
1988
1989
static int DefragSturgesNovakLinuxIpv6Test(void)
1990
{
1991
    /* Expected data. */
1992
    uint8_t expected[] = {
1993
        D_1,
1994
        D_1,
1995
        D_1,
1996
        D_4,
1997
        D_4,
1998
        D_2,
1999
        D_5,
2000
        D_5,
2001
        D_5,
2002
        D_6,
2003
        D_6,
2004
        D_6,
2005
        D_7,
2006
        D_7,
2007
        D_7,
2008
        D_3_3,
2009
        D_3_3,
2010
        D_3_3,
2011
        D_3_4,
2012
        D_3_4,
2013
        D_10,
2014
        D_3_5,
2015
        D_11,
2016
        D_11,
2017
    };
2018
2019
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
2020
    PASS;
2021
}
2022
2023
static int DefragSturgesNovakWindowsIpv4Test(void)
2024
{
2025
    /* Expected data. */
2026
    uint8_t expected[] = {
2027
        D_1,
2028
        D_1,
2029
        D_1,
2030
        D_4,
2031
        D_2,
2032
        D_2,
2033
        D_3,
2034
        D_3,
2035
        D_3,
2036
        D_6,
2037
        D_6,
2038
        D_6,
2039
        D_7,
2040
        D_3_2,
2041
        D_3_2,
2042
        D_3_3,
2043
        D_3_3,
2044
        D_3_3,
2045
        D_3_4,
2046
        D_3_4,
2047
        D_3_5,
2048
        D_3_5,
2049
        D_3_6,
2050
        D_11,
2051
    };
2052
2053
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
2054
                    sizeof(expected)));
2055
    PASS;
2056
}
2057
2058
static int DefragSturgesNovakWindowsIpv6Test(void)
2059
{
2060
    /* Expected data. */
2061
    uint8_t expected[] = {
2062
        D_1,
2063
        D_1,
2064
        D_1,
2065
        D_4,
2066
        D_2,
2067
        D_2,
2068
        D_3,
2069
        D_3,
2070
        D_3,
2071
        D_6,
2072
        D_6,
2073
        D_6,
2074
        D_7,
2075
        D_3_2,
2076
        D_3_2,
2077
        D_3_3,
2078
        D_3_3,
2079
        D_3_3,
2080
        D_3_4,
2081
        D_3_4,
2082
        D_3_5,
2083
        D_3_5,
2084
        D_3_6,
2085
        D_11,
2086
    };
2087
2088
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
2089
    PASS;
2090
}
2091
2092
static int DefragSturgesNovakSolarisTest(void)
2093
{
2094
    /* Expected data. */
2095
    uint8_t expected[] = {
2096
        D_1,
2097
        D_1,
2098
        D_1,
2099
        D_4,
2100
        D_2,
2101
        D_2,
2102
        D_3,
2103
        D_3,
2104
        D_3,
2105
        D_6,
2106
        D_6,
2107
        D_6,
2108
        D_7,
2109
        D_7,
2110
        D_7,
2111
        D_3_3,
2112
        D_3_3,
2113
        D_3_3,
2114
        D_3_4,
2115
        D_3_4,
2116
        D_3_5,
2117
        D_3_5,
2118
        D_3_6,
2119
        D_11,
2120
    };
2121
2122
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
2123
                    sizeof(expected)));
2124
    PASS;
2125
}
2126
2127
static int DefragSturgesNovakSolarisIpv6Test(void)
2128
{
2129
    /* Expected data. */
2130
    uint8_t expected[] = {
2131
        D_1,
2132
        D_1,
2133
        D_1,
2134
        D_4,
2135
        D_2,
2136
        D_2,
2137
        D_3,
2138
        D_3,
2139
        D_3,
2140
        D_6,
2141
        D_6,
2142
        D_6,
2143
        D_7,
2144
        D_7,
2145
        D_7,
2146
        D_3_3,
2147
        D_3_3,
2148
        D_3_3,
2149
        D_3_4,
2150
        D_3_4,
2151
        D_3_5,
2152
        D_3_5,
2153
        D_3_6,
2154
        D_11,
2155
    };
2156
2157
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
2158
    PASS;
2159
}
2160
2161
static int DefragSturgesNovakFirstTest(void)
2162
{
2163
    /* Expected data. */
2164
    uint8_t expected[] = {
2165
        D_1,
2166
        D_1,
2167
        D_1,
2168
        D_4,
2169
        D_2,
2170
        D_2,
2171
        D_3,
2172
        D_3,
2173
        D_3,
2174
        D_6,
2175
        D_3_1,
2176
        D_6,
2177
        D_7,
2178
        D_3_2,
2179
        D_3_2,
2180
        D_3_3,
2181
        D_3_3,
2182
        D_3_3,
2183
        D_3_4,
2184
        D_3_4,
2185
        D_3_5,
2186
        D_3_5,
2187
        D_3_6,
2188
        D_11,
2189
    };
2190
2191
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2192
                    sizeof(expected)));
2193
    PASS;
2194
}
2195
2196
static int DefragSturgesNovakFirstIpv6Test(void)
2197
{
2198
    /* Expected data. */
2199
    uint8_t expected[] = {
2200
        D_1,
2201
        D_1,
2202
        D_1,
2203
        D_4,
2204
        D_2,
2205
        D_2,
2206
        D_3,
2207
        D_3,
2208
        D_3,
2209
        D_6,
2210
        D_3_1,
2211
        D_6,
2212
        D_7,
2213
        D_3_2,
2214
        D_3_2,
2215
        D_3_3,
2216
        D_3_3,
2217
        D_3_3,
2218
        D_3_4,
2219
        D_3_4,
2220
        D_3_5,
2221
        D_3_5,
2222
        D_3_6,
2223
        D_11,
2224
    };
2225
2226
    return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
2227
}
2228
2229
static int
2230
DefragSturgesNovakLastTest(void)
2231
{
2232
    /* Expected data. */
2233
    uint8_t expected[] = {
2234
        D_1,
2235
        D_4,
2236
        D_4,
2237
        D_4,
2238
        D_4,
2239
        D_2,
2240
        D_5,
2241
        D_5,
2242
        D_5,
2243
        D_6,
2244
        D_6,
2245
        D_6,
2246
        D_7,
2247
        D_7,
2248
        D_7,
2249
        D_3_3,
2250
        D_8,
2251
        D_3_3,
2252
        D_3_4,
2253
        D_9,
2254
        D_10,
2255
        D_3_5,
2256
        D_11,
2257
        D_11,
2258
    };
2259
2260
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2261
                    sizeof(expected)));
2262
    PASS;
2263
}
2264
2265
static int DefragSturgesNovakLastIpv6Test(void)
2266
{
2267
    /* Expected data. */
2268
    uint8_t expected[] = {
2269
        D_1,
2270
        D_4,
2271
        D_4,
2272
        D_4,
2273
        D_4,
2274
        D_2,
2275
        D_5,
2276
        D_5,
2277
        D_5,
2278
        D_6,
2279
        D_6,
2280
        D_6,
2281
        D_7,
2282
        D_7,
2283
        D_7,
2284
        D_3_3,
2285
        D_8,
2286
        D_3_3,
2287
        D_3_4,
2288
        D_9,
2289
        D_10,
2290
        D_3_5,
2291
        D_11,
2292
        D_11,
2293
    };
2294
2295
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
2296
    PASS;
2297
}
2298
2299
static int DefragTimeoutTest(void)
2300
{
2301
    int i;
2302
2303
    /* Setup a small number of trackers. */
2304
    FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2305
2306
    DefragInit();
2307
2308
    /* Load in 16 packets. */
2309
    for (i = 0; i < 16; i++) {
2310
        Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
2311
        FAIL_IF_NULL(p);
2312
2313
        Packet *tp = Defrag(NULL, NULL, p);
2314
        SCFree(p);
2315
        FAIL_IF_NOT_NULL(tp);
2316
    }
2317
2318
    /* Build a new packet but push the timestamp out by our timeout.
2319
     * This should force our previous fragments to be timed out. */
2320
    Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2321
    FAIL_IF_NULL(p);
2322
2323
    p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2324
    Packet *tp = Defrag(NULL, NULL, p);
2325
    FAIL_IF_NOT_NULL(tp);
2326
2327
    DefragTracker *tracker = DefragLookupTrackerFromHash(p);
2328
    FAIL_IF_NULL(tracker);
2329
2330
    FAIL_IF(tracker->id != 99);
2331
2332
    SCMutexUnlock(&tracker->lock);
2333
    SCFree(p);
2334
2335
    DefragDestroy();
2336
    PASS;
2337
}
2338
2339
/**
2340
 * QA found that if you send a packet where more frags is 0, offset is
2341
 * > 0 and there is no data in the packet that the re-assembler will
2342
 * fail.  The fix was simple, but this unit test is just to make sure
2343
 * its not introduced.
2344
 */
2345
static int DefragNoDataIpv4Test(void)
2346
{
2347
    DefragContext *dc = NULL;
2348
    Packet *p = NULL;
2349
    int id = 12;
2350
2351
    DefragInit();
2352
2353
    dc = DefragContextNew();
2354
    FAIL_IF_NULL(dc);
2355
2356
    /* This packet has an offset > 0, more frags set to 0 and no data. */
2357
    p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2358
    FAIL_IF_NULL(p);
2359
2360
    /* We do not expect a packet returned. */
2361
    FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2362
2363
    /* The fragment should have been ignored so no fragments should
2364
     * have been allocated from the pool. */
2365
    FAIL_IF(dc->frag_pool->outstanding != 0);
2366
2367
    DefragContextDestroy(dc);
2368
    SCFree(p);
2369
2370
    DefragDestroy();
2371
    PASS;
2372
}
2373
2374
static int DefragTooLargeIpv4Test(void)
2375
{
2376
    DefragContext *dc = NULL;
2377
    Packet *p = NULL;
2378
2379
    DefragInit();
2380
2381
    dc = DefragContextNew();
2382
    FAIL_IF_NULL(dc);
2383
2384
    /* Create a fragment that would extend past the max allowable size
2385
     * for an IPv4 packet. */
2386
    p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2387
    FAIL_IF_NULL(p);
2388
2389
    /* We do not expect a packet returned. */
2390
    FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2391
2392
    /* We do expect an event. */
2393
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE));
2394
2395
    /* The fragment should have been ignored so no fragments should have
2396
     * been allocated from the pool. */
2397
    FAIL_IF(dc->frag_pool->outstanding != 0);
2398
2399
    DefragContextDestroy(dc);
2400
    SCFree(p);
2401
2402
    DefragDestroy();
2403
    PASS;
2404
}
2405
2406
/**
2407
 * Test that fragments in different VLANs that would otherwise be
2408
 * re-assembled, are not re-assembled.  Just use simple in-order
2409
 * fragments.
2410
 */
2411
static int DefragVlanTest(void)
2412
{
2413
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2414
2415
    DefragInit();
2416
2417
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2418
    FAIL_IF_NULL(p1);
2419
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2420
    FAIL_IF_NULL(p2);
2421
2422
    /* With no VLAN IDs set, packets should re-assemble. */
2423
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2424
    FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2425
    SCFree(r);
2426
2427
    /* With mismatched VLANs, packets should not re-assemble. */
2428
    p1->vlan_id[0] = 1;
2429
    p2->vlan_id[0] = 2;
2430
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2431
    FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2432
2433
    SCFree(p1);
2434
    SCFree(p2);
2435
    DefragDestroy();
2436
2437
    PASS;
2438
}
2439
2440
/**
2441
 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2442
 */
2443
static int DefragVlanQinQTest(void)
2444
{
2445
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2446
2447
    DefragInit();
2448
2449
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2450
    FAIL_IF_NULL(p1);
2451
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2452
    FAIL_IF_NULL(p2);
2453
2454
    /* With no VLAN IDs set, packets should re-assemble. */
2455
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2456
    FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2457
    SCFree(r);
2458
2459
    /* With mismatched VLANs, packets should not re-assemble. */
2460
    p1->vlan_id[0] = 1;
2461
    p2->vlan_id[0] = 1;
2462
    p1->vlan_id[1] = 1;
2463
    p2->vlan_id[1] = 2;
2464
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2465
    FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2466
2467
    SCFree(p1);
2468
    SCFree(p2);
2469
    DefragDestroy();
2470
2471
    PASS;
2472
}
2473
2474
/**
2475
 * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2476
 */
2477
static int DefragVlanQinQinQTest(void)
2478
{
2479
    Packet *r = NULL;
2480
2481
    DefragInit();
2482
2483
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2484
    FAIL_IF_NULL(p1);
2485
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2486
    FAIL_IF_NULL(p2);
2487
2488
    /* With no VLAN IDs set, packets should re-assemble. */
2489
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2490
    FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2491
    SCFree(r);
2492
2493
    /* With mismatched VLANs, packets should not re-assemble. */
2494
    p1->vlan_id[0] = 1;
2495
    p2->vlan_id[0] = 1;
2496
    p1->vlan_id[1] = 2;
2497
    p2->vlan_id[1] = 2;
2498
    p1->vlan_id[2] = 3;
2499
    p2->vlan_id[2] = 4;
2500
    FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2501
    FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2502
2503
    PacketFree(p1);
2504
    PacketFree(p2);
2505
    DefragDestroy();
2506
2507
    PASS;
2508
}
2509
static int DefragTrackerReuseTest(void)
2510
{
2511
    int id = 1;
2512
    Packet *p1 = NULL;
2513
    DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2514
2515
    DefragInit();
2516
2517
    /* Build a packet, its not a fragment but shouldn't matter for
2518
     * this test. */
2519
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2520
    FAIL_IF_NULL(p1);
2521
2522
    /* Get a tracker. It shouldn't look like its already in use. */
2523
    tracker1 = DefragGetTracker(NULL, NULL, p1);
2524
    FAIL_IF_NULL(tracker1);
2525
    FAIL_IF(tracker1->seen_last);
2526
    FAIL_IF(tracker1->remove);
2527
    DefragTrackerRelease(tracker1);
2528
2529
    /* Get a tracker again, it should be the same one. */
2530
    tracker2 = DefragGetTracker(NULL, NULL, p1);
2531
    FAIL_IF_NULL(tracker2);
2532
    FAIL_IF(tracker2 != tracker1);
2533
    DefragTrackerRelease(tracker1);
2534
2535
    /* Now mark the tracker for removal. It should not be returned
2536
     * when we get a tracker for a packet that may have the same
2537
     * attributes. */
2538
    tracker1->remove = 1;
2539
2540
    tracker2 = DefragGetTracker(NULL, NULL, p1);
2541
    FAIL_IF_NULL(tracker2);
2542
    FAIL_IF(tracker2 == tracker1);
2543
    FAIL_IF(tracker2->remove);
2544
2545
    SCFree(p1);
2546
    DefragDestroy();
2547
    PASS;
2548
}
2549
2550
/**
2551
 * IPV4: Test the case where you have a packet fragmented in 3 parts
2552
 * and send like:
2553
 * - Offset: 2; MF: 1
2554
 * - Offset: 0; MF: 1
2555
 * - Offset: 1; MF: 0
2556
 *
2557
 * Only the fragments with offset 0 and 1 should be reassembled.
2558
 */
2559
static int DefragMfIpv4Test(void)
2560
{
2561
    int ip_id = 9;
2562
    Packet *p = NULL;
2563
2564
    DefragInit();
2565
2566
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2567
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2568
    Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2569
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2570
2571
    p = Defrag(NULL, NULL, p1);
2572
    FAIL_IF_NOT_NULL(p);
2573
2574
    p = Defrag(NULL, NULL, p2);
2575
    FAIL_IF_NOT_NULL(p);
2576
2577
    /* This should return a packet as MF=0. */
2578
    p = Defrag(NULL, NULL, p3);
2579
    FAIL_IF_NULL(p);
2580
2581
    /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2582
     * fragments should be in the re-assembled packet. */
2583
    FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2584
2585
    /* Verify the payload of the IPv4 packet. */
2586
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2587
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
2588
2589
    SCFree(p1);
2590
    SCFree(p2);
2591
    SCFree(p3);
2592
    SCFree(p);
2593
    DefragDestroy();
2594
    PASS;
2595
}
2596
2597
/**
2598
 * IPV6: Test the case where you have a packet fragmented in 3 parts
2599
 * and send like:
2600
 * - Offset: 2; MF: 1
2601
 * - Offset: 0; MF: 1
2602
 * - Offset: 1; MF: 0
2603
 *
2604
 * Only the fragments with offset 0 and 1 should be reassembled.
2605
 */
2606
static int DefragMfIpv6Test(void)
2607
{
2608
    int ip_id = 9;
2609
    Packet *p = NULL;
2610
2611
    DefragInit();
2612
2613
    Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2614
    Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2615
    Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2616
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2617
2618
    p = Defrag(NULL, NULL, p1);
2619
    FAIL_IF_NOT_NULL(p);
2620
2621
    p = Defrag(NULL, NULL, p2);
2622
    FAIL_IF_NOT_NULL(p);
2623
2624
    /* This should return a packet as MF=0. */
2625
    p = Defrag(NULL, NULL, p3);
2626
    FAIL_IF_NULL(p);
2627
2628
    /* For IPv6 the expected length is just the length of the payload
2629
     * of 2 fragments, so 16. */
2630
    FAIL_IF(IPV6_GET_PLEN(p) != 16);
2631
2632
    /* Verify the payload of the IPv4 packet. */
2633
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2634
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
2635
2636
    SCFree(p1);
2637
    SCFree(p2);
2638
    SCFree(p3);
2639
    SCFree(p);
2640
    DefragDestroy();
2641
    PASS;
2642
}
2643
2644
/**
2645
 * \brief Test that fragments that match other than the proto don't
2646
 * actually get matched.
2647
 */
2648
static int DefragTestBadProto(void)
2649
{
2650
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2651
    int id = 12;
2652
2653
    DefragInit();
2654
2655
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2656
    FAIL_IF_NULL(p1);
2657
    p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2658
    FAIL_IF_NULL(p2);
2659
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2660
    FAIL_IF_NULL(p3);
2661
2662
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2663
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2664
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2665
2666
    SCFree(p1);
2667
    SCFree(p2);
2668
    SCFree(p3);
2669
2670
    DefragDestroy();
2671
    PASS;
2672
}
2673
2674
/**
2675
 * \test Test a report Linux overlap issue that doesn't appear to be
2676
 *     covered by the Sturges/Novak tests above.
2677
 */
2678
static int DefragTestJeremyLinux(void)
2679
{
2680
    uint8_t expected[] = "AAAAAAAA"
2681
                         "AAAAAAAA"
2682
                         "AAAAAAAA"
2683
                         "CCCCCCCC"
2684
                         "CCCCCCCC"
2685
                         "CCCCCCCC"
2686
                         "CCCCCCCC"
2687
                         "CCCCCCCC"
2688
                         "CCCCCCCC"
2689
                         "BBBBBBBB"
2690
                         "BBBBBBBB"
2691
                         "DDDDDDDD"
2692
                         "DDDDDD";
2693
2694
    DefragInit();
2695
    default_policy = DEFRAG_POLICY_LINUX;
2696
2697
    int id = 1;
2698
    Packet *packets[4];
2699
    int i = 0;
2700
2701
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2702
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2703
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2704
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2705
2706
    Packet *r = Defrag(NULL, NULL, packets[0]);
2707
    FAIL_IF_NOT_NULL(r);
2708
2709
    r = Defrag(NULL, NULL, packets[1]);
2710
    FAIL_IF_NOT_NULL(r);
2711
2712
    r = Defrag(NULL, NULL, packets[2]);
2713
    FAIL_IF_NOT_NULL(r);
2714
2715
    r = Defrag(NULL, NULL, packets[3]);
2716
    FAIL_IF_NULL(r);
2717
2718
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2719
2720
    for (i = 0; i < 4; i++) {
2721
        SCFree(packets[i]);
2722
    }
2723
    SCFree(r);
2724
2725
    DefragDestroy();
2726
    PASS;
2727
}
2728
2729
/**
2730
 * | 0        | 8        | 16       | 24       | 32       |
2731
 * |----------|----------|----------|----------|----------|
2732
 * |                                  AAAAAAAA | AAAAAAAA |
2733
 * |          | BBBBBBBB | BBBBBBBB |          |          |
2734
 * |          |          | CCCCCCCC | CCCCCCCC |          |
2735
 * | DDDDDDDD |          |          |          |          |
2736
 *
2737
 * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
2738
 */
2739
static int DefragBsdFragmentAfterNoMfIpv4Test(void)
2740
{
2741
    DefragInit();
2742
    default_policy = DEFRAG_POLICY_BSD;
2743
    Packet *packets[4];
2744
2745
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2746
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2747
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2748
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2749
2750
    Packet *r = Defrag(NULL, NULL, packets[0]);
2751
    FAIL_IF_NOT_NULL(r);
2752
2753
    r = Defrag(NULL, NULL, packets[1]);
2754
    FAIL_IF_NOT_NULL(r);
2755
2756
    r = Defrag(NULL, NULL, packets[2]);
2757
    FAIL_IF_NOT_NULL(r);
2758
2759
    r = Defrag(NULL, NULL, packets[3]);
2760
    FAIL_IF_NULL(r);
2761
2762
    // clang-format off
2763
    uint8_t expected[] = {
2764
  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2765
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2766
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2767
  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2768
  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2769
    };
2770
    // clang-format on
2771
2772
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2773
        printf("Expected:\n");
2774
        PrintRawDataFp(stdout, expected, sizeof(expected));
2775
        printf("Got:\n");
2776
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2777
        FAIL;
2778
    }
2779
2780
    DefragDestroy();
2781
    PASS;
2782
}
2783
2784
static int DefragBsdFragmentAfterNoMfIpv6Test(void)
2785
{
2786
    DefragInit();
2787
    default_policy = DEFRAG_POLICY_BSD;
2788
    Packet *packets[4];
2789
2790
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2791
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2792
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2793
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2794
2795
    Packet *r = Defrag(NULL, NULL, packets[0]);
2796
    FAIL_IF_NOT_NULL(r);
2797
2798
    r = Defrag(NULL, NULL, packets[1]);
2799
    FAIL_IF_NOT_NULL(r);
2800
2801
    r = Defrag(NULL, NULL, packets[2]);
2802
    FAIL_IF_NOT_NULL(r);
2803
2804
    r = Defrag(NULL, NULL, packets[3]);
2805
    FAIL_IF_NULL(r);
2806
2807
    // clang-format off
2808
    uint8_t expected[] = {
2809
  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2810
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2811
  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2812
  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2813
  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2814
    };
2815
    // clang-format on
2816
2817
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
2818
        printf("Expected:\n");
2819
        PrintRawDataFp(stdout, expected, sizeof(expected));
2820
        printf("Got:\n");
2821
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2822
        FAIL;
2823
    }
2824
2825
    DefragDestroy();
2826
    PASS;
2827
}
2828
2829
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
2830
{
2831
    DefragInit();
2832
    default_policy = DEFRAG_POLICY_BSD;
2833
    Packet *packets[4];
2834
2835
    /* Packet 1: off=16, mf=1 */
2836
    packets[0] = BuildIpv4TestPacketWithContent(
2837
            IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
2838
2839
    /* Packet 2: off=8, mf=1 */
2840
    packets[1] = BuildIpv4TestPacketWithContent(
2841
            IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
2842
2843
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2844
    packets[2] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
2845
2846
    /* Packet 4: off=8, mf=1 */
2847
    packets[3] =
2848
            BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
2849
2850
    Packet *r = Defrag(NULL, NULL, packets[0]);
2851
    FAIL_IF_NOT_NULL(r);
2852
2853
    r = Defrag(NULL, NULL, packets[1]);
2854
    FAIL_IF_NOT_NULL(r);
2855
2856
    r = Defrag(NULL, NULL, packets[2]);
2857
    FAIL_IF_NOT_NULL(r);
2858
2859
    r = Defrag(NULL, NULL, packets[3]);
2860
    FAIL_IF_NULL(r);
2861
2862
    // clang-format off
2863
    const uint8_t expected[] = {
2864
  // AACCBBDD
2865
  // AACCDDBB
2866
  // AABBDDCC
2867
  // DDCCBBAA
2868
  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2869
  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2870
  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2871
  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2872
    };
2873
    // clang-format on
2874
2875
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
2876
2877
    DefragDestroy();
2878
    PASS;
2879
}
2880
2881
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
2882
{
2883
    DefragInit();
2884
    default_policy = DEFRAG_POLICY_BSD;
2885
    Packet *packets[4];
2886
2887
    /* Packet 1: off=16, mf=1 */
2888
    packets[0] = BuildIpv6TestPacketWithContent(
2889
            IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
2890
2891
    /* Packet 2: off=8, mf=1 */
2892
    packets[1] = BuildIpv6TestPacketWithContent(
2893
            IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
2894
2895
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2896
    packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
2897
2898
    /* Packet 4: off=8, mf=1 */
2899
    packets[3] =
2900
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
2901
2902
    Packet *r = Defrag(NULL, NULL, packets[0]);
2903
    FAIL_IF_NOT_NULL(r);
2904
2905
    r = Defrag(NULL, NULL, packets[1]);
2906
    FAIL_IF_NOT_NULL(r);
2907
2908
    r = Defrag(NULL, NULL, packets[2]);
2909
    FAIL_IF_NOT_NULL(r);
2910
2911
    r = Defrag(NULL, NULL, packets[3]);
2912
    FAIL_IF_NULL(r);
2913
2914
    // clang-format off
2915
    const uint8_t expected[] = {
2916
  // AACCBBDD
2917
  // AACCDDBB
2918
  // AABBDDCC
2919
  // DDCCBBAA
2920
  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2921
  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2922
  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2923
  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2924
    };
2925
    // clang-format on
2926
2927
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
2928
2929
    DefragDestroy();
2930
    PASS;
2931
}
2932
2933
/**
2934
 * #### Input
2935
 *
2936
 * | 96 (0)   | 104 (8)  | 112 (16) | 120 (24) |
2937
 * |----------|----------|----------|----------|
2938
 * |          | EEEEEEEE | EEEEEEEE | EEEEEEEE |
2939
 * | MMMMMMMM | MMMMMMMM | MMMMMMMM |          |
2940
 *
2941
 * #### Expected Output
2942
 *
2943
 * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
2944
 */
2945
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
2946
{
2947
    DefragInit();
2948
    default_policy = DEFRAG_POLICY_BSD;
2949
    Packet *packets[2];
2950
2951
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2952
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2953
2954
    Packet *r = Defrag(NULL, NULL, packets[0]);
2955
    FAIL_IF_NOT_NULL(r);
2956
2957
    r = Defrag(NULL, NULL, packets[1]);
2958
    FAIL_IF_NULL(r);
2959
2960
    // clang-format off
2961
    const uint8_t expected[] = {
2962
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2963
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2964
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2965
  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
2966
    };
2967
    // clang-format on
2968
2969
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2970
        printf("Expected:\n");
2971
        PrintRawDataFp(stdout, expected, sizeof(expected));
2972
        printf("Got:\n");
2973
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2974
        FAIL;
2975
    }
2976
2977
    PASS;
2978
}
2979
2980
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
2981
{
2982
    DefragInit();
2983
    default_policy = DEFRAG_POLICY_BSD;
2984
    Packet *packets[2];
2985
2986
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2987
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2988
2989
    Packet *r = Defrag(NULL, NULL, packets[0]);
2990
    FAIL_IF_NOT_NULL(r);
2991
2992
    r = Defrag(NULL, NULL, packets[1]);
2993
    FAIL_IF_NULL(r);
2994
2995
    // clang-format off
2996
    const uint8_t expected[] = {
2997
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2998
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2999
  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3000
  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3001
    };
3002
    // clang-format on
3003
3004
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3005
        printf("Expected:\n");
3006
        PrintRawDataFp(stdout, expected, sizeof(expected));
3007
        printf("Got:\n");
3008
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3009
        FAIL;
3010
    }
3011
3012
    PASS;
3013
}
3014
3015
/**
3016
 * Reassembly should fail.
3017
 *
3018
 * |0       |8       |16      |24      |32      |40      |48      |
3019
 * |========|========|========|========|========|========|========|
3020
 * |        |        |AABBCCDD|AABBDDCC|        |        |        |
3021
 * |        |        |        |        |        |AACCBBDD|        |
3022
 * |        |AACCDDBB|AADDBBCC|        |        |        |        |
3023
 * |ZZZZZZZZ|        |        |        |        |        |        |
3024
 * |        |        |        |        |        |        |DDCCBBAA|
3025
 */
3026
static int DefragBsdMissingFragmentIpv4Test(void)
3027
{
3028
    DefragInit();
3029
    default_policy = DEFRAG_POLICY_BSD;
3030
    Packet *packets[5];
3031
3032
    packets[0] = BuildIpv4TestPacketWithContent(
3033
            IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
3034
3035
    packets[1] =
3036
            BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
3037
3038
    packets[2] = BuildIpv4TestPacketWithContent(
3039
            IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
3040
3041
    /* ICMP header. */
3042
    packets[3] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
3043
3044
    packets[4] =
3045
            BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
3046
3047
    Packet *r = Defrag(NULL, NULL, packets[0]);
3048
    FAIL_IF_NOT_NULL(r);
3049
3050
    r = Defrag(NULL, NULL, packets[1]);
3051
    FAIL_IF_NOT_NULL(r);
3052
3053
    r = Defrag(NULL, NULL, packets[2]);
3054
    FAIL_IF_NOT_NULL(r);
3055
3056
    r = Defrag(NULL, NULL, packets[3]);
3057
    FAIL_IF_NOT_NULL(r);
3058
3059
    r = Defrag(NULL, NULL, packets[4]);
3060
    FAIL_IF_NOT_NULL(r);
3061
3062
#if 0
3063
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3064
#endif
3065
3066
    for (int i = 0; i < 5; i++) {
3067
        SCFree(packets[i]);
3068
    }
3069
3070
    DefragDestroy();
3071
3072
    PASS;
3073
}
3074
3075
static int DefragBsdMissingFragmentIpv6Test(void)
3076
{
3077
    DefragInit();
3078
    default_policy = DEFRAG_POLICY_BSD;
3079
    Packet *packets[5];
3080
3081
    packets[0] = BuildIpv6TestPacketWithContent(
3082
            IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
3083
3084
    packets[1] =
3085
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
3086
3087
    packets[2] = BuildIpv6TestPacketWithContent(
3088
            IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
3089
3090
    /* ICMP header. */
3091
    packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
3092
3093
    packets[4] =
3094
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
3095
3096
    Packet *r = Defrag(NULL, NULL, packets[0]);
3097
    FAIL_IF_NOT_NULL(r);
3098
3099
    r = Defrag(NULL, NULL, packets[1]);
3100
    FAIL_IF_NOT_NULL(r);
3101
3102
    r = Defrag(NULL, NULL, packets[2]);
3103
    FAIL_IF_NOT_NULL(r);
3104
3105
    r = Defrag(NULL, NULL, packets[3]);
3106
    FAIL_IF_NOT_NULL(r);
3107
3108
    r = Defrag(NULL, NULL, packets[4]);
3109
    FAIL_IF_NOT_NULL(r);
3110
3111
#if 0
3112
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3113
#endif
3114
3115
    for (int i = 0; i < 5; i++) {
3116
        SCFree(packets[i]);
3117
    }
3118
3119
    DefragDestroy();
3120
3121
    PASS;
3122
}
3123
3124
#endif /* UNITTESTS */
3125
3126
void DefragRegisterTests(void)
3127
0
{
3128
#ifdef UNITTESTS
3129
    UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
3130
    UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
3131
    UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
3132
    UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
3133
            DefragSturgesNovakLinuxIpv4Test);
3134
    UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
3135
                   DefragSturgesNovakWindowsIpv4Test);
3136
    UtRegisterTest("DefragSturgesNovakSolarisTest",
3137
                   DefragSturgesNovakSolarisTest);
3138
    UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
3139
    UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
3140
3141
    UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
3142
    UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
3143
3144
    UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
3145
    UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
3146
    UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
3147
    UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
3148
    UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
3149
    UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
3150
    UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
3151
    UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
3152
3153
    UtRegisterTest("DefragVlanTest", DefragVlanTest);
3154
    UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
3155
    UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
3156
    UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
3157
    UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
3158
    UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
3159
    UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
3160
    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
3161
3162
    UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
3163
3164
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
3165
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
3166
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
3167
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
3168
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
3169
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
3170
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2",
3171
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
3172
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
3173
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
3174
    UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
3175
    UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
3176
#endif /* UNITTESTS */
3177
0
}