"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/preprocessors/spp_frag3.c" (16 Oct 2020, 160308 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spp_frag3.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

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