• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jasonish / suricata / 23019292042

12 Mar 2026 07:08PM UTC coverage: 79.245% (-0.004%) from 79.249%
23019292042

push

github

jasonish
github-ci: add schema ordering check for yaml schema

266163 of 335873 relevant lines covered (79.25%)

4877167.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.36
/src/defrag.c
1
/* Copyright (C) 2007-2024 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Endace Technology Limited, Jason Ish <jason.ish@endace.com>
22
 *
23
 * Defragmentation module.
24
 * References:
25
 *   - RFC 815
26
 *   - OpenBSD PF's IP normalization (pf_norm.c)
27
 *
28
 * \todo pool for frag packet storage
29
 * \todo policy bsd-right
30
 * \todo profile hash function
31
 * \todo log anomalies
32
 */
33

34
#include "suricata-common.h"
35

36
#include "queue.h"
37

38
#include "suricata.h"
39
#include "threads.h"
40
#include "conf.h"
41
#include "decode-ipv6.h"
42
#include "util-hashlist.h"
43
#include "util-pool.h"
44
#include "util-time.h"
45
#include "util-print.h"
46
#include "util-debug.h"
47
#include "util-fix_checksum.h"
48
#include "util-random.h"
49
#include "stream-tcp-private.h"
50
#include "stream-tcp-reassemble.h"
51
#include "util-host-os-info.h"
52
#include "util-validate.h"
53

54
#include "defrag.h"
55
#include "defrag-hash.h"
56
#include "defrag-config.h"
57

58
#include "tmqh-packetpool.h"
59
#include "decode.h"
60

61
#ifdef UNITTESTS
62
#include "util-unittest.h"
63
#endif
64

65
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
1,465✔
66
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
747✔
67

68
/**
69
 * Default timeout (in seconds) before a defragmentation tracker will
70
 * be released.
71
 */
72
#define TIMEOUT_DEFAULT 60
747✔
73

74
/**
75
 * Maximum allowed timeout, 24 hours.
76
 */
77
#define TIMEOUT_MAX (60 * 60 * 24)
2,908✔
78

79
/**
80
 * Minimum allowed timeout, 1 second.
81
 */
82
#define TIMEOUT_MIN 1
2,908✔
83

84
/** Fragment reassembly policies. */
85
enum defrag_policies {
86
    DEFRAG_POLICY_FIRST = 1,
87
    DEFRAG_POLICY_LAST,
88
    DEFRAG_POLICY_BSD,
89
    DEFRAG_POLICY_BSD_RIGHT,
90
    DEFRAG_POLICY_LINUX,
91
    DEFRAG_POLICY_WINDOWS,
92
    DEFRAG_POLICY_SOLARIS,
93

94
    DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
95
};
96

97
static uint8_t default_policy = DEFRAG_POLICY_BSD;
98

99
/** The global DefragContext so all threads operate from the same
100
 * context. */
101
static DefragContext *defrag_context;
102

103
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
187,889,721✔
104

187,889,721✔
105
/**
187,889,721✔
106
 * \brief Reset a frag for reuse in a pool.
187,889,721✔
107
 */
187,889,721✔
108
static void
187,889,721✔
109
DefragFragReset(Frag *frag)
187,889,721✔
110
{
187,889,721✔
111
    if (frag->pkt != NULL)
248,118✔
112
        SCFree(frag->pkt);
248,118✔
113
    memset(frag, 0, sizeof(*frag));
248,118✔
114
}
248,118✔
115

116
/**
117
 * \brief Allocate a new frag for use in a pool.
118
 */
119
static int
120
DefragFragInit(void *data, void *initdata)
121
{
119,810,243✔
122
    Frag *frag = data;
119,810,243✔
123

124
    memset(frag, 0, sizeof(*frag));
119,810,243✔
125
    return 1;
119,810,243✔
126
}
119,810,243✔
127

128
/**
129
 * \brief Free all frags associated with a tracker.
130
 */
131
void
132
DefragTrackerFreeFrags(DefragTracker *tracker)
133
{
183,560,647✔
134
    Frag *frag, *tmp;
183,560,647✔
135

136
    /* Lock the frag pool as we'll be return items to it. */
137
    SCMutexLock(&defrag_context->frag_pool_lock);
183,560,647✔
138

139
    RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
183,670,817✔
140
        RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
241,003✔
141
        DefragFragReset(frag);
241,003✔
142
        PoolReturn(defrag_context->frag_pool, frag);
241,003✔
143
    }
241,003✔
144

145
    SCMutexUnlock(&defrag_context->frag_pool_lock);
183,560,647✔
146
}
183,560,647✔
147

148
/**
149
 * \brief Create a new DefragContext.
150
 *
151
 * \retval On success a return an initialized DefragContext, otherwise
152
 *     NULL will be returned.
153
 */
154
static DefragContext *
155
DefragContextNew(void)
156
{
3,655✔
157
    DefragContext *dc;
3,655✔
158

159
    dc = SCCalloc(1, sizeof(*dc));
3,655✔
160
    if (unlikely(dc == NULL))
3,655✔
161
        return NULL;
×
162

163
    /* Initialize the pool of trackers. */
164
    intmax_t tracker_pool_size;
3,655✔
165
    if (!SCConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
3,655✔
166
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
734✔
167
    }
734✔
168

169
    /* Initialize the pool of frags. */
170
    intmax_t frag_pool_size;
3,655✔
171
    if (!SCConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0 ||
3,655✔
172
            frag_pool_size > UINT32_MAX) {
3,655✔
173
        frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
747✔
174
    }
747✔
175
    uint32_t frag_pool_prealloc = (uint32_t)frag_pool_size / 2;
3,655✔
176
    dc->frag_pool = PoolInit((uint32_t)frag_pool_size, frag_pool_prealloc, sizeof(Frag), NULL,
3,655✔
177
            DefragFragInit, dc, NULL, NULL);
3,655✔
178
    if (dc->frag_pool == NULL) {
3,655✔
179
        FatalError("Defrag: Failed to initialize fragment pool.");
×
180
    }
×
181
    if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
3,655✔
182
        FatalError("Defrag: Failed to initialize frag pool mutex.");
×
183
    }
×
184

185
    /* Set the default timeout. */
186
    intmax_t timeout;
3,655✔
187
    if (!SCConfGetInt("defrag.timeout", &timeout)) {
3,655✔
188
        dc->timeout = TIMEOUT_DEFAULT;
747✔
189
    } else {
2,971✔
190
        if (timeout < TIMEOUT_MIN) {
2,908✔
191
            FatalError("defrag: Timeout less than minimum allowed value.");
×
192
        }
×
193
        else if (timeout > TIMEOUT_MAX) {
2,908✔
194
            FatalError("defrag: Timeout greater than maximum allowed value.");
×
195
        }
×
196
        dc->timeout = (uint32_t)timeout;
2,908✔
197
    }
2,908✔
198

199
    SCLogDebug("Defrag Initialized:");
3,655✔
200
    SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
3,655✔
201
    SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
3,655✔
202
    SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
3,655✔
203
    SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
3,655✔
204
    SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
3,655✔
205

206
    return dc;
3,655✔
207
}
3,655✔
208

209
static void
210
DefragContextDestroy(DefragContext *dc)
211
{
3,470✔
212
    if (dc == NULL)
3,470✔
213
        return;
×
214

215
    PoolFree(dc->frag_pool);
3,470✔
216
    SCFree(dc);
3,470✔
217
}
3,470✔
218

219
/**
220
 * Attempt to re-assemble a packet.
221
 *
222
 * \param tracker The defragmentation tracker to reassemble from.
223
 */
224
static Packet *
225
Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
226
{
98,342✔
227
    Packet *rp = NULL;
98,342✔
228

229
    /* Should not be here unless we have seen the last fragment. */
230
    if (!tracker->seen_last) {
98,342✔
231
        return NULL;
×
232
    }
×
233

234
    /* Check that we have the first fragment and its of a valid size. */
235
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
98,342✔
236
    if (first == NULL) {
98,342✔
237
        goto done;
×
238
    } else if (first->offset != 0) {
98,342✔
239
        /* Still waiting for the first fragment. */
240
        goto done;
89,145✔
241
    } else if (first->len < sizeof(IPV4Hdr)) {
89,184✔
242
        /* First fragment isn't enough for an IPv6 header. */
243
        goto error_remove_tracker;
×
244
    }
×
245

246
    /* Check that we have all the data. Relies on the fact that
247
     * fragments are inserted in frag_offset order. */
248
    Frag *frag = NULL;
9,197✔
249
    size_t len = 0;
9,197✔
250
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
782,474✔
251
        if (frag->offset > len) {
782,474✔
252
            /* This fragment starts after the end of the previous
253
             * fragment.  We have a hole. */
254
            goto done;
7,239✔
255
        }
7,239✔
256
        else {
775,235✔
257
            /* Update the packet length to the largest known data offset. */
258
            len = MAX(len, frag->offset + frag->data_len);
775,235✔
259
        }
775,235✔
260
    }
782,474✔
261

262
    const IPV4Hdr *oip4h = PacketGetIPv4(p);
1,958✔
263

264
    /* Allocate a Packet for the reassembled packet.  On failure we
265
     * SCFree all the resources held by this tracker. */
266
    rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_RAW_IPPROTO(oip4h));
1,958✔
267
    if (rp == NULL) {
1,958✔
268
        goto error_remove_tracker;
×
269
    }
×
270
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
1,958✔
271
    rp->flags |= PKT_REBUILT_FRAGMENT;
1,958✔
272
    rp->datalink = tracker->datalink;
1,958✔
273

274
    int fragmentable_offset = 0;
1,958✔
275
    uint16_t fragmentable_len = 0;
1,958✔
276
    uint16_t hlen = 0;
1,958✔
277
    int ip_hdr_offset = 0;
1,958✔
278

279
    /* Assume more frags. */
280
    uint16_t prev_offset = 0;
1,958✔
281
    bool more_frags = 1;
1,958✔
282

283
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
30,896✔
284
        SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
30,896✔
285
                frag, frag->data_len, frag->offset, frag->pcap_cnt);
30,896✔
286

287
        /* Previous fragment has no more fragments, and this packet
288
         * doesn't overlap. We're done. */
289
        if (!more_frags && frag->offset > prev_offset) {
30,896✔
290
            break;
76✔
291
        }
76✔
292

293
        if (frag->skip)
30,820✔
294
            continue;
×
295
        if (frag->ltrim >= frag->data_len)
30,820✔
296
            continue;
359✔
297
        if (frag->offset == 0) {
30,461✔
298

299
            if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
1,958✔
300
                goto error_remove_tracker;
×
301

302
            hlen = frag->hlen;
1,958✔
303
            ip_hdr_offset = tracker->ip_hdr_offset;
1,958✔
304

305
            /* This is the start of the fragmentable portion of the
306
             * first packet.  All fragment offsets are relative to
307
             * this. */
308
            fragmentable_offset = tracker->ip_hdr_offset + frag->hlen;
1,958✔
309
            fragmentable_len = frag->data_len;
1,958✔
310
        }
1,958✔
311
        else {
28,503✔
312
            int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
28,503✔
313
            if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
28,503✔
314
                SCLogDebug("Failed re-assemble "
×
315
                           "fragmented packet, exceeds size of packet buffer.");
×
316
                goto error_remove_tracker;
×
317
            }
×
318
            if (PacketCopyDataOffset(rp,
28,503✔
319
                    fragmentable_offset + frag->offset + frag->ltrim,
28,503✔
320
                    frag->pkt + frag->data_offset + frag->ltrim,
28,503✔
321
                    frag->data_len - frag->ltrim) == -1) {
28,503✔
322
                goto error_remove_tracker;
×
323
            }
×
324
            if (frag->offset > UINT16_MAX - frag->data_len) {
28,503✔
325
                SCLogDebug("Failed re-assemble "
×
326
                           "fragmentable_len exceeds UINT16_MAX");
×
327
                goto error_remove_tracker;
×
328
            }
×
329
            if (frag->offset + frag->data_len > fragmentable_len)
28,503✔
330
                fragmentable_len = frag->offset + frag->data_len;
26,184✔
331
        }
28,503✔
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
        more_frags = frag->more_frags;
30,461✔
342
        prev_offset = frag->offset;
30,461✔
343
    }
30,461✔
344

345
    SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
1,958✔
346
            fragmentable_len);
1,958✔
347

348
    IPV4Hdr *ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
1,958✔
349
    uint16_t old = ip4h->ip_len + ip4h->ip_off;
1,958✔
350
    DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len);
1,958✔
351
    ip4h->ip_len = htons(fragmentable_len + hlen);
1,958✔
352
    ip4h->ip_off = 0;
1,958✔
353
    ip4h->ip_csum = FixChecksum(ip4h->ip_csum, old, ip4h->ip_len + ip4h->ip_off);
1,958✔
354
    SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
1,958✔
355

356
    tracker->remove = 1;
1,958✔
357
    DefragTrackerFreeFrags(tracker);
1,958✔
358
done:
98,342✔
359
    return rp;
98,342✔
360

361
error_remove_tracker:
×
362
    tracker->remove = 1;
×
363
    DefragTrackerFreeFrags(tracker);
×
364
    if (rp != NULL)
×
365
        PacketFreeOrRelease(rp);
×
366
    return NULL;
×
367
}
1,958✔
368

369
/**
370
 * Attempt to re-assemble a packet.
371
 *
372
 * \param tracker The defragmentation tracker to reassemble from.
373
 */
374
static Packet *
375
Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
376
{
9,009✔
377
    Packet *rp = NULL;
9,009✔
378

379
    /* Should not be here unless we have seen the last fragment. */
380
    if (!tracker->seen_last)
9,009✔
381
        return NULL;
×
382

383
    /* Check that we have the first fragment and its of a valid size. */
384
    Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
9,009✔
385
    if (first == NULL) {
9,009✔
386
        goto done;
×
387
    } else if (first->offset != 0) {
9,009✔
388
        /* Still waiting for the first fragment. */
389
        goto done;
1,908✔
390
    } else if (first->len < sizeof(IPV6Hdr)) {
7,101✔
391
        /* First fragment isn't enough for an IPv6 header. */
392
        goto error_remove_tracker;
×
393
    }
×
394

395
    /* Check that we have all the data. Relies on the fact that
396
     * fragments are inserted if frag_offset order. */
397
    size_t len = 0;
7,101✔
398
    Frag *frag = NULL;
7,101✔
399
    RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
33,003✔
400
        if (frag->skip) {
33,003✔
401
            continue;
×
402
        }
×
403

404
        if (frag == first) {
33,003✔
405
            if (frag->offset != 0) {
×
406
                goto done;
×
407
            }
×
408
            len = frag->data_len;
×
409
        }
×
410
        else {
33,003✔
411
            if (frag->offset > len) {
33,003✔
412
                /* This fragment starts after the end of the previous
413
                 * fragment.  We have a hole. */
414
                goto done;
4,396✔
415
            }
4,396✔
416
            else {
28,607✔
417
                len = MAX(len, frag->offset + frag->data_len);
28,607✔
418
            }
28,607✔
419
        }
33,003✔
420
    }
33,003✔
421

422
    const IPV6Hdr *oip6h = PacketGetIPv6(p);
2,705✔
423

424
    /* Allocate a Packet for the reassembled packet.  On failure we
425
     * SCFree all the resources held by this tracker. */
426
    rp = PacketDefragPktSetup(
2,705✔
427
            p, (const uint8_t *)oip6h, IPV6_GET_RAW_PLEN(oip6h) + sizeof(IPV6Hdr), 0);
2,705✔
428
    if (rp == NULL) {
2,705✔
429
        goto error_remove_tracker;
×
430
    }
×
431
    PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
2,705✔
432
    rp->flags |= PKT_REBUILT_FRAGMENT;
2,705✔
433
    rp->datalink = tracker->datalink;
2,705✔
434

435
    uint16_t unfragmentable_len = 0;
2,705✔
436
    int fragmentable_offset = 0;
2,705✔
437
    uint16_t fragmentable_len = 0;
2,705✔
438
    int ip_hdr_offset = 0;
2,705✔
439
    uint8_t next_hdr = 0;
2,705✔
440

441
    /* Assume more frags. */
442
    uint16_t prev_offset = 0;
2,705✔
443
    bool more_frags = 1;
2,705✔
444

445
    RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
9,577✔
446
        if (!more_frags && frag->offset > prev_offset) {
9,577✔
447
            break;
528✔
448
        }
528✔
449
        if (frag->skip)
9,049✔
450
            continue;
×
451
        if (frag->data_len - frag->ltrim <= 0)
9,049✔
452
            continue;
1,602✔
453
        if (frag->offset == 0) {
7,447✔
454
            IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
2,705✔
455
                frag->frag_hdr_offset);
2,705✔
456
            next_hdr = frag_hdr->ip6fh_nxt;
2,705✔
457

458
            /* This is the first packet, we use this packets link and
459
             * IPv6 headers. We also copy in its data, but remove the
460
             * fragmentation header. */
461
            if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
2,705✔
462
                goto error_remove_tracker;
×
463
            if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
2,705✔
464
                frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
2,705✔
465
                frag->data_len) == -1)
2,705✔
466
                goto error_remove_tracker;
×
467
            ip_hdr_offset = tracker->ip_hdr_offset;
2,705✔
468

469
            /* This is the start of the fragmentable portion of the
470
             * first packet.  All fragment offsets are relative to
471
             * this. */
472
            fragmentable_offset = frag->frag_hdr_offset;
2,705✔
473
            fragmentable_len = frag->data_len;
2,705✔
474

475
            /* unfragmentable part is the part between the ipv6 header
476
             * and the frag header. */
477
            DEBUG_VALIDATE_BUG_ON(fragmentable_offset < ip_hdr_offset + IPV6_HEADER_LEN);
2,705✔
478
            DEBUG_VALIDATE_BUG_ON(
2,705✔
479
                    fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN > UINT16_MAX);
2,705✔
480
            unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN);
2,705✔
481
            if (unfragmentable_len >= fragmentable_offset)
2,705✔
482
                goto error_remove_tracker;
×
483
        }
2,705✔
484
        else {
4,742✔
485
            if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
4,742✔
486
                frag->pkt + frag->data_offset + frag->ltrim,
4,742✔
487
                frag->data_len - frag->ltrim) == -1)
4,742✔
488
                goto error_remove_tracker;
×
489
            if (frag->offset + frag->data_len > fragmentable_len)
4,742✔
490
                fragmentable_len = frag->offset + frag->data_len;
4,658✔
491
        }
4,742✔
492

493
        /* Even if this fragment is flagged as having no more
494
         * fragments, still continue. The next fragment may have the
495
         * same offset with data that is preferred.
496
         *
497
         * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
498
         *
499
         * This is due to not all fragments being completely trimmed,
500
         * but relying on the copy ordering. */
501
        more_frags = frag->more_frags;
7,447✔
502
        prev_offset = frag->offset;
7,447✔
503
    }
7,447✔
504

505
    IPV6Hdr *ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + tracker->ip_hdr_offset);
2,705✔
506
    DEBUG_VALIDATE_BUG_ON(unfragmentable_len > UINT16_MAX - fragmentable_len);
2,705✔
507
    ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
2,705✔
508
    /* if we have no unfragmentable part, so no ext hdrs before the frag
509
     * header, we need to update the ipv6 headers next header field. This
510
     * points to the frag header, and we will make it point to the layer
511
     * directly after the frag header. */
512
    if (unfragmentable_len == 0)
2,705✔
513
        ip6h->s_ip6_nxt = next_hdr;
1,903✔
514
    SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
2,705✔
515
            unfragmentable_len + fragmentable_len);
2,705✔
516

517
    tracker->remove = 1;
2,705✔
518
    DefragTrackerFreeFrags(tracker);
2,705✔
519
done:
9,009✔
520
    return rp;
9,009✔
521

522
error_remove_tracker:
×
523
    tracker->remove = 1;
×
524
    DefragTrackerFreeFrags(tracker);
×
525
    if (rp != NULL)
×
526
        PacketFreeOrRelease(rp);
×
527
    return NULL;
×
528
}
2,705✔
529

530
/**
531
 * The RB_TREE compare function for fragments.
532
 *
533
 * When it comes to adding fragments, we want subsequent ones with the
534
 * same offset to be treated as greater than, so we don't have an
535
 * equal return value here.
536
 */
537
int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
1,939,065✔
538
    if (a->offset < b->offset) {
1,939,065✔
539
        return -1;
417,080✔
540
    }
417,080✔
541
    return 1;
1,521,985✔
542
}
1,939,065✔
543

544
/**
545
 * Insert a new IPv4/IPv6 fragment into a tracker.
546
 *
547
 * \todo Allocate packet buffers from a pool.
548
 */
549
static Packet *
550
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
551
{
448,650✔
552
    Packet *r = NULL;
448,650✔
553
    uint16_t ltrim = 0;
448,650✔
554

555
    bool more_frags;
448,650✔
556
    uint16_t frag_offset;
448,650✔
557

558
    /* IPv4 header length - IPv4 only. */
559
    uint8_t hlen = 0;
448,650✔
560

561
    /* This is the offset of the start of the data in the packet that
562
     * falls after the IP header. */
563
    uint16_t data_offset;
448,650✔
564

565
    /* The length of the (fragmented) data.  This is the length of the
566
     * data that falls after the IP header. */
567
    uint16_t data_len;
448,650✔
568

569
    /* Where the fragment ends. */
570
    uint16_t frag_end;
448,650✔
571

572
    /* Offset in the packet to the IPv6 header. */
573
    uint16_t ip_hdr_offset;
448,650✔
574

575
    /* Offset in the packet to the IPv6 frag header. IPv6 only. */
576
    uint16_t frag_hdr_offset = 0;
448,650✔
577

578
    /* Address family */
579
    int af = tracker->af;
448,650✔
580

581
    /* settings for updating a payload when an ip6 fragment with
582
     * unfragmentable exthdrs are encountered. */
583
    uint32_t ip6_nh_set_offset = 0;
448,650✔
584
    uint8_t ip6_nh_set_value = 0;
448,650✔
585

586
#ifdef DEBUG
587
    uint64_t pcap_cnt = PcapPacketCntGet(p);
588
#endif
589

590
    if (tracker->af == AF_INET) {
448,650✔
591
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
186,139✔
592
        more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
186,139✔
593
        frag_offset = (uint16_t)((uint16_t)IPV4_GET_RAW_FRAGOFFSET(ip4h) << (uint16_t)3);
186,139✔
594
        hlen = IPV4_GET_RAW_HLEN(ip4h);
186,139✔
595
        data_offset = (uint16_t)((uint8_t *)ip4h + hlen - GET_PKT_DATA(p));
186,139✔
596
        data_len = IPV4_GET_RAW_IPLEN(ip4h) - hlen;
186,139✔
597
        frag_end = frag_offset + data_len;
186,139✔
598
        ip_hdr_offset = (uint16_t)((uint8_t *)ip4h - GET_PKT_DATA(p));
186,139✔
599

600
        /* Ignore fragment if the end of packet extends past the
601
         * maximum size of a packet. */
602
        if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
186,139✔
603
            ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
2,096✔
604
            return NULL;
2,096✔
605
        }
2,096✔
606
    }
186,139✔
607
    else if (tracker->af == AF_INET6) {
262,511✔
608
        const IPV6Hdr *ip6h = PacketGetIPv6(p);
262,511✔
609
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
262,511✔
610
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
262,511✔
611
        data_offset = p->l3.vars.ip6.eh.fh_data_offset;
262,511✔
612
        data_len = p->l3.vars.ip6.eh.fh_data_len;
262,511✔
613
        frag_end = frag_offset + data_len;
262,511✔
614
        ip_hdr_offset = (uint16_t)((uint8_t *)ip6h - GET_PKT_DATA(p));
262,511✔
615
        frag_hdr_offset = p->l3.vars.ip6.eh.fh_header_offset;
262,511✔
616

617
        SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
262,511✔
618
                "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
262,511✔
619
                more_frags ? "true" : "false", frag_offset, data_offset,
262,511✔
620
                data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
262,511✔
621

622
        /* handle unfragmentable exthdrs */
623
        if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
262,511✔
624
            SCLogDebug("we have exthdrs before fraghdr %u bytes",
240,483✔
625
                    (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
240,483✔
626

627
            /* get the offset of the 'next' field in exthdr before the FH,
628
             * relative to the buffer start */
629

630
            /* store offset and FH 'next' value for updating frag buffer below */
631
            ip6_nh_set_offset = p->l3.vars.ip6.eh.fh_prev_hdr_offset;
240,483✔
632
            ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
240,483✔
633
            SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
240,483✔
634
        }
240,483✔
635

636
        /* Ignore fragment if the end of packet extends past the
637
         * maximum size of a packet. */
638
        if (frag_offset + data_len > IPV6_MAXPACKET) {
262,511✔
639
            ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
325✔
640
            return NULL;
325✔
641
        }
325✔
642
    }
262,511✔
643
    else {
×
644
        DEBUG_VALIDATE_BUG_ON(1);
×
645
        return NULL;
×
646
    }
×
647

648
    /* Update timeout. */
649
    tracker->timeout = SCTIME_FROM_SECS(SCTIME_SECS(p->ts) + tracker->host_timeout);
446,229✔
650

651
    Frag *prev = NULL, *next = NULL;
446,229✔
652
    bool overlap = false;
446,229✔
653
    ltrim = 0;
446,229✔
654

655
    if (!RB_EMPTY(&tracker->fragment_tree)) {
446,229✔
656
        Frag key = {
259,117✔
657
            .offset = frag_offset - 1,
259,117✔
658
        };
259,117✔
659
        next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
259,117✔
660
        if (next == NULL) {
259,117✔
661
            prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
126,649✔
662
            next = IP_FRAGMENTS_RB_NEXT(prev);
126,649✔
663
        } else {
153,913✔
664
            prev = IP_FRAGMENTS_RB_PREV(next);
132,468✔
665
            if (prev == NULL) {
132,468✔
666
                prev = next;
71,138✔
667
                next = IP_FRAGMENTS_RB_NEXT(prev);
71,138✔
668
            }
71,138✔
669
        }
132,468✔
670
        while (prev != NULL) {
11,383,679✔
671
            if (prev->skip) {
11,353,869✔
672
                goto next;
×
673
            }
×
674
            if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
11,353,869✔
675
                overlap = true;
216,918✔
676
            }
216,918✔
677

678
            switch (tracker->policy) {
11,353,869✔
679
            case DEFRAG_POLICY_BSD:
10,829,544✔
680
                if (frag_offset < prev->offset + prev->data_len) {
10,829,544✔
681
                    if (prev->offset <= frag_offset) {
229,228✔
682
                        /* We prefer the data from the previous
683
                         * fragment, so trim off the data in the new
684
                         * fragment that exists in the previous
685
                         * fragment. */
686
                        uint16_t prev_end = prev->offset + prev->data_len;
213,886✔
687
                        if (prev_end > frag_end) {
213,886✔
688
                            /* Just skip. */
689
                            /* TODO: Set overlap flag. */
690
                            goto done;
1,539✔
691
                        }
1,539✔
692
                        ltrim = prev_end - frag_offset;
212,347✔
693

694
                        if ((next != NULL) && (frag_end > next->offset)) {
212,347✔
695
                            next->ltrim = frag_end - next->offset;
76,544✔
696
                        }
76,544✔
697

698
                        goto insert;
212,347✔
699
                    }
213,886✔
700

701
                    /* If the end of this fragment overlaps the start
702
                     * of the previous fragment, then trim up the
703
                     * start of previous fragment so this fragment is
704
                     * used.
705
                     *
706
                     * See:
707
                     * DefragBsdSubsequentOverlapsStartOfOriginal.
708
                     */
709
                    if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
15,342✔
710
                        uint16_t prev_ltrim = frag_end - prev->offset;
2,957✔
711
                        if (prev_ltrim > prev->ltrim) {
2,957✔
712
                            prev->ltrim = prev_ltrim;
2,957✔
713
                        }
2,957✔
714
                    }
2,957✔
715

716
                    if ((next != NULL) && (frag_end > next->offset)) {
15,342✔
717
                        next->ltrim = frag_end - next->offset;
293✔
718
                    }
293✔
719

720
                    goto insert;
15,342✔
721
                }
229,228✔
722
                break;
10,600,316✔
723
            case DEFRAG_POLICY_LINUX:
10,600,323✔
724
                /* Check if new fragment overlaps the end of previous
725
                 * fragment, if it does, trim the new fragment.
726
                 *
727
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
728
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
729
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
730
                 */
731
                if (prev->offset + prev->ltrim < frag_offset + ltrim &&
118✔
732
                        prev->offset + prev->data_len > frag_offset + ltrim) {
118✔
733
                    ltrim += prev->offset + prev->data_len - frag_offset;
6✔
734
                }
6✔
735

736
                /* Check if new fragment overlaps the beginning of
737
                 * previous fragment, if it does, tim the previous
738
                 * fragment.
739
                 *
740
                 * Old:          AAAAAAAA AAAAAAAA
741
                 * New: BBBBBBBB BBBBBBBB BBBBBBBB
742
                 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
743
                 */
744
                if (frag_offset + ltrim < prev->offset + prev->ltrim &&
118✔
745
                        frag_end > prev->offset + prev->ltrim) {
118✔
746
                    prev->ltrim += frag_end - (prev->offset + prev->ltrim);
7✔
747
                    goto insert;
7✔
748
                }
7✔
749

750
                /* If the new fragment completely overlaps the
751
                 * previous fragment, mark the previous to be
752
                 * skipped. Re-assembly would succeed without doing
753
                 * this, but this will prevent the bytes from being
754
                 * copied just to be overwritten. */
755
                if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
111✔
756
                        frag_end >= prev->offset + prev->data_len) {
111✔
757
                    prev->skip = 1;
4✔
758
                    goto insert;
4✔
759
                }
4✔
760

761
                break;
107✔
762
            case DEFRAG_POLICY_WINDOWS:
523,893✔
763
                /* If new fragment fits inside a previous fragment, drop it. */
764
                if (frag_offset + ltrim >= prev->offset + ltrim &&
523,892✔
765
                        frag_end <= prev->offset + prev->data_len) {
523,892✔
766
                    goto done;
8✔
767
                }
8✔
768

769
                /* If new fragment starts before and ends after
770
                 * previous fragment, drop the previous fragment. */
771
                if (frag_offset + ltrim < prev->offset + ltrim &&
523,884✔
772
                        frag_end > prev->offset + prev->data_len) {
523,884✔
773
                    prev->skip = 1;
2✔
774
                    goto insert;
2✔
775
                }
2✔
776

777
                /* Check if new fragment overlaps the end of previous
778
                 * fragment, if it does, trim the new fragment.
779
                 *
780
                 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
781
                 * New:          BBBBBBBB BBBBBBBB BBBBBBBB
782
                 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
783
                 */
784
                if (frag_offset + ltrim > prev->offset + prev->ltrim &&
523,882✔
785
                        frag_offset + ltrim < prev->offset + prev->data_len) {
523,882✔
786
                    ltrim += prev->offset + prev->data_len - frag_offset;
2✔
787
                    goto insert;
2✔
788
                }
2✔
789

790
                /* If new fragment starts at same offset as an
791
                 * existing fragment, but ends after it, trim the new
792
                 * fragment. */
793
                if (frag_offset + ltrim == prev->offset + ltrim &&
523,880✔
794
                        frag_end > prev->offset + prev->data_len) {
523,880✔
795
                    ltrim += prev->offset + prev->data_len - frag_offset;
2✔
796
                    goto insert;
2✔
797
                }
2✔
798
                break;
523,878✔
799
            case DEFRAG_POLICY_SOLARIS:
523,884✔
800
                if (frag_offset < prev->offset + prev->data_len) {
98✔
801
                    if (frag_offset >= prev->offset) {
16✔
802
                        ltrim = prev->offset + prev->data_len - frag_offset;
12✔
803
                    }
12✔
804
                    if ((frag_offset < prev->offset) &&
16✔
805
                        (frag_end >= prev->offset + prev->data_len)) {
16✔
806
                        prev->skip = 1;
4✔
807
                    }
4✔
808
                    goto insert;
16✔
809
                }
16✔
810
                break;
82✔
811
            case DEFRAG_POLICY_FIRST:
98✔
812
                if ((frag_offset >= prev->offset) &&
98✔
813
                    (frag_end <= prev->offset + prev->data_len)) {
98✔
814
                    goto done;
8✔
815
                }
8✔
816
                if (frag_offset < prev->offset) {
90✔
817
                    goto insert;
4✔
818
                }
4✔
819
                if (frag_offset < prev->offset + prev->data_len) {
86✔
820
                    ltrim = prev->offset + prev->data_len - frag_offset;
4✔
821
                    goto insert;
4✔
822
                }
4✔
823
                break;
82✔
824
            case DEFRAG_POLICY_LAST:
119✔
825
                if (frag_offset <= prev->offset) {
119✔
826
                    if (frag_end > prev->offset) {
22✔
827
                        prev->ltrim = frag_end - prev->offset;
12✔
828
                    }
12✔
829
                    goto insert;
22✔
830
                }
22✔
831
                break;
97✔
832
            default:
97✔
833
                break;
×
834
            }
11,353,869✔
835

836
        next:
11,124,562✔
837
            prev = next;
11,124,562✔
838
            if (next != NULL) {
11,124,562✔
839
                next = IP_FRAGMENTS_RB_NEXT(next);
11,094,752✔
840
            }
11,094,752✔
841
            continue;
11,124,562✔
842

843
        insert:
227,752✔
844
            /* If existing fragment has been trimmed up completely
845
             * (complete overlap), remove it now instead of holding
846
             * onto it. */
847
            if (prev->skip || prev->ltrim >= prev->data_len) {
227,752✔
848
                RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
7,115✔
849
                DefragFragReset(prev);
7,115✔
850
                SCMutexLock(&defrag_context->frag_pool_lock);
7,115✔
851
                PoolReturn(defrag_context->frag_pool, prev);
7,115✔
852
                SCMutexUnlock(&defrag_context->frag_pool_lock);
7,115✔
853
            }
7,115✔
854
            break;
227,752✔
855
        }
11,353,869✔
856
    }
259,117✔
857

858
    if (ltrim >= data_len) {
444,674✔
859
        /* Full packet has been trimmed due to the overlap policy. Overlap
860
         * already set. */
861
        goto done;
137,133✔
862
    }
137,133✔
863

864
    /* Allocate fragment and insert. */
865
    SCMutexLock(&defrag_context->frag_pool_lock);
307,541✔
866
    Frag *new = PoolGet(defrag_context->frag_pool);
307,541✔
867
    SCMutexUnlock(&defrag_context->frag_pool_lock);
307,541✔
868
    if (new == NULL) {
307,541✔
869
        if (af == AF_INET) {
1✔
870
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
1✔
871
        } else {
1✔
872
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
×
873
        }
×
874
        if (tv != NULL && dtv != NULL) {
1✔
875
            StatsCounterIncr(&tv->stats, dtv->counter_defrag_no_frags);
1✔
876
        }
1✔
877
        goto error_remove_tracker;
1✔
878
    }
1✔
879
    new->pkt = SCMalloc(GET_PKT_LEN(p));
307,540✔
880
    if (new->pkt == NULL) {
307,540✔
881
        SCMutexLock(&defrag_context->frag_pool_lock);
×
882
        PoolReturn(defrag_context->frag_pool, new);
×
883
        SCMutexUnlock(&defrag_context->frag_pool_lock);
×
884
        if (af == AF_INET) {
×
885
            ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
×
886
        } else {
×
887
            ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
×
888
        }
×
889
        goto error_remove_tracker;
×
890
    }
×
891
    memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
307,540✔
892
    new->len = (GET_PKT_LEN(p) - ltrim);
307,540✔
893
    /* in case of unfragmentable exthdrs, update the 'next hdr' field
894
     * in the raw buffer so the reassembled packet will point to the
895
     * correct next header after stripping the frag header */
896
    if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
307,540✔
897
        if (new->len > ip6_nh_set_offset) {
157,944✔
898
            SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
157,944✔
899
                    new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
157,944✔
900
            new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
157,944✔
901
        }
157,944✔
902
    }
157,944✔
903

904
    new->hlen = hlen;
307,540✔
905
    new->offset = frag_offset + ltrim;
307,540✔
906
    new->data_offset = data_offset;
307,540✔
907
    new->data_len = data_len - ltrim;
307,540✔
908
    new->frag_hdr_offset = frag_hdr_offset;
307,540✔
909
    new->more_frags = more_frags;
307,540✔
910
#ifdef DEBUG
911
    new->pcap_cnt = pcap_cnt;
912
#endif
913
    if (new->offset == 0) {
307,540✔
914
        tracker->ip_hdr_offset = ip_hdr_offset;
165,926✔
915
        tracker->datalink = p->datalink;
165,926✔
916
    }
165,926✔
917

918
    IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
307,540✔
919

920
    if (!more_frags) {
307,540✔
921
        tracker->seen_last = 1;
92,234✔
922
    }
92,234✔
923

924
    if (tracker->seen_last) {
307,540✔
925
        if (tracker->af == AF_INET) {
107,351✔
926
            r = Defrag4Reassemble(tv, tracker, p);
98,342✔
927
            if (r != NULL && tv != NULL && dtv != NULL) {
98,342✔
928
                StatsCounterIncr(&tv->stats, dtv->counter_defrag_ipv4_reassembled);
1,958✔
929
                const uint32_t len = GET_PKT_LEN(r) - (uint32_t)tracker->ip_hdr_offset;
1,958✔
930
                DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
1,958✔
931
                if (DecodeIPV4(tv, dtv, r, GET_PKT_DATA(r) + tracker->ip_hdr_offset,
1,958✔
932
                            (uint16_t)len) != TM_ECODE_OK) {
1,958✔
933
                    r->root = NULL;
×
934
                    TmqhOutputPacketpool(tv, r);
×
935
                    r = NULL;
×
936
                } else {
1,958✔
937
                    PacketDefragPktSetupParent(p);
1,958✔
938
                }
1,958✔
939
            }
1,958✔
940
        }
98,342✔
941
        else if (tracker->af == AF_INET6) {
9,009✔
942
            r = Defrag6Reassemble(tv, tracker, p);
9,009✔
943
            if (r != NULL && tv != NULL && dtv != NULL) {
9,009✔
944
                StatsCounterIncr(&tv->stats, dtv->counter_defrag_ipv6_reassembled);
2,705✔
945
                const uint32_t len = GET_PKT_LEN(r) - (uint32_t)tracker->ip_hdr_offset;
2,705✔
946
                DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
2,705✔
947
                if (DecodeIPV6(tv, dtv, r, GET_PKT_DATA(r) + tracker->ip_hdr_offset,
2,705✔
948
                            (uint16_t)len) != TM_ECODE_OK) {
2,705✔
949
                    r->root = NULL;
×
950
                    TmqhOutputPacketpool(tv, r);
×
951
                    r = NULL;
×
952
                } else {
2,705✔
953
                    PacketDefragPktSetupParent(p);
2,705✔
954
                }
2,705✔
955
            }
2,705✔
956
        }
9,009✔
957
    }
107,351✔
958

959

960
done:
446,228✔
961
    if (overlap) {
446,228✔
962
        if (af == AF_INET) {
216,913✔
963
            ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
123,877✔
964
        }
123,877✔
965
        else {
93,036✔
966
            ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
93,036✔
967
        }
93,036✔
968
    }
216,913✔
969
    return r;
446,228✔
970
error_remove_tracker:
1✔
971
    tracker->remove = 1;
1✔
972
    DefragTrackerFreeFrags(tracker);
1✔
973
    return NULL;
1✔
974
}
307,540✔
975

976
/**
977
 * \brief Get the defrag policy based on the destination address of
978
 * the packet.
979
 *
980
 * \param p The packet used to get the destination address.
981
 *
982
 * \retval The defrag policy to use.
983
 */
984
uint8_t
985
DefragGetOsPolicy(Packet *p)
986
{
182,734✔
987
    int policy = -1;
182,734✔
988

989
    if (PacketIsIPv4(p)) {
182,734✔
990
        policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
19,368✔
991
    } else if (PacketIsIPv6(p)) {
163,423✔
992
        policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
163,366✔
993
    }
163,366✔
994

995
    if (policy == -1) {
182,734✔
996
        return default_policy;
182,727✔
997
    }
182,727✔
998

999
    /* Map the OS policies returned from the configured host info to
1000
     * defrag specific policies. */
1001
    switch (policy) {
7✔
1002
        /* BSD. */
1003
    case OS_POLICY_BSD:
×
1004
    case OS_POLICY_HPUX10:
×
1005
    case OS_POLICY_IRIX:
×
1006
        return DEFRAG_POLICY_BSD;
×
1007

1008
        /* BSD-Right. */
1009
    case OS_POLICY_BSD_RIGHT:
×
1010
        return DEFRAG_POLICY_BSD_RIGHT;
×
1011

1012
        /* Linux. */
1013
    case OS_POLICY_OLD_LINUX:
×
1014
    case OS_POLICY_LINUX:
×
1015
        return DEFRAG_POLICY_LINUX;
×
1016

1017
        /* First. */
1018
    case OS_POLICY_OLD_SOLARIS:
×
1019
    case OS_POLICY_HPUX11:
×
1020
    case OS_POLICY_MACOS:
×
1021
    case OS_POLICY_FIRST:
×
1022
        return DEFRAG_POLICY_FIRST;
×
1023

1024
        /* Solaris. */
1025
    case OS_POLICY_SOLARIS:
×
1026
        return DEFRAG_POLICY_SOLARIS;
×
1027

1028
        /* Windows. */
1029
    case OS_POLICY_WINDOWS:
7✔
1030
    case OS_POLICY_VISTA:
7✔
1031
    case OS_POLICY_WINDOWS2K3:
7✔
1032
        return DEFRAG_POLICY_WINDOWS;
7✔
1033

1034
        /* Last. */
1035
    case OS_POLICY_LAST:
×
1036
        return DEFRAG_POLICY_LAST;
×
1037

1038
    default:
×
1039
        return default_policy;
×
1040
    }
7✔
1041
}
7✔
1042

1043
/** \internal
1044
 *
1045
 *  \retval NULL or a *LOCKED* tracker */
1046
static DefragTracker *
1047
DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1048
{
448,653✔
1049
    return DefragGetTrackerFromHash(tv, dtv, p);
448,653✔
1050
}
448,653✔
1051

1052
/**
1053
 * \brief Entry point for IPv4 and IPv6 fragments.
1054
 *
1055
 * \param tv ThreadVars for the calling decoder.
1056
 * \param p The packet fragment.
1057
 *
1058
 * \retval A new Packet resembling the re-assembled packet if the most
1059
 *     recent fragment allowed the packet to be re-assembled, otherwise
1060
 *     NULL is returned.
1061
 */
1062
Packet *
1063
Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1064
{
451,509✔
1065
    uint16_t frag_offset;
451,509✔
1066
    uint8_t more_frags;
451,509✔
1067
    DefragTracker *tracker;
451,509✔
1068
    int af;
451,509✔
1069

1070
    if (PacketIsIPv4(p)) {
451,509✔
1071
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
186,139✔
1072
        af = AF_INET;
186,139✔
1073
        more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
186,139✔
1074
        frag_offset = IPV4_GET_RAW_FRAGOFFSET(ip4h);
186,139✔
1075
    } else if (PacketIsIPv6(p)) {
284,175✔
1076
        af = AF_INET6;
265,370✔
1077
        frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
265,370✔
1078
        more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
265,370✔
1079
    } else {
265,370✔
1080
        return NULL;
×
1081
    }
×
1082

1083
    if (frag_offset == 0 && more_frags == 0) {
451,509✔
1084
        return NULL;
2,859✔
1085
    }
2,859✔
1086

1087
    if (af == AF_INET) {
448,650✔
1088
        StatsCounterIncr(&tv->stats, dtv->counter_defrag_ipv4_fragments);
186,139✔
1089
    } else if (af == AF_INET6) {
281,317✔
1090
        StatsCounterIncr(&tv->stats, dtv->counter_defrag_ipv6_fragments);
262,511✔
1091
    }
262,511✔
1092

1093
    /* return a locked tracker or NULL */
1094
    tracker = DefragGetTracker(tv, dtv, p);
448,650✔
1095
    if (tracker == NULL) {
448,650✔
1096
        if (tv != NULL && dtv != NULL) {
×
1097
            StatsCounterIncr(&tv->stats, dtv->counter_defrag_max_hit);
×
1098
        }
×
1099
        return NULL;
×
1100
    }
×
1101

1102
    Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
448,650✔
1103
    DefragTrackerRelease(tracker);
448,650✔
1104

1105
    return rp;
448,650✔
1106
}
448,650✔
1107

1108
void
1109
DefragInit(void)
1110
{
3,652✔
1111
    intmax_t tracker_pool_size;
3,652✔
1112
    if (!SCConfGetInt("defrag.trackers", &tracker_pool_size)) {
3,652✔
1113
        tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
731✔
1114
    }
731✔
1115

1116
    /* Load the defrag-per-host lookup. */
1117
    DefragPolicyLoadFromConfig();
3,652✔
1118

1119
    /* Allocate the DefragContext. */
1120
    defrag_context = DefragContextNew();
3,652✔
1121
    if (defrag_context == NULL) {
3,652✔
1122
        FatalError("Failed to allocate memory for the Defrag module.");
×
1123
    }
×
1124

1125
    DefragSetDefaultTimeout(defrag_context->timeout);
3,652✔
1126
    DefragInitConfig(false);
3,652✔
1127
}
3,652✔
1128

1129
void DefragDestroy(void)
1130
{
3,467✔
1131
    DefragHashShutdown();
3,467✔
1132
    DefragContextDestroy(defrag_context);
3,467✔
1133
    defrag_context = NULL;
3,467✔
1134
    DefragTreeDestroy();
3,467✔
1135
}
3,467✔
1136

1137
#ifdef UNITTESTS
1138
#include "util-unittest-helper.h"
1139
#include "packet.h"
1140

1141
#define IP_MF 0x2000
138✔
1142

1143
ThreadVars test_tv = { 0 };
1144
DecodeThreadVars test_dtv = { 0 };
1145

1146
/**
1147
 * Allocate a test packet.  Nothing to fancy, just a simple IP packet
1148
 * with some payload of no particular protocol.
1149
 */
1150
static Packet *BuildIpv4TestPacket(
1151
        uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
1152
{
150✔
1153
    Packet *p = NULL;
150✔
1154
    int hlen = 20;
150✔
1155
    int ttl = 64;
150✔
1156
    uint8_t *pcontent;
150✔
1157
    IPV4Hdr ip4h;
150✔
1158

1159
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
150✔
1160
    if (unlikely(p == NULL))
150✔
1161
        return NULL;
1162

1163
    PacketInit(p);
150✔
1164

1165
    struct timeval tval;
150✔
1166
    gettimeofday(&tval, NULL);
150✔
1167
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
150✔
1168
    //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1169
    ip4h.ip_verhl = 4 << 4;
150✔
1170
    ip4h.ip_verhl |= hlen >> 2;
150✔
1171
    ip4h.ip_len = htons(hlen + content_len);
150✔
1172
    ip4h.ip_id = htons(id);
150✔
1173
    if (mf)
150✔
1174
        ip4h.ip_off = htons(IP_MF | off);
131✔
1175
    else
19✔
1176
        ip4h.ip_off = htons(off);
19✔
1177
    ip4h.ip_ttl = ttl;
150✔
1178
    ip4h.ip_proto = proto;
150✔
1179

1180
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
150✔
1181
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
150✔
1182

1183
    /* copy content_len crap, we need full length */
1184
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
150✔
1185
    IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
150✔
1186
    SET_IPV4_SRC_ADDR(ip4p, &p->src);
150✔
1187
    SET_IPV4_DST_ADDR(ip4p, &p->dst);
150✔
1188

1189
    pcontent = SCCalloc(1, content_len);
150✔
1190
    if (unlikely(pcontent == NULL))
150✔
1191
        return NULL;
1192
    memset(pcontent, content, content_len);
150✔
1193
    PacketCopyDataOffset(p, hlen, pcontent, content_len);
150✔
1194
    SET_PKT_LEN(p, hlen + content_len);
150✔
1195
    SCFree(pcontent);
150✔
1196

1197
    ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
150✔
1198

1199
    /* Self test. */
1200
    FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
150✔
1201
    FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
150✔
1202
    FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
150✔
1203
    FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
150✔
1204
    FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
150✔
1205
    FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
150✔
1206
    FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
150✔
1207
    FAIL_IF(IPV4_GET_RAW_IPPROTO(ip4p) != proto);
150✔
1208

1209
    return p;
150✔
1210
}
150✔
1211

1212
/**
1213
 * Allocate a test packet, much like BuildIpv4TestPacket, but with
1214
 * the full content provided by the caller.
1215
 */
1216
static int BuildIpv4TestPacketWithContent(Packet **packet, uint8_t proto, uint16_t id, uint16_t off,
1217
        int mf, const uint8_t *content, int content_len)
1218
{
9✔
1219
    Packet *p = NULL;
9✔
1220
    int hlen = 20;
9✔
1221
    int ttl = 64;
9✔
1222
    IPV4Hdr ip4h;
9✔
1223

1224
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
9✔
1225
    FAIL_IF_NULL(p);
9✔
1226

1227
    PacketInit(p);
9✔
1228

1229
    struct timeval tval;
9✔
1230
    gettimeofday(&tval, NULL);
9✔
1231
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
9✔
1232
    ip4h.ip_verhl = 4 << 4;
9✔
1233
    ip4h.ip_verhl |= hlen >> 2;
9✔
1234
    ip4h.ip_len = htons(hlen + content_len);
9✔
1235
    ip4h.ip_id = htons(id);
9✔
1236
    if (mf)
9✔
1237
        ip4h.ip_off = htons(IP_MF | off);
7✔
1238
    else
2✔
1239
        ip4h.ip_off = htons(off);
2✔
1240
    ip4h.ip_ttl = ttl;
9✔
1241
    ip4h.ip_proto = proto;
9✔
1242

1243
    ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
9✔
1244
    ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
9✔
1245

1246
    /* copy content_len crap, we need full length */
1247
    PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
9✔
1248
    IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
9✔
1249
    SET_IPV4_SRC_ADDR(ip4p, &p->src);
9✔
1250
    SET_IPV4_DST_ADDR(ip4p, &p->dst);
9✔
1251

1252
    PacketCopyDataOffset(p, hlen, content, content_len);
9✔
1253
    SET_PKT_LEN(p, hlen + content_len);
9✔
1254

1255
    ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
9✔
1256

1257
    /* Self test. */
1258
    FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
9✔
1259
    FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
9✔
1260
    FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
9✔
1261
    FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
9✔
1262
    FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
9✔
1263
    FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
9✔
1264
    FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
9✔
1265
    FAIL_IF(IPV4_GET_RAW_IPPROTO(ip4p) != proto);
9✔
1266

1267
    *packet = p;
9✔
1268
    PASS;
9✔
1269
}
9✔
1270

1271
static Packet *BuildIpv6TestPacket(
1272
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
1273
{
117✔
1274
    Packet *p = NULL;
117✔
1275
    uint8_t *pcontent;
117✔
1276
    IPV6Hdr ip6h;
117✔
1277

1278
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
117✔
1279
    if (unlikely(p == NULL))
117✔
1280
        return NULL;
1281

1282
    PacketInit(p);
117✔
1283

1284
    struct timeval tval;
117✔
1285
    gettimeofday(&tval, NULL);
117✔
1286
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
117✔
1287

1288
    ip6h.s_ip6_nxt = 44;
117✔
1289
    ip6h.s_ip6_hlim = 2;
117✔
1290

1291
    /* Source and dest address - very bogus addresses. */
1292
    ip6h.s_ip6_src[0] = 0x01010101;
117✔
1293
    ip6h.s_ip6_src[1] = 0x01010101;
117✔
1294
    ip6h.s_ip6_src[2] = 0x01010101;
117✔
1295
    ip6h.s_ip6_src[3] = 0x01010101;
117✔
1296
    ip6h.s_ip6_dst[0] = 0x02020202;
117✔
1297
    ip6h.s_ip6_dst[1] = 0x02020202;
117✔
1298
    ip6h.s_ip6_dst[2] = 0x02020202;
117✔
1299
    ip6h.s_ip6_dst[3] = 0x02020202;
117✔
1300

1301
    /* copy content_len crap, we need full length */
1302
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
117✔
1303

1304
    IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
117✔
1305
    IPV6_SET_RAW_VER(ip6p, 6);
117✔
1306
    /* Fragmentation header. */
1307
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
117✔
1308
    fh->ip6fh_nxt = proto;
117✔
1309
    fh->ip6fh_ident = htonl(id);
117✔
1310
    fh->ip6fh_offlg = htons((off << 3) | mf);
117✔
1311

1312
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
117✔
1313

1314
    pcontent = SCCalloc(1, content_len);
117✔
1315
    if (unlikely(pcontent == NULL))
117✔
1316
        return NULL;
1317
    memset(pcontent, content, content_len);
117✔
1318
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
117✔
1319
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
117✔
1320
    SCFree(pcontent);
117✔
1321

1322
    ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
117✔
1323

1324
    SET_IPV6_SRC_ADDR(ip6p, &p->src);
117✔
1325
    SET_IPV6_DST_ADDR(ip6p, &p->dst);
117✔
1326

1327
    /* Self test. */
1328
    if (IPV6_GET_RAW_VER(ip6p) != 6)
117✔
1329
        goto error;
1330
    if (IPV6_GET_RAW_NH(ip6p) != 44)
117✔
1331
        goto error;
1332
    if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
117✔
1333
        goto error;
1334

1335
    return p;
117✔
1336
error:
1337
    if (p != NULL)
1338
        PacketFree(p);
1339
    return NULL;
1340
}
117✔
1341

1342
static Packet *BuildIpv6TestPacketWithContent(
1343
        uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1344
{
9✔
1345
    Packet *p = NULL;
9✔
1346
    IPV6Hdr ip6h;
9✔
1347

1348
    p = SCCalloc(1, sizeof(*p) + default_packet_size);
9✔
1349
    if (unlikely(p == NULL))
9✔
1350
        return NULL;
1351

1352
    PacketInit(p);
9✔
1353

1354
    struct timeval tval;
9✔
1355
    gettimeofday(&tval, NULL);
9✔
1356
    p->ts = SCTIME_FROM_TIMEVAL(&tval);
9✔
1357

1358
    ip6h.s_ip6_nxt = 44;
9✔
1359
    ip6h.s_ip6_hlim = 2;
9✔
1360

1361
    /* Source and dest address - very bogus addresses. */
1362
    ip6h.s_ip6_src[0] = 0x01010101;
9✔
1363
    ip6h.s_ip6_src[1] = 0x01010101;
9✔
1364
    ip6h.s_ip6_src[2] = 0x01010101;
9✔
1365
    ip6h.s_ip6_src[3] = 0x01010101;
9✔
1366
    ip6h.s_ip6_dst[0] = 0x02020202;
9✔
1367
    ip6h.s_ip6_dst[1] = 0x02020202;
9✔
1368
    ip6h.s_ip6_dst[2] = 0x02020202;
9✔
1369
    ip6h.s_ip6_dst[3] = 0x02020202;
9✔
1370

1371
    /* copy content_len crap, we need full length */
1372
    PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
9✔
1373

1374
    IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
9✔
1375
    IPV6_SET_RAW_VER(ip6p, 6);
9✔
1376
    /* Fragmentation header. */
1377
    IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
9✔
1378
    fh->ip6fh_nxt = proto;
9✔
1379
    fh->ip6fh_ident = htonl(id);
9✔
1380
    fh->ip6fh_offlg = htons((off << 3) | mf);
9✔
1381

1382
    DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
9✔
1383

1384
    PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
9✔
1385
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
9✔
1386

1387
    ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
9✔
1388

1389
    SET_IPV6_SRC_ADDR(ip6p, &p->src);
9✔
1390
    SET_IPV6_DST_ADDR(ip6p, &p->dst);
9✔
1391

1392
    /* Self test. */
1393
    if (IPV6_GET_RAW_VER(ip6p) != 6)
9✔
1394
        goto error;
1395
    if (IPV6_GET_RAW_NH(ip6p) != 44)
9✔
1396
        goto error;
1397
    if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
9✔
1398
        goto error;
1399

1400
    return p;
9✔
1401
error:
1402
    if (p != NULL)
1403
        PacketFree(p);
1404
    return NULL;
1405
}
9✔
1406

1407
/**
1408
 * Test the simplest possible re-assembly scenario.  All packet in
1409
 * order and no overlaps.
1410
 */
1411
static int DefragInOrderSimpleTest(void)
1412
{
1✔
1413
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1✔
1414
    Packet *reassembled = NULL;
1✔
1415
    int id = 12;
1✔
1416

1417
    DefragInit();
1✔
1418

1419
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1✔
1420
    FAIL_IF_NULL(p1);
1✔
1421
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1✔
1422
    FAIL_IF_NULL(p2);
1✔
1423
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1✔
1424
    FAIL_IF_NULL(p3);
1✔
1425

1426
    FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1✔
1427
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1✔
1428

1429
    reassembled = Defrag(&test_tv, &test_dtv, p3);
1✔
1430
    FAIL_IF_NULL(reassembled);
1✔
1431

1432
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1✔
1433
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1✔
1434

1435
    /* 20 bytes in we should find 8 bytes of A. */
1436
    for (int i = 20; i < 20 + 8; i++) {
9✔
1437
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
8✔
1438
    }
8✔
1439

1440
    /* 28 bytes in we should find 8 bytes of B. */
1441
    for (int i = 28; i < 28 + 8; i++) {
9✔
1442
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
8✔
1443
    }
8✔
1444

1445
    /* And 36 bytes in we should find 3 bytes of C. */
1446
    for (int i = 36; i < 36 + 3; i++) {
4✔
1447
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
3✔
1448
    }
3✔
1449

1450
    PacketFree(p1);
1✔
1451
    PacketFree(p2);
1✔
1452
    PacketFree(p3);
1✔
1453
    PacketFree(reassembled);
1✔
1454

1455
    DefragDestroy();
1✔
1456
    PASS;
1✔
1457
}
1✔
1458

1459
/**
1460
 * Simple fragmented packet in reverse order.
1461
 */
1462
static int DefragReverseSimpleTest(void)
1463
{
1✔
1464
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1✔
1465
    Packet *reassembled = NULL;
1✔
1466
    int id = 12;
1✔
1467

1468
    DefragInit();
1✔
1469

1470
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1✔
1471
    FAIL_IF_NULL(p1);
1✔
1472
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1✔
1473
    FAIL_IF_NULL(p2);
1✔
1474
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1✔
1475
    FAIL_IF_NULL(p3);
1✔
1476

1477
    FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1✔
1478
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1✔
1479
    reassembled = Defrag(&test_tv, &test_dtv, p1);
1✔
1480
    FAIL_IF_NULL(reassembled);
1✔
1481

1482
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1✔
1483
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1✔
1484

1485
    /* 20 bytes in we should find 8 bytes of A. */
1486
    for (int i = 20; i < 20 + 8; i++) {
9✔
1487
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
8✔
1488
    }
8✔
1489

1490
    /* 28 bytes in we should find 8 bytes of B. */
1491
    for (int i = 28; i < 28 + 8; i++) {
9✔
1492
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
8✔
1493
    }
8✔
1494

1495
    /* And 36 bytes in we should find 3 bytes of C. */
1496
    for (int i = 36; i < 36 + 3; i++) {
4✔
1497
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
3✔
1498
    }
3✔
1499

1500
    PacketFree(p1);
1✔
1501
    PacketFree(p2);
1✔
1502
    PacketFree(p3);
1✔
1503
    PacketFree(reassembled);
1✔
1504

1505
    DefragDestroy();
1✔
1506
    PASS;
1✔
1507
}
1✔
1508

1509
/**
1510
 * Test the simplest possible re-assembly scenario.  All packet in
1511
 * order and no overlaps.
1512
 */
1513
static int DefragInOrderSimpleIpv6Test(void)
1514
{
1✔
1515
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1✔
1516
    Packet *reassembled = NULL;
1✔
1517
    int id = 12;
1✔
1518

1519
    DefragInit();
1✔
1520

1521
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1✔
1522
    FAIL_IF_NULL(p1);
1✔
1523
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1✔
1524
    FAIL_IF_NULL(p2);
1✔
1525
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1✔
1526
    FAIL_IF_NULL(p3);
1✔
1527

1528
    FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1✔
1529
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1✔
1530
    reassembled = Defrag(&test_tv, &test_dtv, p3);
1✔
1531
    FAIL_IF_NULL(reassembled);
1✔
1532

1533
    const IPV6Hdr *ip6h = PacketGetIPv6(reassembled);
1✔
1534
    FAIL_IF(IPV6_GET_RAW_PLEN(ip6h) != 19);
1✔
1535

1536
    /* 40 bytes in we should find 8 bytes of A. */
1537
    for (int i = 40; i < 40 + 8; i++) {
9✔
1538
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
8✔
1539
    }
8✔
1540

1541
    /* 28 bytes in we should find 8 bytes of B. */
1542
    for (int i = 48; i < 48 + 8; i++) {
9✔
1543
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
8✔
1544
    }
8✔
1545

1546
    /* And 36 bytes in we should find 3 bytes of C. */
1547
    for (int i = 56; i < 56 + 3; i++) {
4✔
1548
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
3✔
1549
    }
3✔
1550

1551
    PacketFree(p1);
1✔
1552
    PacketFree(p2);
1✔
1553
    PacketFree(p3);
1✔
1554
    PacketFree(reassembled);
1✔
1555

1556
    DefragDestroy();
1✔
1557
    PASS;
1✔
1558
}
1✔
1559

1560
static int DefragReverseSimpleIpv6Test(void)
1561
{
1✔
1562
    DefragContext *dc = NULL;
1✔
1563
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1✔
1564
    Packet *reassembled = NULL;
1✔
1565
    int id = 12;
1✔
1566

1567
    DefragInit();
1✔
1568

1569
    dc = DefragContextNew();
1✔
1570
    FAIL_IF_NULL(dc);
1✔
1571

1572
    p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1✔
1573
    FAIL_IF_NULL(p1);
1✔
1574
    p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1✔
1575
    FAIL_IF_NULL(p2);
1✔
1576
    p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1✔
1577
    FAIL_IF_NULL(p3);
1✔
1578

1579
    FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1✔
1580
    FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1✔
1581
    reassembled = Defrag(&test_tv, &test_dtv, p1);
1✔
1582
    FAIL_IF_NULL(reassembled);
1✔
1583

1584
    /* 40 bytes in we should find 8 bytes of A. */
1585
    for (int i = 40; i < 40 + 8; i++) {
9✔
1586
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
8✔
1587
    }
8✔
1588

1589
    /* 28 bytes in we should find 8 bytes of B. */
1590
    for (int i = 48; i < 48 + 8; i++) {
9✔
1591
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
8✔
1592
    }
8✔
1593

1594
    /* And 36 bytes in we should find 3 bytes of C. */
1595
    for (int i = 56; i < 56 + 3; i++) {
4✔
1596
        FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
3✔
1597
    }
3✔
1598

1599
    DefragContextDestroy(dc);
1✔
1600
    PacketFree(p1);
1✔
1601
    PacketFree(p2);
1✔
1602
    PacketFree(p3);
1✔
1603
    PacketFree(reassembled);
1✔
1604

1605
    DefragDestroy();
1✔
1606
    PASS;
1✔
1607
}
1✔
1608

1609
static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
1610
{
6✔
1611
    int i;
6✔
1612

1613
    DefragInit();
6✔
1614

1615
    /*
1616
     * Build the packets.
1617
     */
1618

1619
    int id = 1;
6✔
1620
    Packet *packets[17];
6✔
1621
    memset(packets, 0x00, sizeof(packets));
6✔
1622

1623
    /*
1624
     * Original fragments.
1625
     */
1626

1627
    /* <1> A*24 at 0. */
1628
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
6✔
1629

1630
    /* <2> B*16 at 32. */
1631
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
6✔
1632

1633
    /* <3> C*24 at 48. */
1634
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
6✔
1635

1636
    /* <3_1> D*8 at 80. */
1637
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
6✔
1638

1639
    /* <3_2> E*16 at 104. */
1640
    packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
6✔
1641

1642
    /* <3_3> F*24 at 120. */
1643
    packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
6✔
1644

1645
    /* <3_4> G*16 at 144. */
1646
    packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
6✔
1647

1648
    /* <3_5> H*16 at 160. */
1649
    packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
6✔
1650

1651
    /* <3_6> I*8 at 176. */
1652
    packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
6✔
1653

1654
    /*
1655
     * Overlapping subsequent fragments.
1656
     */
1657

1658
    /* <4> J*32 at 8. */
1659
    packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
6✔
1660

1661
    /* <5> K*24 at 48. */
1662
    packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
6✔
1663

1664
    /* <6> L*24 at 72. */
1665
    packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
6✔
1666

1667
    /* <7> M*24 at 96. */
1668
    packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
6✔
1669

1670
    /* <8> N*8 at 128. */
1671
    packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
6✔
1672

1673
    /* <9> O*8 at 152. */
1674
    packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
6✔
1675

1676
    /* <10> P*8 at 160. */
1677
    packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
6✔
1678

1679
    /* <11> Q*16 at 176. */
1680
    packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
6✔
1681

1682
    default_policy = policy;
6✔
1683

1684
    /* Send all but the last. */
1685
    for (i = 0; i < 9; i++) {
60✔
1686
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
54✔
1687
        FAIL_IF_NOT_NULL(tp);
54✔
1688
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP));
54✔
1689
    }
54✔
1690
    int overlap = 0;
6✔
1691
    for (; i < 16; i++) {
48✔
1692
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
42✔
1693
        FAIL_IF_NOT_NULL(tp);
42✔
1694
        if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
42✔
1695
            overlap++;
42✔
1696
        }
42✔
1697
    }
42✔
1698
    FAIL_IF_NOT(overlap);
6✔
1699

1700
    /* And now the last one. */
1701
    Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
6✔
1702
    FAIL_IF_NULL(reassembled);
6✔
1703

1704
    FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
6✔
1705
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 20 + 192);
6✔
1706
    FAIL_IF(expected_len != 192);
6✔
1707

1708
    if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
6✔
1709
        printf("Expected:\n");
1710
        PrintRawDataFp(stdout, expected, expected_len);
1711
        printf("Got:\n");
1712
        PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
1713
        FAIL;
1714
    }
1715
    PacketFree(reassembled);
6✔
1716

1717
    /* Make sure all frags were returned back to the pool. */
1718
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
6✔
1719

1720
    for (i = 0; i < 17; i++) {
108✔
1721
        PacketFree(packets[i]);
102✔
1722
    }
102✔
1723
    DefragDestroy();
6✔
1724
    PASS;
6✔
1725
}
6✔
1726

1727
static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
1728
{
6✔
1729
    int i;
6✔
1730

1731
    DefragInit();
6✔
1732

1733
    /*
1734
     * Build the packets.
1735
     */
1736

1737
    int id = 1;
6✔
1738
    Packet *packets[17];
6✔
1739
    memset(packets, 0x00, sizeof(packets));
6✔
1740

1741
    /*
1742
     * Original fragments.
1743
     */
1744

1745
    /* <1> A*24 at 0. */
1746
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
6✔
1747

1748
    /* <2> B*16 at 32. */
1749
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
6✔
1750

1751
    /* <3> C*24 at 48. */
1752
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
6✔
1753

1754
    /* <3_1> D*8 at 80. */
1755
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
6✔
1756

1757
    /* <3_2> E*16 at 104. */
1758
    packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
6✔
1759

1760
    /* <3_3> F*24 at 120. */
1761
    packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
6✔
1762

1763
    /* <3_4> G*16 at 144. */
1764
    packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
6✔
1765

1766
    /* <3_5> H*16 at 160. */
1767
    packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
6✔
1768

1769
    /* <3_6> I*8 at 176. */
1770
    packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
6✔
1771

1772
    /*
1773
     * Overlapping subsequent fragments.
1774
     */
1775

1776
    /* <4> J*32 at 8. */
1777
    packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
6✔
1778

1779
    /* <5> K*24 at 48. */
1780
    packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
6✔
1781

1782
    /* <6> L*24 at 72. */
1783
    packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
6✔
1784

1785
    /* <7> M*24 at 96. */
1786
    packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
6✔
1787

1788
    /* <8> N*8 at 128. */
1789
    packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
6✔
1790

1791
    /* <9> O*8 at 152. */
1792
    packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
6✔
1793

1794
    /* <10> P*8 at 160. */
1795
    packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
6✔
1796

1797
    /* <11> Q*16 at 176. */
1798
    packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
6✔
1799

1800
    default_policy = policy;
6✔
1801

1802
    /* Send all but the last. */
1803
    for (i = 0; i < 9; i++) {
60✔
1804
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
54✔
1805
        FAIL_IF_NOT_NULL(tp);
54✔
1806
        FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP));
54✔
1807
    }
54✔
1808
    int overlap = 0;
6✔
1809
    for (; i < 16; i++) {
48✔
1810
        Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
42✔
1811
        FAIL_IF_NOT_NULL(tp);
42✔
1812
        if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
42✔
1813
            overlap++;
42✔
1814
        }
42✔
1815
    }
42✔
1816
    FAIL_IF_NOT(overlap);
6✔
1817

1818
    /* And now the last one. */
1819
    Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
6✔
1820
    FAIL_IF_NULL(reassembled);
6✔
1821
    FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
6✔
1822

1823
    FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(reassembled)) != 192);
6✔
1824

1825
    PacketFree(reassembled);
6✔
1826

1827
    /* Make sure all frags were returned to the pool. */
1828
    FAIL_IF(defrag_context->frag_pool->outstanding != 0);
6✔
1829

1830
    for (i = 0; i < 17; i++) {
108✔
1831
        PacketFree(packets[i]);
102✔
1832
    }
102✔
1833
    DefragDestroy();
6✔
1834
    PASS;
6✔
1835
}
6✔
1836

1837
/* Define data that matches the naming "Target-Based Fragmentation
1838
 * Reassembly".
1839
 *
1840
 * For example, the data refers to a fragment of data as <1>, or <3_6>
1841
 * and uses these to diagram the input fragments and the resulting
1842
 * policies. We build test cases for the papers scenario but assign
1843
 * specific values to each segment.
1844
 */
1845
#define D_1   'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
32✔
1846
#define D_2   'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
18✔
1847
#define D_3   'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
24✔
1848
#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
2✔
1849
#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
8✔
1850
#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
34✔
1851
#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
22✔
1852
#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
20✔
1853
#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
8✔
1854
#define D_4   'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
22✔
1855
#define D_5   'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
12✔
1856
#define D_6   'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
34✔
1857
#define D_7   'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
28✔
1858
#define D_8   'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
2✔
1859
#define D_9   'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
2✔
1860
#define D_10  'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
4✔
1861
#define D_11  'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
16✔
1862

1863
static int
1864
DefragSturgesNovakBsdTest(void)
1865
{
1✔
1866
    /* Expected data. */
1867
    uint8_t expected[] = {
1✔
1868
        D_1,
1✔
1869
        D_1,
1✔
1870
        D_1,
1✔
1871
        D_4,
1✔
1872
        D_4,
1✔
1873
        D_2,
1✔
1874
        D_3,
1✔
1875
        D_3,
1✔
1876
        D_3,
1✔
1877
        D_6,
1✔
1878
        D_6,
1✔
1879
        D_6,
1✔
1880
        D_7,
1✔
1881
        D_7,
1✔
1882
        D_7,
1✔
1883
        D_3_3,
1✔
1884
        D_3_3,
1✔
1885
        D_3_3,
1✔
1886
        D_3_4,
1✔
1887
        D_3_4,
1✔
1888
        D_3_5,
1✔
1889
        D_3_5,
1✔
1890
        D_3_6,
1✔
1891
        D_11,
1✔
1892
    };
1✔
1893

1894
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1✔
1895
                    sizeof(expected)));
1✔
1896
    PASS;
1✔
1897
}
1✔
1898

1899
static int DefragSturgesNovakBsdIpv6Test(void)
1900
{
1✔
1901
    /* Expected data. */
1902
    uint8_t expected[] = {
1✔
1903
        D_1,
1✔
1904
        D_1,
1✔
1905
        D_1,
1✔
1906
        D_4,
1✔
1907
        D_4,
1✔
1908
        D_2,
1✔
1909
        D_3,
1✔
1910
        D_3,
1✔
1911
        D_3,
1✔
1912
        D_6,
1✔
1913
        D_6,
1✔
1914
        D_6,
1✔
1915
        D_7,
1✔
1916
        D_7,
1✔
1917
        D_7,
1✔
1918
        D_3_3,
1✔
1919
        D_3_3,
1✔
1920
        D_3_3,
1✔
1921
        D_3_4,
1✔
1922
        D_3_4,
1✔
1923
        D_3_5,
1✔
1924
        D_3_5,
1✔
1925
        D_3_6,
1✔
1926
        D_11,
1✔
1927
    };
1✔
1928

1929
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
1✔
1930
    PASS;
1✔
1931
}
1✔
1932

1933
static int DefragSturgesNovakLinuxIpv4Test(void)
1934
{
1✔
1935
    /* Expected data. */
1936
    uint8_t expected[] = {
1✔
1937
        D_1,
1✔
1938
        D_1,
1✔
1939
        D_1,
1✔
1940
        D_4,
1✔
1941
        D_4,
1✔
1942
        D_2,
1✔
1943
        D_5,
1✔
1944
        D_5,
1✔
1945
        D_5,
1✔
1946
        D_6,
1✔
1947
        D_6,
1✔
1948
        D_6,
1✔
1949
        D_7,
1✔
1950
        D_7,
1✔
1951
        D_7,
1✔
1952
        D_3_3,
1✔
1953
        D_3_3,
1✔
1954
        D_3_3,
1✔
1955
        D_3_4,
1✔
1956
        D_3_4,
1✔
1957
        D_10,
1✔
1958
        D_3_5,
1✔
1959
        D_11,
1✔
1960
        D_11,
1✔
1961
    };
1✔
1962

1963
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1✔
1964
                    sizeof(expected)));
1✔
1965
    PASS;
1✔
1966
}
1✔
1967

1968
static int DefragSturgesNovakLinuxIpv6Test(void)
1969
{
1✔
1970
    /* Expected data. */
1971
    uint8_t expected[] = {
1✔
1972
        D_1,
1✔
1973
        D_1,
1✔
1974
        D_1,
1✔
1975
        D_4,
1✔
1976
        D_4,
1✔
1977
        D_2,
1✔
1978
        D_5,
1✔
1979
        D_5,
1✔
1980
        D_5,
1✔
1981
        D_6,
1✔
1982
        D_6,
1✔
1983
        D_6,
1✔
1984
        D_7,
1✔
1985
        D_7,
1✔
1986
        D_7,
1✔
1987
        D_3_3,
1✔
1988
        D_3_3,
1✔
1989
        D_3_3,
1✔
1990
        D_3_4,
1✔
1991
        D_3_4,
1✔
1992
        D_10,
1✔
1993
        D_3_5,
1✔
1994
        D_11,
1✔
1995
        D_11,
1✔
1996
    };
1✔
1997

1998
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
1✔
1999
    PASS;
1✔
2000
}
1✔
2001

2002
static int DefragSturgesNovakWindowsIpv4Test(void)
2003
{
1✔
2004
    /* Expected data. */
2005
    uint8_t expected[] = {
1✔
2006
        D_1,
1✔
2007
        D_1,
1✔
2008
        D_1,
1✔
2009
        D_4,
1✔
2010
        D_2,
1✔
2011
        D_2,
1✔
2012
        D_3,
1✔
2013
        D_3,
1✔
2014
        D_3,
1✔
2015
        D_6,
1✔
2016
        D_6,
1✔
2017
        D_6,
1✔
2018
        D_7,
1✔
2019
        D_3_2,
1✔
2020
        D_3_2,
1✔
2021
        D_3_3,
1✔
2022
        D_3_3,
1✔
2023
        D_3_3,
1✔
2024
        D_3_4,
1✔
2025
        D_3_4,
1✔
2026
        D_3_5,
1✔
2027
        D_3_5,
1✔
2028
        D_3_6,
1✔
2029
        D_11,
1✔
2030
    };
1✔
2031

2032
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1✔
2033
                    sizeof(expected)));
1✔
2034
    PASS;
1✔
2035
}
1✔
2036

2037
static int DefragSturgesNovakWindowsIpv6Test(void)
2038
{
1✔
2039
    /* Expected data. */
2040
    uint8_t expected[] = {
1✔
2041
        D_1,
1✔
2042
        D_1,
1✔
2043
        D_1,
1✔
2044
        D_4,
1✔
2045
        D_2,
1✔
2046
        D_2,
1✔
2047
        D_3,
1✔
2048
        D_3,
1✔
2049
        D_3,
1✔
2050
        D_6,
1✔
2051
        D_6,
1✔
2052
        D_6,
1✔
2053
        D_7,
1✔
2054
        D_3_2,
1✔
2055
        D_3_2,
1✔
2056
        D_3_3,
1✔
2057
        D_3_3,
1✔
2058
        D_3_3,
1✔
2059
        D_3_4,
1✔
2060
        D_3_4,
1✔
2061
        D_3_5,
1✔
2062
        D_3_5,
1✔
2063
        D_3_6,
1✔
2064
        D_11,
1✔
2065
    };
1✔
2066

2067
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
1✔
2068
    PASS;
1✔
2069
}
1✔
2070

2071
static int DefragSturgesNovakSolarisTest(void)
2072
{
1✔
2073
    /* Expected data. */
2074
    uint8_t expected[] = {
1✔
2075
        D_1,
1✔
2076
        D_1,
1✔
2077
        D_1,
1✔
2078
        D_4,
1✔
2079
        D_2,
1✔
2080
        D_2,
1✔
2081
        D_3,
1✔
2082
        D_3,
1✔
2083
        D_3,
1✔
2084
        D_6,
1✔
2085
        D_6,
1✔
2086
        D_6,
1✔
2087
        D_7,
1✔
2088
        D_7,
1✔
2089
        D_7,
1✔
2090
        D_3_3,
1✔
2091
        D_3_3,
1✔
2092
        D_3_3,
1✔
2093
        D_3_4,
1✔
2094
        D_3_4,
1✔
2095
        D_3_5,
1✔
2096
        D_3_5,
1✔
2097
        D_3_6,
1✔
2098
        D_11,
1✔
2099
    };
1✔
2100

2101
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1✔
2102
                    sizeof(expected)));
1✔
2103
    PASS;
1✔
2104
}
1✔
2105

2106
static int DefragSturgesNovakSolarisIpv6Test(void)
2107
{
1✔
2108
    /* Expected data. */
2109
    uint8_t expected[] = {
1✔
2110
        D_1,
1✔
2111
        D_1,
1✔
2112
        D_1,
1✔
2113
        D_4,
1✔
2114
        D_2,
1✔
2115
        D_2,
1✔
2116
        D_3,
1✔
2117
        D_3,
1✔
2118
        D_3,
1✔
2119
        D_6,
1✔
2120
        D_6,
1✔
2121
        D_6,
1✔
2122
        D_7,
1✔
2123
        D_7,
1✔
2124
        D_7,
1✔
2125
        D_3_3,
1✔
2126
        D_3_3,
1✔
2127
        D_3_3,
1✔
2128
        D_3_4,
1✔
2129
        D_3_4,
1✔
2130
        D_3_5,
1✔
2131
        D_3_5,
1✔
2132
        D_3_6,
1✔
2133
        D_11,
1✔
2134
    };
1✔
2135

2136
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
1✔
2137
    PASS;
1✔
2138
}
1✔
2139

2140
static int DefragSturgesNovakFirstTest(void)
2141
{
1✔
2142
    /* Expected data. */
2143
    uint8_t expected[] = {
1✔
2144
        D_1,
1✔
2145
        D_1,
1✔
2146
        D_1,
1✔
2147
        D_4,
1✔
2148
        D_2,
1✔
2149
        D_2,
1✔
2150
        D_3,
1✔
2151
        D_3,
1✔
2152
        D_3,
1✔
2153
        D_6,
1✔
2154
        D_3_1,
1✔
2155
        D_6,
1✔
2156
        D_7,
1✔
2157
        D_3_2,
1✔
2158
        D_3_2,
1✔
2159
        D_3_3,
1✔
2160
        D_3_3,
1✔
2161
        D_3_3,
1✔
2162
        D_3_4,
1✔
2163
        D_3_4,
1✔
2164
        D_3_5,
1✔
2165
        D_3_5,
1✔
2166
        D_3_6,
1✔
2167
        D_11,
1✔
2168
    };
1✔
2169

2170
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1✔
2171
                    sizeof(expected)));
1✔
2172
    PASS;
1✔
2173
}
1✔
2174

2175
static int DefragSturgesNovakFirstIpv6Test(void)
2176
{
1✔
2177
    /* Expected data. */
2178
    uint8_t expected[] = {
1✔
2179
        D_1,
1✔
2180
        D_1,
1✔
2181
        D_1,
1✔
2182
        D_4,
1✔
2183
        D_2,
1✔
2184
        D_2,
1✔
2185
        D_3,
1✔
2186
        D_3,
1✔
2187
        D_3,
1✔
2188
        D_6,
1✔
2189
        D_3_1,
1✔
2190
        D_6,
1✔
2191
        D_7,
1✔
2192
        D_3_2,
1✔
2193
        D_3_2,
1✔
2194
        D_3_3,
1✔
2195
        D_3_3,
1✔
2196
        D_3_3,
1✔
2197
        D_3_4,
1✔
2198
        D_3_4,
1✔
2199
        D_3_5,
1✔
2200
        D_3_5,
1✔
2201
        D_3_6,
1✔
2202
        D_11,
1✔
2203
    };
1✔
2204

2205
    return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
1✔
2206
}
1✔
2207

2208
static int
2209
DefragSturgesNovakLastTest(void)
2210
{
1✔
2211
    /* Expected data. */
2212
    uint8_t expected[] = {
1✔
2213
        D_1,
1✔
2214
        D_4,
1✔
2215
        D_4,
1✔
2216
        D_4,
1✔
2217
        D_4,
1✔
2218
        D_2,
1✔
2219
        D_5,
1✔
2220
        D_5,
1✔
2221
        D_5,
1✔
2222
        D_6,
1✔
2223
        D_6,
1✔
2224
        D_6,
1✔
2225
        D_7,
1✔
2226
        D_7,
1✔
2227
        D_7,
1✔
2228
        D_3_3,
1✔
2229
        D_8,
1✔
2230
        D_3_3,
1✔
2231
        D_3_4,
1✔
2232
        D_9,
1✔
2233
        D_10,
1✔
2234
        D_3_5,
1✔
2235
        D_11,
1✔
2236
        D_11,
1✔
2237
    };
1✔
2238

2239
    FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
1✔
2240
                    sizeof(expected)));
1✔
2241
    PASS;
1✔
2242
}
1✔
2243

2244
static int DefragSturgesNovakLastIpv6Test(void)
2245
{
1✔
2246
    /* Expected data. */
2247
    uint8_t expected[] = {
1✔
2248
        D_1,
1✔
2249
        D_4,
1✔
2250
        D_4,
1✔
2251
        D_4,
1✔
2252
        D_4,
1✔
2253
        D_2,
1✔
2254
        D_5,
1✔
2255
        D_5,
1✔
2256
        D_5,
1✔
2257
        D_6,
1✔
2258
        D_6,
1✔
2259
        D_6,
1✔
2260
        D_7,
1✔
2261
        D_7,
1✔
2262
        D_7,
1✔
2263
        D_3_3,
1✔
2264
        D_8,
1✔
2265
        D_3_3,
1✔
2266
        D_3_4,
1✔
2267
        D_9,
1✔
2268
        D_10,
1✔
2269
        D_3_5,
1✔
2270
        D_11,
1✔
2271
        D_11,
1✔
2272
    };
1✔
2273

2274
    FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
1✔
2275
    PASS;
1✔
2276
}
1✔
2277

2278
static int DefragTimeoutTest(void)
2279
{
1✔
2280
    int i;
1✔
2281

2282
    /* Setup a small number of trackers. */
2283
    FAIL_IF_NOT(SCConfSet("defrag.trackers", "16"));
1✔
2284

2285
    DefragInit();
1✔
2286

2287
    /* Load in 16 packets. */
2288
    for (i = 0; i < 16; i++) {
17✔
2289
        Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
16✔
2290
        FAIL_IF_NULL(p);
16✔
2291

2292
        Packet *tp = Defrag(&test_tv, &test_dtv, p);
16✔
2293
        PacketFree(p);
16✔
2294
        FAIL_IF_NOT_NULL(tp);
16✔
2295
    }
16✔
2296

2297
    /* Build a new packet but push the timestamp out by our timeout.
2298
     * This should force our previous fragments to be timed out. */
2299
    Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
1✔
2300
    FAIL_IF_NULL(p);
1✔
2301

2302
    p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
1✔
2303
    Packet *tp = Defrag(&test_tv, &test_dtv, p);
1✔
2304
    FAIL_IF_NOT_NULL(tp);
1✔
2305

2306
    DefragTracker *tracker = DefragLookupTrackerFromHash(p);
1✔
2307
    FAIL_IF_NULL(tracker);
1✔
2308

2309
    FAIL_IF(tracker->id != 99);
1✔
2310

2311
    SCMutexUnlock(&tracker->lock);
1✔
2312
    PacketFree(p);
1✔
2313

2314
    DefragDestroy();
1✔
2315
    PASS;
1✔
2316
}
1✔
2317

2318
/**
2319
 * QA found that if you send a packet where more frags is 0, offset is
2320
 * > 0 and there is no data in the packet that the re-assembler will
2321
 * fail.  The fix was simple, but this unit test is just to make sure
2322
 * its not introduced.
2323
 */
2324
static int DefragNoDataIpv4Test(void)
2325
{
1✔
2326
    DefragContext *dc = NULL;
1✔
2327
    Packet *p = NULL;
1✔
2328
    int id = 12;
1✔
2329

2330
    DefragInit();
1✔
2331

2332
    dc = DefragContextNew();
1✔
2333
    FAIL_IF_NULL(dc);
1✔
2334

2335
    /* This packet has an offset > 0, more frags set to 0 and no data. */
2336
    p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
1✔
2337
    FAIL_IF_NULL(p);
1✔
2338

2339
    /* We do not expect a packet returned. */
2340
    FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
1✔
2341

2342
    /* The fragment should have been ignored so no fragments should
2343
     * have been allocated from the pool. */
2344
    FAIL_IF(dc->frag_pool->outstanding != 0);
1✔
2345

2346
    DefragContextDestroy(dc);
1✔
2347
    PacketFree(p);
1✔
2348

2349
    DefragDestroy();
1✔
2350
    PASS;
1✔
2351
}
1✔
2352

2353
static int DefragTooLargeIpv4Test(void)
2354
{
1✔
2355
    DefragContext *dc = NULL;
1✔
2356
    Packet *p = NULL;
1✔
2357

2358
    DefragInit();
1✔
2359

2360
    dc = DefragContextNew();
1✔
2361
    FAIL_IF_NULL(dc);
1✔
2362

2363
    /* Create a fragment that would extend past the max allowable size
2364
     * for an IPv4 packet. */
2365
    p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
1✔
2366
    FAIL_IF_NULL(p);
1✔
2367

2368
    /* We do not expect a packet returned. */
2369
    FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
1✔
2370

2371
    /* We do expect an event. */
2372
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE));
1✔
2373

2374
    /* The fragment should have been ignored so no fragments should have
2375
     * been allocated from the pool. */
2376
    FAIL_IF(dc->frag_pool->outstanding != 0);
1✔
2377

2378
    DefragContextDestroy(dc);
1✔
2379
    PacketFree(p);
1✔
2380

2381
    DefragDestroy();
1✔
2382
    PASS;
1✔
2383
}
1✔
2384

2385
/**
2386
 * Test that fragments in different VLANs that would otherwise be
2387
 * re-assembled, are not re-assembled.  Just use simple in-order
2388
 * fragments.
2389
 */
2390
static int DefragVlanTest(void)
2391
{
1✔
2392
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
1✔
2393

2394
    DefragInit();
1✔
2395

2396
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
1✔
2397
    FAIL_IF_NULL(p1);
1✔
2398
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
1✔
2399
    FAIL_IF_NULL(p2);
1✔
2400

2401
    /* With no VLAN IDs set, packets should re-assemble. */
2402
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2403
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
1✔
2404
    PacketFree(r);
1✔
2405

2406
    /* With mismatched VLANs, packets should not re-assemble. */
2407
    p1->vlan_id[0] = 1;
1✔
2408
    p2->vlan_id[0] = 2;
1✔
2409
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2410
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
1✔
2411

2412
    PacketFree(p1);
1✔
2413
    PacketFree(p2);
1✔
2414
    DefragDestroy();
1✔
2415

2416
    PASS;
1✔
2417
}
1✔
2418

2419
/**
2420
 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2421
 */
2422
static int DefragVlanQinQTest(void)
2423
{
1✔
2424
    Packet *p1 = NULL, *p2 = NULL, *r = NULL;
1✔
2425

2426
    DefragInit();
1✔
2427

2428
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
1✔
2429
    FAIL_IF_NULL(p1);
1✔
2430
    p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
1✔
2431
    FAIL_IF_NULL(p2);
1✔
2432

2433
    /* With no VLAN IDs set, packets should re-assemble. */
2434
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2435
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
1✔
2436
    PacketFree(r);
1✔
2437

2438
    /* With mismatched VLANs, packets should not re-assemble. */
2439
    p1->vlan_id[0] = 1;
1✔
2440
    p2->vlan_id[0] = 1;
1✔
2441
    p1->vlan_id[1] = 1;
1✔
2442
    p2->vlan_id[1] = 2;
1✔
2443
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2444
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
1✔
2445

2446
    PacketFree(p1);
1✔
2447
    PacketFree(p2);
1✔
2448
    DefragDestroy();
1✔
2449

2450
    PASS;
1✔
2451
}
1✔
2452

2453
/**
2454
 * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2455
 */
2456
static int DefragVlanQinQinQTest(void)
2457
{
1✔
2458
    Packet *r = NULL;
1✔
2459

2460
    DefragInit();
1✔
2461

2462
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
1✔
2463
    FAIL_IF_NULL(p1);
1✔
2464
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
1✔
2465
    FAIL_IF_NULL(p2);
1✔
2466

2467
    /* With no VLAN IDs set, packets should re-assemble. */
2468
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2469
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
1✔
2470
    PacketFree(r);
1✔
2471

2472
    /* With mismatched VLANs, packets should not re-assemble. */
2473
    p1->vlan_id[0] = 1;
1✔
2474
    p2->vlan_id[0] = 1;
1✔
2475
    p1->vlan_id[1] = 2;
1✔
2476
    p2->vlan_id[1] = 2;
1✔
2477
    p1->vlan_id[2] = 3;
1✔
2478
    p2->vlan_id[2] = 4;
1✔
2479
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
1✔
2480
    FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
1✔
2481

2482
    PacketFree(p1);
1✔
2483
    PacketFree(p2);
1✔
2484
    DefragDestroy();
1✔
2485

2486
    PASS;
1✔
2487
}
1✔
2488
static int DefragTrackerReuseTest(void)
2489
{
1✔
2490
    int id = 1;
1✔
2491
    Packet *p1 = NULL;
1✔
2492
    DefragTracker *tracker1 = NULL, *tracker2 = NULL;
1✔
2493

2494
    DefragInit();
1✔
2495

2496
    /* Build a packet, its not a fragment but shouldn't matter for
2497
     * this test. */
2498
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
1✔
2499
    FAIL_IF_NULL(p1);
1✔
2500

2501
    /* Get a tracker. It shouldn't look like its already in use. */
2502
    tracker1 = DefragGetTracker(&test_tv, &test_dtv, p1);
1✔
2503
    FAIL_IF_NULL(tracker1);
1✔
2504
    FAIL_IF(tracker1->seen_last);
1✔
2505
    FAIL_IF(tracker1->remove);
1✔
2506
    DefragTrackerRelease(tracker1);
1✔
2507

2508
    /* Get a tracker again, it should be the same one. */
2509
    tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
1✔
2510
    FAIL_IF_NULL(tracker2);
1✔
2511
    FAIL_IF(tracker2 != tracker1);
1✔
2512
    DefragTrackerRelease(tracker1);
1✔
2513

2514
    /* Now mark the tracker for removal. It should not be returned
2515
     * when we get a tracker for a packet that may have the same
2516
     * attributes. */
2517
    tracker1->remove = 1;
1✔
2518

2519
    tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
1✔
2520
    FAIL_IF_NULL(tracker2);
1✔
2521
    /* DefragGetTracker will have returned tracker1 to the stack,
2522
     * the set up a new tracker. Since it pops the stack, it got
2523
     * tracker1. */
2524
    FAIL_IF(tracker2 != tracker1);
1✔
2525
    FAIL_IF(tracker2->remove);
1✔
2526

2527
    PacketFree(p1);
1✔
2528
    DefragDestroy();
1✔
2529
    PASS;
1✔
2530
}
1✔
2531

2532
/**
2533
 * IPV4: Test the case where you have a packet fragmented in 3 parts
2534
 * and send like:
2535
 * - Offset: 2; MF: 1
2536
 * - Offset: 0; MF: 1
2537
 * - Offset: 1; MF: 0
2538
 *
2539
 * Only the fragments with offset 0 and 1 should be reassembled.
2540
 */
2541
static int DefragMfIpv4Test(void)
2542
{
1✔
2543
    int ip_id = 9;
1✔
2544
    Packet *p = NULL;
1✔
2545

2546
    DefragInit();
1✔
2547

2548
    Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
1✔
2549
    Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
1✔
2550
    Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
1✔
2551
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
1✔
2552

2553
    p = Defrag(&test_tv, &test_dtv, p1);
1✔
2554
    FAIL_IF_NOT_NULL(p);
1✔
2555

2556
    p = Defrag(&test_tv, &test_dtv, p2);
1✔
2557
    FAIL_IF_NOT_NULL(p);
1✔
2558

2559
    /* This should return a packet as MF=0. */
2560
    p = Defrag(&test_tv, &test_dtv, p3);
1✔
2561
    FAIL_IF_NULL(p);
1✔
2562

2563
    /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2564
     * fragments should be in the re-assembled packet. */
2565
    FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(p)) != 36);
1✔
2566

2567
    /* Verify the payload of the IPv4 packet. */
2568
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
1✔
2569
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
1✔
2570

2571
    PacketFree(p1);
1✔
2572
    PacketFree(p2);
1✔
2573
    PacketFree(p3);
1✔
2574
    PacketFree(p);
1✔
2575
    DefragDestroy();
1✔
2576
    PASS;
1✔
2577
}
1✔
2578

2579
/**
2580
 * IPV6: Test the case where you have a packet fragmented in 3 parts
2581
 * and send like:
2582
 * - Offset: 2; MF: 1
2583
 * - Offset: 0; MF: 1
2584
 * - Offset: 1; MF: 0
2585
 *
2586
 * Only the fragments with offset 0 and 1 should be reassembled.
2587
 */
2588
static int DefragMfIpv6Test(void)
2589
{
1✔
2590
    int ip_id = 9;
1✔
2591
    Packet *p = NULL;
1✔
2592

2593
    DefragInit();
1✔
2594

2595
    Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
1✔
2596
    Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
1✔
2597
    Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
1✔
2598
    FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
1✔
2599

2600
    p = Defrag(&test_tv, &test_dtv, p1);
1✔
2601
    FAIL_IF_NOT_NULL(p);
1✔
2602

2603
    p = Defrag(&test_tv, &test_dtv, p2);
1✔
2604
    FAIL_IF_NOT_NULL(p);
1✔
2605

2606
    /* This should return a packet as MF=0. */
2607
    p = Defrag(&test_tv, &test_dtv, p3);
1✔
2608
    FAIL_IF_NULL(p);
1✔
2609

2610
    /* For IPv6 the expected length is just the length of the payload
2611
     * of 2 fragments, so 16. */
2612
    FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(p)) != 16);
1✔
2613

2614
    /* Verify the payload of the IPv4 packet. */
2615
    uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
1✔
2616
    FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
1✔
2617

2618
    PacketFree(p1);
1✔
2619
    PacketFree(p2);
1✔
2620
    PacketFree(p3);
1✔
2621
    PacketFree(p);
1✔
2622
    DefragDestroy();
1✔
2623
    PASS;
1✔
2624
}
1✔
2625

2626
/**
2627
 * \brief Test that fragments that match other than the proto don't
2628
 * actually get matched.
2629
 */
2630
static int DefragTestBadProto(void)
2631
{
1✔
2632
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1✔
2633
    int id = 12;
1✔
2634

2635
    DefragInit();
1✔
2636

2637
    p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1✔
2638
    FAIL_IF_NULL(p1);
1✔
2639
    p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
1✔
2640
    FAIL_IF_NULL(p2);
1✔
2641
    p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1✔
2642
    FAIL_IF_NULL(p3);
1✔
2643

2644
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p1));
1✔
2645
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p2));
1✔
2646
    FAIL_IF_NOT_NULL(Defrag(&test_tv, &test_dtv, p3));
1✔
2647

2648
    PacketFree(p1);
1✔
2649
    PacketFree(p2);
1✔
2650
    PacketFree(p3);
1✔
2651

2652
    DefragDestroy();
1✔
2653
    PASS;
1✔
2654
}
1✔
2655

2656
/**
2657
 * \test Test a report Linux overlap issue that doesn't appear to be
2658
 *     covered by the Sturges/Novak tests above.
2659
 */
2660
static int DefragTestJeremyLinux(void)
2661
{
1✔
2662

2663
    uint8_t expected[] = "AAAAAAAA"
1✔
2664
                         "AAAAAAAA"
1✔
2665
                         "AAAAAAAA"
1✔
2666
                         "CCCCCCCC"
1✔
2667
                         "CCCCCCCC"
1✔
2668
                         "CCCCCCCC"
1✔
2669
                         "CCCCCCCC"
1✔
2670
                         "CCCCCCCC"
1✔
2671
                         "CCCCCCCC"
1✔
2672
                         "BBBBBBBB"
1✔
2673
                         "BBBBBBBB"
1✔
2674
                         "DDDDDDDD"
1✔
2675
                         "DDDDDD";
1✔
2676

2677
    DefragInit();
1✔
2678
    default_policy = DEFRAG_POLICY_LINUX;
1✔
2679

2680
    int id = 1;
1✔
2681
    Packet *packets[4];
1✔
2682
    int i = 0;
1✔
2683

2684
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1✔
2685
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
1✔
2686
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
1✔
2687
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
1✔
2688

2689
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2690
    FAIL_IF_NOT_NULL(r);
1✔
2691

2692
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2693
    FAIL_IF_NOT_NULL(r);
1✔
2694

2695
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
2696
    FAIL_IF_NOT_NULL(r);
1✔
2697

2698
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
2699
    FAIL_IF_NULL(r);
1✔
2700

2701
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
1✔
2702

2703
    for (i = 0; i < 4; i++) {
5✔
2704
        PacketFree(packets[i]);
4✔
2705
    }
4✔
2706
    PacketFree(r);
1✔
2707

2708
    DefragDestroy();
1✔
2709
    PASS;
1✔
2710
}
1✔
2711

2712
/**
2713
 * | 0        | 8        | 16       | 24       | 32       |
2714
 * |----------|----------|----------|----------|----------|
2715
 * |                                  AAAAAAAA | AAAAAAAA |
2716
 * |          | BBBBBBBB | BBBBBBBB |          |          |
2717
 * |          |          | CCCCCCCC | CCCCCCCC |          |
2718
 * | DDDDDDDD |          |          |          |          |
2719
 *
2720
 * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
2721
 */
2722
static int DefragBsdFragmentAfterNoMfIpv4Test(void)
2723
{
1✔
2724
    DefragInit();
1✔
2725
    default_policy = DEFRAG_POLICY_BSD;
1✔
2726
    Packet *packets[4];
1✔
2727

2728
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
1✔
2729
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
1✔
2730
    packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
1✔
2731
    packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
1✔
2732

2733
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2734
    FAIL_IF_NOT_NULL(r);
1✔
2735

2736
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2737
    FAIL_IF_NOT_NULL(r);
1✔
2738

2739
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
2740
    FAIL_IF_NOT_NULL(r);
1✔
2741

2742
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
2743
    FAIL_IF_NULL(r);
1✔
2744

2745
    // clang-format off
2746
    uint8_t expected[] = {
1✔
2747
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
1✔
2748
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
1✔
2749
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
1✔
2750
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
1✔
2751
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
1✔
2752
    };
1✔
2753
    // clang-format on
2754

2755
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
1✔
2756
        printf("Expected:\n");
2757
        PrintRawDataFp(stdout, expected, sizeof(expected));
2758
        printf("Got:\n");
2759
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2760
        FAIL;
2761
    }
2762

2763
    for (int i = 0; i < 4; i++) {
5✔
2764
        PacketFree(packets[i]);
4✔
2765
    }
4✔
2766
    PacketFree(r);
1✔
2767
    DefragDestroy();
1✔
2768
    PASS;
1✔
2769
}
1✔
2770

2771
static int DefragBsdFragmentAfterNoMfIpv6Test(void)
2772
{
1✔
2773
    DefragInit();
1✔
2774
    default_policy = DEFRAG_POLICY_BSD;
1✔
2775
    Packet *packets[4];
1✔
2776

2777
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
1✔
2778
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
1✔
2779
    packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
1✔
2780
    packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
1✔
2781

2782
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2783
    FAIL_IF_NOT_NULL(r);
1✔
2784

2785
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2786
    FAIL_IF_NOT_NULL(r);
1✔
2787

2788
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
2789
    FAIL_IF_NOT_NULL(r);
1✔
2790

2791
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
2792
    FAIL_IF_NULL(r);
1✔
2793

2794
    // clang-format off
2795
    uint8_t expected[] = {
1✔
2796
        'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
1✔
2797
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
1✔
2798
        'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
1✔
2799
        'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
1✔
2800
        'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
1✔
2801
    };
1✔
2802
    // clang-format on
2803

2804
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
1✔
2805
        printf("Expected:\n");
2806
        PrintRawDataFp(stdout, expected, sizeof(expected));
2807
        printf("Got:\n");
2808
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2809
        FAIL;
2810
    }
2811

2812
    for (int i = 0; i < 4; i++) {
5✔
2813
        PacketFree(packets[i]);
4✔
2814
    }
4✔
2815
    PacketFree(r);
1✔
2816
    DefragDestroy();
1✔
2817
    PASS;
1✔
2818
}
1✔
2819

2820
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
2821
{
1✔
2822
    DefragInit();
1✔
2823
    default_policy = DEFRAG_POLICY_BSD;
1✔
2824
    Packet *packets[4];
1✔
2825

2826
    /* Packet 1: off=16, mf=1 */
2827
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
2828
            &packets[0], IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
1✔
2829

2830
    /* Packet 2: off=8, mf=1 */
2831
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
2832
            &packets[1], IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16));
1✔
2833

2834
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2835
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
2836
            &packets[2], IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
1✔
2837

2838
    /* Packet 4: off=8, mf=1 */
2839
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
2840
            &packets[3], IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
1✔
2841

2842
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2843
    FAIL_IF_NOT_NULL(r);
1✔
2844

2845
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2846
    FAIL_IF_NOT_NULL(r);
1✔
2847

2848
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
2849
    FAIL_IF_NOT_NULL(r);
1✔
2850

2851
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
2852
    FAIL_IF_NULL(r);
1✔
2853

2854
    // clang-format off
2855
    const uint8_t expected[] = {
1✔
2856
        // AACCBBDD
2857
        // AACCDDBB
2858
        // AABBDDCC
2859
        // DDCCBBAA
2860
        'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
1✔
2861
        'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
1✔
2862
        'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
1✔
2863
        'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
1✔
2864
    };
1✔
2865
    // clang-format on
2866

2867
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
1✔
2868

2869
    for (int i = 0; i < 4; i++) {
5✔
2870
        PacketFree(packets[i]);
4✔
2871
    }
4✔
2872
    PacketFree(r);
1✔
2873
    DefragDestroy();
1✔
2874
    PASS;
1✔
2875
}
1✔
2876

2877
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
2878
{
1✔
2879
    DefragInit();
1✔
2880
    default_policy = DEFRAG_POLICY_BSD;
1✔
2881
    Packet *packets[4];
1✔
2882

2883
    /* Packet 1: off=16, mf=1 */
2884
    packets[0] = BuildIpv6TestPacketWithContent(
1✔
2885
            IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
1✔
2886

2887
    /* Packet 2: off=8, mf=1 */
2888
    packets[1] = BuildIpv6TestPacketWithContent(
1✔
2889
            IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
1✔
2890

2891
    /* Packet 3: off=0, mf=1: IP and ICMP header. */
2892
    packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
1✔
2893

2894
    /* Packet 4: off=8, mf=1 */
2895
    packets[3] =
1✔
2896
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
1✔
2897

2898
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2899
    FAIL_IF_NOT_NULL(r);
1✔
2900

2901
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2902
    FAIL_IF_NOT_NULL(r);
1✔
2903

2904
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
2905
    FAIL_IF_NOT_NULL(r);
1✔
2906

2907
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
2908
    FAIL_IF_NULL(r);
1✔
2909

2910
    // clang-format off
2911
    const uint8_t expected[] = {
1✔
2912
        // AACCBBDD
2913
        // AACCDDBB
2914
        // AABBDDCC
2915
        // DDCCBBAA
2916
        'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
1✔
2917
        'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
1✔
2918
        'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
1✔
2919
        'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
1✔
2920
    };
1✔
2921
    // clang-format on
2922

2923
    FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
1✔
2924

2925
    for (int i = 0; i < 4; i++) {
5✔
2926
        PacketFree(packets[i]);
4✔
2927
    }
4✔
2928
    PacketFree(r);
1✔
2929
    DefragDestroy();
1✔
2930
    PASS;
1✔
2931
}
1✔
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
{
1✔
2947
    DefragInit();
1✔
2948
    default_policy = DEFRAG_POLICY_BSD;
1✔
2949
    Packet *packets[2];
1✔
2950

2951
    packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
1✔
2952
    packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
1✔
2953

2954
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2955
    FAIL_IF_NOT_NULL(r);
1✔
2956

2957
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2958
    FAIL_IF_NULL(r);
1✔
2959

2960
    // clang-format off
2961
    const uint8_t expected[] = {
1✔
2962
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
2963
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
2964
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
2965
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
1✔
2966
    };
1✔
2967
    // clang-format on
2968

2969
    if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
1✔
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
    for (int i = 0; i < 2; i++) {
3✔
2978
        PacketFree(packets[i]);
2✔
2979
    }
2✔
2980
    PacketFree(r);
1✔
2981
    DefragDestroy();
1✔
2982
    PASS;
1✔
2983
}
1✔
2984

2985
static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
2986
{
1✔
2987
    DefragInit();
1✔
2988
    default_policy = DEFRAG_POLICY_BSD;
1✔
2989
    Packet *packets[2];
1✔
2990

2991
    packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
1✔
2992
    packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
1✔
2993

2994
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
2995
    FAIL_IF_NOT_NULL(r);
1✔
2996

2997
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
2998
    FAIL_IF_NULL(r);
1✔
2999

3000
    // clang-format off
3001
    const uint8_t expected[] = {
1✔
3002
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
3003
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
3004
        'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
1✔
3005
        'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
1✔
3006
    };
1✔
3007
    // clang-format on
3008

3009
    if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
1✔
3010
        printf("Expected:\n");
3011
        PrintRawDataFp(stdout, expected, sizeof(expected));
3012
        printf("Got:\n");
3013
        PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3014
        FAIL;
3015
    }
3016

3017
    for (int i = 0; i < 2; i++) {
3✔
3018
        PacketFree(packets[i]);
2✔
3019
    }
2✔
3020
    PacketFree(r);
1✔
3021
    DefragDestroy();
1✔
3022
    PASS;
1✔
3023
}
1✔
3024

3025
/**
3026
 * Reassembly should fail.
3027
 *
3028
 * |0       |8       |16      |24      |32      |40      |48      |
3029
 * |========|========|========|========|========|========|========|
3030
 * |        |        |AABBCCDD|AABBDDCC|        |        |        |
3031
 * |        |        |        |        |        |AACCBBDD|        |
3032
 * |        |AACCDDBB|AADDBBCC|        |        |        |        |
3033
 * |ZZZZZZZZ|        |        |        |        |        |        |
3034
 * |        |        |        |        |        |        |DDCCBBAA|
3035
 */
3036
static int DefragBsdMissingFragmentIpv4Test(void)
3037
{
1✔
3038
    DefragInit();
1✔
3039
    default_policy = DEFRAG_POLICY_BSD;
1✔
3040
    Packet *packets[5];
1✔
3041

3042
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
3043
            &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
1✔
3044

3045
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
3046
            &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8));
1✔
3047

3048
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
3049
            &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16));
1✔
3050

3051
    /* ICMP header. */
3052
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
3053
            &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
1✔
3054

3055
    FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
1✔
3056
            &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
1✔
3057

3058
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
3059
    FAIL_IF_NOT_NULL(r);
1✔
3060

3061
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
3062
    FAIL_IF_NOT_NULL(r);
1✔
3063

3064
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
3065
    FAIL_IF_NOT_NULL(r);
1✔
3066

3067
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
3068
    FAIL_IF_NOT_NULL(r);
1✔
3069

3070
    r = Defrag(&test_tv, &test_dtv, packets[4]);
1✔
3071
    FAIL_IF_NOT_NULL(r);
1✔
3072

3073
#if 0
3074
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3075
#endif
3076

3077
    for (int i = 0; i < 5; i++) {
6✔
3078
        PacketFree(packets[i]);
5✔
3079
    }
5✔
3080
    DefragDestroy();
1✔
3081
    PASS;
1✔
3082
}
1✔
3083

3084
static int DefragBsdMissingFragmentIpv6Test(void)
3085
{
1✔
3086
    DefragInit();
1✔
3087
    default_policy = DEFRAG_POLICY_BSD;
1✔
3088
    Packet *packets[5];
1✔
3089

3090
    packets[0] = BuildIpv6TestPacketWithContent(
1✔
3091
            IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
1✔
3092

3093
    packets[1] =
1✔
3094
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
1✔
3095

3096
    packets[2] = BuildIpv6TestPacketWithContent(
1✔
3097
            IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
1✔
3098

3099
    /* ICMP header. */
3100
    packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
1✔
3101

3102
    packets[4] =
1✔
3103
            BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
1✔
3104

3105
    Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
1✔
3106
    FAIL_IF_NOT_NULL(r);
1✔
3107

3108
    r = Defrag(&test_tv, &test_dtv, packets[1]);
1✔
3109
    FAIL_IF_NOT_NULL(r);
1✔
3110

3111
    r = Defrag(&test_tv, &test_dtv, packets[2]);
1✔
3112
    FAIL_IF_NOT_NULL(r);
1✔
3113

3114
    r = Defrag(&test_tv, &test_dtv, packets[3]);
1✔
3115
    FAIL_IF_NOT_NULL(r);
1✔
3116

3117
    r = Defrag(&test_tv, &test_dtv, packets[4]);
1✔
3118
    FAIL_IF_NOT_NULL(r);
1✔
3119

3120
#if 0
3121
    PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3122
#endif
3123

3124
    for (int i = 0; i < 5; i++) {
6✔
3125
        PacketFree(packets[i]);
5✔
3126
    }
5✔
3127
    DefragDestroy();
1✔
3128
    PASS;
1✔
3129
}
1✔
3130

3131
#endif /* UNITTESTS */
3132

3133
void DefragRegisterTests(void)
3134
{
1✔
3135
#ifdef UNITTESTS
1✔
3136
    UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
1✔
3137
    UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
1✔
3138
    UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
1✔
3139
    UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
1✔
3140
            DefragSturgesNovakLinuxIpv4Test);
1✔
3141
    UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
1✔
3142
                   DefragSturgesNovakWindowsIpv4Test);
1✔
3143
    UtRegisterTest("DefragSturgesNovakSolarisTest",
1✔
3144
                   DefragSturgesNovakSolarisTest);
1✔
3145
    UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
1✔
3146
    UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
1✔
3147

3148
    UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
1✔
3149
    UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
1✔
3150

3151
    UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
1✔
3152
    UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
1✔
3153
    UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
1✔
3154
    UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
1✔
3155
    UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
1✔
3156
    UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
1✔
3157
    UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
1✔
3158
    UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
1✔
3159

3160
    UtRegisterTest("DefragVlanTest", DefragVlanTest);
1✔
3161
    UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
1✔
3162
    UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
1✔
3163
    UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
1✔
3164
    UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
1✔
3165
    UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
1✔
3166
    UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
1✔
3167
    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
1✔
3168

3169
    UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
1✔
3170

3171
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
1✔
3172
    UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
1✔
3173
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
1✔
3174
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
1✔
3175
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
1✔
3176
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
1✔
3177
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2",
1✔
3178
            DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
1✔
3179
    UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
1✔
3180
            DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
1✔
3181
    UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
1✔
3182
    UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
1✔
3183
#endif /* UNITTESTS */
1✔
3184
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc