1 /* $Id$ */
2 
3 /**
4  * @file    spp_frag3.c
5  * @author  Martin Roesch <roesch@sourcefire.com>
6  * @date    Thu Sep 30 14:12:37 EDT 2004
7  *
8  * @brief   Frag3: IP defragmentation preprocessor for Snort.
9  */
10 
11 /*
12  ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
13  ** Copyright (C) 2004-2013 Sourcefire, Inc.
14  **
15  ** This program is free software; you can redistribute it and/or modify
16  ** it under the terms of the GNU General Public License Version 2 as
17  ** published by the Free Software Foundation.  You may not use, modify or
18  ** distribute this program under any other version of the GNU General
19  ** Public License.
20  **
21  ** This program is distributed in the hope that it will be useful,
22  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
23  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  ** GNU General Public License for more details.
25  **
26  ** You should have received a copy of the GNU General Public License
27  ** along with this program; if not, write to the Free Software
28  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
29  */
30 
31 /*
32  * Notes:
33  * Frag3 sports the following improvements over frag2:
34  *  - Target-based IP defragmentation, harder to evade
35  *  - 8 Anomaly detection event types
36  *  - Two separate memory management strategies to tailor
37  *    performance for specific environments
38  *  - Up to 250% faster than frag2.
39  *
40  *  The mechanism for processing frags is based on the Linux IP stack
41  *  implementation of IP defragmentation with proper amounts of paranoia
42  *  and an IDS perspective applied.  Some of this code was derived from
43  *  frag2 originally, but it's basically unrecognizeable if you compare
44  *  it to frag2 IMO.
45  *
46  *  I switched from using the UBI libs to using sfxhash and linked lists for
47  *  fragment management because I suspected that the management code was
48  *  the cause of performance issues that we were observing at Sourcefire
49  *  in certain customer situations.  Splay trees are cool and really hard
50  *  to screw with from an attack perspective, but they also incur a lot
51  *  of overhead for managing the tree and lose the order of the fragments in
52  *  the FragTracker's fraglist, so I dropped them.  Originally the
53  *  frag3 code was just supposed to migrate away from the splay tree system
54  *  that I was using in frag2, but I figured since I was doing the work to
55  *  pull out the splay trees I may as well solve some of the other problems
56  *  we were seeing.
57  *
58  *  Initial performance testing that I've done shows that frag3 can be as much
59  *  as 250% faster than frag2, but we still need to do more testing and
60  *  optimization, we may be able to squeeze out some more performance.
61  *
62  *  Frag3 is also capable of performing "Target-based" IP defragmentation.
63  *  What this means practically is that frag3 can model the IP stack of a
64  *  target on the network to avoid Ptacek-Newsham evasions of the IDS through
65  *  sensor/target desynchronization.  In terms of implentation, this is
66  *  reflected by passing a "context" into the defragmentation engine that has
67  *  a specific configuration for a specific target type.  Windows can put
68  *  fragments back together differently than Linux/BSD/etc, so we model that
69  *  inside frag3 so we can't be evaded.
70  *
71  *  Configuration of frag3 is pretty straight forward, there's a global config
72  *  that contains data about how the hash tables will be structured, what type
73  *  of memory management to use and whether or not to generate alerts, then
74  *  specific target-contexts are setup and bound to IP address sets.  Check
75  *  the README file for specifics!
76  */
77 
78 /*  I N C L U D E S  ************************************************/
79 #ifdef HAVE_CONFIG_H
80 #include "config.h"
81 #endif
82 
83 #include <assert.h>
84 #include <sys/types.h>
85 #include <stdlib.h>
86 #include <ctype.h>
87 #include <rpc/types.h>
88 #include <errno.h>
89 
90 #include "spp_frag3.h"
91 #include "snort_bounds.h"
92 #include "generators.h"
93 #include "log.h"
94 #include "detect.h"
95 #include "decode.h"
96 #include "encode.h"
97 #include "event.h"
98 #include "util.h"
99 #include "snort_debug.h"
100 #include "plugbase.h"
101 #include "parser.h"
102 #include "mstring.h"
103 #include "checksum.h"
104 #include "perf.h"
105 #include "event_queue.h"
106 #include "timersub.h"
107 #include "fpcreate.h"
108 
109 #include "sfutil/sflsq.h"
110 #include "sfutil/sfxhash.h"
111 
112 #include "snort.h"
113 #include "memory_stats.h"
114 #include "profiler.h"
115 
116 #include "active.h"
117 #include "session_api.h"
118 #include "spp_normalize.h"
119 #include "reload.h"
120 
121 #ifdef REG_TEST
122 #include "reg_test.h"
123 #endif
124 
125 #ifdef TARGET_BASED
126 #include "sftarget_hostentry.h"
127 #include "sftarget_protocol_reference.h"
128 #endif
129 #include "sfPolicy.h"
130 
131 extern OptTreeNode *otn_tmp;
132 
133 /*  D E F I N E S  **************************************************/
134 #define PP_FRAG3_PRIORITY PRIORITY_CORE + PP_CORE_ORDER_FRAG3
135 
136 /* flags for the FragTracker->frag_flags field */
137 #define FRAG_GOT_FIRST      0x00000001
138 #define FRAG_GOT_LAST       0x00000002
139 #define FRAG_REBUILT        0x00000004
140 #define FRAG_BAD            0x00000008
141 #define FRAG_NO_BSD_VULN    0x00000010
142 #define FRAG_DROP_FRAGMENTS 0x00000020
143 
144 /* default frag timeout, 90-120 might be better values, can we do
145  * target-based quanta?  */
146 #define FRAG_PRUNE_QUANTA   60
147 
148 /* default 4MB memcap */
149 #define FRAG_MEMCAP   4194304
150 
151 /* min acceptable ttl (should be 1?) */
152 #define FRAG3_MIN_TTL        1
153 
154 /* target-based defragmentation policy enums */
155 #define FRAG_POLICY_FIRST       1
156 #define FRAG_POLICY_LINUX       2
157 #define FRAG_POLICY_BSD         3
158 #define FRAG_POLICY_BSD_RIGHT   4
159 #define FRAG_POLICY_LAST        5
160 /* Combo of FIRST & LAST, depending on overlap situation. */
161 #define FRAG_POLICY_WINDOWS     6
162 /* Combo of FIRST & LAST, depending on overlap situation. */
163 #define FRAG_POLICY_SOLARIS     7
164 #define FRAG_POLICY_DEFAULT     FRAG_POLICY_BSD
165 
166 /* max packet size */
167 #define DATASIZE (ETHERNET_HEADER_LEN+IP_MAXPACKET)
168 
169 /* max frags in a single frag tracker */
170 #define DEFAULT_MAX_FRAGS   8192
171 
172 /*max preallocated frags */
173 #define MAX_PREALLOC_FRAGS 50000
174 #define MIN_FRAG_MEMCAP 16384
175 
176 /* return values for CheckTimeout() */
177 #define FRAG_TIME_OK            0
178 #define FRAG_TIMEOUT            1
179 
180 /* return values for Frag3Insert() */
181 #define FRAG_INSERT_OK          0
182 #define FRAG_INSERT_FAILED      1
183 #define FRAG_INSERT_REJECTED    2
184 #define FRAG_INSERT_TIMEOUT     3
185 #define FRAG_INSERT_ATTACK      4
186 #define FRAG_INSERT_ANOMALY     5
187 #define FRAG_INSERT_TTL         6
188 #define FRAG_INSERT_OVERLAP_LIMIT  7
189 
190 /* return values for Frag3CheckFirstLast() */
191 #define FRAG_FIRSTLAST_OK       0
192 #define FRAG_LAST_DUPLICATE     1
193 
194 /* return values for Frag3Expire() */
195 #define FRAG_OK                 0
196 #define FRAG_TRACKER_TIMEOUT    1
197 #define FRAG_LAST_OFFSET_ADJUST 2
198 
199 /* flag for detecting attacks/alerting */
200 #define FRAG3_DETECT_ANOMALIES  0x01
201 
202 /*  D A T A   S T R U C T U R E S  **********************************/
203 
204 /* runtime context for a specific instance of an engine */
205 typedef struct _Frag3Context
206 {
207     uint16_t   frag_policy;  /* policy to use for target-based reassembly */
208     uint32_t   frag_timeout; /* timeout for frags in this policy */
209 
210     uint8_t    min_ttl;       /* Minimum TTL to accept */
211 
212     char        frag3_alerts;      /* Whether or not frag3 alerts are enabled */
213 
214     IpAddrSet  *bound_addrs; /* addresses bound to this context */
215 
216     /**limit on number of fragments before excessive fragmentation event is generated.
217      */
218     uint32_t   overlap_limit;
219 
220     /**Fragment that is too small to be legal
221      */
222     uint32_t   min_fragment_length;
223 
224 } Frag3Context;
225 
226 /* struct to manage an individual fragment */
227 typedef struct _Frag3Frag
228 {
229     uint8_t   *data;     /* ptr to adjusted start position */
230     uint16_t   size;     /* adjusted frag size */
231     uint16_t   offset;   /* adjusted offset position */
232 
233     uint8_t   *fptr;     /* free pointer */
234     uint16_t   flen;     /* free len, unneeded? */
235 
236     struct _Frag3Frag *prev;
237     struct _Frag3Frag *next;
238 
239     int         ord;
240     char        last;
241 } Frag3Frag;
242 
243 typedef struct _fragkey
244 {
245     uint32_t   sip[4];
246     uint32_t   dip[4];
247     uint32_t   id;
248     uint16_t   vlan_tag;
249     uint8_t    proto;         /* IP protocol, unused for IPv6 */
250     uint8_t    ipver;         /* Version */
251 #ifdef MPLS
252     uint32_t   mlabel;
253     /* For 64 bit alignment since this is allocated in front of a FragTracker
254      * and the structures are laid on top of that allocated memory */
255 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
256 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
257     uint16_t   address_space_id_src;
258     uint16_t   address_space_id_dst;
259 #else
260     uint16_t   addressSpaceId;
261     uint16_t   addressSpaceIdPad1;
262 #endif
263 #else
264     uint32_t   mpad;
265 #endif
266 #else
267 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
268 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
269     uint16_t   address_space_id_src;
270     uint16_t   address_space_id_dst;
271 #else
272     uint16_t   addressSpaceId;
273     uint16_t   addressSpaceIdPad1;
274 #endif
275     uint32_t   addressSpaceIdPad2;
276 #endif
277 #endif
278 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
279     uint32_t   carrierId;
280 #endif
281 } FRAGKEY;
282 
283 /* Only track a certain number of alerts per session */
284 #define MAX_FRAG_ALERTS  8
285 
286 /* global configuration data struct for this preprocessor */
287 typedef struct _Frag3Config
288 {
289     int disabled;
290     uint32_t   max_frags;            /* max frags to track */
291     unsigned long memcap;            /* memcap for frag3 */
292     int ten_percent;                 /* holder for self preservation data */
293     uint32_t   static_frags;         /* static frag nodes to keep around */
294     uint8_t    use_prealloc;         /* flag to indicate prealloc nodes in use */
295     uint8_t    use_prealloc_frags;   /* flag to indicate prealloc nodes in use */
296     Frag3Context *default_context;
297     Frag3Context **frag3ContextList;  /* List of Frag3 Contexts configured */
298     uint8_t numFrag3Contexts;
299     uint32_t ref_count;
300 
301 } Frag3Config;
302 
303 /* tracker for a fragmented packet set */
304 typedef struct _FragTracker
305 {
306     uint32_t sip[4];
307     uint32_t dip[4];
308     uint32_t id;           /* IP ID */
309     uint8_t protocol;      /* IP protocol */
310     uint8_t ipver;         /* Version */
311 
312     uint8_t ttl;           /* ttl used to detect evasions */
313     uint8_t alerted;
314     uint32_t frag_flags;   /* bit field */
315 
316     uint32_t frag_bytes;   /* number of fragment bytes stored, based
317                              * on aligned fragment offsets/sizes
318                              */
319 
320     uint32_t calculated_size; /* calculated size of reassembled pkt, based on
321                                 * last frag offset
322                                 */
323 
324     uint32_t frag_pkts;   /* nummber of frag pkts stored under this tracker */
325 
326     struct timeval frag_time; /* time we started tracking this frag */
327 
328     Frag3Frag *fraglist;      /* list of fragments */
329     Frag3Frag *fraglist_tail; /* tail ptr for easy appending */
330     int fraglist_count;       /* handy dandy counter */
331 
332     uint32_t alert_gid[MAX_FRAG_ALERTS]; /* flag alerts seen in a frag list  */
333     uint32_t alert_sid[MAX_FRAG_ALERTS]; /* flag alerts seen in a frag list  */
334     uint8_t  alert_count;                /* count alerts seen in a frag list */
335 
336     uint32_t ip_options_len;  /* length of ip options for this set of frags */
337     uint32_t ip_option_count; /* number of ip options for this set of frags */
338     uint8_t *ip_options_data; /* ip options from offset 0 packet */
339 
340     uint32_t copied_ip_options_len;  /* length of 'copied' ip options */
341     uint32_t copied_ip_option_count; /* number of 'copied' ip options */
342 
343     Frag3Context *context;
344 
345     int ordinal;
346 #ifdef TARGET_BASED
347     int ipprotocol;
348     int application_protocol;
349 #endif
350     uint32_t frag_policy;
351     /**Count of IP fragment overlap for each packet id.
352      */
353     uint32_t overlap_count;
354 
355     /* Configuration in use when this tracker was created */
356     tSfPolicyId policy_id;
357     tSfPolicyUserContextId config;
358 
359 } FragTracker;
360 
361 /* statistics tracking struct */
362 typedef struct _Frag3Stats
363 {
364     uint32_t  total;
365     uint32_t  overlaps;
366     uint32_t  reassembles;
367     uint32_t  prunes;
368     uint32_t  timeouts;
369     uint32_t  fragtrackers_created;
370     uint32_t  fragtrackers_released;
371     uint32_t  fragtrackers_autoreleased;
372     uint32_t  fragnodes_created;
373     uint32_t  fragnodes_released;
374     uint32_t  discards;
375     uint32_t  anomalies;
376     uint32_t  alerts;
377     uint32_t  drops;
378 
379 } Frag3Stats;
380 
381 
382 /*  G L O B A L S  **************************************************/
383 static tSfPolicyUserContextId frag3_config = NULL;  /* current configuration */
384 
385 /* Config to use to evaluate
386  * If a frag tracker is found in the hash table, the configuration under
387  * which it was created will be used */
388 static Frag3Config *frag3_eval_config = NULL;
389 
390 static SFXHASH *f_cache = NULL;                 /* fragment hash table */
391 static Frag3Frag *prealloc_frag_list = NULL;    /* head for prealloc queue */
392 
393 static unsigned long frag3_mem_in_use = 0;            /* memory in use, used for self pres */
394 
395 static uint32_t prealloc_nodes_in_use;  /* counter for debug */
396 
397 static Frag3Stats f3stats;               /* stats struct */
398 
399 static Packet* defrag_pkt = NULL;
400 #ifdef GRE
401 static Packet* encap_defrag_pkt = NULL;
402 #endif
403 
404 static uint32_t pkt_snaplen = 0;
405 
406 static uint32_t old_static_frags;
407 static unsigned long hashTableSize;
408 static unsigned long fcache_new_memcap;
409 
410 /* enum for policy names */
411 static char *frag_policy_names[] = { "no policy!",
412     "FIRST",
413     "LINUX",
414     "BSD",
415     "BSD_RIGHT",
416     "LAST",
417     "WINDOWS",
418     "SOLARIS"};
419 
420 #ifdef PERF_PROFILING
421 PreprocStats frag3PerfStats;
422 PreprocStats frag3InsertPerfStats;
423 PreprocStats frag3RebuildPerfStats;
424 #endif
425 
426 /*
427  * external globals for startup
428  */
429 extern char *file_name;
430 extern int file_line;
431 
432 
433 /*  P R O T O T Y P E S  ********************************************/
434 static void Frag3ParseGlobalArgs(Frag3Config *, char *);
435 static void Frag3ParseArgs(struct _SnortConfig *, char *, Frag3Context *);
436 static inline int Frag3Expire(Packet *, FragTracker *, Frag3Context *);
437 static FragTracker *Frag3GetTracker(Packet *, FRAGKEY *);
438 static int Frag3NewTracker(Packet *p, FRAGKEY *fkey, Frag3Context *);
439 static int Frag3Insert(Packet *, FragTracker *, FRAGKEY *, Frag3Context *);
440 static void Frag3Rebuild(FragTracker *, Packet *);
441 static inline int Frag3IsComplete(FragTracker *);
442 static int Frag3HandleIPOptions(FragTracker *, Packet *);
443 static void Frag3PrintStats(int);
444 static void Frag3FreeConfig(Frag3Config *);
445 static void Frag3FreeConfigs(tSfPolicyUserContextId);
446 
447 #ifdef SNORT_RELOAD
448 static void Frag3ReloadGlobal(struct _SnortConfig *, char *, void **);
449 static void Frag3ReloadEngine(struct _SnortConfig *, char *, void **);
450 static int Frag3ReloadVerify(struct _SnortConfig *, void *);
451 static void * Frag3ReloadSwap(struct _SnortConfig *, void *);
452 static void Frag3ReloadSwapFree(void *);
453 static uint32_t Frag3MemReloadAdjust(unsigned);
454 static bool Frag3ReloadAdjust(bool, tSfPolicyId, void *);
455 #endif
456 
457 /* deletion funcs */
458 static int Frag3Prune(FragTracker *);
459 static struct timeval *pkttime;    /* packet timestamp */
460 static void Frag3DeleteFrag(Frag3Frag *);
461 static void Frag3RemoveTracker(void *, void *);
462 static void Frag3DeleteTracker(FragTracker *);
463 static int Frag3AutoFree(void *, void *);
464 static int Frag3UserFree(void *, void *);
465 
466 /* fraglist handler funcs */
467 static inline void Frag3FraglistAddNode(FragTracker *, Frag3Frag *, Frag3Frag *);
468 static inline void Frag3FraglistDeleteNode(FragTracker *, Frag3Frag *);
469 
470 /* prealloc queue handler funcs */
471 static inline Frag3Frag *Frag3PreallocPop();
472 static inline void Frag3PreallocPush(Frag3Frag *);
473 
474 /* main preprocessor functions */
475 static void Frag3Defrag(Packet *, void *);
476 static void Frag3CleanExit(int, void *);
477 static void Frag3Reset(int, void *);
478 static void Frag3ResetStats(int, void *);
479 static void Frag3Init(struct _SnortConfig *, char *);
480 static void Frag3GlobalInit(struct _SnortConfig *, char *);
481 static int Frag3VerifyConfig(struct _SnortConfig *);
482 static void Frag3PostConfigInit(struct _SnortConfig *, void *);
483 
FragIPToStr(uint32_t ip[4],uint8_t proto)484 char *FragIPToStr(uint32_t ip[4], uint8_t proto)
485 {
486     char *ret_str;
487     sfaddr_t srcip;
488     sfip_set_raw(&srcip, ip, proto == 4 ? AF_INET : AF_INET6);
489 
490     ret_str = sfip_to_str(&srcip);
491     return ret_str;
492 }
493 
494 #ifdef DEBUG_FRAG3
495 /**
496  * Print out a FragTracker structure
497  *
498  * @param ft Pointer to the FragTracker to print
499  *
500  * @return none
501  */
PrintFragTracker(FragTracker * ft)502 static void PrintFragTracker(FragTracker *ft)
503 {
504     LogMessage("FragTracker %p\n", ft);
505     if(ft)
506     {
507         LogMessage("        sip: %s\n", FragIPToStr(ft->sip, ft->ipver));
508         LogMessage("        dip: %s\n", FragIPToStr(ft->dip, ft->ipver));
509         LogMessage("         id: %d\n", ft->id);
510         LogMessage("      proto: 0x%X\n", ft->protocol);
511         LogMessage("      ipver: 0x%X\n", ft->ipver);
512         LogMessage("        ttl: %d\n", ft->ttl);
513         LogMessage("    alerted: %d\n", ft->alerted);
514         LogMessage(" frag_flags: 0x%X\n", ft->frag_flags);
515         LogMessage(" frag_bytes: %d\n", ft->frag_bytes);
516         LogMessage("  calc_size: %d\n", ft->calculated_size);
517         LogMessage("  frag_pkts: %d\n", ft->frag_pkts);
518         LogMessage("  frag_time: %lu %lu\n", ft->frag_time.tv_sec,
519                 ft->frag_time.tv_usec);
520         LogMessage("   fraglist: %p\n", ft->fraglist);
521         LogMessage("    fl_tail: %p\n", ft->fraglist_tail);
522         LogMessage("fraglst cnt: %d\n", ft->fraglist_count);
523     }
524 }
525 
526 /**
527  * Print out a FragKey structure
528  *
529  * @param fkey Pointer to the FragKey to print
530  *
531  * @return none
532  */
PrintFragKey(FRAGKEY * fkey)533 static void PrintFragKey(FRAGKEY *fkey)
534 {
535     LogMessage("FragKey %p\n", fkey);
536 
537     if(fkey)
538     {
539         LogMessage("   sip: %s\n", FragIPToStr(fkey->sip, fkey->ipver));
540         LogMessage("   dip: %s\n", FragIPToStr(fkey->dip, fkey->ipver));
541         LogMessage("     id: %d\n", fkey->id);
542         LogMessage("  proto: 0x%X\n", fkey->proto);
543 #ifdef MPLS
544         LogMessage(" mlabel: 0x%08X\n", fkey->mlabel);
545 #endif
546 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
547         LogMessage(" addr id: %d\n", fkey->addressSpaceId);
548 #endif
549 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
550         LogMessage(" carrier id: %u\n", fkey->carrierId);
551 #endif
552     }
553 }
554 
555 /**
556  * Print out a Frag3Frag structure
557  *
558  * @param f Pointer to the Frag3Frag to print
559  *
560  * @return none
561  */
PrintFrag3Frag(Frag3Frag * f)562 static void PrintFrag3Frag(Frag3Frag *f)
563 {
564     LogMessage("Frag3Frag: %p\n", f);
565 
566     if(f)
567     {
568         LogMessage("    data: %p\n", f->data);
569         LogMessage("    size: %d\n", f->size);
570         LogMessage("  offset: %d\n", f->offset);
571         LogMessage("    fptr: %p\n", f->fptr);
572         LogMessage("    flen: %d\n", f->flen);
573         LogMessage("    prev: %p\n", f->prev);
574         LogMessage("    next: %p\n", f->next);
575     }
576 }
577 
578 #endif  /* DEBUG_FRAG3 */
579 
580 /**
581  * Print out the global runtime configuration
582  *
583  * @param None
584  *
585  * @return none
586  */
Frag3PrintGlobalConfig(Frag3Config * gconfig)587 static void Frag3PrintGlobalConfig(Frag3Config *gconfig)
588 {
589     if (gconfig == NULL)
590         return;
591 
592     LogMessage("Frag3 global config:\n");
593     if(gconfig->disabled)
594     {
595         LogMessage("      Frag3: INACTIVE\n");
596     }
597     LogMessage("    Max frags: %d\n", gconfig->max_frags);
598     if(!gconfig->use_prealloc)
599         LogMessage("    Fragment memory cap: %lu bytes\n",
600                 gconfig->memcap);
601     else
602     {
603         if (gconfig->static_frags)
604             LogMessage("    Preallocated frag nodes: %u\n",
605                 gconfig->static_frags);
606         if (!gconfig->use_prealloc_frags)
607             LogMessage("    Memory cap used to determine preallocated frag nodes: %lu\n",
608                     gconfig->memcap);
609     }
610 }
611 
612 
613 /**
614  * Print out a defrag engine runtime context
615  *
616  * @param context Pointer to the context structure to print
617  *
618  * @return none
619  */
Frag3PrintEngineConfig(Frag3Context * context)620 static void Frag3PrintEngineConfig(Frag3Context *context)
621 {
622 
623     LogMessage("Frag3 engine config:\n");
624     if (context->bound_addrs != NULL)
625     {
626         IpAddrSetPrint("    Bound Addresses: ", context->bound_addrs);
627     }
628     else
629     {
630         LogMessage("    Bound Address: default\n");
631     }
632     LogMessage("    Target-based policy: %s\n",
633             frag_policy_names[context->frag_policy]);
634     LogMessage("    Fragment timeout: %d seconds\n",
635             context->frag_timeout);
636     LogMessage("    Fragment min_ttl:   %d\n", context->min_ttl);
637     LogMessage("    Fragment Anomalies: %s\n",
638             context->frag3_alerts ? "Alert" : "No Alert");
639 
640     LogMessage("    Overlap Limit:     %d\n",
641             context->overlap_limit);
642     LogMessage("    Min fragment Length:     %d\n",
643             context->min_fragment_length);
644 }
645 
646 /**
647  * Generate an event due to IP options being detected in a frag packet
648  *
649  * @param context Current run context
650  *
651  * @return none
652  */
EventAnomIpOpts(Frag3Context * context)653 static inline void EventAnomIpOpts(Frag3Context *context)
654 {
655     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
656         return;
657 
658     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */
659             FRAG3_IPOPTIONS,         /* SID */
660             1,                       /* rev */
661             0,                       /* classification enum */
662             3,                       /* priority (low) */
663             FRAG3_IPOPTIONS_STR,     /* event message */
664             NULL);                   /* rule info ptr */
665 
666    f3stats.alerts++;
667 }
668 
669 /**
670  * Generate an event due to a Teardrop-style attack detected in a frag packet
671  *
672  * @param context Current run context
673  *
674  * @return none
675  */
EventAttackTeardrop(Frag3Context * context)676 static inline void EventAttackTeardrop(Frag3Context *context)
677 {
678     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
679         return;
680 
681     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */
682             FRAG3_TEARDROP,          /* SID */
683             1,                       /* rev */
684             0,                       /* classification enum */
685             3,                       /* priority (low) */
686             FRAG3_TEARDROP_STR,      /* event message */
687             NULL);                   /* rule info ptr */
688 
689    f3stats.alerts++;
690 }
691 
692 /**
693  * Generate an event for very small fragment
694  *
695  * @param context Current run context
696  *
697  * @return none
698  */
EventTinyFragments(Frag3Context * context)699 static inline void EventTinyFragments(Frag3Context *context)
700 {
701     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
702         return;
703 
704     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */
705             FRAG3_TINY_FRAGMENT,          /* SID */
706             1,                       /* rev */
707             0,                       /* classification enum */
708             3,                       /* priority (low) */
709             FRAG3_TINY_FRAGMENT_STR, /* event message */
710             NULL);                   /* rule info ptr */
711 
712    f3stats.alerts++;
713 }
714 
715 /**
716  * Generate an event due to excessive fragment overlap detected in a frag packet
717  *
718  * @param context Current run context
719  *
720  * @return none
721  */
EventExcessiveOverlap(Frag3Context * context)722 static inline void EventExcessiveOverlap(Frag3Context *context)
723 {
724     //@TBD dschahal do I need this
725     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
726         return;
727 
728     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */
729             FRAG3_EXCESSIVE_OVERLAP,          /* SID */
730             1,                       /* rev */
731             0,                       /* classification enum */
732             3,                       /* priority (low) */
733             FRAG3_EXCESSIVE_OVERLAP_STR, /* event message */
734             NULL);                   /* rule info ptr */
735 
736    f3stats.alerts++;
737 }
738 
739 /**
740  * Generate an event due to a fragment being too short, typcially based
741  * on a non-last fragment that doesn't properly end on an 8-byte boundary
742  *
743  * @param context Current run context
744  *
745  * @return none
746  */
EventAnomShortFrag(Frag3Context * context)747 static inline void EventAnomShortFrag(Frag3Context *context)
748 {
749     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
750         return;
751 
752     SnortEventqAdd(GENERATOR_SPP_FRAG3,   /* GID */
753             FRAG3_SHORT_FRAG,             /* SID */
754             1,                            /* rev */
755             0,                            /* classification enum */
756             3,                            /* priority (low) */
757             FRAG3_SHORT_FRAG_STR,         /* event message */
758             NULL);                        /* rule info ptr */
759 
760    f3stats.alerts++;
761    f3stats.anomalies++;
762 }
763 
764 /**
765  * This fragment's size will end after the already calculated reassembled
766  * fragment end, as in a Bonk/Boink/etc attack.
767  *
768  * @param context Current run context
769  *
770  * @return none
771  */
EventAnomOversize(Frag3Context * context)772 static inline void EventAnomOversize(Frag3Context *context)
773 {
774     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
775         return;
776 
777     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */
778             FRAG3_ANOMALY_OVERSIZE,  /* SID */
779             1,                       /* rev */
780             0,                       /* classification enum */
781             3,                       /* priority (low) */
782             FRAG3_ANOM_OVERSIZE_STR, /* event message */
783             NULL);                   /* rule info ptr */
784 
785    f3stats.alerts++;
786    f3stats.anomalies++;
787 }
788 
789 /**
790  * The current fragment will be inserted with a size of 0 bytes, that's
791  * an anomaly if I've ever seen one.
792  *
793  * @param context Current run context
794  *
795  * @return none
796  */
EventAnomZeroFrag(Frag3Context * context)797 static inline void EventAnomZeroFrag(Frag3Context *context)
798 {
799     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
800         return;
801 
802     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */
803             FRAG3_ANOMALY_ZERO,      /* SID */
804             1,                       /* rev */
805             0,                       /* classification enum */
806             3,                       /* priority (low) */
807             FRAG3_ANOM_ZERO_STR,     /* event message */
808             NULL);                   /* rule info ptr */
809 
810    f3stats.alerts++;
811    f3stats.anomalies++;
812 }
813 
814 /**
815  * The reassembled packet will be bigger than 64k, generate an event.
816  *
817  * @param context Current run context
818  *
819  * @return none
820  */
EventAnomBadsizeLg(Frag3Context * context)821 static inline void EventAnomBadsizeLg(Frag3Context *context)
822 {
823     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
824         return;
825 
826     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */
827             FRAG3_ANOMALY_BADSIZE_LG,   /* SID */
828             1,                       /* rev */
829             0,                       /* classification enum */
830             3,                       /* priority (low) */
831             FRAG3_ANOM_BADSIZE_LG_STR,  /* event message */
832             NULL);                   /* rule info ptr */
833 
834    f3stats.alerts++;
835    f3stats.anomalies++;
836 }
837 
838 /**
839  * Fragment size is negative after insertion (end < offset).
840  *
841  * @param context Current run context
842  *
843  * @return none
844  */
EventAnomBadsizeSm(Frag3Context * context)845 static inline void EventAnomBadsizeSm(Frag3Context *context)
846 {
847     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
848         return;
849 
850     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */
851             FRAG3_ANOMALY_BADSIZE_SM,  /* SID */
852             1,                         /* rev */
853             0,                         /* classification enum */
854             3,                         /* priority (low) */
855             FRAG3_ANOM_BADSIZE_SM_STR, /* event message */
856             NULL);                     /* rule info ptr */
857 
858    f3stats.alerts++;
859    f3stats.anomalies++;
860 }
861 
862 /**
863  * There is an overlap with this fragment, someone is probably being naughty.
864  *
865  * @param context Current run context
866  *
867  * @return none
868  */
EventAnomOverlap(Frag3Context * context)869 static inline void EventAnomOverlap(Frag3Context *context)
870 {
871     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
872         return;
873 
874     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */
875             FRAG3_ANOMALY_OVLP,   /* SID */
876             1,                    /* rev */
877             0,                    /* classification enum */
878             3,                    /* priority (low) */
879             FRAG3_ANOM_OVLP_STR,  /* event message */
880             NULL);                /* rule info ptr */
881 
882    f3stats.alerts++;
883    f3stats.anomalies++;
884 }
885 
886 /**
887  * Generate an event due to TTL below the configured minimum
888  *
889  * @param context Current run context
890  *
891  * @return none
892  */
EventAnomScMinTTL(Frag3Context * context)893 static inline void EventAnomScMinTTL(Frag3Context *context)
894 {
895     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
896         return;
897 
898     SnortEventqAdd(GENERATOR_SPP_FRAG3, /* GID */
899             FRAG3_MIN_TTL_EVASION,   /* SID */
900             1,                       /* rev */
901             0,                       /* classification enum */
902             3,                       /* priority (low) */
903             FRAG3_MIN_TTL_EVASION_STR,  /* event message */
904             NULL);                   /* rule info ptr */
905 
906    f3stats.alerts++;
907 }
908 
frag3_print_mem_stats(FILE * fd,char * buffer,PreprocMemInfo * meminfo)909 int frag3_print_mem_stats(FILE *fd, char* buffer, PreprocMemInfo *meminfo)
910 {
911     int len = 0;
912     time_t curr_time;
913 
914     if (fd)
915     {
916         len = fprintf(fd, ",%lu,%u"
917                  ",%lu,%u,%u"
918                  ",%lu,%u,%u,%lu"
919                  , frag3_mem_in_use
920                  , prealloc_nodes_in_use
921                  , meminfo[PP_MEM_CATEGORY_SESSION].used_memory
922                  , meminfo[PP_MEM_CATEGORY_SESSION].num_of_alloc
923                  , meminfo[PP_MEM_CATEGORY_SESSION].num_of_free
924                  , meminfo[PP_MEM_CATEGORY_CONFIG].used_memory
925                  , meminfo[PP_MEM_CATEGORY_CONFIG].num_of_alloc
926                  , meminfo[PP_MEM_CATEGORY_CONFIG].num_of_free
927                  , meminfo[PP_MEM_CATEGORY_SESSION].used_memory +
928                    meminfo[PP_MEM_CATEGORY_CONFIG].used_memory);
929 
930         return len;
931     }
932 
933     curr_time = time(NULL);
934 
935     if (buffer)
936     {
937         len = snprintf(buffer, CS_STATS_BUF_SIZE, "\n\nMemory Statistics of Frag3 on: %s\n"
938             "    Memory in use         : %lu\n"
939             "    prealloc nodes in use : %u\n\n"
940             , ctime(&curr_time)
941             , frag3_mem_in_use
942             , prealloc_nodes_in_use);
943     } else {
944         LogMessage("\n");
945         LogMessage("Memory Statistics of Frag3 on: %s\n", ctime(&curr_time));
946         LogMessage("    Memory in use         : %lu\n", frag3_mem_in_use);
947         LogMessage("    prealloc nodes in use : %u\n\n", prealloc_nodes_in_use);
948     }
949 
950     return len;
951 }
952 
953 /**
954  * Main setup function to register frag3 with the rest of Snort.
955  *
956  * @param none
957  *
958  * @return none
959  */
SetupFrag3(void)960 void SetupFrag3(void)
961 {
962     RegisterMemoryStatsFunction(PP_FRAG3, frag3_print_mem_stats);
963 #ifndef SNORT_RELOAD
964     RegisterPreprocessor("frag3_global", Frag3GlobalInit);
965     RegisterPreprocessor("frag3_engine", Frag3Init);
966 #else
967     RegisterPreprocessor("frag3_global", Frag3GlobalInit,
968                          Frag3ReloadGlobal, Frag3ReloadVerify, Frag3ReloadSwap,
969                          Frag3ReloadSwapFree);
970     RegisterPreprocessor("frag3_engine", Frag3Init, Frag3ReloadEngine,
971                          NULL, NULL, NULL);
972 #endif
973 
974     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Preprocessor: frag3 is setup...\n"););
975 }
976 
Frag3KeyHashFunc(SFHASHFCN * p,unsigned char * d,int n)977 uint32_t Frag3KeyHashFunc(SFHASHFCN *p, unsigned char *d, int n)
978 {
979     uint32_t a,b,c;
980     uint32_t offset = 0;
981 #ifdef MPLS
982     uint32_t tmp = 0;
983 #endif
984 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
985     uint32_t tmp2 = 0;
986 #endif
987 
988     a = *(uint32_t *)d;        /* IPv6 sip[0] */
989     b = *(uint32_t *)(d+4);    /* IPv6 sip[1] */
990     c = *(uint32_t *)(d+8);    /* IPv6 sip[2] */
991     mix(a,b,c);
992 
993     a += *(uint32_t *)(d+12);  /* IPv6 sip[3] */
994     b += *(uint32_t *)(d+16);  /* IPv6 dip[0] */
995     c += *(uint32_t *)(d+20);  /* IPv6 dip[1] */
996     mix(a,b,c);
997 
998     a += *(uint32_t *)(d+24);  /* IPv6 dip[2] */
999     b += *(uint32_t *)(d+28);  /* IPv6 dip[3] */
1000     c += *(uint32_t *)(d+32);  /* IPv6 id */
1001     mix(a,b,c);
1002 
1003     offset = 36;
1004 
1005     a += *(uint32_t *)(d+offset);  /* vlan, proto, ipver */
1006 #ifdef MPLS
1007     tmp = *(uint32_t*)(d+offset+4);
1008     if( tmp )
1009     {
1010         b += tmp;   /* mpls label */
1011     }
1012     offset += 8;    /* skip past vlan/proto/ipver & mpls label */
1013 #else
1014     offset += 4;    /* skip past vlan/proto/ipver */
1015 #endif
1016 
1017 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
1018     tmp2 = *(uint32_t*)(d+offset); /* after offset that has been moved */
1019     c += tmp2; /* address space id and 16bits of zero'd pad */
1020 #endif
1021 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
1022     mix(a,b,c);
1023     a += *(uint32_t*)(d+offset+4);
1024 #endif
1025 
1026     final(a,b,c);
1027 
1028     return c;
1029 }
1030 
Frag3KeyCmpFunc(const void * s1,const void * s2,size_t n)1031 int Frag3KeyCmpFunc(const void *s1, const void *s2, size_t n)
1032 {
1033 #ifndef SPARCV9 /* ie, everything else, use 64bit comparisons */
1034     uint64_t *a, *b;
1035 
1036     a = (uint64_t*)s1;
1037     b = (uint64_t*)s2;
1038     if (*a - *b) return 1;      /* Compares IPv4 sip/dip */
1039                                 /* Compares IPv6 sip[0,1] */
1040     a++;
1041     b++;
1042     if (*a - *b) return 1;      /* Compares IPv6 sip[2,3] */
1043 
1044     a++;
1045     b++;
1046     if (*a - *b) return 1;      /* Compares IPv6 dip[0,1] */
1047 
1048     a++;
1049     b++;
1050     if (*a - *b) return 1;      /* Compares IPv6 dip[2,3] */
1051 
1052     a++;
1053     b++;
1054     if (*a - *b) return 1;      /* Compares IPv4 id/pad, vlan/proto/ipver */
1055                                 /* Compares IPv6 id, vlan/proto/ipver */
1056 
1057 #ifdef MPLS
1058     a++;
1059     b++;
1060 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
1061     if (*a - *b) return 1;      /* Compares MPLS label, AddressSpace ID and 16bit pad */
1062 #else
1063     {
1064         uint32_t *x, *y;
1065         x = (uint32_t *)a;
1066         y = (uint32_t *)b;
1067         //x++;
1068         //y++;
1069         if (*x - *y) return 1;  /* Compares mpls label, no pad */
1070     }
1071 #endif
1072 #else
1073 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
1074     a++;
1075     b++;
1076     {
1077         uint16_t *x, *y;
1078         x = (uint16_t *)a;
1079         y = (uint16_t *)b;
1080         //x++;
1081         //y++;
1082         if (*x - *y) return 1;  /* Compares addressSpaceID, no pad */
1083     }
1084 #endif
1085 #endif
1086 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
1087     a++;
1088     b++;
1089     {
1090         uint32_t *x, *y;
1091         x = (uint32_t *)a;
1092         y = (uint32_t *)b;
1093         if (*x - *y) return 1; /* Compares carrierID */
1094     }
1095 #endif
1096 
1097 #else /* SPARCV9 */
1098     uint32_t *a,*b;
1099 
1100     a = (uint32_t*)s1;
1101     b = (uint32_t*)s2;
1102     if ((*a - *b) || (*(a+1) - *(b+1))) return 1;       /* Compares IPv4 sip/dip */
1103                                 /* Compares IPv6 sip[0,1] */
1104     a+=2;
1105     b+=2;
1106     if ((*a - *b) || (*(a+1) - *(b+1))) return 1;       /* Compares IPv6 sip[2,3] */
1107 
1108     a+=2;
1109     b+=2;
1110     if ((*a - *b) || (*(a+1) - *(b+1))) return 1;       /* Compares IPv6 dip[0,1] */
1111 
1112     a+=2;
1113     b+=2;
1114     if ((*a - *b) || (*(a+1) - *(b+1))) return 1;       /* Compares IPv6 dip[2,3] */
1115 
1116     a+=2;
1117     b+=2;
1118     if ((*a - *b) || (*(a+1) - *(b+1))) return 1;       /* Compares IPv4 id/pad, vlan/proto/ipver */
1119                                 /* Compares IPv6 id, vlan/proto/ipver */
1120 
1121 #ifdef MPLS
1122     a+=2;
1123     b+=2;
1124     {
1125         uint32_t *x, *y;
1126         x = (uint32_t *)a;
1127         y = (uint32_t *)b;
1128         //x++;
1129         //y++;
1130         if (*x - *y) return 1;  /* Compares mpls label */
1131     }
1132 #endif
1133 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
1134 #ifdef MPLS
1135     a++;
1136     b++;
1137 #else
1138     a+=2;
1139     b+=2;
1140 #endif
1141     {
1142         uint16_t *x, *y;
1143         x = (uint16_t *)a;
1144         y = (uint16_t *)b;
1145         //x++;
1146         //y++;
1147         if (*x - *y) return 1;  /* Compares addressSpaceID, no pad */
1148     }
1149 #endif
1150 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
1151     a++;
1152     b++;
1153     {
1154         uint32_t *x, *y;
1155         x = (uint32_t *)a;
1156         y = (uint32_t *)b;
1157         if (*x - *y) return 1; /* Compares carrierID */
1158     }
1159 #endif
1160 #endif /* SPARCV9 */
1161 
1162     return 0;
1163 }
1164 
1165 /**
1166  * Global init function, handles setting up the runtime hash table and
1167  * memory management mode. Global configuration applies only to default configuration,
1168  * which is in vlanGroup 0
1169  *
1170  * @param args argument string to process for config data
1171  *
1172  * @return none
1173  */
Frag3GlobalInit(struct _SnortConfig * sc,char * args)1174 static void Frag3GlobalInit(struct _SnortConfig *sc, char *args)
1175 {
1176     Frag3Config *pCurrentPolicyConfig = NULL;
1177     Frag3Config *pDefaultPolicyConfig = NULL;
1178     tSfPolicyId policy_id = getParserPolicy(sc);
1179 
1180     if (frag3_config == NULL)
1181     {
1182         //create a context
1183         frag3_config = sfPolicyConfigCreate();
1184 
1185         defrag_pkt = Encode_New();
1186 #ifdef GRE
1187         encap_defrag_pkt = Encode_New();
1188 #endif
1189 
1190 #ifdef PERF_PROFILING
1191         RegisterPreprocessorProfile("frag3", &frag3PerfStats, 0, &totalPerfStats, NULL);
1192         RegisterPreprocessorProfile("frag3insert", &frag3InsertPerfStats, 1, &frag3PerfStats, NULL);
1193         RegisterPreprocessorProfile("frag3rebuild", &frag3RebuildPerfStats, 1, &frag3PerfStats, NULL);
1194 #endif
1195 
1196         AddFuncToPreprocCleanExitList(Frag3CleanExit, NULL, PP_FRAG3_PRIORITY, PP_FRAG3);
1197         AddFuncToPreprocResetList(Frag3Reset, NULL, PP_FRAG3_PRIORITY, PP_FRAG3);
1198         AddFuncToPreprocResetStatsList(Frag3ResetStats, NULL, PP_FRAG3_PRIORITY, PP_FRAG3);
1199         AddFuncToConfigCheckList(sc, Frag3VerifyConfig);
1200         AddFuncToPreprocPostConfigList(sc, Frag3PostConfigInit, NULL);
1201         RegisterPreprocStats("frag3", Frag3PrintStats);
1202     }
1203 
1204     sfPolicyUserPolicySet (frag3_config, policy_id);
1205     pCurrentPolicyConfig = (Frag3Config *)sfPolicyUserDataGetCurrent(frag3_config);
1206     pDefaultPolicyConfig = (Frag3Config *)sfPolicyUserDataGetDefault(frag3_config);
1207 
1208     if ((policy_id != getDefaultPolicy()) && (pDefaultPolicyConfig == NULL))
1209     {
1210         ParseError("Frag3: Must configure default policy if other policies "
1211                    "are going to be used.\n");
1212     }
1213 
1214     if (pCurrentPolicyConfig != NULL)
1215     {
1216         FatalError("%s(%d) The frag3 global configuration can only be "
1217                    "configured once.\n", file_name, file_line);
1218     }
1219 
1220     pCurrentPolicyConfig = (Frag3Config *)SnortPreprocAlloc(1, sizeof(Frag3Config),
1221                               PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1222     sfPolicyUserDataSetCurrent(frag3_config, pCurrentPolicyConfig);
1223 
1224     /* setup default values */
1225     pCurrentPolicyConfig->max_frags = DEFAULT_MAX_FRAGS;
1226     pCurrentPolicyConfig->memcap = FRAG_MEMCAP;
1227     pCurrentPolicyConfig->static_frags = 0;
1228     pCurrentPolicyConfig->use_prealloc = 0;
1229     pCurrentPolicyConfig->use_prealloc_frags = 0;
1230 
1231     Frag3ParseGlobalArgs(pCurrentPolicyConfig, args);
1232 
1233     if (policy_id != getDefaultPolicy())
1234     {
1235         /* Can't set these in alternate policies */
1236         pCurrentPolicyConfig->memcap = pDefaultPolicyConfig->memcap;
1237         pCurrentPolicyConfig->max_frags = pDefaultPolicyConfig->max_frags;
1238         pCurrentPolicyConfig->use_prealloc = pDefaultPolicyConfig->use_prealloc;
1239         pCurrentPolicyConfig->use_prealloc_frags = pDefaultPolicyConfig->use_prealloc_frags;
1240         pCurrentPolicyConfig->static_frags = pDefaultPolicyConfig->static_frags;
1241     }
1242 
1243     /*
1244      * we really only need one frag cache no matter how many different
1245      * contexts we have loaded
1246      */
1247     if(f_cache == NULL)
1248     {
1249         /* we keep FragTrackers in the hash table.. */
1250         hashTableSize = (unsigned long) (pCurrentPolicyConfig->max_frags * 1.4);
1251         unsigned long maxFragMem = pCurrentPolicyConfig->max_frags * (
1252                             sizeof(FragTracker) +
1253                             sizeof(SFXHASH_NODE) +
1254                             sizeof (FRAGKEY) +
1255                             sizeof(SFXHASH_NODE *));
1256         unsigned long tableMem = (hashTableSize + 1) * sizeof(SFXHASH_NODE *);
1257         unsigned long maxMem = maxFragMem + tableMem;
1258         f_cache = sfxhash_new(
1259                 hashTableSize,       /* number of hash buckets */
1260                 sizeof(FRAGKEY),     /* size of the key we're going to use */
1261                 sizeof(FragTracker), /* size of the storage node */
1262                 maxMem,              /* memcap for frag trackers */
1263                 1,                   /* use auto node recovery */
1264                 Frag3AutoFree,       /* anr free function */
1265                 Frag3UserFree,       /* user free function */
1266                 1);                  /* recycle node flag */
1267 
1268         /* can't proceed if we can't get a fragment cache */
1269         if(!f_cache)
1270         {
1271             LogMessage("WARNING: Unable to generate new sfxhash for frag3, "
1272                        "defragmentation disabled.\n");
1273             return;
1274         }
1275 
1276         sfxhash_set_keyops(f_cache, Frag3KeyHashFunc, Frag3KeyCmpFunc);
1277     }
1278 
1279     /* display the global config for the user */
1280     Frag3PrintGlobalConfig(pCurrentPolicyConfig);
1281 
1282 #ifdef REG_TEST
1283     LogMessage("\n");
1284     LogMessage("    FragTracker Size: %lu\n",(unsigned long)sizeof(FragTracker));
1285     LogMessage("\n");
1286 #endif
1287 
1288     /* register the preprocessor func node */
1289     if ( !pCurrentPolicyConfig->disabled )
1290     {
1291         AddFuncToPreprocList(sc, Frag3Defrag, PP_FRAG3_PRIORITY, PP_FRAG3, PROTO_BIT__IP);
1292         session_api->enable_preproc_all_ports( sc, PP_FRAG3, PROTO_BIT__IP );
1293     }
1294 }
1295 
1296 /**
1297  * Setup a frag3 engine context
1298  *
1299  * @param args list of configuration arguments
1300  *
1301  * @return none
1302  */
Frag3Init(struct _SnortConfig * sc,char * args)1303 static void Frag3Init(struct _SnortConfig *sc, char *args)
1304 {
1305     Frag3Context *context;      /* context pointer */
1306     tSfPolicyId policy_id = getParserPolicy(sc);
1307     Frag3Config *config = NULL;
1308 
1309     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Initializing frag3\n"););
1310 
1311     config = (Frag3Config *)sfPolicyUserDataGet(frag3_config, policy_id);
1312 
1313     if (config == NULL)
1314     {
1315         FatalError("[!] Unable to configure frag3 engine!\n"
1316                 "Frag3 global config has not been established, "
1317                 "please issue a \"preprocessor frag3_global\" directive\n");
1318         return;
1319     }
1320 
1321 
1322     /*
1323      * setup default context config.  Thinking maybe we should go with
1324      * FRAG_POLICY_FIRST or FRAG_POLICY_LINUX as the default instead of
1325      * BSD since Win32/Linux have a higher incidence of occurrence.  Anyone
1326      * with an opinion on the matter feel free to email me...
1327      */
1328     context = (Frag3Context *) SnortPreprocAlloc(1, sizeof(Frag3Context),
1329                           PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1330     context->frag_policy = FRAG_POLICY_DEFAULT;
1331     context->frag_timeout = FRAG_PRUNE_QUANTA; /* 60 seconds */
1332     context->min_ttl = FRAG3_MIN_TTL;
1333     context->frag3_alerts = 0;
1334 
1335     /* parse the configuration for this engine */
1336     Frag3ParseArgs(sc, args, context);
1337 
1338     if (context->bound_addrs == NULL)
1339     {
1340         if (config->default_context != NULL)
1341             FatalError("Frag3 => only one non-bound engine can be specified.\n");
1342 
1343         config->default_context = context;
1344     }
1345 
1346     /* Now add this context to the internal list */
1347     if (config->frag3ContextList == NULL)
1348     {
1349         config->numFrag3Contexts = 1;
1350         config->frag3ContextList =
1351             (Frag3Context **)SnortPreprocAlloc(1, sizeof (Frag3Context *),
1352                              PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1353     }
1354     else
1355     {
1356         Frag3Context **tmpContextList;
1357 
1358         config->numFrag3Contexts++;
1359         tmpContextList = (Frag3Context **)
1360             SnortPreprocAlloc(config->numFrag3Contexts, sizeof (Frag3Context *),
1361                             PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1362 
1363         memcpy(tmpContextList, config->frag3ContextList,
1364                sizeof(Frag3Context *) * (config->numFrag3Contexts - 1));
1365 
1366         SnortPreprocFree(config->frag3ContextList,
1367                  (config->numFrag3Contexts-1) * sizeof (Frag3Context *), PP_FRAG3,
1368                  PP_MEM_CATEGORY_CONFIG);
1369         config->frag3ContextList = tmpContextList;
1370     }
1371 
1372     config->frag3ContextList[config->numFrag3Contexts - 1] = context;
1373 
1374     /* print this engine config */
1375     Frag3PrintEngineConfig(context);
1376 }
1377 
FragPolicyIdFromName(char * name)1378 static int FragPolicyIdFromName(char *name)
1379 {
1380     if (!name)
1381     {
1382         return FRAG_POLICY_DEFAULT;
1383     }
1384 
1385     if(!strcasecmp(name, "bsd"))
1386     {
1387         return FRAG_POLICY_BSD;
1388     }
1389     else if(!strcasecmp(name, "bsd-right"))
1390     {
1391         return FRAG_POLICY_BSD_RIGHT;
1392     }
1393     else if(!strcasecmp(name, "linux"))
1394     {
1395         return FRAG_POLICY_LINUX;
1396     }
1397     else if(!strcasecmp(name, "first"))
1398     {
1399         return FRAG_POLICY_FIRST;
1400     }
1401     else if(!strcasecmp(name, "windows"))
1402     {
1403         return FRAG_POLICY_WINDOWS;
1404     }
1405     else if(!strcasecmp(name, "solaris"))
1406     {
1407         return FRAG_POLICY_SOLARIS;
1408     }
1409     else if(!strcasecmp(name, "last"))
1410     {
1411         return FRAG_POLICY_LAST;
1412     }
1413     return FRAG_POLICY_DEFAULT;
1414 }
1415 
1416 #ifdef TARGET_BASED
FragPolicyIdFromHostAttributeEntry(HostAttributeEntry * host_entry)1417 int FragPolicyIdFromHostAttributeEntry(HostAttributeEntry *host_entry)
1418 {
1419     if (!host_entry)
1420         return 0;
1421 
1422     host_entry->hostInfo.fragPolicy = FragPolicyIdFromName(host_entry->hostInfo.fragPolicyName);
1423     host_entry->hostInfo.fragPolicySet = 1;
1424 
1425     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1426         "Frag3 INIT: %s(%d) for Entry %s\n",
1427         frag_policy_names[host_entry->hostInfo.fragPolicy],
1428         host_entry->hostInfo.fragPolicy,
1429         host_entry->hostInfo.fragPolicyName););
1430 
1431     return 0;
1432 }
1433 #endif
1434 
1435 /**
1436  * Verify frag3 setup is complete
1437  *
1438  * @param args list of configuration arguments
1439  *
1440  * @return none
1441  */
Frag3VerifyConfigPolicy(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)1442 static int Frag3VerifyConfigPolicy(
1443         struct _SnortConfig *sc,
1444         tSfPolicyUserContextId config,
1445         tSfPolicyId policyId,
1446         void* pData
1447         )
1448 {
1449     Frag3Config *pPolicyConfig = (Frag3Config *)pData;
1450 
1451     if ( pPolicyConfig->disabled )
1452         return 0;
1453 
1454     //do any housekeeping before processingFrag3Config
1455     if ((policyId != getDefaultPolicy())
1456         && (pPolicyConfig->numFrag3Contexts == 0))
1457     {
1458         WarningMessage("Frag3VerifyConfig: PolicyId %d, policy engine required "
1459                 "but not configured.\n", policyId);
1460         return -1;
1461     }
1462 
1463 #ifdef TARGET_BASED
1464     SFAT_SetPolicyIds(FragPolicyIdFromHostAttributeEntry, policyId);
1465 #endif
1466 
1467     return 0;
1468 }
1469 
Frag3VerifyConfig(struct _SnortConfig * sc)1470 static int Frag3VerifyConfig(struct _SnortConfig *sc)
1471 {
1472     if (sfPolicyUserDataIterate (sc, frag3_config, Frag3VerifyConfigPolicy))
1473         return -1;
1474 
1475     return 0;
1476 }
1477 
1478 /**
1479  * Handle the preallocation of frags
1480  *
1481  * @param int unused
1482  *        void *arg unused inputs
1483  *        (these aren't used, just need to match function prototype)
1484  *
1485  * @return none
1486  */
Frag3PostConfigInit(struct _SnortConfig * sc,void * arg)1487 static void Frag3PostConfigInit(struct _SnortConfig *sc, void *arg)
1488 {
1489     Frag3Frag *tmp; /* for initializing the prealloc queue */
1490     unsigned int i;          /* counter */
1491     Frag3Config *config = NULL;
1492 
1493     config = sfPolicyUserDataGetDefault(frag3_config);
1494     if (config == NULL)
1495         return;
1496 
1497     pkt_snaplen = DAQ_GetSnapLen();
1498 
1499     /*
1500      * user has decided to prealloc the node structs for performance
1501      */
1502     if(config->use_prealloc)
1503     {
1504         if (config->static_frags == 0)
1505         {
1506             config->static_frags = (uint32_t)(config->memcap /
1507                 (sizeof(Frag3Frag) + sizeof(uint8_t) * pkt_snaplen) + 1);
1508 
1509             config->ten_percent = config->static_frags >> 5;
1510         }
1511 
1512         for (i = 0; i < config->static_frags; i++)
1513         {
1514             tmp = (Frag3Frag *) SnortPreprocAlloc(1, sizeof(Frag3Frag),
1515                                    PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1516             tmp->fptr = (uint8_t *) SnortPreprocAlloc(pkt_snaplen, sizeof(uint8_t),
1517                                    PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
1518             Frag3PreallocPush(tmp);
1519         }
1520 
1521         prealloc_nodes_in_use = 0;
1522     }
1523 }
1524 
1525 /**
1526  * Config parser for global config.
1527  *
1528  * @param args List of configuration parameters
1529  *
1530  * @return none
1531  */
Frag3ParseGlobalArgs(Frag3Config * gconfig,char * args)1532 static void Frag3ParseGlobalArgs(Frag3Config *gconfig, char *args)
1533 {
1534     char **toks;
1535     int num_toks;
1536     int i = 0;
1537     char *index;
1538     char **stoks = NULL;
1539     int s_toks;
1540     char *endPtr;
1541     long ivalue;
1542     unsigned long value;
1543 
1544     if ((args == NULL) || (gconfig == NULL))
1545         return;
1546 
1547     toks = mSplit(args, ",", 0, &num_toks, 0);
1548     for (i = 0; i < num_toks; i++)
1549     {
1550         index = toks[i];
1551 
1552         stoks = mSplit(index, " ", 0, &s_toks, 0);
1553 
1554         if(!strcasecmp(stoks[0], "max_frags"))
1555         {
1556             if (s_toks != 2)
1557             {
1558                 FatalError("%s(%d) => Missing argument to max_frags in "
1559                            "config file.\n",
1560                            file_name, file_line);
1561             }
1562 
1563             gconfig->max_frags = ivalue = strtol(stoks[1], &endPtr, 10);
1564 
1565             if ((endPtr == &stoks[1][0]) || (ivalue <= 0))
1566             {
1567                 FatalError("%s(%d) => Invalid max_frags in config file. "
1568                            "Integer parameter required.\n", file_name,
1569                            file_line);
1570             }
1571         }
1572         else if(!strcasecmp(stoks[0], "memcap"))
1573         {
1574             if (s_toks != 2)
1575             {
1576                 FatalError("%s(%d) => Missing argument to memcap in "
1577                            "config file.\n",
1578                            file_name, file_line);
1579             }
1580 
1581             gconfig->memcap = value = strtoul(stoks[1], &endPtr, 10);
1582 
1583             if (!*stoks[1] || *stoks[1] == '-' || *endPtr)
1584             {
1585                 FatalError("%s(%d) => Invalid memcap in config file. "
1586                            "Integer parameter required.\n", file_name,
1587                            file_line);
1588             }
1589 
1590             if (gconfig->memcap < MIN_FRAG_MEMCAP)
1591             {
1592                 LogMessage("WARNING: %s(%d) => Ludicrous (<16k) memcap "
1593                            "size, setting to default (%d bytes)\n",
1594                            file_name, file_line, FRAG_MEMCAP);
1595 
1596                 gconfig->memcap = FRAG_MEMCAP;
1597             }
1598 
1599             /* ok ok, it's really 9.375%, sue me */
1600             gconfig->ten_percent = ((gconfig->memcap >> 5) + (gconfig->memcap >> 6));
1601         }
1602         else if(!strcasecmp(stoks[0], "prealloc_memcap"))
1603         {
1604             /* Use memcap to calculate prealloc_frag value */
1605             unsigned long memcap = FRAG_MEMCAP;
1606 
1607             if (s_toks != 2)
1608             {
1609                 FatalError("%s(%d) => Missing argument to prealloc_memcap in "
1610                            "config file.\n",
1611                            file_name, file_line);
1612             }
1613 
1614             memcap = value = strtoul(stoks[1], &endPtr, 10);
1615 
1616             if (!*stoks[1] || *stoks[1] == '-' || *endPtr)
1617             {
1618                 FatalError("%s(%d) => Invalid prealloc_memcap in config file. "
1619                            "Integer parameter required.\n", file_name,
1620                            file_line);
1621             }
1622 
1623             if(memcap <MIN_FRAG_MEMCAP)
1624             {
1625                 LogMessage("WARNING: %s(%d) => Ludicrous (<16k) prealloc_memcap "
1626                            "size, setting to default (%d bytes)\n",
1627                            file_name, file_line, FRAG_MEMCAP);
1628                 memcap = FRAG_MEMCAP;
1629             }
1630 
1631             gconfig->use_prealloc = 1;
1632             gconfig->memcap = memcap;
1633         }
1634         else if(!strcasecmp(stoks[0], "prealloc_frags"))
1635         {
1636             if (s_toks != 2)
1637             {
1638                 FatalError("%s(%d) => Missing argument to prealloc_frags "
1639                            "in config file.\n",
1640                            file_name, file_line);
1641             }
1642 
1643             gconfig->static_frags = value = strtoul(stoks[1], &endPtr, 10);
1644             gconfig->use_prealloc_frags = gconfig->use_prealloc = 1;
1645 
1646             if (!*stoks[1] || *stoks[1] == '-' || *endPtr || value > MAX_PREALLOC_FRAGS)
1647             {
1648                 FatalError("%s(%d) => Invalid prealloc_frags in config file. Entered value is not allowed. "
1649                         "Integer parameter (in the range of 0 to %d) required.\n", file_name,
1650                         file_line,MAX_PREALLOC_FRAGS);
1651             }
1652         }
1653         else if(!strcasecmp(stoks[0], "disabled"))
1654         {
1655             gconfig->disabled = 1;
1656         }
1657         else
1658         {
1659             FatalError("%s(%d) => Invalid Frag3 global option (%s)\n",
1660                        file_name, file_line, index);
1661         }
1662 
1663         mSplitFree(&stoks, s_toks);
1664     }
1665 
1666     mSplitFree(&toks, num_toks);
1667 }
1668 
1669 /**
1670  * Config parser for engine context config.
1671  *
1672  * @param args List of configuration parameters
1673  *
1674  * @return none
1675  */
Frag3ParseArgs(struct _SnortConfig * sc,char * args,Frag3Context * context)1676 static void Frag3ParseArgs(struct _SnortConfig *sc, char *args, Frag3Context *context)
1677 {
1678     char **toks;
1679     int num_toks;
1680     int i = 0;
1681 
1682     toks = mSplit(args, " ", 13, &num_toks, 0);
1683 
1684     while(i < num_toks)
1685     {
1686         int error = 0;
1687         int increment = 1;
1688         char *index = toks[i];
1689         char *arg = NULL;
1690         char *endptr;
1691         int32_t value = 0;
1692 
1693         /* In case an option takes an argument */
1694         if ((i + 1) < num_toks)
1695             arg = toks[i + 1];
1696 
1697         if(!strcasecmp(index, "timeout"))
1698         {
1699             if (arg == NULL)
1700             {
1701                 error = 1;
1702             }
1703             else
1704             {
1705                 value = SnortStrtol(arg, &endptr, 10);
1706                 if ((errno == ERANGE) || (*endptr != '\0') || (value < 0))
1707                     error = 1;
1708             }
1709 
1710             if (error)
1711             {
1712                 ParseError("Bad timeout in frag3 config.  Positive integer "
1713                         "parameter required.");
1714             }
1715 
1716             increment = 2;
1717             context->frag_timeout = (uint32_t)value;
1718         }
1719         else if(!strcasecmp(index, "min_ttl"))
1720         {
1721             if (arg == NULL)
1722             {
1723                 error = 1;
1724             }
1725             else
1726             {
1727                 value = SnortStrtol(arg, &endptr, 10);
1728                 if ((errno == ERANGE) || (*endptr != '\0')
1729                         || (value < 0) || (value > UINT8_MAX))
1730                 {
1731                     error = 1;
1732                 }
1733             }
1734 
1735             if (error)
1736             {
1737                 ParseError("Bad min_ttl in frag3 config.  Positive integer "
1738                         "less than 256 required.");
1739             }
1740 
1741             increment = 2;
1742             context->min_ttl = (uint8_t)value;
1743         }
1744         else if(!strcasecmp(index, "detect_anomalies"))
1745         {
1746             context->frag3_alerts |= FRAG3_DETECT_ANOMALIES;
1747         }
1748         else if(!strcasecmp(index, "policy"))
1749         {
1750             if (arg == NULL)
1751             {
1752                 ParseError("Frag3 policy requires a policy "
1753                         "identifier argument.");
1754             }
1755 
1756             increment = 2;
1757             context->frag_policy = FragPolicyIdFromName(arg);
1758 
1759             if ((context->frag_policy == FRAG_POLICY_DEFAULT) &&
1760                 (strcasecmp(arg, "bsd")))
1761             {
1762                 ParseError("Bad policy name \"%s\" in frag3 config.", arg);
1763             }
1764         }
1765         else if(!strcasecmp(index, "bind_to"))
1766         {
1767             if (arg == NULL)
1768             {
1769                 ParseError("Frag3 bind_to requires an IP list or "
1770                         "CIDR block argument.");
1771             }
1772 
1773             /* Fatals on bad ip address */
1774             context->bound_addrs = IpAddrSetParse(sc, arg);
1775             increment = 2;
1776         }
1777         else if(!strcasecmp(index, "min_fragment_length"))
1778         {
1779             if (arg == NULL)
1780             {
1781                 error = 1;
1782             }
1783             else
1784             {
1785                 value = SnortStrtol(arg, &endptr, 10);
1786                 if ((errno == ERANGE) || (*endptr != '\0') || (value < 0))
1787                     error = 1;
1788             }
1789 
1790             if (error)
1791             {
1792                 ParseError("Bad min_fragment_length in frag3 config.  Positive "
1793                         "integer parameter required.");
1794             }
1795 
1796             increment = 2;
1797             context->min_fragment_length = (uint32_t)value;
1798         }
1799         else if(!strcasecmp(index, "overlap_limit"))
1800         {
1801             if (arg == NULL)
1802             {
1803                 error = 1;
1804             }
1805             else
1806             {
1807                 value = SnortStrtol(arg, &endptr, 10);
1808                 if ((errno == ERANGE) || (*endptr != '\0') || (value < 0))
1809                     error = 1;
1810             }
1811 
1812             if (error)
1813             {
1814                 ParseError("Bad overlap_limit in frag3 config.  Positive "
1815                         "integer parameter required.");
1816             }
1817 
1818             increment = 2;
1819             context->overlap_limit = (uint32_t)value;
1820         }
1821         else
1822         {
1823             ParseError("Invalid Frag3 engine option (%s).", index);
1824         }
1825 
1826         i += increment;
1827     }
1828 
1829     mSplitFree(&toks, num_toks);
1830 }
1831 
1832 /**
1833  * Main runtime entry point for Frag3
1834  *
1835  * @param p Current packet to process.
1836  * @param context Context for this defrag engine
1837  *
1838  * @return none
1839  */
Frag3Defrag(Packet * p,void * context)1840 static void Frag3Defrag(Packet *p, void *context)
1841 {
1842     FRAGKEY fkey;            /* fragkey for this packet */
1843     FragTracker *ft;         /* FragTracker to process the packet on */
1844     Frag3Context *f3context = NULL; /* engine context */
1845     int engineIndex;
1846     int insert_return = 0;   /* return value from the insert function */
1847     tSfPolicyId policy_id = getNapRuntimePolicy();
1848     PROFILE_VARS;
1849 
1850     // preconditions - what we registered for
1851     assert(IPH_IS_VALID(p) && !(p->error_flags & PKT_ERR_CKSUM_IP));
1852 
1853     /* check to make sure this preprocessor should run */
1854     if ( !p->frag_flag )
1855         return;
1856 
1857     frag3_eval_config = (Frag3Config *)sfPolicyUserDataGet(frag3_config, policy_id);
1858 
1859     memset(&fkey, 0, sizeof(FRAGKEY));
1860     ft = Frag3GetTracker(p, &fkey);
1861     if (ft != NULL)
1862     {
1863         f3context = ft->context;
1864         frag3_eval_config = (Frag3Config *)sfPolicyUserDataGet(ft->config, ft->policy_id);
1865     }
1866 
1867     if (frag3_eval_config == NULL)
1868         return;
1869 
1870     if (ft == NULL)
1871     {
1872         /* Find an engine context for this packet */
1873         for (engineIndex = 0; engineIndex < frag3_eval_config->numFrag3Contexts; engineIndex++)
1874         {
1875             f3context = frag3_eval_config->frag3ContextList[engineIndex];
1876 
1877             if (f3context->bound_addrs == NULL)
1878                 continue;
1879 
1880             /* Does this engine context handle fragments to this IP address? */
1881             if(sfvar_ip_in(f3context->bound_addrs, GET_DST_ADDR(p)))
1882                 {
1883                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1884                                             "[FRAG3] Found engine context in IpAddrSet\n"););
1885                     break;
1886                 }
1887         }
1888 
1889         if (engineIndex == frag3_eval_config->numFrag3Contexts)
1890             f3context = frag3_eval_config->default_context;
1891 
1892         if (!f3context)
1893         {
1894             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1895                                     "[FRAG3] Could not find Frag3 engine context "
1896                                     "for IP %s\n", inet_ntoa(GET_SRC_ADDR(p))););
1897             return;
1898         }
1899     }
1900 
1901     /*
1902      * First case: if frag offset is 0 & UDP, let that packet go
1903      * through the rest of the system.  Ugly HACK to detect DNS
1904      * attack on 0 offset UDP.
1905      *
1906      * Second case: If frag offset is 0 & !more frags, this is a
1907      * full-frame "fragment", let the packet go through the rest
1908      * of the system.
1909      *
1910      * In other words:
1911      *   a = frag_offset != 0
1912      *   b = !UDP
1913      *   c = More Fragments
1914      *
1915      * if (a | (b & c))
1916      *    Disable Inspection since we'll look at the payload in
1917      *    a rebuilt packet later.  So don't process it further.
1918      */
1919     if ((p->frag_offset != 0) || ((GET_IPH_PROTO(p) != IPPROTO_UDP) && (p->mf)))
1920     {
1921         DisableDetect( p );
1922         otn_tmp = NULL;
1923     }
1924 
1925     /*
1926      * pkt's not going to make it to the target, bail
1927      */
1928     if(GET_IPH_TTL(p) < f3context->min_ttl)
1929     {
1930         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1931                 "[FRAG3] Fragment discarded due to low TTL "
1932                 "[0x%X->0x%X], TTL: %d  " "Offset: %d Length: %d\n",
1933                 ntohl(p->iph->ip_src.s_addr),
1934                 ntohl(p->iph->ip_dst.s_addr),
1935                 GET_IPH_TTL(p), p->frag_offset,
1936                 p->dsize););
1937 
1938         EventAnomScMinTTL(f3context);
1939         f3stats.discards++;
1940         return;
1941     }
1942 
1943     f3stats.total++;
1944     UpdateIPFragStats(&sfBase, p->pkth->caplen);
1945 
1946     PREPROC_PROFILE_START(frag3PerfStats);
1947 
1948     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1949                 "\n++++++++++++++++++++++++++++++++++++++++++++++\n"););
1950     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1951                 "[**] [FRAG3] Inspecting fragment...\n"););
1952     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1953                 "[FRAG3] Got frag packet (mem use: %ld frag "
1954                 "trackers: %d  p->pkt_flags: 0x%X "
1955                 "prealloc nodes in use: %lu/%lu)\n",
1956                 frag3_mem_in_use,
1957                 sfxhash_count(f_cache),
1958                 p->packet_flags, prealloc_nodes_in_use,
1959                 frag3_eval_config->static_frags););
1960 
1961     pkttime = (struct timeval *) &p->pkth->ts;
1962 
1963     /*
1964      * try to get the tracker that this frag should go with
1965      */
1966     if (ft == NULL)
1967     {
1968         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Adding New FragTracker...\n"););
1969 
1970         /*
1971          * first frag for this packet, start a new tracker
1972          */
1973         Frag3NewTracker(p, &fkey, f3context);
1974 
1975         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
1976                     "[FRAG3] mem use: %ld frag "
1977                     "trackers: %d  prealloc "
1978                     "nodes in use: %lu/%lu\n",
1979                     frag3_mem_in_use,
1980                     sfxhash_count(f_cache),
1981                     prealloc_nodes_in_use,
1982                     frag3_eval_config->static_frags););
1983         /*
1984          * all done, return control to Snort
1985          */
1986         PREPROC_PROFILE_END(frag3PerfStats);
1987         return;
1988     }
1989     else if (Frag3Expire(p, ft, f3context) == FRAG_TRACKER_TIMEOUT)
1990     {
1991         /* Time'd out FragTrackers are just purged of their packets.
1992          * Reset the timestamp per this packet.
1993          * And reset the rest of the tracker as if this is the
1994          * first packet on the tracker, and continue. */
1995 
1996         /* This fixes an issue raised on bugtraq relating to
1997          * timeout frags not getting purged correctly when
1998          * the entire set of frags show up later. */
1999 
2000         ft->ttl = GET_IPH_TTL(p); /* store the first ttl we got */
2001         ft->calculated_size = 0;
2002         ft->alerted = 0;
2003         ft->frag_flags = 0;
2004         ft->frag_bytes = 0;
2005         ft->frag_pkts = 0;
2006         ft->alert_count = 0;
2007         ft->ip_options_len = 0;
2008         ft->ip_option_count = 0;
2009         ft->ip_options_data = NULL;
2010         ft->copied_ip_options_len = 0;
2011         ft->copied_ip_option_count = 0;
2012         ft->context = f3context;
2013         ft->ordinal = 0;
2014     }
2015 
2016     // Update frag time when we get a frag associated with this tracker
2017     ft->frag_time.tv_sec = p->pkth->ts.tv_sec;
2018     ft->frag_time.tv_usec = p->pkth->ts.tv_usec;
2019 
2020     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Found frag tracker\n"););
2021 
2022     //dont forward fragments to target if some previous fragment was dropped
2023     if ( ft->frag_flags & FRAG_DROP_FRAGMENTS )
2024     {
2025         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2026                     "Blocking fragments due to earlier fragment drop\n"););
2027         DisableDetect( p );
2028         Active_DAQDropPacket( p );
2029         if (pkt_trace_enabled)
2030         {
2031             addPktTraceData(VERDICT_REASON_DEFRAG, snprintf(trace_line, MAX_TRACE_LINE,
2032                 "Defragmentation: earlier fragment was already blocked, %s\n", getPktTraceActMsg()));
2033         }
2034         else addPktTraceData(VERDICT_REASON_DEFRAG, 0);
2035         f3stats.drops++;
2036     }
2037 
2038     /*
2039      * insert the fragment into the FragTracker
2040      */
2041     if((insert_return = Frag3Insert(p, ft, &fkey, f3context)) != FRAG_INSERT_OK)
2042     {
2043         /*
2044          * we can pad this switch out for a variety of entertaining behaviors
2045          * later if we're so inclined
2046          */
2047         switch(insert_return)
2048         {
2049             case FRAG_INSERT_FAILED:
2050 #ifdef DEBUG
2051                 LogMessage("WARNING: Insert into Fraglist failed, "
2052                            "(offset: %u).\n", p->frag_offset);
2053 #endif
2054                 PREPROC_PROFILE_END(frag3PerfStats);
2055                 return;
2056             case FRAG_INSERT_TTL:
2057                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2058                         "[FRAG3] Fragment discarded due to large TTL Delta "
2059                         "[0x%X->0x%X], TTL: %d  orig TTL: %d "
2060                         "Offset: %d Length: %d\n",
2061                         ntohl(p->iph->ip_src.s_addr),
2062                         ntohl(p->iph->ip_dst.s_addr),
2063                         GET_IPH_TTL(p), ft->ttl, p->frag_offset,
2064                         p->dsize););
2065                 f3stats.discards++;
2066                 PREPROC_PROFILE_END(frag3PerfStats);
2067                 return;
2068             case FRAG_INSERT_ATTACK:
2069             case FRAG_INSERT_ANOMALY:
2070                 f3stats.discards++;
2071                 PREPROC_PROFILE_END(frag3PerfStats);
2072                 return;
2073             case FRAG_INSERT_TIMEOUT:
2074 #ifdef DEBUG
2075                 LogMessage("WARNING: Insert into Fraglist failed due to timeout, "
2076                            "(offset: %u).\n", p->frag_offset);
2077 #endif
2078                 PREPROC_PROFILE_END(frag3PerfStats);
2079                 return;
2080             case FRAG_INSERT_OVERLAP_LIMIT:
2081 #ifdef DEBUG
2082                 LogMessage("WARNING: Excessive IP fragment overlap, "
2083                            "(More: %u, offset: %u, offsetSize: %u).\n",
2084                            p->mf, (p->frag_offset<<3), p->ip_frag_len);
2085 #endif
2086                 f3stats.discards++;
2087                 PREPROC_PROFILE_END(frag3PerfStats);
2088                 return;
2089             default:
2090                 break;
2091         }
2092     }
2093 
2094     p->fragtracker = (void *)ft;
2095 
2096     /*
2097      * check to see if it's reassembly time
2098      */
2099     if(Frag3IsComplete(ft))
2100     {
2101         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2102                     "[*] Fragment is complete, rebuilding!\n"););
2103 
2104         /*
2105          * if the frag completes but it's bad we're just going to drop it
2106          * instead of wasting time on putting it back together
2107          */
2108         if(!(ft->frag_flags & FRAG_BAD))
2109         {
2110             Frag3Rebuild(ft, p);
2111 
2112             if (p->frag_offset != 0 ||
2113                 (GET_IPH_PROTO(p) != IPPROTO_UDP && ft->frag_flags & FRAG_REBUILT))
2114             {
2115                 /* Need to reset some things here because the
2116                  * rebuilt packet will have reset the do_detect
2117                  * flag when it hits Preprocess.
2118                  */
2119                 do_detect_content = do_detect = 0;
2120                 otn_tmp = NULL;
2121             }
2122         }
2123 
2124         if (Active_PacketWasDropped())
2125         {
2126             Frag3DeleteTracker(ft);
2127             ft->frag_flags |= FRAG_DROP_FRAGMENTS;
2128         }
2129         else
2130         {
2131             Frag3RemoveTracker(&fkey, ft);
2132             p->fragtracker = NULL;
2133 
2134             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2135                         "[FRAG3] Dumped fragtracker (mem use: %ld frag "
2136                         "trackers: %d  prealloc nodes in use: %lu/%lu)\n",
2137                         frag3_mem_in_use, sfxhash_count(f_cache),
2138                         prealloc_nodes_in_use, frag3_eval_config->static_frags););
2139         }
2140     }
2141 
2142     PREPROC_PROFILE_END(frag3PerfStats);
2143     return;
2144 }
2145 
2146 /**
2147  * Check to see if a FragTracker has timed out
2148  *
2149  * @param current_time Time at this moment
2150  * @param start_time Time to compare current_time to
2151  * @param f3context Engine context
2152  *
2153  * @return status
2154  * @retval  FRAG_TIMEOUT Current time diff is greater than the current
2155  *                       context's timeout value
2156  * @retval  FRAG_TIME_OK Current time diff is within the context's prune
2157  *                       window
2158  */
CheckTimeout(struct timeval * current_time,struct timeval * start_time,Frag3Context * f3context)2159 static inline int CheckTimeout(struct timeval *current_time,
2160         struct timeval *start_time,
2161         Frag3Context *f3context)
2162 {
2163     struct timeval tv_diff; /* storage struct for the difference between
2164                                current_time and start_time */
2165 
2166     TIMERSUB(current_time, start_time, &tv_diff);
2167     if(tv_diff.tv_sec >= (int)f3context->frag_timeout)
2168     {
2169         return FRAG_TIMEOUT;
2170     }
2171 
2172     return FRAG_TIME_OK;
2173 }
2174 
2175 /**
2176  * Time-related expiration of fragments from the system.  Checks the current
2177  * FragTracker for timeout, then walks up the LRU list looking to see if
2178  * anyone should have timed out.
2179  *
2180  * @param p Current packet (contains pointer to the current timestamp)
2181  * @param ft FragTracker to check for a timeout
2182  * @param fkey FragKey of the current FragTracker for sfxhash lookup
2183  * @param f3context Context of the defrag engine, contains the timeout value
2184  *
2185  * @return status
2186  * @retval FRAG_TRACKER_TIMEOUT The current FragTracker has timed out
2187  * @retval FRAG_OK The current FragTracker has not timed out
2188  */
Frag3Expire(Packet * p,FragTracker * ft,Frag3Context * f3context)2189 static inline int Frag3Expire(Packet *p, FragTracker *ft, Frag3Context *f3context)
2190 {
2191     /*
2192      * Check the FragTracker that was passed in first
2193      */
2194     if(CheckTimeout(
2195                 pkttime,
2196                 &(ft)->frag_time,
2197                 f3context) == FRAG_TIMEOUT)
2198     {
2199         /*
2200          * Oops, we've timed out, whack the FragTracker
2201          */
2202 #if defined(DEBUG_FRAG3) && defined(DEBUG)
2203         if (DEBUG_FRAG & GetDebugLevel())
2204         {
2205             char *src_str = SnortStrdup(FragIPToStr(ft->sip, ft->ipver));
2206             LogMessage("(spp_frag3) Current Fragment dropped due to timeout! "
2207                 "[%s->%s ID: %d]\n", src_str, FragIPToStr(ft->dip, ft->ipver), ft->id);
2208             free(src_str);
2209         }
2210 #endif
2211 
2212         /*
2213          * Don't remove the tracker.
2214          * Remove all of the packets that are stored therein.
2215          *
2216          * If the existing tracker times out because of a delay
2217          * relative to the timeout
2218          */
2219         //Frag3RemoveTracker(fkey, ft);
2220         Frag3DeleteTracker(ft);
2221 
2222         f3stats.timeouts++;
2223         sfBase.iFragTimeouts++;
2224 
2225         return FRAG_TRACKER_TIMEOUT;
2226     }
2227 
2228     return FRAG_OK;
2229 }
2230 
2231 /**
2232  * Check to see if we've got the first or last fragment on a FragTracker and
2233  * set the appropriate frag_flags
2234  *
2235  * @param p Packet to get the info from
2236  * @param ft FragTracker to set the flags on
2237  *
2238  * @return none
2239  */
Frag3CheckFirstLast(Packet * p,FragTracker * ft)2240 static inline int Frag3CheckFirstLast(Packet *p, FragTracker *ft)
2241 {
2242     uint16_t fragLength;
2243     int retVal = FRAG_FIRSTLAST_OK;
2244     uint16_t endOfThisFrag;
2245 
2246     /* set the frag flag if this is the first fragment */
2247     if(p->mf && p->frag_offset == 0)
2248     {
2249         ft->frag_flags |= FRAG_GOT_FIRST;
2250 
2251         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got first frag\n"););
2252     }
2253     else if((!p->mf) && (p->frag_offset > 0)) /* set for last frag too */
2254     {
2255         /* Use the actual length here, because packet may have been
2256         * truncated.  Don't want to try to copy more than we actually
2257         * captured. */
2258         //fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4;
2259         fragLength = p->ip_frag_len;
2260         endOfThisFrag = (p->frag_offset << 3) + fragLength;
2261 
2262         if (ft->frag_flags & FRAG_GOT_LAST)
2263         {
2264             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got last frag again!\n"););
2265             switch (ft->frag_policy)
2266             {
2267                 case FRAG_POLICY_BSD:
2268                 case FRAG_POLICY_LINUX:
2269                 case FRAG_POLICY_BSD_RIGHT:
2270                 case FRAG_POLICY_LAST:
2271                 case FRAG_POLICY_WINDOWS:
2272                 case FRAG_POLICY_FIRST:
2273                     if (ft->calculated_size > endOfThisFrag)
2274                     {
2275                        /* Already have a 'last frag' with a higher
2276                         * end point.  Leave it as is.
2277                         *
2278                         * Some OS's do not respond at all -- we'll
2279                         * still try to rebuild anyway in that case,
2280                         * because there is really something wrong
2281                         * and we should look at it.
2282                         */
2283                         retVal = FRAG_LAST_DUPLICATE;
2284                     }
2285                     break;
2286                 case FRAG_POLICY_SOLARIS:
2287                     if (ft->calculated_size > endOfThisFrag)
2288                     {
2289                        /* Already have a 'last frag' with a higher
2290                         * end point.  Leave it as is.
2291                         *
2292                         * Some OS's do not respond at all -- we'll
2293                         * still try to rebuild anyway in that case,
2294                         * because there is really something wrong
2295                         * and we should look at it.
2296                         */
2297                         retVal = FRAG_LAST_DUPLICATE;
2298                     }
2299                     else
2300                     {
2301                         /* Solaris does some weird stuff here... */
2302                         /* Usually, Solaris takes the higher end point.
2303                          * But in one strange case (when it hasn't seen
2304                          * any frags beyond the existing last frag), it
2305                          * actually appends that new last frag to the
2306                          * end of the previous last frag, regardless of
2307                          * the offset.  Effectively, it adjusts the
2308                          * offset of the new last frag to immediately
2309                          * after the existing last frag.
2310                          */
2311                         /* XXX: how to handle that case? punt?  */
2312                         retVal = FRAG_LAST_OFFSET_ADJUST;
2313                     }
2314                     break;
2315             }
2316         }
2317 
2318         ft->frag_flags |= FRAG_GOT_LAST;
2319 
2320         /*
2321          * If this is the last frag (and we don't have a frag that already
2322          * extends beyond this one), set the size that we're expecting.
2323          */
2324         if ((ft->calculated_size < endOfThisFrag) &&
2325             (retVal != FRAG_LAST_OFFSET_ADJUST))
2326         {
2327             ft->calculated_size = endOfThisFrag;
2328 
2329             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got last frag, Bytes: %d, "
2330                     "Calculated size: %d\n",
2331                     ft->frag_bytes,
2332                     ft->calculated_size););
2333         }
2334     }
2335 
2336     if (p->frag_offset != 0)
2337     {
2338         ft->frag_flags |= FRAG_NO_BSD_VULN;
2339     }
2340 
2341     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Frag Status: %s:%s\n",
2342                 ft->frag_flags&FRAG_GOT_FIRST?"FIRST":"No FIRST",
2343                 ft->frag_flags&FRAG_GOT_LAST?"LAST":"No LAST"););
2344     return retVal;
2345 }
2346 
2347 /**
2348  * Lookup a FragTracker in the f_cache sfxhash table based on an input key
2349  *
2350  * @param p The current packet to get the key info from
2351  * @param fkey Pointer to a container for the FragKey
2352  *
2353  * @return Pointer to the FragTracker in the hash bucket or NULL if there is
2354  *         no fragment in the hash bucket
2355  */
Frag3GetTracker(Packet * p,FRAGKEY * fkey)2356 static FragTracker *Frag3GetTracker(Packet *p, FRAGKEY *fkey)
2357 {
2358     FragTracker *returned; /* FragTracker ptr returned by the lookup */
2359 
2360     /*
2361      * we have to setup the key first, downstream functions depend on
2362      * it being setup here
2363      */
2364     if (IS_IP4(p))
2365     {
2366         COPY4(fkey->sip, sfaddr_get_ip6_ptr(&p->ip4h->ip_addrs->ip_src));
2367         COPY4(fkey->dip, sfaddr_get_ip6_ptr(&p->ip4h->ip_addrs->ip_dst));
2368         fkey->id = GET_IPH_ID(p);
2369         fkey->ipver = 4;
2370         fkey->proto = GET_IPH_PROTO(p);
2371     }
2372     else
2373     {
2374         IP6Frag *fragHdr;
2375         COPY4(fkey->sip, sfaddr_get_ip6_ptr(&p->ip6h->ip_addrs->ip_src));
2376         COPY4(fkey->dip, sfaddr_get_ip6_ptr(&p->ip6h->ip_addrs->ip_dst));
2377         fkey->ipver = 6;
2378         /* Data points to the offset, and does not include the next hdr
2379          * and reserved.  Offset it by -2 to get there */
2380         fragHdr = (IP6Frag *)p->ip6_extensions[p->ip6_frag_index].data;
2381         /* Can't rely on the next header.  Only the 0 offset packet
2382          * is required to have it in the frag header */
2383         //fkey->proto = fragHdr->ip6f_nxt;
2384         fkey->proto = 0;
2385         fkey->id = fragHdr->ip6f_ident;
2386     }
2387     if (p->vh && !ScVlanAgnostic())
2388         fkey->vlan_tag = (uint16_t)VTH_VLAN(p->vh);
2389     else
2390         fkey->vlan_tag = 0;
2391 
2392 #ifdef MPLS
2393     if(ScMplsOverlappingIp() && p->mpls)
2394         fkey->mlabel = p->mplsHdr.label;
2395     else
2396         fkey->mlabel = 0;
2397 #endif
2398 
2399 #ifdef HAVE_DAQ_ADDRESS_SPACE_ID
2400 #if !defined(SFLINUX) && defined(DAQ_CAPA_VRF)
2401     fkey->address_space_id_dst = DAQ_GetDestinationAddressSpaceID(p->pkth);
2402     fkey->address_space_id_src = DAQ_GetSourceAddressSpaceID(p->pkth);
2403 #else
2404     if (!ScAddressSpaceAgnostic())
2405         fkey->addressSpaceId = DAQ_GetAddressSpaceID(p->pkth);
2406     else
2407         fkey->addressSpaceId = 0;
2408 #endif
2409 #endif
2410 #if !defined(SFLINUX) && defined(DAQ_CAPA_CARRIER_ID)
2411     fkey->carrierId = GET_OUTER_IPH_PROTOID(p, pkth);
2412 #endif
2413 
2414     /*
2415      * if the hash table is empty we're done
2416      */
2417     if(sfxhash_count(f_cache) == 0)
2418         return NULL;
2419 
2420     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2421                 "[*] Looking up FragTracker using key:\n"););
2422 
2423 #ifdef DEBUG_FRAG3
2424     PrintFragKey(fkey);
2425 #endif
2426 
2427     returned = (FragTracker *) sfxhash_find(f_cache, fkey);
2428 
2429     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2430                 "Frag3GetTracker returning %p for\n", returned););
2431 
2432     return returned;
2433 }
2434 
2435 /**
2436  * Handle IP Options in fragmented packets.
2437  *
2438  * @param ft Current frag tracker for this packet
2439  * @param p Current packet to check for options
2440  * @param context In case we get an anomaly
2441  *
2442  * @return status
2443  * @retval 0 on an error
2444  * @retval 1 on success
2445  */
Frag3HandleIPOptions(FragTracker * ft,Packet * p)2446 static int Frag3HandleIPOptions(FragTracker *ft,
2447                                 Packet *p)
2448 {
2449     unsigned int i = 0;          /* counter */
2450     if(p->frag_offset == 0)
2451     {
2452         /*
2453          * This is the first packet.  If it has IP options,
2454          * save them off, so we can set them on the reassembled packet.
2455          */
2456         if (p->ip_options_len)
2457         {
2458             if (ft->ip_options_data)
2459             {
2460                 /* Already seen 0 offset packet and copied some IP options */
2461                 if ((ft->frag_flags & FRAG_GOT_FIRST)
2462                         && (ft->ip_option_count != p->ip_option_count))
2463                 {
2464                     EventAnomIpOpts(ft->context);
2465                 }
2466             }
2467             else
2468             {
2469                 /* Allocate and copy in the options */
2470                 ft->ip_options_data = SnortPreprocAlloc(1, p->ip_options_len, PP_FRAG3,
2471                                                          PP_MEM_CATEGORY_SESSION);
2472                 memcpy(ft->ip_options_data, p->ip_options_data, p->ip_options_len);
2473                 ft->ip_options_len = p->ip_options_len;
2474                 ft->ip_option_count = p->ip_option_count;
2475             }
2476         }
2477     }
2478     else
2479     {
2480         /* check that options match those from other non-offset 0 packets */
2481 
2482         /* XXX: could check each individual option here, but that
2483          * would be performance ugly.  So, we'll just check that the
2484          * option counts match.  Alert if invalid, but still include in
2485          * reassembly.
2486          */
2487         if (ft->copied_ip_option_count)
2488         {
2489             if (ft->copied_ip_option_count != p->ip_option_count)
2490             {
2491                 EventAnomIpOpts(ft->context);
2492             }
2493         }
2494         else
2495         {
2496             ft->copied_ip_option_count = p->ip_option_count;
2497             for (i = 0;i< p->ip_option_count && i < IP_OPTMAX; i++)
2498             {
2499                 /* Is the high bit set?  If not, weird anomaly. */
2500                 if (!(p->ip_options[i].code & 0x80))
2501                     EventAnomIpOpts(ft->context);
2502             }
2503         }
2504     }
2505     return 1;
2506 }
2507 
FragGetPolicy(Packet * p,Frag3Context * f3context)2508 int FragGetPolicy(Packet *p, Frag3Context *f3context)
2509 {
2510 #ifdef TARGET_BASED
2511     int frag_policy;
2512     /* Not caching this host_entry in the frag tracker so we can
2513      * swap the table out after processing this packet if we need
2514      * to.  */
2515     HostAttributeEntry *host_entry;
2516 
2517     if (!IsAdaptiveConfigured())
2518         return f3context->frag_policy;
2519 
2520     host_entry = SFAT_LookupHostEntryByDst(p);
2521 
2522     if (host_entry && (isFragPolicySet(host_entry) == POLICY_SET))
2523     {
2524         frag_policy = getFragPolicy(host_entry);
2525 
2526         if (frag_policy != SFAT_UNKNOWN_FRAG_POLICY)
2527         {
2528             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2529                 "FragGetPolicy: Policy Map Entry: %d(%s)\n",
2530                 frag_policy, frag_policy_names[frag_policy]););
2531 
2532             return frag_policy;
2533         }
2534     }
2535 #endif
2536 
2537     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2538         "FragGetPolicy: Using configured default %d(%s)\n",
2539         f3context->frag_policy, frag_policy_names[f3context->frag_policy]););
2540 
2541     return f3context->frag_policy;
2542 }
2543 
2544 /**
2545  * Didn't find a FragTracker in the hash table, create a new one and put it
2546  * into the f_cache
2547  *
2548  * @param p Current packet to fill in FragTracker fields
2549  * @param fkey FragKey struct to use for table insertion
2550  *
2551  * @return status
2552  * @retval 0 on an error
2553  * @retval 1 on success
2554  */
Frag3NewTracker(Packet * p,FRAGKEY * fkey,Frag3Context * f3context)2555 static int Frag3NewTracker(Packet *p, FRAGKEY *fkey, Frag3Context *f3context)
2556 {
2557     FragTracker *tmp;
2558     Frag3Frag *f = NULL;
2559     //int ret = 0;
2560     const uint8_t *fragStart;
2561     uint16_t fragLength;
2562     uint16_t frag_end;
2563     SFXHASH_NODE *hnode;
2564     tSfPolicyId policy_id = getNapRuntimePolicy();
2565 
2566     fragStart = p->ip_frag_start;
2567     //fragStart = (uint8_t *)p->iph + GET_IPH_HLEN(p) * 4;
2568     /* Use the actual length here, because packet may have been
2569      * truncated.  Don't want to try to copy more than we actually
2570      * captured. */
2571     //fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4;
2572     fragLength = p->ip_frag_len;
2573 #ifdef DEBUG_MSGS
2574     if (p->actual_ip_len != ntohs(GET_IPH_LEN(p)))
2575     {
2576         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2577             "IP Actual Length (%d) != specified length (%d), "
2578             "truncated packet (%d)?\n",
2579             p->actual_ip_len, ntohs(GET_IPH_LEN(p)), pkt_snaplen););
2580     }
2581 #endif
2582 
2583     /* Just to double check */
2584     if (fragLength > pkt_snaplen)
2585     {
2586         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2587             "Overly large fragment %d 0x%x 0x%x %d\n",
2588             fragLength, GET_IPH_LEN(p), GET_IPH_OFF(p),
2589             p->frag_offset << 3););
2590 
2591         /* Ah, crap.  Return that tracker. */
2592         return 0;
2593     }
2594 
2595     // Try to get a new one
2596     if (!(hnode = sfxhash_get_node(f_cache, fkey)) || !hnode->data)
2597     {
2598         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2599                     "Frag3NewTracker: sfxhash_get_node() failed\n"););
2600         return 0;
2601     }
2602 
2603     tmp = (FragTracker *)hnode->data;
2604     memset(tmp, 0, sizeof(FragTracker));
2605 
2606     /*
2607      * setup the frag tracker
2608      */
2609     COPY4(tmp->sip,fkey->sip);
2610     COPY4(tmp->dip,fkey->dip);
2611     tmp->id = fkey->id;
2612     if (IS_IP4(p))
2613     {
2614         tmp->protocol = fkey->proto;
2615         tmp->ipver = 4;
2616     }
2617     else /* IPv6 */
2618     {
2619         if (p->frag_offset == 0)
2620         {
2621             IP6Frag *fragHdr = (IP6Frag *)p->ip6_extensions[p->ip6_frag_index].data;
2622             tmp->protocol = fragHdr->ip6f_nxt;
2623         }
2624         tmp->ipver = 6;
2625     }
2626     tmp->ttl = GET_IPH_TTL(p); /* store the first ttl we got */
2627     tmp->calculated_size = 0;
2628     tmp->alerted = 0;
2629     tmp->frag_flags = 0;
2630     tmp->frag_bytes = 0;
2631     tmp->frag_pkts = 0;
2632     tmp->frag_time.tv_sec = p->pkth->ts.tv_sec;
2633     tmp->frag_time.tv_usec = p->pkth->ts.tv_usec;
2634     tmp->alert_count = 0;
2635     tmp->ip_options_len = 0;
2636     tmp->ip_option_count = 0;
2637     tmp->ip_options_data = NULL;
2638     tmp->copied_ip_options_len = 0;
2639     tmp->copied_ip_option_count = 0;
2640     tmp->ordinal = 0;
2641     tmp->frag_policy = FragGetPolicy(p, f3context);
2642     tmp->context = f3context;
2643 
2644     tmp->policy_id = policy_id;
2645     tmp->config = frag3_config;
2646     ((Frag3Config *)sfPolicyUserDataGet(tmp->config, tmp->policy_id))->ref_count++;
2647 
2648     /*
2649      * get our first fragment storage struct
2650      */
2651     if(!frag3_eval_config->use_prealloc)
2652     {
2653         if(frag3_mem_in_use > frag3_eval_config->memcap)
2654         {
2655             if (Frag3Prune(tmp) == 0)
2656             {
2657                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2658                     "Frag3NewTracker: Pruning failed\n"););
2659 
2660                 return 0;
2661             }
2662         }
2663 
2664         f = (Frag3Frag *) SnortPreprocAlloc(1, sizeof(Frag3Frag), PP_FRAG3,
2665                                  PP_MEM_CATEGORY_SESSION);
2666         frag3_mem_in_use += sizeof(Frag3Frag);
2667 
2668         f->fptr = (uint8_t *) SnortPreprocAlloc(1, fragLength, PP_FRAG3,
2669                                  PP_MEM_CATEGORY_SESSION);
2670         frag3_mem_in_use += fragLength;
2671 
2672         sfBase.frag3_mem_in_use = frag3_mem_in_use;
2673     }
2674     else
2675     {
2676         while((f = Frag3PreallocPop()) == NULL)
2677         {
2678             if (Frag3Prune(tmp) == 0)
2679             {
2680                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2681                     "Frag3NewTracker: Pruning failed\n"););
2682 
2683                 return 0;
2684             }
2685         }
2686     }
2687 
2688     f3stats.fragnodes_created++;
2689     sfBase.iFragCreates++;
2690     sfBase.iCurrentFrags++;
2691     if (sfBase.iCurrentFrags > sfBase.iMaxFrags)
2692         sfBase.iMaxFrags = sfBase.iCurrentFrags;
2693 
2694     /* initialize the fragment list */
2695     tmp->fraglist = NULL;
2696 
2697     /*
2698      * setup the Frag3Frag struct with the current packet's data
2699      */
2700     memcpy(f->fptr, fragStart, fragLength);
2701 
2702     f->size = f->flen = fragLength;
2703     f->offset = p->frag_offset << 3;
2704     frag_end = f->offset + fragLength;
2705     f->ord = tmp->ordinal++;
2706     f->data = f->fptr;     /* ptr to adjusted start position */
2707     if (!p->mf)
2708     {
2709         f->last = 1;
2710     }
2711     else
2712     {
2713         /*
2714          * all non-last frags are supposed to end on 8-byte boundries
2715          */
2716         if(frag_end & 7)
2717         {
2718             /*
2719              * bonk/boink/jolt/etc attack...
2720              */
2721             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2722                         "[..] Short frag (Bonk, etc) attack!\n"););
2723 
2724             EventAnomShortFrag(f3context);
2725 
2726             /* don't return, might still be interesting... */
2727         }
2728 
2729         /* can't have non-full fragments... */
2730         frag_end &= ~7;
2731 
2732         /* Adjust len to take into account the jolting/non-full fragment. */
2733         f->size = frag_end - f->offset;
2734     }
2735 
2736     /* insert the fragment into the frag list */
2737     tmp->fraglist = f;
2738     tmp->fraglist_tail = f;
2739     tmp->fraglist_count = 1;  /* XXX: Are these duplciates? */
2740     tmp->frag_pkts = 1;
2741 
2742     /*
2743      * mark the FragTracker if this is the first/last frag
2744      */
2745     Frag3CheckFirstLast(p, tmp);
2746 
2747     tmp->frag_bytes += fragLength;
2748 
2749     Frag3HandleIPOptions(tmp, p);
2750 
2751     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2752                 "[#] accumulated bytes on FragTracker: %d\n",
2753                 tmp->frag_bytes););
2754 
2755     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2756                 "Initial fragment for tracker, ptr %p, offset %d, "
2757                 "size %d\n", f, f->offset, f->size););
2758 
2759 #ifdef DEBUG_FRAG3
2760     PrintFragKey(fkey);
2761 #endif
2762 
2763     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2764                 "Calling sfxhash(add), overhead at %lu\n",
2765                 f_cache->overhead_bytes););
2766 
2767     f3stats.fragtrackers_created++;
2768     pc.frag_trackers++;
2769 
2770     p->fragtracker = (void *)tmp;
2771 
2772     return 1;
2773 }
2774 
2775 /**
2776  * Handle the creation of the new frag node and list insertion.
2777  * Separating this from actually calculating the values.
2778  *
2779  * @param ft FragTracker to hold the packet
2780  * @param fragStart Pointer to start of the packet data
2781  * @param fragLength Length of packet data
2782  * @param len Length of this fragment
2783  * @param slide Adjustment to make to left side of data (for left overlaps)
2784  * @param trunc Adjustment to maek to right side of data (for right overlaps)
2785  * @param frag_offset Offset for this fragment
2786  * @prarm left FragNode prior to this one
2787  * @param retFrag this one after its inserted (returned)
2788  *
2789  * @return status
2790  * @retval FRAG_INSERT_FAILED Memory problem, insertion failed
2791  * @retval FRAG_INSERT_OK All okay
2792  */
AddFragNode(FragTracker * ft,Packet * p,Frag3Context * f3context,const uint8_t * fragStart,int16_t fragLength,char lastfrag,int16_t len,uint16_t slide,uint16_t trunc,uint16_t frag_offset,Frag3Frag * left,Frag3Frag ** retFrag)2793 static int AddFragNode(FragTracker *ft,
2794                 Packet *p,
2795                 Frag3Context *f3context,
2796                 const uint8_t *fragStart,
2797                 int16_t fragLength,
2798                 char lastfrag,
2799                 int16_t len,
2800                 uint16_t slide,
2801                 uint16_t trunc,
2802                 uint16_t frag_offset,
2803                 Frag3Frag *left,
2804                 Frag3Frag **retFrag)
2805 {
2806     Frag3Frag *newfrag = NULL;  /* new frag container */
2807     int16_t newSize = len - slide - trunc;
2808 
2809     if (newSize <= 0)
2810     {
2811         /*
2812          * zero size frag
2813          */
2814         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2815             "zero size frag after left & right trimming "
2816             "(len: %d  slide: %d  trunc: %d)\n",
2817             len, slide, trunc););
2818 
2819         f3stats.discards++;
2820 
2821 #ifdef DEBUG_MSGS
2822         newfrag = ft->fraglist;
2823         while (newfrag)
2824         {
2825             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2826                    "Size: %d, offset: %d, len %d, "
2827                    "Prev: 0x%x, Next: 0x%x, This: 0x%x, Ord: %d, %s\n",
2828                    newfrag->size, newfrag->offset,
2829                    newfrag->flen, newfrag->prev,
2830                    newfrag->next, newfrag, newfrag->ord,
2831                    newfrag->last ? "Last":""););
2832             newfrag = newfrag->next;
2833         }
2834 #endif
2835 
2836         return FRAG_INSERT_ANOMALY;
2837     }
2838 
2839     /*
2840      * grab/generate a new frag node
2841      */
2842     if(!frag3_eval_config->use_prealloc)
2843     {
2844         if(frag3_mem_in_use > frag3_eval_config->memcap)
2845         {
2846             if (Frag3Prune(ft) == 0)
2847             {
2848                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2849                     "Frag3Insert: Pruning failed\n"););
2850 
2851                 return FRAG_INSERT_FAILED;
2852             }
2853         }
2854 
2855         /*
2856          * build a frag struct to track this particular fragment
2857          */
2858         newfrag = (Frag3Frag *) SnortPreprocAlloc(1, sizeof(Frag3Frag),
2859                                      PP_FRAG3, PP_MEM_CATEGORY_SESSION);
2860         frag3_mem_in_use += sizeof(Frag3Frag);
2861 
2862         /*
2863          * allocate some space to hold the actual data
2864          */
2865         newfrag->fptr = (uint8_t*)SnortPreprocAlloc(1, fragLength, PP_FRAG3,
2866                                                 PP_MEM_CATEGORY_SESSION);
2867         frag3_mem_in_use += fragLength;
2868 
2869         sfBase.frag3_mem_in_use = frag3_mem_in_use;
2870     }
2871     else
2872     {
2873         /*
2874          * fragments are preallocated, grab one from the list
2875          */
2876         while((newfrag = Frag3PreallocPop()) == NULL)
2877         {
2878             if (Frag3Prune(ft) == 0)
2879             {
2880                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2881                     "Frag3Insert: Pruning failed\n"););
2882 
2883                 return FRAG_INSERT_FAILED;
2884             }
2885         }
2886 
2887         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2888                     "got newfrag (%p) from prealloc\n", newfrag););
2889     }
2890 
2891     f3stats.fragnodes_created++;
2892 
2893     newfrag->flen = fragLength;
2894     memcpy(newfrag->fptr, fragStart, fragLength);
2895     newfrag->ord = ft->ordinal++;
2896 
2897     /*
2898      * twiddle the frag values for overlaps
2899      */
2900     newfrag->data = newfrag->fptr + slide;
2901     newfrag->size = newSize;
2902     newfrag->offset = frag_offset;
2903     newfrag->last = lastfrag;
2904 
2905     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2906                 "[+] Adding new frag, offset %d, size %d\n"
2907                 "   nf->data = nf->fptr(%p) + slide (%d)\n"
2908                 "   nf->size = len(%d) - slide(%d) - trunc(%d)\n",
2909                 newfrag->offset, newfrag->size, newfrag->fptr,
2910                 slide, fragLength, slide, trunc););
2911 
2912     /*
2913      * insert the new frag into the list
2914      */
2915     Frag3FraglistAddNode(ft, left, newfrag);
2916 
2917     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2918                 "[*] Inserted new frag %d@%d ptr %p data %p prv %p nxt %p\n",
2919                 newfrag->size, newfrag->offset, newfrag, newfrag->data,
2920                 newfrag->prev, newfrag->next););
2921 
2922     /*
2923      * record the current size of the data in the fraglist
2924      */
2925     ft->frag_bytes += newfrag->size;
2926 
2927     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2928                 "[#] accumulated bytes on FragTracker %d, count"
2929                 " %d\n", ft->frag_bytes, ft->fraglist_count););
2930 
2931     *retFrag = newfrag;
2932     return FRAG_INSERT_OK;
2933 }
2934 
2935 /**
2936  * Duplicate a frag node and insert it into the list.
2937  *
2938  * @param ft FragTracker to hold the packet
2939  * @prarm left FragNode prior to this one (to be dup'd)
2940  * @param retFrag this one after its inserted (returned)
2941  *
2942  * @return status
2943  * @retval FRAG_INSERT_FAILED Memory problem, insertion failed
2944  * @retval FRAG_INSERT_OK All okay
2945  */
DupFragNode(FragTracker * ft,Frag3Frag * left,Frag3Frag ** retFrag)2946 static int DupFragNode(FragTracker *ft,
2947                 Frag3Frag *left,
2948                 Frag3Frag **retFrag)
2949 {
2950     Frag3Frag *newfrag = NULL;  /* new frag container */
2951 
2952     /*
2953      * grab/generate a new frag node
2954      */
2955     if(!frag3_eval_config->use_prealloc)
2956     {
2957         if(frag3_mem_in_use > frag3_eval_config->memcap)
2958         {
2959             if (Frag3Prune(ft) == 0)
2960             {
2961                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2962                     "Frag3Insert: Pruning failed\n"););
2963 
2964                 return FRAG_INSERT_FAILED;
2965             }
2966         }
2967 
2968         /*
2969          * build a frag struct to track this particular fragment
2970          */
2971         newfrag = (Frag3Frag *) SnortPreprocAlloc(1, sizeof(Frag3Frag),
2972                                     PP_FRAG3, PP_MEM_CATEGORY_SESSION);
2973         frag3_mem_in_use += sizeof(Frag3Frag);
2974 
2975         /*
2976          * allocate some space to hold the actual data
2977          */
2978         newfrag->fptr = (uint8_t*)SnortPreprocAlloc(1, left->flen,
2979                                 PP_FRAG3, PP_MEM_CATEGORY_SESSION);
2980         frag3_mem_in_use += left->flen;
2981 
2982         sfBase.frag3_mem_in_use = frag3_mem_in_use;
2983     }
2984     else
2985     {
2986         /*
2987          * fragments are preallocated, grab one from the list
2988          */
2989         while((newfrag = Frag3PreallocPop()) == NULL)
2990         {
2991             if (Frag3Prune(ft) == 0)
2992             {
2993                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
2994                     "Frag3Insert: Pruning failed\n"););
2995 
2996                 return FRAG_INSERT_FAILED;
2997             }
2998         }
2999 
3000         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3001                     "got newfrag (%p) from prealloc\n", newfrag););
3002     }
3003 
3004     f3stats.fragnodes_created++;
3005 
3006     newfrag->ord = ft->ordinal++;
3007     /*
3008      * twiddle the frag values for overlaps
3009      */
3010     newfrag->flen = left->flen;
3011     memcpy(newfrag->fptr, left->fptr, newfrag->flen);
3012     newfrag->data = newfrag->fptr + (left->data - left->fptr);
3013     newfrag->size = left->size;
3014     newfrag->offset = left->offset;
3015     newfrag->last = left->last;
3016 
3017     /*
3018      * insert the new frag into the list
3019      */
3020     Frag3FraglistAddNode(ft, left, newfrag);
3021 
3022     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3023                 "[*] Inserted new frag %d@%d ptr %p data %p prv %p nxt %p\n",
3024                 newfrag->size, newfrag->offset, newfrag, newfrag->data,
3025                 newfrag->prev, newfrag->next););
3026 
3027     /*
3028      * record the current size of the data in the fraglist
3029      */
3030     ft->frag_bytes += newfrag->size;
3031 
3032     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3033                 "[#] accumulated bytes on FragTracker %d, count"
3034                 " %d\n", ft->frag_bytes, ft->fraglist_count););
3035 
3036     *retFrag = newfrag;
3037     return FRAG_INSERT_OK;
3038 }
3039 
3040 /** checks for tiny fragments and raises appropriate alarm
3041  *
3042  * @param p Current packet to insert
3043  * @param ft FragTracker to hold the packet
3044  * @param fkey FragKey with the current FragTracker's key info
3045  * @param f3context context of the current engine for target-based defrag info
3046  *
3047  * @returns 1 if tiny fragment was detected, 0 otherwise
3048  */
checkTinyFragments(Frag3Context * f3context,Packet * p,unsigned int trimmedLength)3049 static inline int checkTinyFragments(
3050         Frag3Context *f3context,
3051         Packet *p,
3052         unsigned int trimmedLength
3053         )
3054 {
3055     //Snort may need to raise a separate event if
3056     //only trimmed length is tiny.
3057     if(p->mf)
3058     {
3059         ///detect tiny fragments before processing overlaps.
3060         if (f3context->min_fragment_length)
3061         {
3062             if (p->ip_frag_len <= f3context->min_fragment_length)
3063             {
3064                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3065                             "Frag3: Received fragment size(%d) is not more than configured min_fragment_length (%d)\n",
3066                             p->ip_frag_len, f3context->min_fragment_length););
3067                 EventTinyFragments(f3context);
3068                 return 1;
3069             }
3070 
3071             ///detect tiny fragments after processing overlaps.
3072             if (trimmedLength <= f3context->min_fragment_length)
3073             {
3074                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3075                             "Frag3: # of New octets in Received fragment(%d) is not more than configured min_fragment_length (%d)\n",
3076                             trimmedLength, f3context->min_fragment_length););
3077                 EventTinyFragments(f3context);
3078                 return 1;
3079             }
3080         }
3081     }
3082 
3083     return 0;
3084 }
3085 
frag3DropAllFragments(Packet * p)3086 int  frag3DropAllFragments(
3087         Packet *p
3088         )
3089 {
3090     FragTracker *ft = (FragTracker *)p->fragtracker;
3091 
3092     //drop this and all following fragments
3093     if (ft && !(ft->frag_flags & FRAG_DROP_FRAGMENTS))
3094     {
3095         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3096                         "Frag3: Will drop all fragments on this packet\n"););
3097         ft->frag_flags |= FRAG_DROP_FRAGMENTS;
3098     }
3099 
3100     return 0;
3101 }
3102 
3103 /**
3104  * This is where the rubber hits the road.  Insert the new fragment's data
3105  * into the current FragTracker's fraglist, doing anomaly detection and
3106  * handling overlaps in a target-based manner.
3107  *
3108  * @param p Current packet to insert
3109  * @param ft FragTracker to hold the packet
3110  * @param fkey FragKey with the current FragTracker's key info
3111  * @param f3context context of the current engine for target-based defrag info
3112  *
3113  * @return status
3114  * @retval FRAG_INSERT_TIMEOUT FragTracker has timed out and been dropped
3115  * @retval FRAG_INSERT_ATTACK  Attack detected during insertion
3116  * @retval FRAG_INSERT_ANOMALY Anomaly detected during insertion
3117  * @retval FRAG_INSERT_TTL Delta of TTL values beyond configured value
3118  * @retval FRAG_INSERT_OK Fragment has been inserted successfully
3119  */
Frag3Insert(Packet * p,FragTracker * ft,FRAGKEY * fkey,Frag3Context * f3context)3120 static int Frag3Insert(Packet *p, FragTracker *ft, FRAGKEY *fkey,
3121         Frag3Context *f3context)
3122 {
3123     uint16_t orig_offset;    /* offset specified in this fragment header */
3124     uint16_t frag_offset;    /* calculated offset for this fragment */
3125     uint32_t frag_end;       /* calculated end point for this fragment */
3126     int16_t trunc = 0;      /* we truncate off the tail */
3127     int32_t overlap = 0;    /* we overlap on either end of the frag */
3128     int16_t len = 0;        /* calculated size of the fragment */
3129     int16_t slide = 0;      /* slide up the front of the current frag */
3130     int done = 0;           /* flag for right-side overlap handling loop */
3131     int addthis = 1;           /* flag for right-side overlap handling loop */
3132     int i = 0;              /* counter */
3133     int firstLastOk;
3134     int ret = FRAG_INSERT_OK;
3135     unsigned char lastfrag = 0; /* Set to 1 when this is the 'last' frag */
3136     unsigned char alerted_overlap = 0; /* Set to 1 when alerted */
3137     Frag3Frag *right = NULL; /* frag ptr for right-side overlap loop */
3138     Frag3Frag *newfrag = NULL;  /* new frag container */
3139     Frag3Frag *left = NULL;     /* left-side overlap fragment ptr */
3140     Frag3Frag *idx = NULL;      /* indexing fragment pointer for loops */
3141     Frag3Frag *dump_me = NULL;  /* frag ptr for complete overlaps to dump */
3142     const uint8_t *fragStart;
3143     int16_t fragLength;
3144     uint32_t reassembled_pkt_size;
3145     PROFILE_VARS;
3146 
3147     sfBase.iFragInserts++;
3148 
3149     PREPROC_PROFILE_START(frag3InsertPerfStats);
3150 
3151     if (IS_IP6(p) && (p->frag_offset == 0))
3152     {
3153         IP6Frag *fragHdr = (IP6Frag *)p->ip6_extensions[p->ip6_frag_index].data;
3154         if (ft->protocol != fragHdr->ip6f_nxt)
3155         {
3156             ft->protocol = fragHdr->ip6f_nxt;
3157         }
3158     }
3159 
3160     /*
3161      * Check to see if this fragment is the first or last one and
3162      * set the appropriate flags and values in the FragTracker
3163      */
3164     firstLastOk = Frag3CheckFirstLast(p, ft);
3165 
3166     fragStart = p->ip_frag_start;
3167     //fragStart = (uint8_t *)p->iph + GET_IPH_HLEN(p) * 4;
3168     /* Use the actual length here, because packet may have been
3169      * truncated.  Don't want to try to copy more than we actually
3170      * captured. */
3171     //len = fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4;
3172     len = fragLength = p->ip_frag_len;
3173 #ifdef DEBUG_MSGS
3174     if (p->actual_ip_len != ntohs(GET_IPH_LEN(p)))
3175     {
3176         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3177             "IP Actual Length (%d) != specified length (%d), "
3178             "truncated packet (%d)?\n",
3179             p->actual_ip_len, ntohs(GET_IPH_LEN(p)), pkt_snaplen););
3180     }
3181 #endif
3182 
3183     /*
3184      * setup local variables for tracking this frag
3185      */
3186     orig_offset = frag_offset = p->frag_offset << 3;
3187     /* Reset the offset to handle the weird Solaris case */
3188     if (firstLastOk == FRAG_LAST_OFFSET_ADJUST)
3189         frag_offset = (uint16_t)ft->calculated_size;
3190     frag_end = frag_offset + fragLength;
3191 
3192     /*
3193      * Copy the calculated size of the reassembled
3194      * packet in a local variable.
3195      */
3196     reassembled_pkt_size = ft->calculated_size;
3197 
3198     /*
3199      * might have last frag...
3200      */
3201     if(!p->mf)
3202     {
3203         if ((frag_end > ft->calculated_size) &&
3204             (firstLastOk == FRAG_LAST_OFFSET_ADJUST))
3205         {
3206             ft->calculated_size = frag_end;
3207         }
3208 
3209         //    ft->frag_flags |= FRAG_GOT_LAST;
3210         //    ft->calculated_size = (p->frag_offset << 3) + fragLength;
3211         lastfrag = 1;
3212     }
3213     else
3214     {
3215         uint16_t oldfrag_end;
3216         /*
3217          * all non-last frags are supposed to end on 8-byte boundries
3218          */
3219         if(frag_end & 7)
3220         {
3221             /*
3222              * bonk/boink/jolt/etc attack...
3223              */
3224             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3225                         "[..] Short frag (Bonk, etc) attack!\n"););
3226 
3227             EventAnomShortFrag(f3context);
3228 
3229             /* don't return, might still be interesting... */
3230         }
3231 
3232         /* can't have non-full fragments... */
3233         oldfrag_end = frag_end;
3234         frag_end &= ~7;
3235 
3236         /* Adjust len to take into account the jolting/non-full fragment. */
3237         len -= (oldfrag_end - frag_end);
3238 
3239         /*
3240          * if the end of this frag is greater than the max frag size we have a
3241          * problem
3242          */
3243         if(frag_end > ft->calculated_size)
3244         {
3245             if(ft->frag_flags & FRAG_GOT_LAST)
3246             {
3247                 /* oversize frag attack */
3248                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3249                             "[..] Oversize frag pkt!\n"););
3250 
3251                 EventAnomOversize(f3context);
3252 
3253                 PREPROC_PROFILE_END(frag3InsertPerfStats);
3254                 return FRAG_INSERT_ANOMALY;
3255             }
3256             ft->calculated_size = frag_end;
3257         }
3258     }
3259 
3260     if(frag_end == frag_offset)
3261     {
3262         /*
3263          * zero size frag...
3264          */
3265         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3266                     "[..] Zero size frag!\n"););
3267 
3268         if(f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES)
3269         {
3270             EventAnomZeroFrag(f3context);
3271         }
3272 
3273         PREPROC_PROFILE_END(frag3InsertPerfStats);
3274         return FRAG_INSERT_ANOMALY;
3275     }
3276 
3277     if(frag_end > IP_MAXPACKET)
3278     {
3279         /*
3280          * oversize pkt...
3281          */
3282         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3283                     "[..] Oversize frag!\n"););
3284 
3285             EventAnomBadsizeLg(f3context);
3286 
3287         ft->frag_flags |= FRAG_BAD;
3288 
3289 	/*
3290          * Restore the value of ft->calculated_size
3291          */
3292         ft->calculated_size = reassembled_pkt_size;
3293 
3294         PREPROC_PROFILE_END(frag3InsertPerfStats);
3295         return FRAG_INSERT_ANOMALY;
3296     }
3297 
3298     /*
3299      * This may alert on bad options, but we still want to
3300      * insert the packet
3301      */
3302     Frag3HandleIPOptions(ft, p);
3303 
3304     ft->frag_pkts++;
3305 
3306     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3307                 "Walking frag list (%d nodes), new frag %d@%d\n",
3308                 ft->fraglist_count, fragLength, frag_offset););
3309 
3310     /*
3311      * Need to figure out where in the frag list this frag should go
3312      * and who its neighbors are
3313      */
3314     for(idx = ft->fraglist; idx; idx = idx->next)
3315     {
3316         i++;
3317         right = idx;
3318 
3319         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3320                     "%d right o %d s %d ptr %p prv %p nxt %p\n",
3321                     i, right->offset, right->size, right,
3322                     right->prev, right->next););
3323 
3324         if(right->offset >= frag_offset)
3325         {
3326             break;
3327         }
3328 
3329         left = right;
3330     }
3331 
3332     /*
3333      * null things out if we walk to the end of the list
3334      */
3335     if(idx == NULL) right = NULL;
3336 
3337     /*
3338      * handle forward (left-side) overlaps...
3339      */
3340     if(left)
3341     {
3342         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3343                     "Dealing with previous (left) frag %d@%d\n",
3344                     left->size, left->offset););
3345 
3346         /*
3347          * generate the overlap of the current packet fragment
3348          * over this left-side fragment
3349          */
3350         /* NOTE: If frag_offset is really large, overlap can be
3351          * negative because its stored as a 32bit int.
3352          */
3353         overlap = left->offset + left->size - frag_offset;
3354 
3355         if(overlap > 0)
3356         {
3357             f3stats.overlaps++;
3358             ft->overlap_count++;
3359 
3360             if(frag_end < ft->calculated_size ||
3361                     ((ft->frag_flags & FRAG_GOT_LAST) &&
3362                      frag_end != ft->calculated_size))
3363             {
3364                 if (!p->mf)
3365                 {
3366                     /*
3367                      * teardrop attack...
3368                      */
3369                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3370                                 "[..] Teardrop attack!\n"););
3371 
3372                     EventAttackTeardrop(f3context);
3373 
3374                     ft->frag_flags |= FRAG_BAD;
3375 
3376                     PREPROC_PROFILE_END(frag3InsertPerfStats);
3377                     return FRAG_INSERT_ATTACK;
3378                 }
3379             }
3380 
3381             /*
3382              * Ok, we've got an overlap so we need to handle it.
3383              *
3384              * The target-based modes here match the data generated by
3385              * Paxson's Active Mapping paper as do the policy types.
3386              */
3387             switch(ft->frag_policy)
3388             {
3389                 /*
3390                  * new frag gets moved around
3391                  */
3392                 case FRAG_POLICY_LINUX:
3393                 case FRAG_POLICY_FIRST:
3394                 case FRAG_POLICY_WINDOWS:
3395                 case FRAG_POLICY_SOLARIS:
3396                 case FRAG_POLICY_BSD:
3397                     frag_offset += (int16_t)overlap;
3398                     slide = (int16_t)overlap;
3399 
3400                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3401                                 "left overlap, new frag moves: %d bytes, "
3402                                 "slide: %d\n", overlap, slide););
3403 
3404                     if(frag_end <= frag_offset)
3405                     {
3406                         /*
3407                          * zero size frag
3408                          */
3409                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3410                                     "zero size frag\n"););
3411 
3412                         EventAnomZeroFrag(f3context);
3413 
3414                         PREPROC_PROFILE_END(frag3InsertPerfStats);
3415                         return FRAG_INSERT_ANOMALY;
3416                     }
3417 
3418                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "left overlap, "
3419                                 "truncating new pkt (slide: %d)\n", slide););
3420 
3421                     break;
3422 
3423                     /*
3424                      * new frag stays where it is, overlapee (existing frag)
3425                      * gets whacked
3426                      */
3427                 case FRAG_POLICY_BSD_RIGHT:
3428                     if (left->offset + left->size >= frag_offset + len)
3429                     {
3430                         /* BSD-right (HP Printers) favor new fragments with
3431                          * lower/equal offset, EXCEPT when the existing
3432                          * fragment ends with at a higher/equal offset.
3433                          */
3434                         frag_offset += (int16_t)overlap;
3435                         slide = (int16_t)overlap;
3436                         goto left_overlap_last;
3437                     }
3438                     /* fall through */
3439                 case FRAG_POLICY_LAST:
3440                     if ((left->offset < frag_offset) && (left->offset + left->size > frag_offset + len))
3441                     {
3442                         /* The new frag is overlapped on both sides by an
3443                          * existing frag -- existing frag needs to be split
3444                          * and the new frag inserted in the middle.
3445                          *
3446                          * Need to duplciate left.  Adjust that guys
3447                          * offset by + (frag_offset + len) and
3448                          * size by - (frag_offset + len - left->offset).
3449                          */
3450                         ret = DupFragNode(ft, left, &right);
3451                         if (ret != FRAG_INSERT_OK)
3452                         {
3453                             /* Some warning here,
3454                              * no, its done in AddFragNode */
3455                             PREPROC_PROFILE_END(frag3InsertPerfStats);
3456                             return ret;
3457                         }
3458                         left->size -= (int16_t)overlap;
3459                         ft->frag_bytes -= (int16_t)overlap;
3460 
3461                         right->offset = frag_offset + len;
3462                         right->size -= (frag_offset + len - left->offset);
3463                         right->data += (frag_offset + len - left->offset);
3464                         ft->frag_bytes -= (frag_offset + len - left->offset);
3465                     }
3466                     else
3467                     {
3468                         left->size -= (int16_t)overlap;
3469                         ft->frag_bytes -= (int16_t)overlap;
3470                     }
3471 
3472 left_overlap_last:
3473                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] left overlap, "
3474                                 "truncating old pkt (offset: %d overlap: %d)\n",
3475                                 left->offset, overlap););
3476 
3477                     if (left->size <= 0)
3478                     {
3479                         dump_me = left;
3480 
3481                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
3482                                 "dumping old frag (offset: %d overlap: %d)\n",
3483                                 dump_me->offset, overlap););
3484 
3485                         left = left->prev;
3486 
3487                         Frag3FraglistDeleteNode(ft, dump_me);
3488                     }
3489 
3490                     break;
3491             }
3492 
3493             /*
3494              * frag can't end before it begins...
3495              */
3496             if(frag_end < frag_offset)
3497             {
3498                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3499                             "frag_end < frag_offset!"););
3500 
3501                 if(f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES)
3502                 {
3503                     EventAnomBadsizeSm(f3context);
3504                 }
3505 
3506                 PREPROC_PROFILE_END(frag3InsertPerfStats);
3507                 return FRAG_INSERT_ANOMALY;
3508             }
3509         }
3510         else
3511         {
3512             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "No left overlap!\n"););
3513         }
3514     }
3515 
3516     if ((uint16_t)fragLength > pkt_snaplen)
3517     {
3518         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3519                     "Overly large fragment %d 0x%x 0x%x %d\n",
3520                     fragLength, GET_IPH_LEN(p), GET_IPH_OFF(p),
3521                     p->frag_offset << 3););
3522         PREPROC_PROFILE_END(frag3InsertPerfStats);
3523         return FRAG_INSERT_FAILED;
3524     }
3525 
3526     /*
3527      * handle tail (right-side) overlaps
3528      *
3529      * We have to walk thru all the right side frags until the offset of the
3530      * existing frag is greater than the end of the new frag
3531      */
3532     while(right && (right->offset < frag_end) && !done)
3533     {
3534         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3535                     "Next (right)fragment %d@%d\n",
3536                     right->size, right->offset););
3537 
3538 #ifdef DEBUG_FRAG3
3539         PrintFrag3Frag(right);
3540 #endif
3541         trunc = 0;
3542         overlap = frag_end - right->offset;
3543 
3544         if (overlap)
3545         {
3546             if(frag_end < ft->calculated_size ||
3547                     ((ft->frag_flags & FRAG_GOT_LAST) &&
3548                      frag_end != ft->calculated_size))
3549             {
3550                 if (!p->mf)
3551                 {
3552                     /*
3553                      * teardrop attack...
3554                      */
3555                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3556                                 "[..] Teardrop attack!\n"););
3557 
3558                     EventAttackTeardrop(f3context);
3559 
3560                     ft->frag_flags |= FRAG_BAD;
3561 
3562                     PREPROC_PROFILE_END(frag3InsertPerfStats);
3563                     return FRAG_INSERT_ATTACK;
3564                 }
3565             }
3566         }
3567 
3568         /*
3569          * partial right-side overlap, this will be the last frag to check
3570          */
3571         if(overlap < right->size)
3572         {
3573             f3stats.overlaps++;
3574             ft->overlap_count++;
3575 
3576             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3577                         "Right-side overlap %d bytes\n", overlap););
3578 
3579             /*
3580              * once again, target-based policy processing
3581              */
3582             switch(ft->frag_policy)
3583             {
3584                 /*
3585                  * existing fragment gets truncated
3586                  */
3587                 case FRAG_POLICY_LAST:
3588                 case FRAG_POLICY_LINUX:
3589                 case FRAG_POLICY_BSD:
3590                     if ((ft->frag_policy == FRAG_POLICY_BSD) &&
3591                         (right->offset == frag_offset))
3592                     {
3593                         slide = (int16_t)(right->offset + right->size - frag_offset);
3594                         frag_offset += (int16_t)slide;
3595                     }
3596                     else
3597                     {
3598                         right->offset += (int16_t)overlap;
3599                         right->data += (int16_t)overlap;
3600                         right->size -= (int16_t)overlap;
3601                         ft->frag_bytes -= (int16_t)overlap;
3602                     }
3603                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] right overlap, "
3604                                 "truncating old frag (offset: %d, "
3605                                 "overlap: %d)\n", right->offset, overlap);
3606                             DebugMessage(DEBUG_FRAG,
3607                                 "Exiting right overlap loop...\n"););
3608                     if (right->size <= 0)
3609                     {
3610                         dump_me = right;
3611 
3612                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
3613                                 "dumping old frag (offset: %d overlap: %d)\n",
3614                                 dump_me->offset, overlap););
3615 
3616                         right = right->next;
3617 
3618                         Frag3FraglistDeleteNode(ft, dump_me);
3619                     }
3620                     break;
3621 
3622                 /*
3623                  * new frag gets truncated
3624                  */
3625                 case FRAG_POLICY_FIRST:
3626                 case FRAG_POLICY_WINDOWS:
3627                 case FRAG_POLICY_SOLARIS:
3628                 case FRAG_POLICY_BSD_RIGHT:
3629                     trunc = (int16_t)overlap;
3630                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] right overlap, "
3631                                 "truncating new frag (offset: %d "
3632                                 "overlap: %d)\n",
3633                                 right->offset, overlap);
3634                             DebugMessage(DEBUG_FRAG,
3635                                 "Exiting right overlap loop...\n"););
3636                     break;
3637             }
3638 
3639             /*
3640              * all done, bail
3641              */
3642             done = 1;
3643         }
3644         else
3645         {
3646             /*
3647              * we've got a full overlap
3648              */
3649             if(!alerted_overlap && (f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
3650             {
3651                 /*
3652                  * retrans/full overlap
3653                  */
3654                 EventAnomOverlap(f3context);
3655                 alerted_overlap = 1;
3656                 f3stats.overlaps++;
3657                 ft->overlap_count++;
3658             }
3659 
3660             /*
3661              * handle the overlap in a target-based manner
3662              */
3663             switch(ft->frag_policy)
3664             {
3665                 /*
3666                  * overlap is treated differently if there is more
3667                  * data beyond the overlapped packet.
3668                  */
3669                 case FRAG_POLICY_WINDOWS:
3670                 case FRAG_POLICY_SOLARIS:
3671                 case FRAG_POLICY_BSD:
3672                     /*
3673                      * Old packet is overlapped on both sides...
3674                      * Drop the old packet.  This follows a
3675                      * POLICY_LAST model.
3676                      */
3677                     if ((frag_end > right->offset + right->size) &&
3678                         (frag_offset < right->offset))
3679                     {
3680                         dump_me = right;
3681                         ft->frag_bytes -= right->size;
3682 
3683                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
3684                                 "dumping old frag (offset: %d overlap: %d)\n",
3685                                 dump_me->offset, overlap););
3686 
3687                         right = right->next;
3688 
3689                         Frag3FraglistDeleteNode(ft, dump_me);
3690                         break;
3691                     }
3692                     else
3693                     {
3694                         if ((ft->frag_policy == FRAG_POLICY_SOLARIS) ||
3695                             (ft->frag_policy == FRAG_POLICY_BSD))
3696                         {
3697                             /* SOLARIS & BSD only */
3698                             if ((frag_end == right->offset + right->size) &&
3699                                 (frag_offset < right->offset))
3700                             {
3701                                 /* If the frag overlaps an entire frag to the
3702                                  * right side of that frag, the old frag if
3703                                  * dumped -- this is a "policy last".
3704                                  */
3705                                 goto right_overlap_last;
3706                             }
3707                         }
3708                     }
3709                     /* Otherwise, treat it as a POLICY_FIRST,
3710                      * and trim accordingly. */
3711 
3712                     /* ie, fall through to the next case */
3713 
3714                 /*
3715                  * overlap is rejected
3716                  */
3717                 case FRAG_POLICY_FIRST:
3718                     /* fix for bug 17823 */
3719                     if (right->offset == frag_offset)
3720                     {
3721                         slide = (int16_t)(right->offset + right->size - frag_offset);
3722                         frag_offset += (int16_t)slide;
3723                         left = right;
3724                         right = right->next;
3725                     }
3726                     else
3727                     {
3728                         trunc = (int16_t)overlap;
3729                     }
3730 
3731                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "right overlap, "
3732                                 "rejecting new overlap data (overlap: %d, "
3733                                 "trunc: %d)\n", overlap, trunc););
3734 
3735                     if (frag_end - trunc <= frag_offset)
3736                     {
3737                         /*
3738                          * zero size frag
3739                          */
3740                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3741                                     "zero size frag (len: %d  overlap: %d)\n",
3742                                     fragLength, overlap););
3743 
3744                         f3stats.discards++;
3745 
3746                         PREPROC_PROFILE_END(frag3InsertPerfStats);
3747                         return FRAG_INSERT_ANOMALY;
3748                     }
3749 
3750                     {
3751                         uint16_t curr_end;
3752                         /* Full overlapping an already received packet
3753                          * and there are more packets beyond that fully
3754                          * overlapped one.
3755                          * Arrgh.  Need to insert this guy in chunks.
3756                          */
3757                         checkTinyFragments(f3context, p, len-slide-trunc);
3758 
3759                         ret = AddFragNode(ft, p, f3context, fragStart, fragLength, 0, len,
3760                                 slide, trunc, frag_offset, left, &newfrag);
3761                         if (ret != FRAG_INSERT_OK)
3762                         {
3763                             /* Some warning here,
3764                              * no, its done in AddFragNode */
3765                             PREPROC_PROFILE_END(frag3InsertPerfStats);
3766                             return ret;
3767                         }
3768 
3769                         curr_end = newfrag->offset + newfrag->size;
3770 
3771                         /* Find the next gap that this one might fill in */
3772                         while (right &&
3773                             (curr_end == right->offset) &&
3774                             (right->offset < frag_end))
3775                         {
3776                             curr_end = right->offset + right->size;
3777                             left = right;
3778                             right = right->next;
3779                         }
3780 
3781                         if (right && (right->offset < frag_end))
3782                         {
3783                             /* Adjust offset to end of 'left' */
3784                             if (left)
3785                                 frag_offset = left->offset + left->size;
3786                             else
3787                                 frag_offset = orig_offset;
3788 
3789                             /* Overlapping to the left by a good deal now */
3790                             slide = frag_offset - orig_offset;
3791                             /*
3792                              * Reset trunc, in case the next one kicks us
3793                              * out of the loop.  This packet will become the
3794                              * right-most entry so far.  Don't truncate any
3795                              * further.
3796                              */
3797                             trunc = 0;
3798                             if (right)
3799                                 continue;
3800                         }
3801 
3802                         if (curr_end < frag_end)
3803                         {
3804                             /* Insert this guy in his proper spot,
3805                              * adjust offset to the right-most endpoint
3806                              * we saw.
3807                              */
3808                             slide = left->offset + left->size - frag_offset;
3809                             frag_offset = curr_end;
3810                             trunc = 0;
3811                         }
3812                         else
3813                         {
3814                             addthis = 0;
3815                         }
3816                     }
3817                     break;
3818 
3819                     /*
3820                      * retrans accepted, dump old frag
3821                      */
3822 right_overlap_last:
3823                 case FRAG_POLICY_BSD_RIGHT:
3824                 case FRAG_POLICY_LAST:
3825                 case FRAG_POLICY_LINUX:
3826                     dump_me = right;
3827                     ft->frag_bytes -= right->size;
3828 
3829                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
3830                                 "dumping old frag (offset: %d overlap: %d)\n",
3831                                 dump_me->offset, overlap););
3832 
3833                     right = right->next;
3834 
3835                     Frag3FraglistDeleteNode(ft, dump_me);
3836 
3837                     break;
3838             }
3839         }
3840     }
3841 
3842     ///detect tiny fragments but continue processing
3843     checkTinyFragments(f3context, p, len-slide-trunc);
3844 
3845     if ((f3context->overlap_limit) &&
3846             (ft->overlap_count >= f3context->overlap_limit))
3847     {
3848         //overlap limit exceeded. Raise event on all subsequent fragments
3849         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Reached overlap limit.\n"););
3850 
3851         EventExcessiveOverlap(f3context);
3852 
3853         PREPROC_PROFILE_END(frag3InsertPerfStats);
3854         return FRAG_INSERT_OVERLAP_LIMIT;
3855     }
3856 
3857     if (addthis)
3858     {
3859         ret = AddFragNode(ft, p, f3context, fragStart, fragLength, lastfrag, len,
3860                       slide, trunc, frag_offset, left, &newfrag);
3861     }
3862     else
3863     {
3864         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3865                     "Fully truncated right overlap\n"););
3866     }
3867 
3868     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3869                 "Frag3Insert(): returning normally\n"););
3870 
3871     PREPROC_PROFILE_END(frag3InsertPerfStats);
3872     return ret;
3873 }
3874 
3875 /**
3876  * Check to see if a FragTracker has met all of its completion criteria
3877  *
3878  * @param ft FragTracker to check
3879  *
3880  * @return status
3881  * @retval 1 If the FragTracker is ready to be rebuilt
3882  * @retval 0 If the FragTracker hasn't fulfilled its completion criteria
3883  */
Frag3IsComplete(FragTracker * ft)3884 static inline int Frag3IsComplete(FragTracker *ft)
3885 {
3886     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3887                 "[$] Checking completion criteria\n"););
3888 
3889     /*
3890      * check to see if the first and last frags have arrived
3891      */
3892     if((ft->frag_flags & FRAG_GOT_FIRST) &&
3893             (ft->frag_flags & FRAG_GOT_LAST))
3894     {
3895         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3896                     "   Got First and Last frags\n"););
3897 
3898         /*
3899          * if we've accumulated enough data to match the calculated size
3900          * of the defragg'd packet, return 1
3901          */
3902         if(ft->frag_bytes == ft->calculated_size)
3903         {
3904             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3905                         "   [!] frag_bytes = calculated_size!\n"););
3906 
3907             sfBase.iFragCompletes++;
3908 
3909             return 1;
3910         }
3911 
3912         if (ft->frag_bytes > ft->calculated_size)
3913         {
3914             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3915                         "   [!] frag_bytes > calculated_size!\n"););
3916 
3917             sfBase.iFragCompletes++;
3918 
3919             return 1;
3920         }
3921 
3922         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3923                     "   Calc size (%d) != frag bytes (%d)\n",
3924                     ft->calculated_size, ft->frag_bytes););
3925 
3926         /*
3927          * no dice
3928          */
3929         return 0;
3930     }
3931 
3932     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3933                 "   Missing First or Last frags (frag_flags: 0x%X)\n",
3934                 ft->frag_flags););
3935 
3936     return 0;
3937 }
3938 
3939 /**
3940  * Reassemble the packet from the data in the FragTracker and reinject into
3941  * Snort's packet analysis system
3942  *
3943  * @param ft FragTracker to rebuild
3944  * @param p Packet to fill in pseudopacket IP structs
3945  *
3946  * @return none
3947  */
Frag3Rebuild(FragTracker * ft,Packet * p)3948 static void Frag3Rebuild(FragTracker *ft, Packet *p)
3949 {
3950     uint8_t *rebuild_ptr = NULL;  /* ptr to the start of the reassembly buffer */
3951     const uint8_t *rebuild_end;  /* ptr to the end of the reassembly buffer */
3952     Frag3Frag *frag;    /* frag pointer for managing fragments */
3953     int ret = 0;
3954     Packet* dpkt;
3955     PROFILE_VARS;
3956 
3957 // XXX NOT YET IMPLEMENTED - debugging
3958 
3959     PREPROC_PROFILE_START(frag3RebuildPerfStats);
3960 
3961 #ifdef GRE
3962     if ( p->encapsulated )
3963         dpkt = encap_defrag_pkt;
3964     else
3965 #endif
3966         dpkt = defrag_pkt;
3967 
3968     Encode_Format(ENC_FLAG_DEF|ENC_FLAG_FWD, p, dpkt, PSEUDO_PKT_IP);
3969     /*
3970      * set the pointer to the end of the rebuild packet
3971      */
3972     rebuild_ptr = (uint8_t*)dpkt->data;
3973     // the encoder ensures enough space for a maximum datagram
3974     rebuild_end = (uint8_t*)dpkt->data + IP_MAXPACKET;
3975 
3976     if (IS_IP4(p))
3977     {
3978         /*
3979          * if there are IP options, copy those in as well
3980          * these are for the inner IP...
3981          */
3982         if (ft->ip_options_data && ft->ip_options_len)
3983         {
3984             /* Adjust the IP header size in pseudo packet for the new length */
3985             uint8_t new_ip_hlen = sizeof(*dpkt->iph) + ft->ip_options_len;
3986 
3987             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
3988                     "Adjusting IP Header to %d bytes\n",
3989                     new_ip_hlen););
3990             SET_IP_HLEN((IPHdr *)dpkt->iph, new_ip_hlen>>2);
3991 
3992             ret = SafeMemcpy(rebuild_ptr, ft->ip_options_data,
3993                 ft->ip_options_len, rebuild_ptr, rebuild_end);
3994 
3995             if (ret == SAFEMEM_ERROR)
3996             {
3997                 /*XXX: Log message, failed to copy */
3998                 ft->frag_flags = ft->frag_flags | FRAG_REBUILT;
3999                 return;
4000             }
4001             rebuild_ptr += ft->ip_options_len;
4002         }
4003         else if (ft->copied_ip_options_len)
4004         {
4005             /* XXX: should we log a warning here?  there were IP options
4006              * copied across all fragments, EXCEPT the offset 0 fragment.
4007              */
4008         }
4009 
4010         /*
4011          * clear the packet fragment fields
4012          */
4013         ((IPHdr *)dpkt->iph)->ip_off = 0x0000;
4014         dpkt->frag_flag = 0;
4015 
4016         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4017                     "[^^] Walking fraglist:\n"););
4018     }
4019 
4020     /*
4021      * walk the fragment list and rebuild the packet
4022      */
4023     for(frag = ft->fraglist; frag; frag = frag->next)
4024     {
4025         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4026                     "   frag: %p\n"
4027                     "   frag->data: %p\n"
4028                     "   frag->offset: %d\n"
4029                     "   frag->size: %d\n"
4030                     "   frag->prev: %p\n"
4031                     "   frag->next: %p\n",
4032                     frag, frag->data, frag->offset,
4033                     frag->size, frag->prev, frag->next););
4034 
4035         /*
4036          * We somehow got a frag that had data beyond the calculated
4037          * end. Don't want to include it.
4038          */
4039         if ((frag->offset + frag->size) > (uint16_t)ft->calculated_size)
4040             continue;
4041 
4042         /*
4043          * try to avoid buffer overflows...
4044          */
4045         if (frag->size)
4046         {
4047             ret = SafeMemcpy(rebuild_ptr+frag->offset, frag->data, frag->size,
4048                              rebuild_ptr, rebuild_end);
4049 
4050             if (ret == SAFEMEM_ERROR)
4051             {
4052                 /*XXX: Log message, failed to copy */
4053                 ft->frag_flags = ft->frag_flags | FRAG_REBUILT;
4054                 return;
4055             }
4056         }
4057     }
4058 
4059     if (IS_IP4(p))
4060     {
4061         /*
4062          * tell the rest of the system that this is a rebuilt fragment
4063          */
4064         dpkt->packet_flags |= PKT_REBUILT_FRAG;
4065         dpkt->frag_flag = 0;
4066         dpkt->dsize = (uint16_t)ft->calculated_size;
4067 
4068         Encode_Update(dpkt);
4069     }
4070     else /* Inner/only is IP6 */
4071     {
4072         IP6RawHdr* rawHdr = (IP6RawHdr*)dpkt->raw_ip6h;
4073 
4074         if ( !rawHdr )
4075         {
4076             /*XXX: Log message, failed to copy */
4077             ft->frag_flags = ft->frag_flags | FRAG_REBUILT;
4078             return;
4079         }
4080 
4081         /* IPv6 Header is already copied over, as are all of the extensions
4082          * that were not part of the fragmented piece. */
4083 
4084         /* Set the 'next' protocol */
4085         if (p->ip6_frag_index > 0)
4086         {
4087             // FIXTHIS use of last_extension works but is ugly
4088             IP6Extension *last_extension = (IP6Extension *)
4089                 (dpkt->pkt + (p->ip6_extensions[p->ip6_frag_index -1].data - p->pkt));
4090             last_extension->ip6e_nxt = ft->protocol;
4091         }
4092         else
4093         {
4094             rawHdr->ip6nxt = ft->protocol;
4095         }
4096         dpkt->dsize = (uint16_t)ft->calculated_size;
4097         Encode_Update(dpkt);
4098     }
4099 
4100     pc.rebuilt_frags++;
4101     sfBase.iFragFlushes++;
4102 
4103     /* Rebuild is complete */
4104     PREPROC_PROFILE_END(frag3RebuildPerfStats);
4105 
4106     /*
4107      * process the packet through the detection engine
4108      */
4109     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4110                 "Processing rebuilt packet:\n"););
4111 
4112     f3stats.reassembles++;
4113 
4114     UpdateIPReassStats(&sfBase, dpkt->pkth->caplen);
4115 
4116 #if defined(DEBUG_FRAG3) && defined(DEBUG)
4117     /*
4118      * Note, that this won't print out the IP Options or any other
4119      * data that is established when the packet is decoded.
4120      */
4121     if (DEBUG_FRAG & GetDebugLevel())
4122     {
4123         //ClearDumpBuf();
4124         printf("++++++++++++++++++Frag3 DEFRAG'd PACKET++++++++++++++\n");
4125         PrintIPPkt(stdout, dpkt->iph->ip_proto, &dpkt);
4126         printf("++++++++++++++++++Frag3 DEFRAG'd PACKET++++++++++++++\n");
4127         //ClearDumpBuf();
4128     }
4129 #endif
4130     SnortEventqPush();
4131     ProcessPacket(dpkt, dpkt->pkth, dpkt->pkt, ft);
4132     SnortEventqPop();
4133 
4134     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4135                 "Done with rebuilt packet, marking rebuilt...\n"););
4136 
4137     ft->frag_flags = ft->frag_flags | FRAG_REBUILT;
4138 }
4139 
4140 /**
4141  * Delete a Frag3Frag struct
4142  *
4143  * @param frag Fragment to delete
4144  *
4145  * @return none
4146  */
Frag3DeleteFrag(Frag3Frag * frag)4147 static void Frag3DeleteFrag(Frag3Frag *frag)
4148 {
4149     /*
4150      * delete the fragment either in prealloc or dynamic mode
4151      */
4152     if(!frag3_eval_config->use_prealloc)
4153     {
4154         SnortPreprocFree(frag->fptr, frag->flen, PP_FRAG3, PP_MEM_CATEGORY_SESSION);
4155         frag3_mem_in_use -= frag->flen;
4156 
4157         SnortPreprocFree(frag, sizeof(Frag3Frag), PP_FRAG3, PP_MEM_CATEGORY_SESSION);
4158         frag3_mem_in_use -= sizeof(Frag3Frag);
4159 
4160         sfBase.frag3_mem_in_use = frag3_mem_in_use;
4161     }
4162     else
4163     {
4164         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "o %d s %d ptr %p prv %p nxt %p\n",
4165                     frag->offset, frag->size, frag, frag->prev, frag->next););
4166         Frag3PreallocPush(frag);
4167     }
4168 
4169     f3stats.fragnodes_released++;
4170 }
4171 
4172 /**
4173  * Delete the contents of a FragTracker, in this instance that just means to
4174  * dump the fraglist.  The sfxhash system deletes the actual FragTracker mem.
4175  *
4176  * @param ft FragTracker to delete
4177  *
4178  * @return none
4179  */
Frag3DeleteTracker(FragTracker * ft)4180 static void Frag3DeleteTracker(FragTracker *ft)
4181 {
4182     Frag3Frag *idx = ft->fraglist;  /* pointer to the fraglist to delete */
4183     Frag3Frag *dump_me = NULL;      /* ptr to the Frag3Frag element to drop */
4184 
4185     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4186                 "Frag3DeleteTracker %d nodes to dump\n", ft->fraglist_count););
4187 
4188     /*
4189      * delete all the nodes in a fraglist
4190      */
4191     while(idx)
4192     {
4193         dump_me = idx;
4194         idx = idx->next;
4195         Frag3DeleteFrag(dump_me);
4196     }
4197     ft->fraglist = NULL;
4198     if (ft->ip_options_data)
4199     {
4200         SnortPreprocFree(ft->ip_options_data, ft->ip_options_len, PP_FRAG3,
4201                  PP_MEM_CATEGORY_SESSION);
4202         ft->ip_options_data = NULL;
4203     }
4204 
4205     return;
4206 }
4207 
4208 /**
4209  * Remove a FragTracker from the f_cache hash table
4210  *
4211  * @param key FragKey of the FragTracker to be removed
4212  * @param data unused in this function
4213  *
4214  * @return none
4215  */
Frag3RemoveTracker(void * key,void * data)4216 static void Frag3RemoveTracker(void *key, void *data)
4217 {
4218     /*
4219      * sfxhash maintains its own self preservation stuff/node freeing stuff
4220      */
4221     if(sfxhash_remove(f_cache, key) != SFXHASH_OK)
4222     {
4223         ErrorMessage("sfxhash_remove() failed in frag3!\n");
4224     }
4225 
4226     return;
4227 }
4228 
4229 /**
4230  * This is the auto-node-release function that gets handed to the sfxhash table
4231  * at initialization.  Handles deletion of sfxhash table data members.
4232  *
4233  * @param key FragKey of the element to be freed
4234  * @param data unused in this implementation
4235  *
4236  * Now Returns 0 because we want to say, yes, delete that hash entry!!!
4237  */
Frag3AutoFree(void * key,void * data)4238 static int Frag3AutoFree(void *key, void *data)
4239 {
4240     FragTracker *ft = (FragTracker *)data;
4241     tSfPolicyUserContextId config;
4242     tSfPolicyId policy_id;
4243     Frag3Config *pPolicyConfig = NULL;
4244 
4245     if (ft == NULL)
4246         return 0;
4247 
4248     config = ft->config;
4249     policy_id = ft->policy_id;
4250     pPolicyConfig = (Frag3Config *)sfPolicyUserDataGet(config, policy_id);
4251 
4252     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4253                 "Calling Frag3DeleteTracker()\n"););
4254 
4255     Frag3DeleteTracker(ft);
4256 
4257     sfBase.iFragDeletes++;
4258     sfBase.iFragAutoFrees++;
4259     sfBase.iCurrentFrags--;
4260     f3stats.fragtrackers_autoreleased++;
4261 
4262     if (pPolicyConfig != NULL)
4263     {
4264         pPolicyConfig->ref_count--;
4265         if ((pPolicyConfig->ref_count == 0) &&
4266             (config != frag3_config))
4267         {
4268             Frag3FreeConfig(pPolicyConfig);
4269             sfPolicyUserDataClear (config, policy_id);
4270 
4271             /* No more outstanding policies for this config */
4272             if (sfPolicyUserPolicyGetActive(config) == 0)
4273                 Frag3FreeConfigs(config);
4274         }
4275     }
4276 
4277     return 0;
4278 }
4279 
4280 /**
4281  * This is the user free function that gets handed to the sfxhash table
4282  * at initialization.  Handles deletion of sfxhash table data members.
4283  *
4284  * @param key FragKey of the element to be freed
4285  * @param data unused in this implementation
4286  *
4287  * Now Returns 0 because we want to say, yes, delete that hash entry!!!
4288  */
Frag3UserFree(void * key,void * data)4289 static int Frag3UserFree(void *key, void *data)
4290 {
4291     FragTracker *ft = (FragTracker *)data;
4292     tSfPolicyUserContextId config;
4293     tSfPolicyId policy_id;
4294     Frag3Config *pPolicyConfig = NULL;
4295 
4296     if (ft == NULL)
4297         return 0;
4298 
4299     config = ft->config;
4300     policy_id = ft->policy_id;
4301     pPolicyConfig = (Frag3Config *)sfPolicyUserDataGet(config, policy_id);
4302 
4303     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4304                 "Calling Frag3DeleteTracker()\n"););
4305 
4306     Frag3DeleteTracker(ft);
4307 
4308     sfBase.iFragDeletes++;
4309     sfBase.iCurrentFrags--;
4310     f3stats.fragtrackers_released++;
4311 
4312     if (pPolicyConfig != NULL)
4313     {
4314         pPolicyConfig->ref_count--;
4315         if ((pPolicyConfig->ref_count == 0) &&
4316             (config != frag3_config))
4317         {
4318             Frag3FreeConfig(pPolicyConfig);
4319             sfPolicyUserDataClear (config, policy_id);
4320 
4321             /* No more outstanding policies for this config */
4322             if (sfPolicyUserPolicyGetActive(config) == 0)
4323                 Frag3FreeConfigs(config);
4324         }
4325     }
4326 
4327     return 0;
4328 }
4329 
4330 /**
4331  * This function gets called either when we run out of prealloc nodes or when
4332  * the memcap is exceeded.  Its job is to free memory up in frag3 by deleting
4333  * old/stale data.  Currently implemented using a simple LRU pruning
4334  * technique, could probably benefit from having some sort of tail selection
4335  * randomization added to it.  Additonally, right now when we hit the wall we
4336  * try to drop at least enough memory to satisfy the "ten_percent" value.
4337  * Hopefully that's not too aggressive, salt to taste!
4338  *
4339  * @param none
4340  *
4341  * @return none
4342  */
Frag3Prune(FragTracker * not_me)4343 static int Frag3Prune(FragTracker *not_me)
4344 {
4345     SFXHASH_NODE *hnode;
4346     int found_this = 0;
4347     int pruned = 0;
4348 #ifdef DEBUG
4349     /* Use these to print out whether the frag tracker has
4350      * expired or not.
4351      */
4352     FragTracker *ft;
4353     struct timeval *fttime;     /* FragTracker timestamp */
4354 #endif
4355 
4356     sfBase.iFragFaults++;
4357     f3stats.prunes++;
4358 
4359     if(!frag3_eval_config->use_prealloc)
4360     {
4361         //while(frag3_mem_in_use > (frag3_eval_config->memcap-globa_config->ten_percent))
4362         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4363                     "(spp_frag3) Frag3Prune: Pruning by memcap! "););
4364         while((frag3_mem_in_use > frag3_eval_config->memcap) ||
4365               (f_cache->count > (frag3_eval_config->max_frags - 5)))
4366         {
4367             hnode = sfxhash_lru_node(f_cache);
4368             if(!hnode)
4369             {
4370                 break;
4371             }
4372 
4373             if (hnode && hnode->data == not_me)
4374             {
4375                 if (found_this)
4376                 {
4377                     /* Uh, problem... we've gone through the entire list */
4378                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4379                         "(spp_frag3) Frag3Prune: Pruning by memcap - empty list! "););
4380                     return pruned;
4381                 }
4382                 sfxhash_gmovetofront(f_cache, hnode);
4383                 found_this = 1;
4384                 continue;
4385             }
4386 #ifdef DEBUG
4387             ft = hnode->data;
4388             fttime = &(ft->frag_time);
4389 
4390             if (CheckTimeout(pkttime,fttime,ft->context)==FRAG_TIMEOUT)
4391             {
4392                 char *src_str = SnortStrdup(FragIPToStr(ft->sip, ft->ipver));
4393                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (timeout)! "
4394                     "[%s->%s ID: %d Count: %d]\n", src_str, FragIPToStr(ft->dip, ft->ipver),
4395                     ft->id, ft->fraglist_count);
4396                 free(src_str);
4397                 f3stats.timeouts++;
4398                 sfBase.iFragTimeouts++;
4399             }
4400             else
4401             {
4402                 char *src_str = SnortStrdup(FragIPToStr(ft->sip, ft->ipver));
4403                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (memory)! "
4404                     "[%s->%s ID: %d Count: %d]\n", src_str, FragIPToStr(ft->dip, ft->ipver),
4405                     ft->id, ft->fraglist_count);
4406                 free(src_str);
4407             }
4408 #endif
4409             Frag3RemoveTracker(hnode->key, hnode->data);
4410             //sfBase.iFragDeletes++;
4411             //f3stats.fragtrackers_released++;
4412             pruned++;
4413         }
4414     }
4415     else
4416     {
4417         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4418                     "(spp_frag3) Frag3Prune: Pruning by prealloc! "););
4419         while (prealloc_nodes_in_use >
4420                (frag3_eval_config->static_frags - frag3_eval_config->ten_percent))
4421         {
4422             hnode = sfxhash_lru_node(f_cache);
4423             if(!hnode)
4424             {
4425                 break;
4426             }
4427 
4428             if (hnode && hnode->data == not_me)
4429             {
4430                 if (found_this)
4431                 {
4432                     /* Uh, problem... we've gone through the entire list */
4433                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4434                               "(spp_frag3) Frag3Prune: Pruning by prealloc - empty list! "););
4435                     return pruned;
4436                 }
4437                 sfxhash_gmovetofront(f_cache, hnode);
4438                 found_this = 1;
4439                 continue;
4440             }
4441 
4442 #ifdef DEBUG
4443             ft = hnode->data;
4444             fttime = &(ft->frag_time);
4445 
4446             if (CheckTimeout(pkttime,fttime,ft->context)==FRAG_TIMEOUT)
4447             {
4448                 char *src_str = SnortStrdup(FragIPToStr(ft->sip, ft->ipver));
4449                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (timeout)! "
4450                     "[%s->%s ID: %d Count: %d]\n", src_str, FragIPToStr(ft->dip, ft->ipver),
4451                     ft->id, ft->fraglist_count);
4452                 free(src_str);
4453                 f3stats.timeouts++;
4454                 sfBase.iFragTimeouts++;
4455             }
4456             else
4457             {
4458                 char *src_str = SnortStrdup(FragIPToStr(ft->sip, ft->ipver));
4459                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (memory)! "
4460                     "[%s->%s ID: %d Count: %d]\n", src_str, FragIPToStr(ft->dip, ft->ipver),
4461                     ft->id, ft->fraglist_count);
4462                 free(src_str);
4463             }
4464 #endif
4465 
4466             Frag3RemoveTracker(hnode->key, hnode->data);
4467             //sfBase.iFragDeletes++;
4468             //f3stats.fragtrackers_released++;
4469             pruned++;
4470         }
4471     }
4472 
4473     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4474                 "(spp_frag3) Frag3Prune: Pruned %d nodes\n", pruned););
4475     return pruned;
4476 }
4477 
4478 /**
4479  * Print out the frag stats from this run
4480  *
4481  * @param none
4482  *
4483  * @return none
4484  */
Frag3PrintStats(int exiting)4485 static void Frag3PrintStats(int exiting)
4486 {
4487     LogMessage("Frag3 statistics:\n");
4488     LogMessage("        Total Fragments: %u\n", f3stats.total);
4489     LogMessage("      Frags Reassembled: %u\n", f3stats.reassembles);
4490     LogMessage("               Discards: %u\n", f3stats.discards);
4491     LogMessage("          Memory Faults: %u\n", f3stats.prunes);
4492     LogMessage("               Timeouts: %u\n", f3stats.timeouts);
4493     LogMessage("               Overlaps: %u\n", f3stats.overlaps);
4494     LogMessage("              Anomalies: %u\n", f3stats.anomalies);
4495     LogMessage("                 Alerts: %u\n", f3stats.alerts);
4496     LogMessage("                  Drops: %u\n", f3stats.drops);
4497     LogMessage("     FragTrackers Added: %u\n", f3stats.fragtrackers_created);
4498     LogMessage("    FragTrackers Dumped: %u\n", f3stats.fragtrackers_released);
4499     LogMessage("FragTrackers Auto Freed: %u\n", f3stats.fragtrackers_autoreleased);
4500     LogMessage("    Frag Nodes Inserted: %u\n", f3stats.fragnodes_created);
4501     LogMessage("     Frag Nodes Deleted: %u\n", f3stats.fragnodes_released);
4502 }
4503 
Frag3FreeConfigsPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)4504 static int Frag3FreeConfigsPolicy(
4505         tSfPolicyUserContextId config,
4506         tSfPolicyId policyId,
4507         void* pData
4508         )
4509 {
4510     Frag3Config *pPolicyConfig = (Frag3Config *)pData;
4511 
4512     //do any housekeeping before freeing Frag3Config
4513     sfPolicyUserDataClear (config, policyId);
4514     Frag3FreeConfig(pPolicyConfig);
4515 
4516     return 0;
4517 }
4518 
Frag3FreeConfigs(tSfPolicyUserContextId config)4519 static void Frag3FreeConfigs(tSfPolicyUserContextId config)
4520 {
4521     if (config == NULL)
4522         return;
4523 
4524     sfPolicyUserDataFreeIterate (config, Frag3FreeConfigsPolicy);
4525 
4526     sfPolicyConfigDelete(config);
4527 }
4528 
Frag3FreeConfig(Frag3Config * config)4529 static void Frag3FreeConfig(Frag3Config *config)
4530 {
4531     int engineIndex;
4532     Frag3Context *f3context;
4533 
4534     if (config == NULL)
4535         return;
4536 
4537     /* Cleanup the list of Frag3 engine contexts */
4538     for (engineIndex = 0; engineIndex < config->numFrag3Contexts; engineIndex++)
4539     {
4540         f3context = config->frag3ContextList[engineIndex];
4541         if (f3context->bound_addrs != NULL)
4542         {
4543             sfvar_free(f3context->bound_addrs);
4544         }
4545 
4546         SnortPreprocFree(f3context, sizeof(Frag3Context), PP_FRAG3,
4547                   PP_MEM_CATEGORY_CONFIG);
4548     }
4549 
4550     if (config->frag3ContextList != NULL)
4551         SnortPreprocFree(config->frag3ContextList,
4552                  config->numFrag3Contexts * sizeof (Frag3Context *),
4553                  PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
4554 
4555     SnortPreprocFree(config, sizeof(Frag3Config), PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
4556 }
4557 
4558 /**
4559  * CleanExit func required by preprocessors
4560  */
Frag3CleanExit(int signal,void * foo)4561 static void Frag3CleanExit(int signal, void *foo)
4562 {
4563     Frag3Frag *tmp;
4564     Frag3Config *pDefaultPolicyConfig = NULL;
4565 
4566     sfxhash_delete(f_cache);
4567     f_cache = NULL;
4568 
4569     pDefaultPolicyConfig = (Frag3Config *)sfPolicyUserDataGetDefault(frag3_config);
4570 
4571     /* Cleanup the preallocated frag nodes */
4572     if(pDefaultPolicyConfig->use_prealloc)
4573     {
4574         tmp = Frag3PreallocPop();
4575         while (tmp)
4576         {
4577             SnortPreprocFree(tmp->fptr, pkt_snaplen * sizeof(uint8_t),
4578                       PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
4579             SnortPreprocFree(tmp, sizeof(Frag3Frag),
4580                       PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
4581             tmp = Frag3PreallocPop();
4582         }
4583     }
4584 
4585     Frag3FreeConfigs(frag3_config);
4586 
4587     Encode_Delete(defrag_pkt);
4588     defrag_pkt = NULL;
4589 
4590 #ifdef GRE
4591     Encode_Delete(encap_defrag_pkt);
4592     encap_defrag_pkt = NULL;
4593 #endif
4594 }
4595 
Frag3Reset(int signal,void * foo)4596 static void Frag3Reset(int signal, void *foo)
4597 {
4598     if (f_cache != NULL)
4599         sfxhash_make_empty(f_cache);
4600 }
4601 
Frag3ResetStats(int signal,void * foo)4602 static void Frag3ResetStats(int signal, void *foo)
4603 {
4604     memset(&f3stats, 0, sizeof(f3stats));
4605 }
4606 
4607 
4608 /**
4609  * Get a node from the prealloc_list
4610  *
4611  * @return pointer to a Frag3Frag preallocated structure or NULL if the list
4612  * is empty
4613  */
Frag3PreallocPop(void)4614 static inline Frag3Frag *Frag3PreallocPop(void)
4615 {
4616     Frag3Frag *node;
4617 
4618     if(prealloc_frag_list)
4619     {
4620         node = prealloc_frag_list;
4621         prealloc_frag_list = prealloc_frag_list->next;
4622         if (prealloc_frag_list)
4623         {
4624             prealloc_frag_list->prev = NULL;
4625         }
4626         else
4627         {
4628             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4629                         "Using last prealloc frag node\n"););
4630         }
4631         node->next = NULL;
4632         node->prev = NULL;
4633         node->offset = 0;
4634         node->size = 0;
4635         node->flen = 0;
4636         node->last = 0;
4637     }
4638     else
4639     {
4640         return NULL;
4641     }
4642 
4643     if (!node->fptr)
4644     {
4645         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4646                         "Frag3Frag fptr is NULL!\n"););
4647     }
4648 
4649     prealloc_nodes_in_use++;
4650     return node;
4651 }
4652 
4653 /**
4654  * Put a prealloc node back into the prealloc_cache pool
4655  *
4656  * @param node Prealloc node to place back in the pool
4657  *
4658  * @return none
4659  */
Frag3PreallocPush(Frag3Frag * node)4660 static inline void Frag3PreallocPush(Frag3Frag *node)
4661 {
4662     if (!prealloc_frag_list)
4663     {
4664         node->next = NULL;
4665         node->prev = NULL;
4666     }
4667     else
4668     {
4669         node->next = prealloc_frag_list;
4670         node->prev = NULL;
4671         prealloc_frag_list->prev = node;
4672     }
4673 
4674     prealloc_frag_list = node;
4675     node->data = NULL;
4676     if (!node->fptr)
4677     {
4678         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
4679                         "Frag3Frag fptr is NULL!\n"););
4680     }
4681 
4682     prealloc_nodes_in_use--;
4683     return;
4684 }
4685 
4686 /**
4687  * Plug a Frag3Frag into the fraglist of a FragTracker
4688  *
4689  * @param ft FragTracker to put the new node into
4690  * @param prev ptr to preceeding Frag3Frag in fraglist
4691  * @param next ptr to following Frag3Frag in fraglist
4692  * @param node ptr to node to put in list
4693  *
4694  * @return none
4695  */
Frag3FraglistAddNode(FragTracker * ft,Frag3Frag * prev,Frag3Frag * node)4696 static inline void Frag3FraglistAddNode(FragTracker *ft, Frag3Frag *prev,
4697         Frag3Frag *node)
4698 {
4699     if(prev)
4700     {
4701         node->next = prev->next;
4702         node->prev = prev;
4703         prev->next = node;
4704         if (node->next)
4705             node->next->prev = node;
4706         else
4707             ft->fraglist_tail = node;
4708     }
4709     else
4710     {
4711         node->next = ft->fraglist;
4712         if (node->next)
4713             node->next->prev = node;
4714         else
4715             ft->fraglist_tail = node;
4716         ft->fraglist = node;
4717     }
4718 
4719     ft->fraglist_count++;
4720     return;
4721 }
4722 
4723 /**
4724  * Delete a Frag3Frag from a fraglist
4725  *
4726  * @param ft FragTracker to delete the frag from
4727  * @param node node to be deleted
4728  *
4729  * @return none
4730  */
Frag3FraglistDeleteNode(FragTracker * ft,Frag3Frag * node)4731 static inline void Frag3FraglistDeleteNode(FragTracker *ft, Frag3Frag *node)
4732 {
4733     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Deleting list node %p (p %p n %p)\n",
4734                 node, node->prev, node->next););
4735 
4736     if(node->prev)
4737     {
4738         node->prev->next = node->next;
4739     }
4740     else
4741     {
4742         ft->fraglist = node->next;
4743     }
4744 
4745     if(node->next)
4746     {
4747         node->next->prev = node->prev;
4748     }
4749     else
4750     {
4751         ft->fraglist_tail = node->prev;
4752     }
4753 
4754     Frag3DeleteFrag(node);
4755     ft->fraglist_count--;
4756 }
4757 
4758 /*
4759 **
4760 **  NAME
4761 **    fpAddFragAlert::
4762 **
4763 **  DESCRIPTION
4764 **    This function flags an alert per frag tracker.
4765 **
4766 **  FORMAL INPUTS
4767 **    Packet *      - the packet to inspect
4768 **    OptTreeNode * - the rule that generated the alert
4769 **
4770 **  FORMAL OUTPUTS
4771 **    int - 0 if not flagged
4772 **          1 if flagged
4773 **
4774 */
fpAddFragAlert(Packet * p,OptTreeNode * otn)4775 int fpAddFragAlert(Packet *p, OptTreeNode *otn)
4776 {
4777     FragTracker *ft = p->fragtracker;
4778 
4779     if ( !ft )
4780         return 0;
4781 
4782     if ( !otn )
4783         return 0;
4784 
4785     /* Only track a certain number of alerts per session */
4786     if ( ft->alert_count >= MAX_FRAG_ALERTS )
4787         return 0;
4788 
4789     ft->alert_gid[ft->alert_count] = otn->sigInfo.generator;
4790     ft->alert_sid[ft->alert_count] = otn->sigInfo.id;
4791     ft->alert_count++;
4792 
4793     return 1;
4794 }
4795 
4796 /*
4797 **
4798 **  NAME
4799 **    fpFragAlerted::
4800 **
4801 **  DESCRIPTION
4802 **    This function indicates whether or not an alert has been generated previously
4803 **    in this session, but only if this is a rebuilt packet.
4804 **
4805 **  FORMAL INPUTS
4806 **    Packet *      - the packet to inspect
4807 **    OptTreeNode * - the rule that generated the alert
4808 **
4809 **  FORMAL OUTPUTS
4810 **    int - 0 if alert NOT previously generated
4811 **          1 if alert previously generated
4812 **
4813 */
fpFragAlerted(Packet * p,OptTreeNode * otn)4814 int fpFragAlerted(Packet *p, OptTreeNode *otn)
4815 {
4816     FragTracker *ft = p->fragtracker;
4817     SigInfo *si = &otn->sigInfo;
4818     int      i;
4819 
4820     if ( !ft )
4821         return 0;
4822 
4823     for ( i = 0; i < ft->alert_count; i++ )
4824     {
4825         /*  If this is a rebuilt packet and we've seen this alert before, return
4826          *  that we have previously alerted on a non-rebuilt packet.
4827          */
4828         if ( (p->packet_flags & PKT_REBUILT_FRAG)
4829                 && ft->alert_gid[i] == si->generator && ft->alert_sid[i] == si->id )
4830         {
4831             return 1;
4832         }
4833     }
4834 
4835     return 0;
4836 }
4837 
4838 #ifdef TARGET_BASED
fragGetApplicationProtocolId(Packet * p)4839 int fragGetApplicationProtocolId(Packet *p)
4840 {
4841     FragTracker *ft;
4842     /* Not caching this host_entry in the frag tracker so we can
4843      * swap the table out after processing this packet if we need
4844      * to.  */
4845     HostAttributeEntry *host_entry = NULL;
4846     uint16_t src_port = 0;
4847     uint16_t dst_port = 0;
4848     if (!p || !p->fragtracker)
4849     {
4850         return 0;
4851     }
4852 
4853     /* Must be a rebuilt frag... */
4854     if (!(p->packet_flags & PKT_REBUILT_FRAG))
4855     {
4856         return 0;
4857     }
4858 
4859     ft = (FragTracker *)p->fragtracker;
4860 
4861     if (ft->application_protocol != 0)
4862     {
4863         return ft->application_protocol;
4864     }
4865 
4866     switch (GET_IPH_PROTO(p))
4867     {
4868         case IPPROTO_TCP:
4869             ft->ipprotocol = protocolReferenceTCP;
4870             src_port = p->sp;
4871             dst_port = p->dp;
4872             break;
4873         case IPPROTO_UDP:
4874             ft->ipprotocol = protocolReferenceUDP;
4875             src_port = p->sp;
4876             dst_port = p->dp;
4877             break;
4878         case IPPROTO_ICMP:
4879             ft->ipprotocol = protocolReferenceICMP;
4880             break;
4881     }
4882 
4883     host_entry = SFAT_LookupHostEntryBySrc(p);
4884     if (host_entry)
4885     {
4886         ft->application_protocol = getApplicationProtocolId(host_entry,
4887                                     ft->ipprotocol,
4888                                     src_port,
4889                                     SFAT_SERVICE);
4890         if (ft->application_protocol != 0)
4891         {
4892             return ft->application_protocol;
4893         }
4894     }
4895 
4896     host_entry = SFAT_LookupHostEntryByDst(p);
4897     if (host_entry)
4898     {
4899         ft->application_protocol = getApplicationProtocolId(host_entry,
4900                                     ft->ipprotocol,
4901                                     dst_port,
4902                                     SFAT_SERVICE);
4903         if (ft->application_protocol != 0)
4904         {
4905             return ft->application_protocol;
4906         }
4907     }
4908 
4909     return ft->application_protocol;
4910 }
4911 #endif
4912 
4913 
4914 #ifdef SNORT_RELOAD
Frag3ReloadGlobal(struct _SnortConfig * sc,char * args,void ** new_config)4915 static void Frag3ReloadGlobal(struct _SnortConfig *sc, char *args, void **new_config)
4916 {
4917     tSfPolicyUserContextId frag3_swap_config = (tSfPolicyUserContextId)*new_config;
4918     Frag3Config *pDefaultPolicyConfig = NULL;
4919     Frag3Config *pCurrentPolicyConfig = NULL;
4920     tSfPolicyId policy_id = getParserPolicy(sc);
4921 
4922     if (!frag3_swap_config)
4923     {
4924         frag3_swap_config = sfPolicyConfigCreate();
4925         *new_config = (void *)frag3_swap_config;
4926     }
4927 
4928     sfPolicyUserPolicySet (frag3_swap_config, policy_id);
4929     pDefaultPolicyConfig = (Frag3Config *)sfPolicyUserDataGetDefault(frag3_swap_config);
4930     pCurrentPolicyConfig = (Frag3Config *)sfPolicyUserDataGetCurrent(frag3_swap_config);
4931 
4932     if ((policy_id != getDefaultPolicy()) && (pDefaultPolicyConfig == NULL))
4933     {
4934         ParseError("Frag3: Must configure default policy if other policies "
4935                    "are going to be used.\n");
4936     }
4937 
4938     if (pCurrentPolicyConfig != NULL)
4939     {
4940         FatalError("%s(%d) The frag3 global configuration can only be "
4941                    "configured once.\n", file_name, file_line);
4942     }
4943 
4944     pCurrentPolicyConfig = (Frag3Config *)SnortPreprocAlloc(1, sizeof(Frag3Config),
4945                                      PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
4946     sfPolicyUserDataSetCurrent(frag3_swap_config, pCurrentPolicyConfig);
4947 
4948     /* setup default values */
4949     pCurrentPolicyConfig->max_frags = DEFAULT_MAX_FRAGS;
4950     pCurrentPolicyConfig->memcap = FRAG_MEMCAP;
4951     pCurrentPolicyConfig->static_frags = 0;
4952     pCurrentPolicyConfig->use_prealloc = 0;
4953 
4954     Frag3ParseGlobalArgs(pCurrentPolicyConfig, args);
4955 
4956     if (policy_id != getDefaultPolicy())
4957     {
4958         /* Can't set these in alternate policies */
4959         pCurrentPolicyConfig->memcap = pDefaultPolicyConfig->memcap;
4960         pCurrentPolicyConfig->max_frags = pDefaultPolicyConfig->max_frags;
4961         pCurrentPolicyConfig->use_prealloc = pDefaultPolicyConfig->use_prealloc;
4962         pCurrentPolicyConfig->static_frags = pDefaultPolicyConfig->static_frags;
4963     }
4964     else if (pCurrentPolicyConfig->use_prealloc &&
4965              (pCurrentPolicyConfig->static_frags == 0))
4966     {
4967         pCurrentPolicyConfig->static_frags = (uint32_t)pCurrentPolicyConfig->memcap /
4968             (sizeof(Frag3Frag) + sizeof(uint8_t) * pkt_snaplen) + 1;
4969 
4970         pCurrentPolicyConfig->ten_percent = pCurrentPolicyConfig->static_frags >> 5;
4971 #ifdef REG_TEST
4972         if (REG_TEST_FLAG_RELOAD & getRegTestFlags())
4973         {
4974             printf("static frags is zero and memcap     : %lu\n",pCurrentPolicyConfig->memcap);
4975             printf("updated static_frags count          : %u\n",pCurrentPolicyConfig->static_frags);
4976         }
4977 #endif
4978     }
4979 
4980     Frag3PrintGlobalConfig(pCurrentPolicyConfig);
4981 
4982     if ( !pCurrentPolicyConfig->disabled )
4983     {
4984         AddFuncToPreprocList(sc, Frag3Defrag, PP_FRAG3_PRIORITY, PP_FRAG3, PROTO_BIT__IP);
4985         session_api->enable_preproc_all_ports( sc, PP_FRAG3, PROTO_BIT__IP );
4986     }
4987 }
4988 
Frag3ReloadEngine(struct _SnortConfig * sc,char * args,void ** new_config)4989 static void Frag3ReloadEngine(struct _SnortConfig *sc, char *args, void **new_config)
4990 {
4991     tSfPolicyUserContextId frag3_swap_config;
4992     Frag3Context *context;      /* context pointer */
4993     tSfPolicyId policy_id = getParserPolicy(sc);
4994     Frag3Config *config = NULL;
4995 
4996     frag3_swap_config = (tSfPolicyUserContextId)GetRelatedReloadData(sc, "frag3_global");
4997     config = (Frag3Config *)sfPolicyUserDataGet(frag3_swap_config, policy_id);
4998     if (config == NULL)
4999     {
5000         FatalError("[!] Unable to configure frag3 engine!\n"
5001                    "Frag3 global config has not been established, "
5002                    "please issue a \"preprocessor frag3_global\" directive\n");
5003     }
5004 
5005     context = (Frag3Context *) SnortPreprocAlloc(1, sizeof(Frag3Context), PP_FRAG3,
5006                                  PP_MEM_CATEGORY_CONFIG);
5007 
5008     context->frag_policy = FRAG_POLICY_DEFAULT;
5009     context->frag_timeout = FRAG_PRUNE_QUANTA; /* 60 seconds */
5010     context->min_ttl = FRAG3_MIN_TTL;
5011     context->frag3_alerts = 0;
5012 
5013     Frag3ParseArgs(sc, args, context);
5014 
5015     if (context->bound_addrs == NULL)
5016     {
5017         if (config->default_context != NULL)
5018             FatalError("Frag3 => only one non-bound context can be specified.\n");
5019 
5020         config->default_context = context;
5021     }
5022 
5023     if (config->frag3ContextList == NULL)
5024     {
5025         config->numFrag3Contexts = 1;
5026         config->frag3ContextList =
5027             (Frag3Context **)SnortPreprocAlloc(1, sizeof (Frag3Context *),
5028                           PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5029     }
5030     else
5031     {
5032         Frag3Context **tmpContextList;
5033 
5034         config->numFrag3Contexts++;
5035         tmpContextList = (Frag3Context **)
5036             SnortPreprocAlloc(config->numFrag3Contexts, sizeof (Frag3Context *),
5037                               PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5038 
5039         memcpy(tmpContextList, config->frag3ContextList,
5040                sizeof(Frag3Context *) * (config->numFrag3Contexts - 1));
5041 
5042         SnortPreprocFree(config->frag3ContextList,
5043                  (config->numFrag3Contexts - 1) * sizeof (Frag3Context *),
5044                   PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5045         config->frag3ContextList = tmpContextList;
5046     }
5047 
5048     config->frag3ContextList[config->numFrag3Contexts - 1] = context;
5049 
5050     Frag3PrintEngineConfig(context);
5051 }
5052 
Frag3ReloadVerifyPolicy(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)5053 static int Frag3ReloadVerifyPolicy(
5054         struct _SnortConfig *sc,
5055         tSfPolicyUserContextId config,
5056         tSfPolicyId policyId,
5057         void* pData
5058         )
5059 {
5060     Frag3Config *pPolicyConfig = (Frag3Config *)pData;
5061     if ( pPolicyConfig->disabled )
5062         return 0;
5063 
5064     //do any housekeeping before freeing Frag3Config
5065     if ((policyId != getDefaultPolicy())
5066            && (pPolicyConfig->numFrag3Contexts == 0))
5067     {
5068         WarningMessage("Frag3VerifyConfig() policy engine required "
5069                 "but not configured.\n");
5070         return -1;
5071     }
5072 
5073     return 0;
5074 }
5075 
Frag3MemReloadAdjust(unsigned maxWork)5076 static uint32_t Frag3MemReloadAdjust(unsigned maxWork)
5077 {
5078      Frag3Frag *tmp;
5079      SFXHASH_NODE *hnode;
5080 #ifdef REG_TEST
5081      static uint32_t addstaticfrag_cnt, delstaticfrag_cnt;
5082 #endif
5083 
5084      Frag3Config *newConfig = (Frag3Config *)sfPolicyUserDataGetCurrent(frag3_config);
5085      pkt_snaplen = DAQ_GetSnapLen();
5086 
5087      if(newConfig->static_frags == old_static_frags)
5088 	 return maxWork;
5089 
5090      else if(newConfig->static_frags > old_static_frags)
5091      {
5092 	if(newConfig->use_prealloc)
5093 	{
5094 	   for(;maxWork && (newConfig->static_frags > old_static_frags); maxWork--,old_static_frags++)
5095 	   {
5096                 tmp = (Frag3Frag *) SnortPreprocAlloc(1, sizeof(Frag3Frag), PP_FRAG3,
5097                                         PP_MEM_CATEGORY_CONFIG);
5098                 tmp->fptr = (uint8_t *) SnortPreprocAlloc(pkt_snaplen, sizeof(uint8_t),
5099                                       PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5100                 Frag3PreallocPush(tmp);
5101 		prealloc_nodes_in_use++;
5102 #ifdef REG_TEST
5103 		addstaticfrag_cnt++;
5104 #endif
5105 	   }
5106 	}
5107      }
5108      else
5109      {
5110         for(;maxWork && (newConfig->static_frags < old_static_frags); maxWork--,old_static_frags--)
5111         {
5112 	   tmp = Frag3PreallocPop();
5113            if (tmp)
5114            {
5115                 SnortPreprocFree(tmp->fptr, pkt_snaplen * sizeof(uint8_t),
5116                            PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5117                 SnortPreprocFree(tmp, sizeof(Frag3Frag), PP_FRAG3,
5118                            PP_MEM_CATEGORY_CONFIG);
5119 	        prealloc_nodes_in_use--;
5120 #ifdef REG_TEST
5121                 delstaticfrag_cnt++;
5122 #endif
5123           }
5124 	  else
5125 	  {
5126 	    /*exhausted prealloc frags */
5127 	    break;
5128 	  }
5129 	}
5130 	if(maxWork && (newConfig->static_frags < old_static_frags))
5131 	{
5132             for (;maxWork && (newConfig->static_frags < old_static_frags); maxWork--,old_static_frags--)
5133             {
5134                  hnode = sfxhash_lru_node(f_cache);
5135                 if (hnode)
5136                 {
5137                         Frag3RemoveTracker(hnode->key, hnode->data);
5138 			tmp = Frag3PreallocPop();
5139 		        if (tmp)
5140 	                {
5141 		             SnortPreprocFree(tmp->fptr, pkt_snaplen * sizeof(uint8_t),
5142                                      PP_FRAG3, PP_MEM_CATEGORY_CONFIG);
5143 		             SnortPreprocFree(tmp, sizeof(Frag3Frag), PP_FRAG3,
5144                                      PP_MEM_CATEGORY_CONFIG);
5145 			     prealloc_nodes_in_use--;
5146 		        }
5147 #ifdef REG_TEST
5148 		        delstaticfrag_cnt++;
5149 #endif
5150                  }
5151             }
5152 	}
5153      }
5154 #ifdef REG_TEST
5155         if (REG_TEST_FLAG_RELOAD & getRegTestFlags())
5156         {
5157             if(newConfig->static_frags == old_static_frags)
5158 	    {
5159 		if(addstaticfrag_cnt)
5160 			printf("Total prealloc frag nodes added    : %u\n",addstaticfrag_cnt);
5161 		if(delstaticfrag_cnt)
5162 			printf("Total prealloc frag nodes deleted  : %u\n",delstaticfrag_cnt);
5163 	    }
5164         }
5165 #endif
5166      return maxWork;
5167 }
5168 
Frag3ReloadAdjust(bool idle,tSfPolicyId raPolicyId,void * userData)5169 static bool Frag3ReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
5170 {
5171    unsigned initialMaxWork = idle ? 2048 : 5;
5172    unsigned maxWork;
5173    int iRet = -1;
5174 
5175    maxWork = Frag3MemReloadAdjust(initialMaxWork);
5176 
5177    if(maxWork)
5178    {
5179      iRet = sfxhash_change_memcap(f_cache, fcache_new_memcap, &maxWork);
5180 
5181 #ifdef REG_TEST
5182      if(iRet == SFXHASH_OK && maxWork)
5183      {
5184        if (REG_TEST_FLAG_RELOAD & getRegTestFlags())
5185        {
5186           printf("Successfully updated Frag cache memcap :%lu\n",f_cache->mc.memcap);
5187        }
5188      }
5189 #endif
5190    }
5191    return (maxWork != 0) ? true : false;
5192 }
5193 
5194 
Frag3ReloadVerify(struct _SnortConfig * sc,void * swap_config)5195 static int Frag3ReloadVerify(struct _SnortConfig *sc, void *swap_config)
5196 {
5197     int rval;
5198     tSfPolicyUserContextId frag3_swap_config = (tSfPolicyUserContextId)swap_config;
5199     Frag3Config *pCurrDefaultPolicyConfig = NULL;
5200     Frag3Config *pSwapDefaultPolicyConfig = NULL;
5201     tSfPolicyId policy_id = 0;
5202 
5203     pCurrDefaultPolicyConfig = (Frag3Config *)sfPolicyUserDataGetDefault(frag3_config);
5204     pSwapDefaultPolicyConfig = (Frag3Config *)sfPolicyUserDataGetDefault(frag3_swap_config);
5205 
5206     if ((frag3_swap_config == NULL) || (frag3_config == NULL))
5207         return 0;
5208 
5209     if ((rval = sfPolicyUserDataIterate (sc, frag3_swap_config, Frag3ReloadVerifyPolicy)))
5210         return rval;
5211 
5212     policy_id = getParserPolicy(sc);
5213     if ((pSwapDefaultPolicyConfig->static_frags != pCurrDefaultPolicyConfig->static_frags) ||
5214 	(pSwapDefaultPolicyConfig->max_frags != pCurrDefaultPolicyConfig->max_frags))
5215     {
5216 	unsigned long max_frag_mem, table_mem;
5217 
5218         old_static_frags = pCurrDefaultPolicyConfig->static_frags;
5219 
5220         max_frag_mem = pSwapDefaultPolicyConfig->max_frags * (
5221                sizeof(FragTracker) +
5222                sizeof(SFXHASH_NODE) +
5223                sizeof (FRAGKEY) +
5224                sizeof(SFXHASH_NODE *));
5225         table_mem = (hashTableSize + 1) * sizeof(SFXHASH_NODE *);
5226         fcache_new_memcap = max_frag_mem + table_mem;
5227 
5228 #ifdef REG_TEST
5229           if (REG_TEST_FLAG_RELOAD & getRegTestFlags())
5230           {
5231              printf("prealloc static frags old conf : %d new conf : %d\n",old_static_frags,pSwapDefaultPolicyConfig->static_frags);
5232              if (pSwapDefaultPolicyConfig->use_prealloc)
5233                 printf("use_prealloc is enabled!\n");
5234              else
5235                printf("use_prealloc is disabled!\n");
5236 	     printf("Frag cache new memcap value: %lu\n",fcache_new_memcap);
5237           }
5238 #endif
5239           ReloadAdjustRegister(sc, "Frag3Reload", policy_id, &Frag3ReloadAdjust, NULL, NULL);
5240     }
5241 
5242     return 0;
5243 }
5244 
Frag3ReloadSwapPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)5245 static int Frag3ReloadSwapPolicy(
5246         tSfPolicyUserContextId config,
5247         tSfPolicyId policyId,
5248         void* pData
5249         )
5250 {
5251     Frag3Config *pPolicyConfig = (Frag3Config *)pData;
5252 
5253     //do any housekeeping before freeing Frag3Config
5254     if (pPolicyConfig->ref_count == 0)
5255     {
5256         sfPolicyUserDataClear (config, policyId);
5257         Frag3FreeConfig(pPolicyConfig);
5258     }
5259 
5260     return 0;
5261 }
5262 
Frag3ReloadSwap(struct _SnortConfig * sc,void * swap_config)5263 static void * Frag3ReloadSwap(struct _SnortConfig *sc, void *swap_config)
5264 {
5265     tSfPolicyUserContextId frag3_swap_config = (tSfPolicyUserContextId)swap_config;
5266     tSfPolicyUserContextId old_config = frag3_config;
5267 
5268     if (frag3_swap_config == NULL)
5269         return NULL;
5270 
5271     frag3_config = frag3_swap_config;
5272 
5273     sfPolicyUserDataFreeIterate (old_config, Frag3ReloadSwapPolicy);
5274 
5275     if (sfPolicyUserPolicyGetActive(old_config) == 0)
5276         return (void *)old_config;
5277 
5278     return NULL;
5279 }
5280 
Frag3ReloadSwapFree(void * data)5281 static void Frag3ReloadSwapFree(void *data)
5282 {
5283     if (data == NULL)
5284         return;
5285 
5286     Frag3FreeConfigs((tSfPolicyUserContextId)data);
5287 }
5288 #endif
5289