1 /* Copyright (C) 2007-2012 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 normalizaton (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 
53 #include "defrag.h"
54 #include "defrag-hash.h"
55 #include "defrag-queue.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
66 #define DEFAULT_DEFRAG_POOL_SIZE 0xffff
67 
68 /**
69  * Default timeout (in seconds) before a defragmentation tracker will
70  * be released.
71  */
72 #define TIMEOUT_DEFAULT 60
73 
74 /**
75  * Maximum allowed timeout, 24 hours.
76  */
77 #define TIMEOUT_MAX (60 * 60 * 24)
78 
79 /**
80  * Minimum allowed timeout, 1 second.
81  */
82 #define TIMEOUT_MIN 1
83 
84 /** Fragment reassembly policies. */
85 enum defrag_policies {
86     DEFRAG_POLICY_FIRST = 1,
87     DEFRAG_POLICY_LAST,
88     DEFRAG_POLICY_BSD,
89     DEFRAG_POLICY_BSD_RIGHT,
90     DEFRAG_POLICY_LINUX,
91     DEFRAG_POLICY_WINDOWS,
92     DEFRAG_POLICY_SOLARIS,
93 
94     DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
95 };
96 
97 static int 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);
104 
105 /**
106  * Utility/debugging function to dump the frags associated with a
107  * tracker.  Only enable when unit tests are enabled.
108  */
109 #if 0
110 #ifdef UNITTESTS
111 static void
112 DumpFrags(DefragTracker *tracker)
113 {
114     Frag *frag;
115 
116     printf("Dumping frags for packet: ID=%d\n", tracker->id);
117     TAILQ_FOREACH(frag, &tracker->frags, next) {
118         printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip);
119         PrintRawDataFp(stdout, frag->pkt, frag->len);
120     }
121 }
122 #endif /* UNITTESTS */
123 #endif
124 
125 /**
126  * \brief Reset a frag for reuse in a pool.
127  */
128 static void
DefragFragReset(Frag * frag)129 DefragFragReset(Frag *frag)
130 {
131     if (frag->pkt != NULL)
132         SCFree(frag->pkt);
133     memset(frag, 0, sizeof(*frag));
134 }
135 
136 /**
137  * \brief Allocate a new frag for use in a pool.
138  */
139 static int
DefragFragInit(void * data,void * initdata)140 DefragFragInit(void *data, void *initdata)
141 {
142     Frag *frag = data;
143 
144     memset(frag, 0, sizeof(*frag));
145     return 1;
146 }
147 
148 /**
149  * \brief Free all frags associated with a tracker.
150  */
151 void
DefragTrackerFreeFrags(DefragTracker * tracker)152 DefragTrackerFreeFrags(DefragTracker *tracker)
153 {
154     Frag *frag, *tmp;
155 
156     /* Lock the frag pool as we'll be return items to it. */
157     SCMutexLock(&defrag_context->frag_pool_lock);
158 
159     RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
160         RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
161         DefragFragReset(frag);
162         PoolReturn(defrag_context->frag_pool, frag);
163     }
164 
165     SCMutexUnlock(&defrag_context->frag_pool_lock);
166 }
167 
168 /**
169  * \brief Create a new DefragContext.
170  *
171  * \retval On success a return an initialized DefragContext, otherwise
172  *     NULL will be returned.
173  */
174 static DefragContext *
DefragContextNew(void)175 DefragContextNew(void)
176 {
177     DefragContext *dc;
178 
179     dc = SCCalloc(1, sizeof(*dc));
180     if (unlikely(dc == NULL))
181         return NULL;
182 
183     /* Initialize the pool of trackers. */
184     intmax_t tracker_pool_size;
185     if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
186         tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
187     }
188 
189     /* Initialize the pool of frags. */
190     intmax_t frag_pool_size;
191     if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
192         frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
193     }
194     intmax_t frag_pool_prealloc = frag_pool_size / 2;
195     dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
196         sizeof(Frag),
197         NULL, DefragFragInit, dc, NULL, NULL);
198     if (dc->frag_pool == NULL) {
199             FatalError(SC_ERR_FATAL,
200                        "Defrag: Failed to initialize fragment pool.");
201     }
202     if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
203             FatalError(SC_ERR_FATAL,
204                        "Defrag: Failed to initialize frag pool mutex.");
205     }
206 
207     /* Set the default timeout. */
208     intmax_t timeout;
209     if (!ConfGetInt("defrag.timeout", &timeout)) {
210         dc->timeout = TIMEOUT_DEFAULT;
211     }
212     else {
213         if (timeout < TIMEOUT_MIN) {
214                 FatalError(SC_ERR_FATAL,
215                            "defrag: Timeout less than minimum allowed value.");
216         }
217         else if (timeout > TIMEOUT_MAX) {
218                 FatalError(SC_ERR_FATAL,
219                            "defrag: Tiemout greater than maximum allowed value.");
220         }
221         dc->timeout = timeout;
222     }
223 
224     SCLogDebug("Defrag Initialized:");
225     SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
226     SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
227     SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
228     SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
229     SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
230 
231     return dc;
232 }
233 
234 static void
DefragContextDestroy(DefragContext * dc)235 DefragContextDestroy(DefragContext *dc)
236 {
237     if (dc == NULL)
238         return;
239 
240     PoolFree(dc->frag_pool);
241     SCFree(dc);
242 }
243 
244 /**
245  * Attempt to re-assemble a packet.
246  *
247  * \param tracker The defragmentation tracker to reassemble from.
248  */
249 static Packet *
Defrag4Reassemble(ThreadVars * tv,DefragTracker * tracker,Packet * p)250 Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
251 {
252     Packet *rp = NULL;
253 
254     /* Should not be here unless we have seen the last fragment. */
255     if (!tracker->seen_last) {
256         return NULL;
257     }
258 
259     /* Check that we have the first fragment and its of a valid size. */
260     Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
261     if (first == NULL) {
262         goto done;
263     } else if (first->offset != 0) {
264         /* Still waiting for the first fragment. */
265         goto done;
266     } else if (first->len < sizeof(IPV4Hdr)) {
267         /* First fragment isn't enough for an IPv6 header. */
268         goto error_remove_tracker;
269     }
270 
271     /* Check that we have all the data. Relies on the fact that
272      * fragments are inserted if frag_offset order. */
273     Frag *frag = NULL;
274     size_t len = 0;
275     RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
276         if (frag->offset > len) {
277             /* This fragment starts after the end of the previous
278              * fragment.  We have a hole. */
279             goto done;
280         }
281         else {
282             len += frag->data_len;
283         }
284     }
285 
286     /* Allocate a Packet for the reassembled packet.  On failure we
287      * SCFree all the resources held by this tracker. */
288     rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
289     if (rp == NULL) {
290         SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
291                    "fragmentation re-assembly, dumping fragments.");
292         goto error_remove_tracker;
293     }
294     PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
295     rp->flags |= PKT_REBUILT_FRAGMENT;
296     rp->recursion_level = p->recursion_level;
297 
298     int fragmentable_offset = 0;
299     int fragmentable_len = 0;
300     int hlen = 0;
301     int ip_hdr_offset = 0;
302 
303     RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
304         SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
305                 frag, frag->data_len, frag->offset, frag->pcap_cnt);
306 
307         if (frag->skip)
308             continue;
309         if (frag->ltrim >= frag->data_len)
310             continue;
311         if (frag->offset == 0) {
312 
313             if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
314                 goto error_remove_tracker;
315 
316             hlen = frag->hlen;
317             ip_hdr_offset = frag->ip_hdr_offset;
318 
319             /* This is the start of the fragmentable portion of the
320              * first packet.  All fragment offsets are relative to
321              * this. */
322             fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
323             fragmentable_len = frag->data_len;
324         }
325         else {
326             int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
327             if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
328                 SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble "
329                         "fragmented packet, exceeds size of packet buffer.");
330                 goto error_remove_tracker;
331             }
332             if (PacketCopyDataOffset(rp,
333                     fragmentable_offset + frag->offset + frag->ltrim,
334                     frag->pkt + frag->data_offset + frag->ltrim,
335                     frag->data_len - frag->ltrim) == -1) {
336                 goto error_remove_tracker;
337             }
338             if (frag->offset + frag->data_len > fragmentable_len)
339                 fragmentable_len = frag->offset + frag->data_len;
340         }
341 
342         if (!frag->more_frags) {
343             break;
344         }
345     }
346 
347     SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u",
348             ip_hdr_offset, hlen, fragmentable_len);
349 
350     rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
351     int old = rp->ip4h->ip_len + rp->ip4h->ip_off;
352     rp->ip4h->ip_len = htons(fragmentable_len + hlen);
353     rp->ip4h->ip_off = 0;
354     rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
355         old, rp->ip4h->ip_len + rp->ip4h->ip_off);
356     SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
357 
358     tracker->remove = 1;
359     DefragTrackerFreeFrags(tracker);
360 done:
361     return rp;
362 
363 error_remove_tracker:
364     tracker->remove = 1;
365     DefragTrackerFreeFrags(tracker);
366     if (rp != NULL)
367         PacketFreeOrRelease(rp);
368     return NULL;
369 }
370 
371 /**
372  * Attempt to re-assemble a packet.
373  *
374  * \param tracker The defragmentation tracker to reassemble from.
375  */
376 static Packet *
Defrag6Reassemble(ThreadVars * tv,DefragTracker * tracker,Packet * p)377 Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
378 {
379     Packet *rp = NULL;
380 
381     /* Should not be here unless we have seen the last fragment. */
382     if (!tracker->seen_last)
383         return NULL;
384 
385     /* Check that we have the first fragment and its of a valid size. */
386     Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
387     if (first == NULL) {
388         goto done;
389     } else if (first->offset != 0) {
390         /* Still waiting for the first fragment. */
391         goto done;
392     } else if (first->len < sizeof(IPV6Hdr)) {
393         /* First fragment isn't enough for an IPv6 header. */
394         goto error_remove_tracker;
395     }
396 
397     /* Check that we have all the data. Relies on the fact that
398      * fragments are inserted if frag_offset order. */
399     size_t len = 0;
400     Frag *frag = NULL;
401     RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
402         if (frag->skip) {
403             continue;
404         }
405 
406         if (frag == first) {
407             if (frag->offset != 0) {
408                 goto done;
409             }
410             len = frag->data_len;
411         }
412         else {
413             if (frag->offset > len) {
414                 /* This fragment starts after the end of the previous
415                  * fragment.  We have a hole. */
416                 goto done;
417             }
418             else {
419                 len += frag->data_len;
420             }
421         }
422     }
423 
424     /* Allocate a Packet for the reassembled packet.  On failure we
425      * SCFree all the resources held by this tracker. */
426     rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
427             IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
428     if (rp == NULL) {
429         SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
430                 "fragmentation re-assembly, dumping fragments.");
431         goto error_remove_tracker;
432     }
433     PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
434 
435     int unfragmentable_len = 0;
436     int fragmentable_offset = 0;
437     int fragmentable_len = 0;
438     int ip_hdr_offset = 0;
439     uint8_t next_hdr = 0;
440     RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
441         if (frag->skip)
442             continue;
443         if (frag->data_len - frag->ltrim <= 0)
444             continue;
445         if (frag->offset == 0) {
446             IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
447                 frag->frag_hdr_offset);
448             next_hdr = frag_hdr->ip6fh_nxt;
449 
450             /* This is the first packet, we use this packets link and
451              * IPv6 headers. We also copy in its data, but remove the
452              * fragmentation header. */
453             if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
454                 goto error_remove_tracker;
455             if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
456                 frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
457                 frag->data_len) == -1)
458                 goto error_remove_tracker;
459             ip_hdr_offset = frag->ip_hdr_offset;
460 
461             /* This is the start of the fragmentable portion of the
462              * first packet.  All fragment offsets are relative to
463              * this. */
464             fragmentable_offset = frag->frag_hdr_offset;
465             fragmentable_len = frag->data_len;
466 
467             /* unfragmentable part is the part between the ipv6 header
468              * and the frag header. */
469             unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN;
470             if (unfragmentable_len >= fragmentable_offset)
471                 goto error_remove_tracker;
472         }
473         else {
474             if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
475                 frag->pkt + frag->data_offset + frag->ltrim,
476                 frag->data_len - frag->ltrim) == -1)
477                 goto error_remove_tracker;
478             if (frag->offset + frag->data_len > fragmentable_len)
479                 fragmentable_len = frag->offset + frag->data_len;
480         }
481 
482         if (!frag->more_frags) {
483             break;
484         }
485     }
486 
487     rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
488     rp->ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
489     /* if we have no unfragmentable part, so no ext hdrs before the frag
490      * header, we need to update the ipv6 headers next header field. This
491      * points to the frag header, and we will make it point to the layer
492      * directly after the frag header. */
493     if (unfragmentable_len == 0)
494         rp->ip6h->s_ip6_nxt = next_hdr;
495     SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
496             unfragmentable_len + fragmentable_len);
497 
498     tracker->remove = 1;
499     DefragTrackerFreeFrags(tracker);
500 done:
501     return rp;
502 
503 error_remove_tracker:
504     tracker->remove = 1;
505     DefragTrackerFreeFrags(tracker);
506     if (rp != NULL)
507         PacketFreeOrRelease(rp);
508     return NULL;
509 }
510 
511 /**
512  * The RB_TREE compare function for fragments.
513  *
514  * When it comes to adding fragments, we want subsequent ones with the
515  * same offset to be treated as greater than, so we don't have an
516  * equal return value here.
517  */
DefragRbFragCompare(struct Frag_ * a,struct Frag_ * b)518 int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
519     if (a->offset < b->offset) {
520         return -1;
521     }
522     return 1;
523 }
524 
525 /**
526  * Insert a new IPv4/IPv6 fragment into a tracker.
527  *
528  * \todo Allocate packet buffers from a pool.
529  */
530 static Packet *
DefragInsertFrag(ThreadVars * tv,DecodeThreadVars * dtv,DefragTracker * tracker,Packet * p)531 DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
532 {
533     Packet *r = NULL;
534     int ltrim = 0;
535 
536     uint8_t more_frags;
537     uint16_t frag_offset;
538 
539     /* IPv4 header length - IPv4 only. */
540     uint16_t hlen = 0;
541 
542     /* This is the offset of the start of the data in the packet that
543      * falls after the IP header. */
544     uint16_t data_offset;
545 
546     /* The length of the (fragmented) data.  This is the length of the
547      * data that falls after the IP header. */
548     uint16_t data_len;
549 
550     /* Where the fragment ends. */
551     uint16_t frag_end;
552 
553     /* Offset in the packet to the IPv6 header. */
554     uint16_t ip_hdr_offset;
555 
556     /* Offset in the packet to the IPv6 frag header. IPv6 only. */
557     uint16_t frag_hdr_offset = 0;
558 
559     /* Address family */
560     int af = tracker->af;
561 
562     /* settings for updating a payload when an ip6 fragment with
563      * unfragmentable exthdrs are encountered. */
564     int ip6_nh_set_offset = 0;
565     uint8_t ip6_nh_set_value = 0;
566 
567 #ifdef DEBUG
568     uint64_t pcap_cnt = p->pcap_cnt;
569 #endif
570 
571     if (tracker->af == AF_INET) {
572         more_frags = IPV4_GET_MF(p);
573         frag_offset = IPV4_GET_IPOFFSET(p) << 3;
574         hlen = IPV4_GET_HLEN(p);
575         data_offset = (uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p);
576         data_len = IPV4_GET_IPLEN(p) - hlen;
577         frag_end = frag_offset + data_len;
578         ip_hdr_offset = (uint8_t *)p->ip4h - GET_PKT_DATA(p);
579 
580         /* Ignore fragment if the end of packet extends past the
581          * maximum size of a packet. */
582         if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
583             ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
584             return NULL;
585         }
586     }
587     else if (tracker->af == AF_INET6) {
588         more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
589         frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
590         data_offset = p->ip6eh.fh_data_offset;
591         data_len = p->ip6eh.fh_data_len;
592         frag_end = frag_offset + data_len;
593         ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p);
594         frag_hdr_offset = p->ip6eh.fh_header_offset;
595 
596         SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
597                 "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
598                 more_frags ? "true" : "false", frag_offset, data_offset,
599                 data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
600 
601         /* handle unfragmentable exthdrs */
602         if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
603             SCLogDebug("we have exthdrs before fraghdr %u bytes",
604                     (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
605 
606             /* get the offset of the 'next' field in exthdr before the FH,
607              * relative to the buffer start */
608 
609             /* store offset and FH 'next' value for updating frag buffer below */
610             ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset;
611             ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
612             SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
613         }
614 
615         /* Ignore fragment if the end of packet extends past the
616          * maximum size of a packet. */
617         if (frag_offset + data_len > IPV6_MAXPACKET) {
618             ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
619             return NULL;
620         }
621     }
622     else {
623         /* Abort - should not happen. */
624         SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting.");
625         return NULL;
626     }
627 
628     /* Update timeout. */
629     tracker->timeout.tv_sec = p->ts.tv_sec + tracker->host_timeout;
630     tracker->timeout.tv_usec = p->ts.tv_usec;
631 
632     Frag *prev = NULL, *next = NULL;
633     bool overlap = false;
634     ltrim = 0;
635 
636     if (!RB_EMPTY(&tracker->fragment_tree)) {
637         Frag key = {
638             .offset = frag_offset - 1,
639         };
640         next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
641         if (next == NULL) {
642             prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
643             next = IP_FRAGMENTS_RB_NEXT(prev);
644         } else {
645             prev = IP_FRAGMENTS_RB_PREV(next);
646             if (prev == NULL) {
647                 prev = next;
648                 next = IP_FRAGMENTS_RB_NEXT(prev);
649             }
650         }
651         while (prev != NULL) {
652             if (prev->skip) {
653                 goto next;
654             }
655             if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
656                 overlap = true;
657             }
658 
659             switch (tracker->policy) {
660             case DEFRAG_POLICY_BSD:
661                 if (frag_offset < prev->offset + prev->data_len) {
662                     if (frag_offset >= prev->offset) {
663                         ltrim = prev->offset + prev->data_len - frag_offset;
664                     }
665                     if ((next != NULL) && (frag_end > next->offset)) {
666                         next->ltrim = frag_end - next->offset;
667                     }
668                     if ((frag_offset < prev->offset) &&
669                         (frag_end >= prev->offset + prev->data_len)) {
670                         prev->skip = 1;
671                     }
672                     goto insert;
673                 }
674                 break;
675             case DEFRAG_POLICY_LINUX:
676                 /* Check if new fragment overlaps the end of previous
677                  * fragment, if it does, trim the new fragment.
678                  *
679                  * Old: AAAAAAAA AAAAAAAA AAAAAAAA
680                  * New:          BBBBBBBB BBBBBBBB BBBBBBBB
681                  * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
682                  */
683                 if (prev->offset + prev->ltrim < frag_offset + ltrim &&
684                         prev->offset + prev->data_len > frag_offset + ltrim) {
685                     ltrim += prev->offset + prev->data_len - frag_offset;
686                 }
687 
688                 /* Check if new fragment overlaps the beginning of
689                  * previous fragment, if it does, tim the previous
690                  * fragment.
691                  *
692                  * Old:          AAAAAAAA AAAAAAAA
693                  * New: BBBBBBBB BBBBBBBB BBBBBBBB
694                  * Res: BBBBBBBB BBBBBBBB BBBBBBBB
695                  */
696                 if (frag_offset + ltrim < prev->offset + prev->ltrim &&
697                         frag_end > prev->offset + prev->ltrim) {
698                     prev->ltrim += frag_end - (prev->offset + prev->ltrim);
699                     goto insert;
700                 }
701 
702                 /* If the new fragment completely overlaps the
703                  * previous fragment, mark the previous to be
704                  * skipped. Re-assembly would succeed without doing
705                  * this, but this will prevent the bytes from being
706                  * copied just to be overwritten. */
707                 if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
708                         frag_end >= prev->offset + prev->data_len) {
709                     prev->skip = 1;
710                     goto insert;
711                 }
712 
713                 break;
714             case DEFRAG_POLICY_WINDOWS:
715                 /* If new fragment fits inside a previous fragment, drop it. */
716                 if (frag_offset + ltrim >= prev->offset + ltrim &&
717                         frag_end <= prev->offset + prev->data_len) {
718                     goto done;
719                 }
720 
721                 /* If new fragment starts before and ends after
722                  * previous fragment, drop the previous fragment. */
723                 if (frag_offset + ltrim < prev->offset + ltrim &&
724                         frag_end > prev->offset + prev->data_len) {
725                     prev->skip = 1;
726                     goto insert;
727                 }
728 
729                 /* Check if new fragment overlaps the end of previous
730                  * fragment, if it does, trim the new fragment.
731                  *
732                  * Old: AAAAAAAA AAAAAAAA AAAAAAAA
733                  * New:          BBBBBBBB BBBBBBBB BBBBBBBB
734                  * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
735                  */
736                 if (frag_offset + ltrim > prev->offset + prev->ltrim &&
737                         frag_offset + ltrim < prev->offset + prev->data_len) {
738                     ltrim += prev->offset + prev->data_len - frag_offset;
739                     goto insert;
740                 }
741 
742                 /* If new fragment starts at same offset as an
743                  * existing fragment, but ends after it, trim the new
744                  * fragment. */
745                 if (frag_offset + ltrim == prev->offset + ltrim &&
746                         frag_end > prev->offset + prev->data_len) {
747                     ltrim += prev->offset + prev->data_len - frag_offset;
748                     goto insert;
749                 }
750                 break;
751             case DEFRAG_POLICY_SOLARIS:
752                 if (frag_offset < prev->offset + prev->data_len) {
753                     if (frag_offset >= prev->offset) {
754                         ltrim = prev->offset + prev->data_len - frag_offset;
755                     }
756                     if ((frag_offset < prev->offset) &&
757                         (frag_end >= prev->offset + prev->data_len)) {
758                         prev->skip = 1;
759                     }
760                     goto insert;
761                 }
762                 break;
763             case DEFRAG_POLICY_FIRST:
764                 if ((frag_offset >= prev->offset) &&
765                     (frag_end <= prev->offset + prev->data_len)) {
766                     goto done;
767                 }
768                 if (frag_offset < prev->offset) {
769                     goto insert;
770                 }
771                 if (frag_offset < prev->offset + prev->data_len) {
772                     ltrim = prev->offset + prev->data_len - frag_offset;
773                     goto insert;
774                 }
775                 break;
776             case DEFRAG_POLICY_LAST:
777                 if (frag_offset <= prev->offset) {
778                     if (frag_end > prev->offset) {
779                         prev->ltrim = frag_end - prev->offset;
780                     }
781                     goto insert;
782                 }
783                 break;
784             default:
785                 break;
786             }
787 
788         next:
789             prev = next;
790             if (next != NULL) {
791                 next = IP_FRAGMENTS_RB_NEXT(next);
792             }
793             continue;
794 
795         insert:
796             /* If existing fragment has been trimmed up completely
797              * (complete overlap), remove it now instead of holding
798              * onto it. */
799             if (prev->skip || prev->ltrim >= prev->data_len) {
800                 RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
801                 DefragFragReset(prev);
802                 SCMutexLock(&defrag_context->frag_pool_lock);
803                 PoolReturn(defrag_context->frag_pool, prev);
804                 SCMutexUnlock(&defrag_context->frag_pool_lock);
805             }
806             break;
807         }
808     }
809 
810     if (ltrim > data_len) {
811         /* Full packet has been trimmed due to the overlap policy. Overlap
812          * already set. */
813         goto done;
814     }
815 
816     /* Allocate fragment and insert. */
817     SCMutexLock(&defrag_context->frag_pool_lock);
818     Frag *new = PoolGet(defrag_context->frag_pool);
819     SCMutexUnlock(&defrag_context->frag_pool_lock);
820     if (new == NULL) {
821         if (af == AF_INET) {
822             ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
823         } else {
824             ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
825         }
826         goto done;
827     }
828     new->pkt = SCMalloc(GET_PKT_LEN(p));
829     if (new->pkt == NULL) {
830         SCMutexLock(&defrag_context->frag_pool_lock);
831         PoolReturn(defrag_context->frag_pool, new);
832         SCMutexUnlock(&defrag_context->frag_pool_lock);
833         if (af == AF_INET) {
834             ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
835         } else {
836             ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
837         }
838         goto done;
839     }
840     memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
841     new->len = GET_PKT_LEN(p) - ltrim;
842     /* in case of unfragmentable exthdrs, update the 'next hdr' field
843      * in the raw buffer so the reassembled packet will point to the
844      * correct next header after stripping the frag header */
845     if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
846         if (new->len > ip6_nh_set_offset) {
847             SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
848                     new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
849             new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
850         }
851     }
852 
853     new->hlen = hlen;
854     new->offset = frag_offset + ltrim;
855     new->data_offset = data_offset;
856     new->data_len = data_len - ltrim;
857     new->ip_hdr_offset = ip_hdr_offset;
858     new->frag_hdr_offset = frag_hdr_offset;
859     new->more_frags = more_frags;
860 #ifdef DEBUG
861     new->pcap_cnt = pcap_cnt;
862 #endif
863 
864     IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
865 
866     if (!more_frags) {
867         tracker->seen_last = 1;
868     }
869 
870     if (tracker->seen_last) {
871         if (tracker->af == AF_INET) {
872             r = Defrag4Reassemble(tv, tracker, p);
873             if (r != NULL && tv != NULL && dtv != NULL) {
874                 StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
875                 if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
876                                IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
877 
878                     UNSET_TUNNEL_PKT(r);
879                     r->root = NULL;
880                     TmqhOutputPacketpool(tv, r);
881                     r = NULL;
882                 } else {
883                     PacketDefragPktSetupParent(p);
884                 }
885             }
886         }
887         else if (tracker->af == AF_INET6) {
888             r = Defrag6Reassemble(tv, tracker, p);
889             if (r != NULL && tv != NULL && dtv != NULL) {
890                 StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
891                 if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
892                                IPV6_GET_PLEN(r) + IPV6_HEADER_LEN)
893                                != TM_ECODE_OK) {
894 
895                     UNSET_TUNNEL_PKT(r);
896                     r->root = NULL;
897                     TmqhOutputPacketpool(tv, r);
898                     r = NULL;
899                 } else {
900                     PacketDefragPktSetupParent(p);
901                 }
902             }
903         }
904     }
905 
906 
907 done:
908     if (overlap) {
909         if (af == AF_INET) {
910             ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
911         }
912         else {
913             ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
914         }
915     }
916     return r;
917 }
918 
919 /**
920  * \brief Get the defrag policy based on the destination address of
921  * the packet.
922  *
923  * \param p The packet used to get the destination address.
924  *
925  * \retval The defrag policy to use.
926  */
927 uint8_t
DefragGetOsPolicy(Packet * p)928 DefragGetOsPolicy(Packet *p)
929 {
930     int policy = -1;
931 
932     if (PKT_IS_IPV4(p)) {
933         policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
934     }
935     else if (PKT_IS_IPV6(p)) {
936         policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
937     }
938 
939     if (policy == -1) {
940         return default_policy;
941     }
942 
943     /* Map the OS policies returned from the configured host info to
944      * defrag specific policies. */
945     switch (policy) {
946         /* BSD. */
947     case OS_POLICY_BSD:
948     case OS_POLICY_HPUX10:
949     case OS_POLICY_IRIX:
950         return DEFRAG_POLICY_BSD;
951 
952         /* BSD-Right. */
953     case OS_POLICY_BSD_RIGHT:
954         return DEFRAG_POLICY_BSD_RIGHT;
955 
956         /* Linux. */
957     case OS_POLICY_OLD_LINUX:
958     case OS_POLICY_LINUX:
959         return DEFRAG_POLICY_LINUX;
960 
961         /* First. */
962     case OS_POLICY_OLD_SOLARIS:
963     case OS_POLICY_HPUX11:
964     case OS_POLICY_MACOS:
965     case OS_POLICY_FIRST:
966         return DEFRAG_POLICY_FIRST;
967 
968         /* Solaris. */
969     case OS_POLICY_SOLARIS:
970         return DEFRAG_POLICY_SOLARIS;
971 
972         /* Windows. */
973     case OS_POLICY_WINDOWS:
974     case OS_POLICY_VISTA:
975     case OS_POLICY_WINDOWS2K3:
976         return DEFRAG_POLICY_WINDOWS;
977 
978         /* Last. */
979     case OS_POLICY_LAST:
980         return DEFRAG_POLICY_LAST;
981 
982     default:
983         return default_policy;
984     }
985 }
986 
987 /** \internal
988  *
989  *  \retval NULL or a *LOCKED* tracker */
990 static DefragTracker *
DefragGetTracker(ThreadVars * tv,DecodeThreadVars * dtv,Packet * p)991 DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
992 {
993     return DefragGetTrackerFromHash(p);
994 }
995 
996 /**
997  * \brief Entry point for IPv4 and IPv6 fragments.
998  *
999  * \param tv ThreadVars for the calling decoder.
1000  * \param p The packet fragment.
1001  *
1002  * \retval A new Packet resembling the re-assembled packet if the most
1003  *     recent fragment allowed the packet to be re-assembled, otherwise
1004  *     NULL is returned.
1005  */
1006 Packet *
Defrag(ThreadVars * tv,DecodeThreadVars * dtv,Packet * p)1007 Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1008 {
1009     uint16_t frag_offset;
1010     uint8_t more_frags;
1011     DefragTracker *tracker;
1012     int af;
1013 
1014     if (PKT_IS_IPV4(p)) {
1015         af = AF_INET;
1016         more_frags = IPV4_GET_MF(p);
1017         frag_offset = IPV4_GET_IPOFFSET(p);
1018     }
1019     else if (PKT_IS_IPV6(p)) {
1020         af = AF_INET6;
1021         frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1022         more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1023     }
1024     else {
1025         return NULL;
1026     }
1027 
1028     if (frag_offset == 0 && more_frags == 0) {
1029         return NULL;
1030     }
1031 
1032     if (tv != NULL && dtv != NULL) {
1033         if (af == AF_INET) {
1034             StatsIncr(tv, dtv->counter_defrag_ipv4_fragments);
1035         }
1036         else if (af == AF_INET6) {
1037             StatsIncr(tv, dtv->counter_defrag_ipv6_fragments);
1038         }
1039     }
1040 
1041     /* return a locked tracker or NULL */
1042     tracker = DefragGetTracker(tv, dtv, p);
1043     if (tracker == NULL)
1044         return NULL;
1045 
1046     Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1047     DefragTrackerRelease(tracker);
1048 
1049     return rp;
1050 }
1051 
1052 void
DefragInit(void)1053 DefragInit(void)
1054 {
1055     intmax_t tracker_pool_size;
1056     if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1057         tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1058     }
1059 
1060     /* Load the defrag-per-host lookup. */
1061     DefragPolicyLoadFromConfig();
1062 
1063     /* Allocate the DefragContext. */
1064     defrag_context = DefragContextNew();
1065     if (defrag_context == NULL) {
1066             FatalError(SC_ERR_FATAL,
1067                        "Failed to allocate memory for the Defrag module.");
1068     }
1069 
1070     DefragSetDefaultTimeout(defrag_context->timeout);
1071     DefragInitConfig(FALSE);
1072 }
1073 
DefragDestroy(void)1074 void DefragDestroy(void)
1075 {
1076     DefragHashShutdown();
1077     DefragContextDestroy(defrag_context);
1078     defrag_context = NULL;
1079     DefragTreeDestroy();
1080 }
1081 
1082 #ifdef UNITTESTS
1083 #define IP_MF 0x2000
1084 
1085 /**
1086  * Allocate a test packet.  Nothing to fancy, just a simple IP packet
1087  * with some payload of no particular protocol.
1088  */
BuildTestPacket(uint8_t proto,uint16_t id,uint16_t off,int mf,const char content,int content_len)1089 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1090         const char content, int content_len)
1091 {
1092     Packet *p = NULL;
1093     int hlen = 20;
1094     int ttl = 64;
1095     uint8_t *pcontent;
1096     IPV4Hdr ip4h;
1097 
1098     p = SCCalloc(1, sizeof(*p) + default_packet_size);
1099     if (unlikely(p == NULL))
1100         return NULL;
1101 
1102     PACKET_INITIALIZE(p);
1103 
1104     gettimeofday(&p->ts, NULL);
1105     //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1106     ip4h.ip_verhl = 4 << 4;
1107     ip4h.ip_verhl |= hlen >> 2;
1108     ip4h.ip_len = htons(hlen + content_len);
1109     ip4h.ip_id = htons(id);
1110     if (mf)
1111         ip4h.ip_off = htons(IP_MF | off);
1112     else
1113         ip4h.ip_off = htons(off);
1114     ip4h.ip_ttl = ttl;
1115     ip4h.ip_proto = proto;
1116 
1117     ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1118     ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1119 
1120     /* copy content_len crap, we need full length */
1121     PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1122     p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1123     SET_IPV4_SRC_ADDR(p, &p->src);
1124     SET_IPV4_DST_ADDR(p, &p->dst);
1125 
1126     pcontent = SCCalloc(1, content_len);
1127     if (unlikely(pcontent == NULL))
1128         return NULL;
1129     memset(pcontent, content, content_len);
1130     PacketCopyDataOffset(p, hlen, pcontent, content_len);
1131     SET_PKT_LEN(p, hlen + content_len);
1132     SCFree(pcontent);
1133 
1134     p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1135 
1136     /* Self test. */
1137     if (IPV4_GET_VER(p) != 4)
1138         goto error;
1139     if (IPV4_GET_HLEN(p) != hlen)
1140         goto error;
1141     if (IPV4_GET_IPLEN(p) != hlen + content_len)
1142         goto error;
1143     if (IPV4_GET_IPID(p) != id)
1144         goto error;
1145     if (IPV4_GET_IPOFFSET(p) != off)
1146         goto error;
1147     if (IPV4_GET_MF(p) != mf)
1148         goto error;
1149     if (IPV4_GET_IPTTL(p) != ttl)
1150         goto error;
1151     if (IPV4_GET_IPPROTO(p) != proto)
1152         goto error;
1153 
1154     return p;
1155 error:
1156     if (p != NULL)
1157         SCFree(p);
1158     return NULL;
1159 }
1160 
IPV6BuildTestPacket(uint8_t proto,uint32_t id,uint16_t off,int mf,const char content,int content_len)1161 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1162         int mf, const char content, int content_len)
1163 {
1164     Packet *p = NULL;
1165     uint8_t *pcontent;
1166     IPV6Hdr ip6h;
1167 
1168     p = SCCalloc(1, sizeof(*p) + default_packet_size);
1169     if (unlikely(p == NULL))
1170         return NULL;
1171 
1172     PACKET_INITIALIZE(p);
1173 
1174     gettimeofday(&p->ts, NULL);
1175 
1176     ip6h.s_ip6_nxt = 44;
1177     ip6h.s_ip6_hlim = 2;
1178 
1179     /* Source and dest address - very bogus addresses. */
1180     ip6h.s_ip6_src[0] = 0x01010101;
1181     ip6h.s_ip6_src[1] = 0x01010101;
1182     ip6h.s_ip6_src[2] = 0x01010101;
1183     ip6h.s_ip6_src[3] = 0x01010101;
1184     ip6h.s_ip6_dst[0] = 0x02020202;
1185     ip6h.s_ip6_dst[1] = 0x02020202;
1186     ip6h.s_ip6_dst[2] = 0x02020202;
1187     ip6h.s_ip6_dst[3] = 0x02020202;
1188 
1189     /* copy content_len crap, we need full length */
1190     PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1191 
1192     p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1193     IPV6_SET_RAW_VER(p->ip6h, 6);
1194     /* Fragmentation header. */
1195     IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1196     fh->ip6fh_nxt = proto;
1197     fh->ip6fh_ident = htonl(id);
1198     fh->ip6fh_offlg = htons((off << 3) | mf);
1199 
1200     DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1201 
1202     pcontent = SCCalloc(1, content_len);
1203     if (unlikely(pcontent == NULL))
1204         return NULL;
1205     memset(pcontent, content, content_len);
1206     PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1207     SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1208     SCFree(pcontent);
1209 
1210     p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1211 
1212     SET_IPV6_SRC_ADDR(p, &p->src);
1213     SET_IPV6_DST_ADDR(p, &p->dst);
1214 
1215     /* Self test. */
1216     if (IPV6_GET_VER(p) != 6)
1217         goto error;
1218     if (IPV6_GET_NH(p) != 44)
1219         goto error;
1220     if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1221         goto error;
1222 
1223     return p;
1224 error:
1225     if (p != NULL)
1226         SCFree(p);
1227     return NULL;
1228 }
1229 
1230 /**
1231  * Test the simplest possible re-assembly scenario.  All packet in
1232  * order and no overlaps.
1233  */
DefragInOrderSimpleTest(void)1234 static int DefragInOrderSimpleTest(void)
1235 {
1236     Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1237     Packet *reassembled = NULL;
1238     int id = 12;
1239     int i;
1240 
1241     DefragInit();
1242 
1243     p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1244     FAIL_IF_NULL(p1);
1245     p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1246     FAIL_IF_NULL(p2);
1247     p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1248     FAIL_IF_NULL(p3);
1249 
1250     FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1251     FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1252 
1253     reassembled = Defrag(NULL, NULL, p3);
1254     FAIL_IF_NULL(reassembled);
1255 
1256     FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1257     FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1258 
1259     /* 20 bytes in we should find 8 bytes of A. */
1260     for (i = 20; i < 20 + 8; i++) {
1261         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1262     }
1263 
1264     /* 28 bytes in we should find 8 bytes of B. */
1265     for (i = 28; i < 28 + 8; i++) {
1266         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1267     }
1268 
1269     /* And 36 bytes in we should find 3 bytes of C. */
1270     for (i = 36; i < 36 + 3; i++) {
1271         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1272     }
1273 
1274     SCFree(p1);
1275     SCFree(p2);
1276     SCFree(p3);
1277     SCFree(reassembled);
1278 
1279     DefragDestroy();
1280     PASS;
1281 }
1282 
1283 /**
1284  * Simple fragmented packet in reverse order.
1285  */
DefragReverseSimpleTest(void)1286 static int DefragReverseSimpleTest(void)
1287 {
1288     Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1289     Packet *reassembled = NULL;
1290     int id = 12;
1291     int i;
1292 
1293     DefragInit();
1294 
1295     p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1296     FAIL_IF_NULL(p1);
1297     p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1298     FAIL_IF_NULL(p2);
1299     p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1300     FAIL_IF_NULL(p3);
1301 
1302     FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1303     FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1304 
1305     reassembled = Defrag(NULL, NULL, p1);
1306     FAIL_IF_NULL(reassembled);
1307 
1308     FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1309     FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1310 
1311     /* 20 bytes in we should find 8 bytes of A. */
1312     for (i = 20; i < 20 + 8; i++) {
1313         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1314     }
1315 
1316     /* 28 bytes in we should find 8 bytes of B. */
1317     for (i = 28; i < 28 + 8; i++) {
1318         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1319     }
1320 
1321     /* And 36 bytes in we should find 3 bytes of C. */
1322     for (i = 36; i < 36 + 3; i++) {
1323         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1324     }
1325 
1326     SCFree(p1);
1327     SCFree(p2);
1328     SCFree(p3);
1329     SCFree(reassembled);
1330 
1331     DefragDestroy();
1332     PASS;
1333 }
1334 
1335 /**
1336  * Test the simplest possible re-assembly scenario.  All packet in
1337  * order and no overlaps.
1338  */
IPV6DefragInOrderSimpleTest(void)1339 static int IPV6DefragInOrderSimpleTest(void)
1340 {
1341     Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1342     Packet *reassembled = NULL;
1343     int id = 12;
1344     int i;
1345 
1346     DefragInit();
1347 
1348     p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1349     FAIL_IF_NULL(p1);
1350     p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1351     FAIL_IF_NULL(p2);
1352     p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1353     FAIL_IF_NULL(p3);
1354 
1355     FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1356     FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1357     reassembled = Defrag(NULL, NULL, p3);
1358     FAIL_IF_NULL(reassembled);
1359 
1360     FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1361 
1362     /* 40 bytes in we should find 8 bytes of A. */
1363     for (i = 40; i < 40 + 8; i++) {
1364         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1365     }
1366 
1367     /* 28 bytes in we should find 8 bytes of B. */
1368     for (i = 48; i < 48 + 8; i++) {
1369         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1370     }
1371 
1372     /* And 36 bytes in we should find 3 bytes of C. */
1373     for (i = 56; i < 56 + 3; i++) {
1374         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1375     }
1376 
1377     SCFree(p1);
1378     SCFree(p2);
1379     SCFree(p3);
1380     SCFree(reassembled);
1381 
1382     DefragDestroy();
1383     PASS;
1384 }
1385 
IPV6DefragReverseSimpleTest(void)1386 static int IPV6DefragReverseSimpleTest(void)
1387 {
1388     DefragContext *dc = NULL;
1389     Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1390     Packet *reassembled = NULL;
1391     int id = 12;
1392     int i;
1393 
1394     DefragInit();
1395 
1396     dc = DefragContextNew();
1397     FAIL_IF_NULL(dc);
1398 
1399     p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1400     FAIL_IF_NULL(p1);
1401     p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1402     FAIL_IF_NULL(p2);
1403     p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1404     FAIL_IF_NULL(p3);
1405 
1406     FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1407     FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1408     reassembled = Defrag(NULL, NULL, p1);
1409     FAIL_IF_NULL(reassembled);
1410 
1411     /* 40 bytes in we should find 8 bytes of A. */
1412     for (i = 40; i < 40 + 8; i++) {
1413         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1414     }
1415 
1416     /* 28 bytes in we should find 8 bytes of B. */
1417     for (i = 48; i < 48 + 8; i++) {
1418         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1419     }
1420 
1421     /* And 36 bytes in we should find 3 bytes of C. */
1422     for (i = 56; i < 56 + 3; i++) {
1423         FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1424     }
1425 
1426     DefragContextDestroy(dc);
1427     SCFree(p1);
1428     SCFree(p2);
1429     SCFree(p3);
1430     SCFree(reassembled);
1431 
1432     DefragDestroy();
1433     PASS;
1434 }
1435 
DefragDoSturgesNovakTest(int policy,u_char * expected,size_t expected_len)1436 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1437         size_t expected_len)
1438 {
1439     int i;
1440 
1441     DefragInit();
1442 
1443     /*
1444      * Build the packets.
1445      */
1446 
1447     int id = 1;
1448     Packet *packets[17];
1449     memset(packets, 0x00, sizeof(packets));
1450 
1451     /*
1452      * Original fragments.
1453      */
1454 
1455     /* A*24 at 0. */
1456     packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1457 
1458     /* B*15 at 32. */
1459     packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1460 
1461     /* C*24 at 48. */
1462     packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1463 
1464     /* D*8 at 80. */
1465     packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1466 
1467     /* E*16 at 104. */
1468     packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1469 
1470     /* F*24 at 120. */
1471     packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1472 
1473     /* G*16 at 144. */
1474     packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1475 
1476     /* H*16 at 160. */
1477     packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1478 
1479     /* I*8 at 176. */
1480     packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1481 
1482     /*
1483      * Overlapping subsequent fragments.
1484      */
1485 
1486     /* J*32 at 8. */
1487     packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1488 
1489     /* K*24 at 48. */
1490     packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1491 
1492     /* L*24 at 72. */
1493     packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1494 
1495     /* M*24 at 96. */
1496     packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1497 
1498     /* N*8 at 128. */
1499     packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1500 
1501     /* O*8 at 152. */
1502     packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1503 
1504     /* P*8 at 160. */
1505     packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1506 
1507     /* Q*16 at 176. */
1508     packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1509 
1510     default_policy = policy;
1511 
1512     /* Send all but the last. */
1513     for (i = 0; i < 9; i++) {
1514         Packet *tp = Defrag(NULL, NULL, packets[i]);
1515         FAIL_IF_NOT_NULL(tp);
1516         FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP));
1517     }
1518     int overlap = 0;
1519     for (; i < 16; i++) {
1520         Packet *tp = Defrag(NULL, NULL, packets[i]);
1521         FAIL_IF_NOT_NULL(tp);
1522         if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1523             overlap++;
1524         }
1525     }
1526     FAIL_IF_NOT(overlap);
1527 
1528     /* And now the last one. */
1529     Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1530     FAIL_IF_NULL(reassembled);
1531 
1532     FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1533     FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1534 
1535     FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1536     SCFree(reassembled);
1537 
1538     /* Make sure all frags were returned back to the pool. */
1539     FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1540 
1541     for (i = 0; i < 17; i++) {
1542         SCFree(packets[i]);
1543     }
1544     DefragDestroy();
1545     PASS;
1546 }
1547 
IPV6DefragDoSturgesNovakTest(int policy,u_char * expected,size_t expected_len)1548 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1549         size_t expected_len)
1550 {
1551     int i;
1552 
1553     DefragInit();
1554 
1555     /*
1556      * Build the packets.
1557      */
1558 
1559     int id = 1;
1560     Packet *packets[17];
1561     memset(packets, 0x00, sizeof(packets));
1562 
1563     /*
1564      * Original fragments.
1565      */
1566 
1567     /* A*24 at 0. */
1568     packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1569 
1570     /* B*15 at 32. */
1571     packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1572 
1573     /* C*24 at 48. */
1574     packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1575 
1576     /* D*8 at 80. */
1577     packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1578 
1579     /* E*16 at 104. */
1580     packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1581 
1582     /* F*24 at 120. */
1583     packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1584 
1585     /* G*16 at 144. */
1586     packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1587 
1588     /* H*16 at 160. */
1589     packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1590 
1591     /* I*8 at 176. */
1592     packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1593 
1594     /*
1595      * Overlapping subsequent fragments.
1596      */
1597 
1598     /* J*32 at 8. */
1599     packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1600 
1601     /* K*24 at 48. */
1602     packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1603 
1604     /* L*24 at 72. */
1605     packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1606 
1607     /* M*24 at 96. */
1608     packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1609 
1610     /* N*8 at 128. */
1611     packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1612 
1613     /* O*8 at 152. */
1614     packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1615 
1616     /* P*8 at 160. */
1617     packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1618 
1619     /* Q*16 at 176. */
1620     packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1621 
1622     default_policy = policy;
1623 
1624     /* Send all but the last. */
1625     for (i = 0; i < 9; i++) {
1626         Packet *tp = Defrag(NULL, NULL, packets[i]);
1627         FAIL_IF_NOT_NULL(tp);
1628         FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP));
1629     }
1630     int overlap = 0;
1631     for (; i < 16; i++) {
1632         Packet *tp = Defrag(NULL, NULL, packets[i]);
1633         FAIL_IF_NOT_NULL(tp);
1634         if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1635             overlap++;
1636         }
1637     }
1638     FAIL_IF_NOT(overlap);
1639 
1640     /* And now the last one. */
1641     Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1642     FAIL_IF_NULL(reassembled);
1643     FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1644 
1645     FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1646 
1647     SCFree(reassembled);
1648 
1649     /* Make sure all frags were returned to the pool. */
1650     FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1651 
1652     for (i = 0; i < 17; i++) {
1653         SCFree(packets[i]);
1654     }
1655     DefragDestroy();
1656     PASS;
1657 }
1658 
1659 static int
DefragSturgesNovakBsdTest(void)1660 DefragSturgesNovakBsdTest(void)
1661 {
1662     /* Expected data. */
1663     u_char expected[] = {
1664         "AAAAAAAA"
1665         "AAAAAAAA"
1666         "AAAAAAAA"
1667         "JJJJJJJJ"
1668         "JJJJJJJJ"
1669         "BBBBBBBB"
1670         "CCCCCCCC"
1671         "CCCCCCCC"
1672         "CCCCCCCC"
1673         "LLLLLLLL"
1674         "LLLLLLLL"
1675         "LLLLLLLL"
1676         "MMMMMMMM"
1677         "MMMMMMMM"
1678         "MMMMMMMM"
1679         "FFFFFFFF"
1680         "FFFFFFFF"
1681         "FFFFFFFF"
1682         "GGGGGGGG"
1683         "GGGGGGGG"
1684         "HHHHHHHH"
1685         "HHHHHHHH"
1686         "IIIIIIII"
1687         "QQQQQQQQ"
1688     };
1689 
1690     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1691                     sizeof(expected)));
1692     PASS;
1693 }
1694 
IPV6DefragSturgesNovakBsdTest(void)1695 static int IPV6DefragSturgesNovakBsdTest(void)
1696 {
1697     /* Expected data. */
1698     u_char expected[] = {
1699         "AAAAAAAA"
1700         "AAAAAAAA"
1701         "AAAAAAAA"
1702         "JJJJJJJJ"
1703         "JJJJJJJJ"
1704         "BBBBBBBB"
1705         "CCCCCCCC"
1706         "CCCCCCCC"
1707         "CCCCCCCC"
1708         "LLLLLLLL"
1709         "LLLLLLLL"
1710         "LLLLLLLL"
1711         "MMMMMMMM"
1712         "MMMMMMMM"
1713         "MMMMMMMM"
1714         "FFFFFFFF"
1715         "FFFFFFFF"
1716         "FFFFFFFF"
1717         "GGGGGGGG"
1718         "GGGGGGGG"
1719         "HHHHHHHH"
1720         "HHHHHHHH"
1721         "IIIIIIII"
1722         "QQQQQQQQ"
1723     };
1724 
1725     FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1726                     sizeof(expected)));
1727     PASS;
1728 }
1729 
DefragSturgesNovakLinuxIpv4Test(void)1730 static int DefragSturgesNovakLinuxIpv4Test(void)
1731 {
1732     /* Expected data. */
1733     u_char expected[] = {
1734         "AAAAAAAA"
1735         "AAAAAAAA"
1736         "AAAAAAAA"
1737         "JJJJJJJJ"
1738         "JJJJJJJJ"
1739         "BBBBBBBB"
1740         "KKKKKKKK"
1741         "KKKKKKKK"
1742         "KKKKKKKK"
1743         "LLLLLLLL"
1744         "LLLLLLLL"
1745         "LLLLLLLL"
1746         "MMMMMMMM"
1747         "MMMMMMMM"
1748         "MMMMMMMM"
1749         "FFFFFFFF"
1750         "FFFFFFFF"
1751         "FFFFFFFF"
1752         "GGGGGGGG"
1753         "GGGGGGGG"
1754         "PPPPPPPP"
1755         "HHHHHHHH"
1756         "QQQQQQQQ"
1757         "QQQQQQQQ"
1758     };
1759 
1760     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1761                     sizeof(expected)));
1762     PASS;
1763 }
1764 
IPV6DefragSturgesNovakLinuxTest(void)1765 static int IPV6DefragSturgesNovakLinuxTest(void)
1766 {
1767     /* Expected data. */
1768     u_char expected[] = {
1769         "AAAAAAAA"
1770         "AAAAAAAA"
1771         "AAAAAAAA"
1772         "JJJJJJJJ"
1773         "JJJJJJJJ"
1774         "BBBBBBBB"
1775         "KKKKKKKK"
1776         "KKKKKKKK"
1777         "KKKKKKKK"
1778         "LLLLLLLL"
1779         "LLLLLLLL"
1780         "LLLLLLLL"
1781         "MMMMMMMM"
1782         "MMMMMMMM"
1783         "MMMMMMMM"
1784         "FFFFFFFF"
1785         "FFFFFFFF"
1786         "FFFFFFFF"
1787         "GGGGGGGG"
1788         "GGGGGGGG"
1789         "PPPPPPPP"
1790         "HHHHHHHH"
1791         "QQQQQQQQ"
1792         "QQQQQQQQ"
1793     };
1794 
1795     FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1796             sizeof(expected)));
1797     PASS;
1798 }
1799 
DefragSturgesNovakWindowsIpv4Test(void)1800 static int DefragSturgesNovakWindowsIpv4Test(void)
1801 {
1802     /* Expected data. */
1803     u_char expected[] = {
1804         "AAAAAAAA"
1805         "AAAAAAAA"
1806         "AAAAAAAA"
1807         "JJJJJJJJ"
1808         "BBBBBBBB"
1809         "BBBBBBBB"
1810         "CCCCCCCC"
1811         "CCCCCCCC"
1812         "CCCCCCCC"
1813         "LLLLLLLL"
1814         "LLLLLLLL"
1815         "LLLLLLLL"
1816         "MMMMMMMM"
1817         "EEEEEEEE"
1818         "EEEEEEEE"
1819         "FFFFFFFF"
1820         "FFFFFFFF"
1821         "FFFFFFFF"
1822         "GGGGGGGG"
1823         "GGGGGGGG"
1824         "HHHHHHHH"
1825         "HHHHHHHH"
1826         "IIIIIIII"
1827         "QQQQQQQQ"
1828     };
1829 
1830     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1831                     sizeof(expected)));
1832     PASS;
1833 }
1834 
IPV6DefragSturgesNovakWindowsTest(void)1835 static int IPV6DefragSturgesNovakWindowsTest(void)
1836 {
1837     /* Expected data. */
1838     u_char expected[] = {
1839         "AAAAAAAA"
1840         "AAAAAAAA"
1841         "AAAAAAAA"
1842         "JJJJJJJJ"
1843         "BBBBBBBB"
1844         "BBBBBBBB"
1845         "CCCCCCCC"
1846         "CCCCCCCC"
1847         "CCCCCCCC"
1848         "LLLLLLLL"
1849         "LLLLLLLL"
1850         "LLLLLLLL"
1851         "MMMMMMMM"
1852         "EEEEEEEE"
1853         "EEEEEEEE"
1854         "FFFFFFFF"
1855         "FFFFFFFF"
1856         "FFFFFFFF"
1857         "GGGGGGGG"
1858         "GGGGGGGG"
1859         "HHHHHHHH"
1860         "HHHHHHHH"
1861         "IIIIIIII"
1862         "QQQQQQQQ"
1863     };
1864 
1865     FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1866                     sizeof(expected)));
1867     PASS;
1868 }
1869 
DefragSturgesNovakSolarisTest(void)1870 static int DefragSturgesNovakSolarisTest(void)
1871 {
1872     /* Expected data. */
1873     u_char expected[] = {
1874         "AAAAAAAA"
1875         "AAAAAAAA"
1876         "AAAAAAAA"
1877         "JJJJJJJJ"
1878         "BBBBBBBB"
1879         "BBBBBBBB"
1880         "CCCCCCCC"
1881         "CCCCCCCC"
1882         "CCCCCCCC"
1883         "LLLLLLLL"
1884         "LLLLLLLL"
1885         "LLLLLLLL"
1886         "MMMMMMMM"
1887         "MMMMMMMM"
1888         "MMMMMMMM"
1889         "FFFFFFFF"
1890         "FFFFFFFF"
1891         "FFFFFFFF"
1892         "GGGGGGGG"
1893         "GGGGGGGG"
1894         "HHHHHHHH"
1895         "HHHHHHHH"
1896         "IIIIIIII"
1897         "QQQQQQQQ"
1898     };
1899 
1900     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1901                     sizeof(expected)));
1902     PASS;
1903 }
1904 
IPV6DefragSturgesNovakSolarisTest(void)1905 static int IPV6DefragSturgesNovakSolarisTest(void)
1906 {
1907     /* Expected data. */
1908     u_char expected[] = {
1909         "AAAAAAAA"
1910         "AAAAAAAA"
1911         "AAAAAAAA"
1912         "JJJJJJJJ"
1913         "BBBBBBBB"
1914         "BBBBBBBB"
1915         "CCCCCCCC"
1916         "CCCCCCCC"
1917         "CCCCCCCC"
1918         "LLLLLLLL"
1919         "LLLLLLLL"
1920         "LLLLLLLL"
1921         "MMMMMMMM"
1922         "MMMMMMMM"
1923         "MMMMMMMM"
1924         "FFFFFFFF"
1925         "FFFFFFFF"
1926         "FFFFFFFF"
1927         "GGGGGGGG"
1928         "GGGGGGGG"
1929         "HHHHHHHH"
1930         "HHHHHHHH"
1931         "IIIIIIII"
1932         "QQQQQQQQ"
1933     };
1934 
1935     FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1936                     sizeof(expected)));
1937     PASS;
1938 }
1939 
DefragSturgesNovakFirstTest(void)1940 static int DefragSturgesNovakFirstTest(void)
1941 {
1942     /* Expected data. */
1943     u_char expected[] = {
1944         "AAAAAAAA"
1945         "AAAAAAAA"
1946         "AAAAAAAA"
1947         "JJJJJJJJ"
1948         "BBBBBBBB"
1949         "BBBBBBBB"
1950         "CCCCCCCC"
1951         "CCCCCCCC"
1952         "CCCCCCCC"
1953         "LLLLLLLL"
1954         "DDDDDDDD"
1955         "LLLLLLLL"
1956         "MMMMMMMM"
1957         "EEEEEEEE"
1958         "EEEEEEEE"
1959         "FFFFFFFF"
1960         "FFFFFFFF"
1961         "FFFFFFFF"
1962         "GGGGGGGG"
1963         "GGGGGGGG"
1964         "HHHHHHHH"
1965         "HHHHHHHH"
1966         "IIIIIIII"
1967         "QQQQQQQQ"
1968     };
1969 
1970     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1971                     sizeof(expected)));
1972     PASS;
1973 }
1974 
IPV6DefragSturgesNovakFirstTest(void)1975 static int IPV6DefragSturgesNovakFirstTest(void)
1976 {
1977     /* Expected data. */
1978     u_char expected[] = {
1979         "AAAAAAAA"
1980         "AAAAAAAA"
1981         "AAAAAAAA"
1982         "JJJJJJJJ"
1983         "BBBBBBBB"
1984         "BBBBBBBB"
1985         "CCCCCCCC"
1986         "CCCCCCCC"
1987         "CCCCCCCC"
1988         "LLLLLLLL"
1989         "DDDDDDDD"
1990         "LLLLLLLL"
1991         "MMMMMMMM"
1992         "EEEEEEEE"
1993         "EEEEEEEE"
1994         "FFFFFFFF"
1995         "FFFFFFFF"
1996         "FFFFFFFF"
1997         "GGGGGGGG"
1998         "GGGGGGGG"
1999         "HHHHHHHH"
2000         "HHHHHHHH"
2001         "IIIIIIII"
2002         "QQQQQQQQ"
2003     };
2004 
2005     return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2006         sizeof(expected));
2007 }
2008 
2009 static int
DefragSturgesNovakLastTest(void)2010 DefragSturgesNovakLastTest(void)
2011 {
2012     /* Expected data. */
2013     u_char expected[] = {
2014         "AAAAAAAA"
2015         "JJJJJJJJ"
2016         "JJJJJJJJ"
2017         "JJJJJJJJ"
2018         "JJJJJJJJ"
2019         "BBBBBBBB"
2020         "KKKKKKKK"
2021         "KKKKKKKK"
2022         "KKKKKKKK"
2023         "LLLLLLLL"
2024         "LLLLLLLL"
2025         "LLLLLLLL"
2026         "MMMMMMMM"
2027         "MMMMMMMM"
2028         "MMMMMMMM"
2029         "FFFFFFFF"
2030         "NNNNNNNN"
2031         "FFFFFFFF"
2032         "GGGGGGGG"
2033         "OOOOOOOO"
2034         "PPPPPPPP"
2035         "HHHHHHHH"
2036         "QQQQQQQQ"
2037         "QQQQQQQQ"
2038     };
2039 
2040     FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2041                     sizeof(expected)));
2042     PASS;
2043 }
2044 
IPV6DefragSturgesNovakLastTest(void)2045 static int IPV6DefragSturgesNovakLastTest(void)
2046 {
2047     /* Expected data. */
2048     u_char expected[] = {
2049         "AAAAAAAA"
2050         "JJJJJJJJ"
2051         "JJJJJJJJ"
2052         "JJJJJJJJ"
2053         "JJJJJJJJ"
2054         "BBBBBBBB"
2055         "KKKKKKKK"
2056         "KKKKKKKK"
2057         "KKKKKKKK"
2058         "LLLLLLLL"
2059         "LLLLLLLL"
2060         "LLLLLLLL"
2061         "MMMMMMMM"
2062         "MMMMMMMM"
2063         "MMMMMMMM"
2064         "FFFFFFFF"
2065         "NNNNNNNN"
2066         "FFFFFFFF"
2067         "GGGGGGGG"
2068         "OOOOOOOO"
2069         "PPPPPPPP"
2070         "HHHHHHHH"
2071         "QQQQQQQQ"
2072         "QQQQQQQQ"
2073     };
2074 
2075     FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2076                     sizeof(expected)));
2077     PASS;
2078 }
2079 
DefragTimeoutTest(void)2080 static int DefragTimeoutTest(void)
2081 {
2082     int i;
2083 
2084     /* Setup a small numberr of trackers. */
2085     FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2086 
2087     DefragInit();
2088 
2089     /* Load in 16 packets. */
2090     for (i = 0; i < 16; i++) {
2091         Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2092         FAIL_IF_NULL(p);
2093 
2094         Packet *tp = Defrag(NULL, NULL, p);
2095         SCFree(p);
2096         FAIL_IF_NOT_NULL(tp);
2097     }
2098 
2099     /* Build a new packet but push the timestamp out by our timeout.
2100      * This should force our previous fragments to be timed out. */
2101     Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2102     FAIL_IF_NULL(p);
2103 
2104     p->ts.tv_sec += (defrag_context->timeout + 1);
2105     Packet *tp = Defrag(NULL, NULL, p);
2106     FAIL_IF_NOT_NULL(tp);
2107 
2108     DefragTracker *tracker = DefragLookupTrackerFromHash(p);
2109     FAIL_IF_NULL(tracker);
2110 
2111     FAIL_IF(tracker->id != 99);
2112 
2113     SCMutexUnlock(&tracker->lock);
2114     SCFree(p);
2115 
2116     DefragDestroy();
2117     PASS;
2118 }
2119 
2120 /**
2121  * QA found that if you send a packet where more frags is 0, offset is
2122  * > 0 and there is no data in the packet that the re-assembler will
2123  * fail.  The fix was simple, but this unit test is just to make sure
2124  * its not introduced.
2125  */
DefragIPv4NoDataTest(void)2126 static int DefragIPv4NoDataTest(void)
2127 {
2128     DefragContext *dc = NULL;
2129     Packet *p = NULL;
2130     int id = 12;
2131 
2132     DefragInit();
2133 
2134     dc = DefragContextNew();
2135     FAIL_IF_NULL(dc);
2136 
2137     /* This packet has an offset > 0, more frags set to 0 and no data. */
2138     p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2139     FAIL_IF_NULL(p);
2140 
2141     /* We do not expect a packet returned. */
2142     FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2143 
2144     /* The fragment should have been ignored so no fragments should
2145      * have been allocated from the pool. */
2146     FAIL_IF(dc->frag_pool->outstanding != 0);
2147 
2148     DefragContextDestroy(dc);
2149     SCFree(p);
2150 
2151     DefragDestroy();
2152     PASS;
2153 }
2154 
DefragIPv4TooLargeTest(void)2155 static int DefragIPv4TooLargeTest(void)
2156 {
2157     DefragContext *dc = NULL;
2158     Packet *p = NULL;
2159 
2160     DefragInit();
2161 
2162     dc = DefragContextNew();
2163     FAIL_IF_NULL(dc);
2164 
2165     /* Create a fragment that would extend past the max allowable size
2166      * for an IPv4 packet. */
2167     p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2168     FAIL_IF_NULL(p);
2169 
2170     /* We do not expect a packet returned. */
2171     FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2172 
2173     /* We do expect an event. */
2174     FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE));
2175 
2176     /* The fragment should have been ignored so no fragments should have
2177      * been allocated from the pool. */
2178     FAIL_IF(dc->frag_pool->outstanding != 0);
2179 
2180     DefragContextDestroy(dc);
2181     SCFree(p);
2182 
2183     DefragDestroy();
2184     PASS;
2185 }
2186 
2187 /**
2188  * Test that fragments in different VLANs that would otherwise be
2189  * re-assembled, are not re-assembled.  Just use simple in-order
2190  * fragments.
2191  */
DefragVlanTest(void)2192 static int DefragVlanTest(void)
2193 {
2194     Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2195 
2196     DefragInit();
2197 
2198     p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2199     FAIL_IF_NULL(p1);
2200     p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2201     FAIL_IF_NULL(p2);
2202 
2203     /* With no VLAN IDs set, packets should re-assemble. */
2204     FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2205     FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2206     SCFree(r);
2207 
2208     /* With mismatched VLANs, packets should not re-assemble. */
2209     p1->vlan_id[0] = 1;
2210     p2->vlan_id[0] = 2;
2211     FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2212     FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2213 
2214     SCFree(p1);
2215     SCFree(p2);
2216     DefragDestroy();
2217 
2218     PASS;
2219 }
2220 
2221 /**
2222  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2223  */
DefragVlanQinQTest(void)2224 static int DefragVlanQinQTest(void)
2225 {
2226     Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2227 
2228     DefragInit();
2229 
2230     p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2231     FAIL_IF_NULL(p1);
2232     p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2233     FAIL_IF_NULL(p2);
2234 
2235     /* With no VLAN IDs set, packets should re-assemble. */
2236     FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2237     FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2238     SCFree(r);
2239 
2240     /* With mismatched VLANs, packets should not re-assemble. */
2241     p1->vlan_id[0] = 1;
2242     p2->vlan_id[0] = 1;
2243     p1->vlan_id[1] = 1;
2244     p2->vlan_id[1] = 2;
2245     FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2246     FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2247 
2248     SCFree(p1);
2249     SCFree(p2);
2250     DefragDestroy();
2251 
2252     PASS;
2253 }
2254 
DefragTrackerReuseTest(void)2255 static int DefragTrackerReuseTest(void)
2256 {
2257     int id = 1;
2258     Packet *p1 = NULL;
2259     DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2260 
2261     DefragInit();
2262 
2263     /* Build a packet, its not a fragment but shouldn't matter for
2264      * this test. */
2265     p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2266     FAIL_IF_NULL(p1);
2267 
2268     /* Get a tracker. It shouldn't look like its already in use. */
2269     tracker1 = DefragGetTracker(NULL, NULL, p1);
2270     FAIL_IF_NULL(tracker1);
2271     FAIL_IF(tracker1->seen_last);
2272     FAIL_IF(tracker1->remove);
2273     DefragTrackerRelease(tracker1);
2274 
2275     /* Get a tracker again, it should be the same one. */
2276     tracker2 = DefragGetTracker(NULL, NULL, p1);
2277     FAIL_IF_NULL(tracker2);
2278     FAIL_IF(tracker2 != tracker1);
2279     DefragTrackerRelease(tracker1);
2280 
2281     /* Now mark the tracker for removal. It should not be returned
2282      * when we get a tracker for a packet that may have the same
2283      * attributes. */
2284     tracker1->remove = 1;
2285 
2286     tracker2 = DefragGetTracker(NULL, NULL, p1);
2287     FAIL_IF_NULL(tracker2);
2288     FAIL_IF(tracker2 == tracker1);
2289     FAIL_IF(tracker2->remove);
2290 
2291     SCFree(p1);
2292     DefragDestroy();
2293     PASS;
2294 }
2295 
2296 /**
2297  * IPV4: Test the case where you have a packet fragmented in 3 parts
2298  * and send like:
2299  * - Offset: 2; MF: 1
2300  * - Offset: 0; MF: 1
2301  * - Offset: 1; MF: 0
2302  *
2303  * Only the fragments with offset 0 and 1 should be reassembled.
2304  */
DefragMfIpv4Test(void)2305 static int DefragMfIpv4Test(void)
2306 {
2307     int ip_id = 9;
2308     Packet *p = NULL;
2309 
2310     DefragInit();
2311 
2312     Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2313     Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2314     Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2315     FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2316 
2317     p = Defrag(NULL, NULL, p1);
2318     FAIL_IF_NOT_NULL(p);
2319 
2320     p = Defrag(NULL, NULL, p2);
2321     FAIL_IF_NOT_NULL(p);
2322 
2323     /* This should return a packet as MF=0. */
2324     p = Defrag(NULL, NULL, p3);
2325     FAIL_IF_NULL(p);
2326 
2327     /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2328      * fragments should be in the re-assembled packet. */
2329     FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2330 
2331     SCFree(p1);
2332     SCFree(p2);
2333     SCFree(p3);
2334     SCFree(p);
2335     DefragDestroy();
2336     PASS;
2337 }
2338 
2339 /**
2340  * IPV6: Test the case where you have a packet fragmented in 3 parts
2341  * and send like:
2342  * - Offset: 2; MF: 1
2343  * - Offset: 0; MF: 1
2344  * - Offset: 1; MF: 0
2345  *
2346  * Only the fragments with offset 0 and 1 should be reassembled.
2347  */
DefragMfIpv6Test(void)2348 static int DefragMfIpv6Test(void)
2349 {
2350     int ip_id = 9;
2351     Packet *p = NULL;
2352 
2353     DefragInit();
2354 
2355     Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2356     Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2357     Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2358     FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2359 
2360     p = Defrag(NULL, NULL, p1);
2361     FAIL_IF_NOT_NULL(p);
2362 
2363     p = Defrag(NULL, NULL, p2);
2364     FAIL_IF_NOT_NULL(p);
2365 
2366     /* This should return a packet as MF=0. */
2367     p = Defrag(NULL, NULL, p3);
2368     FAIL_IF_NULL(p);
2369 
2370     /* For IPv6 the expected length is just the length of the payload
2371      * of 2 fragments, so 16. */
2372     FAIL_IF(IPV6_GET_PLEN(p) != 16);
2373 
2374     SCFree(p1);
2375     SCFree(p2);
2376     SCFree(p3);
2377     SCFree(p);
2378     DefragDestroy();
2379     PASS;
2380 }
2381 
2382 /**
2383  * \brief Test that fragments that match other than the proto don't
2384  * actually get matched.
2385  */
DefragTestBadProto(void)2386 static int DefragTestBadProto(void)
2387 {
2388     Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2389     int id = 12;
2390 
2391     DefragInit();
2392 
2393     p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2394     FAIL_IF_NULL(p1);
2395     p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2396     FAIL_IF_NULL(p2);
2397     p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2398     FAIL_IF_NULL(p3);
2399 
2400     FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2401     FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2402     FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2403 
2404     SCFree(p1);
2405     SCFree(p2);
2406     SCFree(p3);
2407 
2408     DefragDestroy();
2409     PASS;
2410 }
2411 
2412 /**
2413  * \test Test a report Linux overlap issue that doesn't appear to be
2414  *     covered by the Sturges/Novak tests above.
2415  */
DefragTestJeremyLinux(void)2416 static int DefragTestJeremyLinux(void)
2417 {
2418     char expected[] = "AAAAAAAA"
2419         "AAAAAAAA"
2420         "AAAAAAAA"
2421         "CCCCCCCC"
2422         "CCCCCCCC"
2423         "CCCCCCCC"
2424         "CCCCCCCC"
2425         "CCCCCCCC"
2426         "CCCCCCCC"
2427         "BBBBBBBB"
2428         "BBBBBBBB"
2429         "DDDDDDDD"
2430         "DDDDDD";
2431 
2432     DefragInit();
2433     default_policy = DEFRAG_POLICY_LINUX;
2434 
2435     int id = 1;
2436     Packet *packets[4];
2437     int i = 0;
2438 
2439     packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2440     packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2441     packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2442     packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2443 
2444     Packet *r = Defrag(NULL, NULL, packets[0]);
2445     FAIL_IF_NOT_NULL(r);
2446 
2447     r = Defrag(NULL, NULL, packets[1]);
2448     FAIL_IF_NOT_NULL(r);
2449 
2450     r = Defrag(NULL, NULL, packets[2]);
2451     FAIL_IF_NOT_NULL(r);
2452 
2453     r = Defrag(NULL, NULL, packets[3]);
2454     FAIL_IF_NULL(r);
2455 
2456     FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2457 
2458     for (i = 0; i < 4; i++) {
2459         SCFree(packets[i]);
2460     }
2461     SCFree(r);
2462 
2463     DefragDestroy();
2464     PASS;
2465 }
2466 
2467 #endif /* UNITTESTS */
2468 
DefragRegisterTests(void)2469 void DefragRegisterTests(void)
2470 {
2471 #ifdef UNITTESTS
2472     UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2473     UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2474     UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2475     UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2476             DefragSturgesNovakLinuxIpv4Test);
2477     UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2478                    DefragSturgesNovakWindowsIpv4Test);
2479     UtRegisterTest("DefragSturgesNovakSolarisTest",
2480                    DefragSturgesNovakSolarisTest);
2481     UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2482     UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2483 
2484     UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2485     UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2486 
2487     UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2488     UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2489     UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2490                    IPV6DefragSturgesNovakBsdTest);
2491     UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2492                    IPV6DefragSturgesNovakLinuxTest);
2493     UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2494                    IPV6DefragSturgesNovakWindowsTest);
2495     UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2496                    IPV6DefragSturgesNovakSolarisTest);
2497     UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2498                    IPV6DefragSturgesNovakFirstTest);
2499     UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2500                    IPV6DefragSturgesNovakLastTest);
2501 
2502     UtRegisterTest("DefragVlanTest", DefragVlanTest);
2503     UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2504     UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2505     UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2506     UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2507     UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2508     UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2509 
2510     UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2511 #endif /* UNITTESTS */
2512 }
2513