Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spp_frag3.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /**
00004  * @file    spp_frag3.c
00005  * @author  Martin Roesch <roesch@sourcefire.com>
00006  * @date    Thu Sep 30 14:12:37 EDT 2004
00007  *
00008  * @brief   Frag3: IP defragmentation preprocessor for Snort. 
00009  */
00010 
00011 /*
00012  ** Copyright (C) 2004 Sourcefire Inc.
00013  **
00014  ** This program is free software; you can redistribute it and/or modify
00015  ** it under the terms of the GNU General Public License as published by
00016  ** the Free Software Foundation; either version 2 of the License, or
00017  ** (at your option) any later version.
00018  **
00019  ** This program is distributed in the hope that it will be useful,
00020  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  ** GNU General Public License for more details.
00023  **
00024  ** You should have received a copy of the GNU General Public License
00025  ** along with this program; if not, write to the Free Software
00026  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00027  */
00028 
00029 /*
00030  * Notes: 
00031  * Frag3 sports the following improvements over frag2:
00032  *  - Target-based IP defragmentation, harder to evade
00033  *  - 8 Anomaly detection event types
00034  *  - Two separate memory management strategies to tailor
00035  *    performance for specific environments
00036  *  - Up to 250% faster than frag2.
00037  *
00038  *  The mechanism for processing frags is based on the Linux IP stack 
00039  *  implementation of IP defragmentation with proper amounts of paranoia
00040  *  and an IDS perspective applied.  Some of this code was derived from 
00041  *  frag2 originally, but it's basically unrecognizeable if you compare
00042  *  it to frag2 IMO.
00043  *
00044  *  I switched from using the UBI libs to using sfxhash and linked lists for 
00045  *  fragment management because I suspected that the management code was 
00046  *  the cause of performance issues that we were observing at Sourcefire 
00047  *  in certain customer situations.  Splay trees are cool and really hard
00048  *  to screw with from an attack perspective, but they also incur a lot 
00049  *  of overhead for managing the tree and lose the order of the fragments in 
00050  *  the FragTracker's fraglist, so I dropped them.  Originally the
00051  *  frag3 code was just supposed to migrate away from the splay tree system
00052  *  that I was using in frag2, but I figured since I was doing the work to
00053  *  pull out the splay trees I may as well solve some of the other problems
00054  *  we were seeing.  
00055  *
00056  *  Initial performance testing that I've done shows that frag3 can be as much
00057  *  as 250% faster than frag2, but we still need to do more testing and 
00058  *  optimization, we may be able to squeeze out some more performance.
00059  *
00060  *  Frag3 is also capable of performing "Target-based" IP defragmentation.  
00061  *  What this means practically is that frag3 can model the IP stack of a
00062  *  target on the network to avoid Ptacek-Newsham evasions of the IDS through
00063  *  sensor/target desynchronization.  In terms of implentation, this is
00064  *  reflected by passing a "context" into the defragmentation engine that has
00065  *  a specific configuration for a specific target type.  Windows can put
00066  *  fragments back together differently than Linux/BSD/etc, so we model that
00067  *  inside frag3 so we can't be evaded.
00068  *
00069  *  Configuration of frag3 is pretty straight forward, there's a global config
00070  *  that contains data about how the hash tables will be structured, what type
00071  *  of memory management to use and whether or not to generate alerts, then
00072  *  specific target-contexts are setup and bound to IP address sets.  Check
00073  *  the README file for specifics!
00074  */
00075 
00076 /*  I N C L U D E S  ************************************************/
00077 #ifdef HAVE_CONFIG_H
00078 #include "config.h"
00079 #endif
00080 
00081 #include <sys/types.h>
00082 #include <stdlib.h>
00083 #include <ctype.h>
00084 #include <rpc/types.h>
00085 
00086 #include "bounds.h"
00087 #include "generators.h"
00088 #include "log.h"
00089 #include "detect.h"
00090 #include "decode.h"
00091 #include "event.h"
00092 #include "util.h"
00093 #include "debug.h"
00094 #include "plugbase.h"
00095 #include "parser.h"
00096 #include "mstring.h"
00097 #include "checksum.h"
00098 #include "perf.h"
00099 #include "event_queue.h"
00100 #include "timersub.h"
00101 #include "fpcreate.h"
00102 
00103 #include "sfutil/sflsq.h"
00104 #include "sfutil/sfxhash.h"
00105 
00106 #include "snort.h"
00107 extern OptTreeNode *otn_tmp;
00108 
00109 /*  D E F I N E S  **************************************************/
00110 
00111 /* flags for the FragTracker->frag_flags field */
00112 #define FRAG_GOT_FIRST      0x00000001
00113 #define FRAG_GOT_LAST       0x00000002
00114 #define FRAG_REBUILT        0x00000004
00115 #define FRAG_BAD            0x00000008
00116 
00117 #define FRAG_PRUNE_QUANTA   60          /* default frag timeout, 90-120 might 
00118                                          * be better values, can we do 
00119                                          * target-based quanta?
00120                                          */
00121 
00122 #define FRAG_MEMCAP         4194304     /* default 4MB memcap */
00123 
00124 #define FRAG3_TTL_LIMIT      5          /* default TTL, unnecessary in 
00125                                          * tgt-based systems? */
00126 #define FRAG3_MIN_TTL        1          /* min acceptable ttl (should be 1?) */
00127 
00128 /* target-based defragmentation policy enums */
00129 #define FRAG_POLICY_FIRST       1
00130 #define FRAG_POLICY_LINUX       2
00131 #define FRAG_POLICY_BSD         3
00132 #define FRAG_POLICY_BSD_RIGHT   4
00133 #define FRAG_POLICY_LAST        5
00134 #define FRAG_POLICY_WINDOWS     6 /* Combo of FIRST & LAST, depending on
00135                                    * overlap situation.
00136                                    */
00137 #define FRAG_POLICY_SOLARIS     7 /* Combo of FIRST & LAST, depending on
00138                                    * overlap situation.
00139                                    */
00140 
00141 /* the twiddle is needed for architectures that force word-aligned memory
00142  * access 
00143  */
00144 #if defined (SOLARIS) || defined (SUNOS) || defined (__sparc__) || defined(__sparc64__) || defined (HPUX)
00145 #define SPARC_TWIDDLE       2
00146 #else
00147 #define SPARC_TWIDDLE       0
00148 #endif
00149 
00150 /* max packet size */
00151 #define DATASIZE (ETHERNET_HEADER_LEN+IP_MAXPACKET)
00152 
00153 /* max frags in a single frag tracker */
00154 #define DEFAULT_MAX_FRAGS   8192
00155 
00156 /* return values for CheckTimeout() */
00157 #define FRAG_TIME_OK            0
00158 #define FRAG_TIMEOUT            1
00159 
00160 /* return values for Frag3Insert() */
00161 #define FRAG_INSERT_OK          0
00162 #define FRAG_INSERT_FAILED      1
00163 #define FRAG_INSERT_REJECTED    2
00164 #define FRAG_INSERT_TIMEOUT     3
00165 #define FRAG_INSERT_ATTACK      4
00166 #define FRAG_INSERT_ANOMALY     5
00167 #define FRAG_INSERT_TTL         6
00168 
00169 /* return values for Frag3CheckFirstLast() */
00170 #define FRAG_FIRSTLAST_OK       0
00171 #define FRAG_LAST_DUPLICATE     1
00172 
00173 /* return values for Frag3Expire() */
00174 #define FRAG_OK                 0
00175 #define FRAG_TRACKER_TIMEOUT    1
00176 #define FRAG_LAST_OFFSET_ADJUST 2
00177 
00178 /* flag for detecting attacks/alerting */
00179 #define FRAG3_DETECT_ANOMALIES  0x01
00180 
00181 /*  D A T A   S T R U C T U R E S  **********************************/
00182 
00183 /* global configuration data struct for this preprocessor */
00184 typedef struct 
00185 {
00186     u_int32_t max_frags;        /* max frags to track */
00187     u_int32_t memcap;           /* memcap for frag3 */
00188     u_int32_t static_frags;     /* static frag nodes to keep around */
00189     u_int8_t use_prealloc;      /* flag to indicate prealloc nodes in use */
00190 
00191 } Frag3GlobalConfig;
00192 
00193 /* runtime context for a specific instance of an engine */
00194 typedef struct _Frag3Context
00195 {
00196     u_int16_t frag_policy;  /* policy to use for target-based reassembly */
00197     int32_t frag_timeout; /* timeout for frags in this policy */
00198 
00199     u_int8_t min_ttl;       /* Minimum TTL to accept */
00200     u_int8_t ttl_limit;     /* Size of ttls to avoid detection on */
00201 
00202     char frag3_alerts;      /* Whether or not frag3 alerts are enabled */
00203 
00204     IpAddrSet *bound_addrs; /* addresses bound to this context */
00205 
00206 } Frag3Context;
00207 
00208 /* struct to manage an individual fragment */
00209 typedef struct _Frag3Frag
00210 {
00211     u_int8_t *data;     /* ptr to adjusted start position */
00212     u_int16_t size;     /* adjusted frag size */
00213     u_int16_t offset;   /* adjusted offset position */
00214 
00215     u_int8_t *fptr;     /* free pointer */
00216     u_int16_t flen;     /* free len, unneeded? */
00217 
00218     struct _Frag3Frag *prev;
00219     struct _Frag3Frag *next;
00220 
00221     int ord;
00222     char last;
00223 } Frag3Frag;
00224 
00225 /* key struct for the sfxhash */
00226 typedef struct _fragkey
00227 {
00228     u_int32_t sip;      /* src IP */
00229     u_int32_t dip;      /* dst IP */
00230     u_int16_t id;       /* IP ID */
00231     u_int8_t proto;     /* IP protocol */
00232 } FRAGKEY;
00233 
00234 /* Only track a certain number of alerts per session */
00235 #define MAX_FRAG_ALERTS  8
00236 
00237 /* tracker for a fragmented packet set */
00238 typedef struct _FragTracker
00239 {
00240     u_int32_t sip;          /* src IP */
00241     u_int32_t dip;          /* dst IP */
00242     u_int16_t id;           /* IP ID */
00243     u_int8_t protocol;      /* IP protocol */
00244 
00245     u_int8_t ttl;           /* ttl used to detect evasions */
00246     u_int8_t alerted;
00247     u_int32_t frag_flags;   /* bit field */
00248 
00249     u_int32_t frag_bytes;   /* number of fragment bytes stored, based 
00250                              * on aligned fragment offsets/sizes
00251                              */
00252 
00253     u_int32_t calculated_size; /* calculated size of reassembled pkt, based on 
00254                                 * last frag offset
00255                                 */
00256 
00257     u_int32_t frag_pkts;   /* nummber of frag pkts stored under this tracker */
00258 
00259     struct timeval frag_time; /* time we started tracking this frag */
00260 
00261     Frag3Frag *fraglist;      /* list of fragments */
00262     Frag3Frag *fraglist_tail; /* tail ptr for easy appending */
00263     int fraglist_count;       /* handy dandy counter */
00264 
00265     u_int32_t alert_gid[MAX_FRAG_ALERTS]; /* flag alerts seen in a frag list  */
00266     u_int32_t alert_sid[MAX_FRAG_ALERTS]; /* flag alerts seen in a frag list  */
00267     u_int8_t  alert_count;                /* count alerts seen in a frag list */
00268 
00269     u_int32_t ip_options_len;  /* length of ip options for this set of frags */
00270     u_int32_t ip_option_count; /* number of ip options for this set of frags */
00271     u_int8_t *ip_options_data; /* ip options from offset 0 packet */
00272 
00273     u_int32_t copied_ip_options_len;  /* length of 'copied' ip options */
00274     u_int32_t copied_ip_option_count; /* number of 'copied' ip options */
00275 
00276     Frag3Context *context;
00277 
00278     int ordinal;
00279 
00280 } FragTracker;
00281 
00282 /* statistics tracking struct */
00283 typedef struct _Frag3Stats
00284 {
00285     u_int32_t  total;
00286     u_int32_t  overlaps;
00287     u_int32_t  reassembles;
00288     u_int32_t  prunes;
00289     u_int32_t  timeouts;
00290     u_int32_t  fragtrackers_created;
00291     u_int32_t  fragtrackers_released;
00292     u_int32_t  fragtrackers_autoreleased;
00293     u_int32_t  fragnodes_created;
00294     u_int32_t  fragnodes_released;
00295     u_int32_t  discards;
00296     u_int32_t  anomalies;
00297     u_int32_t  alerts;
00298 
00299 } Frag3Stats;
00300 
00301 
00302 /*  G L O B A L S  **************************************************/
00303 static Frag3GlobalConfig global_config;  /* global configuration struct */
00304 static SFXHASH *f_cache;                 /* fragment hash table */
00305 static Frag3Frag *prealloc_frag_list;    /* head for prealloc queue */
00306 
00307 static char global_init_complete;   /* flag to signal f_cache initialization */ 
00308 
00309 static u_int32_t mem_in_use;             /* memory in use, used for self pres */
00310 
00311 static u_int32_t prealloc_nodes_in_use;  /* counter for debug */
00312 static int ten_percent;                  /* holder for self preservation data */
00313 
00314 static Frag3Stats f3stats;               /* stats struct */
00315 static u_int8_t stats_registered;        /* make sure we only print stats once
00316                                             per run */
00317 
00318 static Packet *defrag_pkt;               /* holder for prealloc'd defrag pkt */
00319 
00320 /* enum for policy names */
00321 static char *policy_names[] = { "no policy!",
00322     "FIRST",
00323     "LINUX",
00324     "BSD",
00325     "BSD_RIGHT",
00326     "LAST",
00327     "WINDOWS",
00328     "SOLARIS"};
00329 
00330 /*
00331  * external globals for startup
00332  */
00333 extern char *file_name;             
00334 extern int file_line;                
00335 extern u_int snaplen;
00336 extern SFPERF sfPerf;
00337 
00338 
00339 /*  P R O T O T Y P E S  ********************************************/
00340 static void Frag3ParseGlobalArgs(u_char *);
00341 static void Frag3ParseArgs(u_char *, Frag3Context *);
00342 static FragTracker *Frag3GetTracker(Packet *, FRAGKEY *);
00343 static int Frag3NewTracker(Packet *p, FRAGKEY *fkey, Frag3Context *);
00344 static int Frag3Insert(Packet *, FragTracker *, FRAGKEY *, Frag3Context *);
00345 static void Frag3Rebuild(FragTracker *, Packet *);
00346 static int INLINE Frag3IsComplete(FragTracker *);
00347 static int Frag3HandleIPOptions(FragTracker *, Packet *);
00348 static void Frag3InitPkt();
00349 
00350 /* deletion funcs */
00351 static int Frag3Prune(FragTracker *);
00352 static struct timeval *pkttime;    /* packet timestamp */
00353 static void Frag3DeleteFrag(Frag3Frag *);
00354 static void Frag3RemoveTracker(void *, void *);
00355 static void Frag3DeleteTracker(FragTracker *);
00356 static int Frag3AutoFree(void *, void *);
00357 static int Frag3UserFree(void *, void *);
00358 
00359 /* fraglist handler funcs */
00360 static INLINE void Frag3FraglistAddNode(FragTracker *, Frag3Frag *, Frag3Frag *); 
00361 static INLINE void Frag3FraglistDeleteNode(FragTracker *, Frag3Frag *);
00362 
00363 /* prealloc queue handler funcs */
00364 static INLINE Frag3Frag *Frag3PreallocPop();
00365 static INLINE void Frag3PreallocPush(Frag3Frag *);
00366 
00367 /* main preprocessor functions */
00368 void Frag3Defrag(Packet *, void *);
00369 void Frag3CleanExit(int, void *);
00370 void Frag3Restart(int, void *);
00371 void Frag3Init(u_char *);
00372 void Frag3GlobalInit(u_char *);
00373 
00374 #ifdef DEBUG_FRAG3
00375 /**
00376  * Print out a FragTracker structure
00377  *
00378  * @param ft Pointer to the FragTracker to print
00379  *
00380  * @return none
00381  */
00382 static void PrintFragTracker(FragTracker *ft)
00383 {
00384     LogMessage("FragTracker %p\n", ft);
00385     if(ft)
00386     {
00387         LogMessage("        sip: 0x%08X\n", ft->sip);
00388         LogMessage("        dip: 0x%08X\n", ft->dip);
00389         LogMessage("         id: %d\n", ft->id);
00390         LogMessage("      proto: 0x%X\n", ft->protocol);
00391         LogMessage("        ttl: %d\n", ft->ttl);
00392         LogMessage("    alerted: %d\n", ft->alerted);
00393         LogMessage(" frag_flags: 0x%X\n", ft->frag_flags);
00394         LogMessage(" frag_bytes: %d\n", ft->frag_bytes);
00395         LogMessage("  calc_size: %d\n", ft->calculated_size);
00396         LogMessage("  frag_pkts: %d\n", ft->frag_pkts);
00397         LogMessage("  frag_time: %lu %lu\n", ft->frag_time.tv_sec, 
00398                 ft->frag_time.tv_usec);
00399         LogMessage("   fraglist: %p\n", ft->fraglist);
00400         LogMessage("    fl_tail: %p\n", ft->fraglist_tail);
00401         LogMessage("fraglst cnt: %d\n", ft->fraglist_count);
00402     }
00403 }
00404 
00405 /**
00406  * Print out a FragKey structure
00407  *
00408  * @param fkey Pointer to the FragKey to print
00409  *
00410  * @return none
00411  */
00412 static void PrintFragKey(FRAGKEY *fkey)
00413 {
00414     LogMessage("FragKey %p\n", fkey);
00415 
00416     if(fkey)
00417     {
00418         LogMessage("    sip: 0x%08X\n", fkey->sip);
00419         LogMessage("    dip: 0x%08X\n", fkey->dip);
00420         LogMessage("     id: %d\n", fkey->id);
00421         LogMessage("  proto: 0x%X\n", fkey->proto);
00422     }
00423 }
00424 
00425 /**
00426  * Print out a Frag3Frag structure
00427  *
00428  * @param f Pointer to the Frag3Frag to print
00429  *
00430  * @return none
00431  */
00432 static void PrintFrag3Frag(Frag3Frag *f)
00433 {
00434     LogMessage("Frag3Frag: %p\n", f);
00435 
00436     if(f)
00437     {
00438         LogMessage("    data: %p\n", f->data);
00439         LogMessage("    size: %d\n", f->size);
00440         LogMessage("  offset: %d\n", f->offset);
00441         LogMessage("    fptr: %p\n", f->fptr);
00442         LogMessage("    flen: %d\n", f->flen);
00443         LogMessage("    prev: %p\n", f->prev);
00444         LogMessage("    next: %p\n", f->next);
00445     }
00446 }
00447 
00448 #endif  /* DEBUG_FRAG3 */
00449 
00450 /**
00451  * Print out the global runtime configuration
00452  *
00453  * @param None
00454  *
00455  * @return none
00456  */
00457 static void Frag3PrintGlobalConfig()
00458 {
00459     LogMessage("Frag3 global config:\n");
00460     LogMessage("    Max frags: %d\n", global_config.max_frags);
00461     if(!global_config.use_prealloc)
00462         LogMessage("    Fragment memory cap: %lu bytes\n", 
00463                 (unsigned long)global_config.memcap);
00464     else
00465         LogMessage("    Preallocated frag nodes: %lu\n", 
00466                 global_config.static_frags);
00467 }
00468 
00469 
00470 /**
00471  * Print out a defrag engine runtime context
00472  *
00473  * @param context Pointer to the context structure to print
00474  *
00475  * @return none
00476  */
00477 static void Frag3PrintEngineConfig(Frag3Context *context)
00478 {
00479     LogMessage("Frag3 engine config:\n");
00480     LogMessage("    Target-based policy: %s\n", 
00481             policy_names[context->frag_policy]);
00482     LogMessage("    Fragment timeout: %d seconds\n", 
00483             context->frag_timeout);
00484     LogMessage("    Fragment min_ttl:   %d\n", context->min_ttl);
00485     LogMessage("    Fragment ttl_limit: %d\n", context->ttl_limit);
00486     LogMessage("    Fragment Problems: %X\n", context->frag3_alerts);
00487     //LogMessage("    Bound Addresses:\n");
00488     IpAddrSetPrint("    Bound Addresses: ", context->bound_addrs);
00489 }
00490 
00491 /**
00492  * Generate an event due to IP options being detected in a frag packet
00493  *
00494  * @param context Current run context
00495  *
00496  * @return none
00497  */
00498 static INLINE void EventAnomIpOpts(Frag3Context *context)
00499 {
00500     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00501         return;
00502 
00503     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */ 
00504             FRAG3_IPOPTIONS,         /* SID */
00505             1,                       /* rev */
00506             0,                       /* classification enum */
00507             3,                       /* priority (low) */
00508             FRAG3_IPOPTIONS_STR,     /* event message */
00509             NULL);                   /* rule info ptr */
00510 
00511    f3stats.alerts++;
00512 }
00513 
00514 /**
00515  * Generate an event due to a Teardrop-style attack detected in a frag packet
00516  *
00517  * @param context Current run context
00518  *
00519  * @return none
00520  */
00521 static INLINE void EventAttackTeardrop(Frag3Context *context)
00522 {
00523     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00524         return;
00525 
00526     SnortEventqAdd(GENERATOR_SPP_FRAG3,     /* GID */ 
00527             FRAG3_TEARDROP,          /* SID */
00528             1,                       /* rev */
00529             0,                       /* classification enum */
00530             3,                       /* priority (low) */
00531             FRAG3_TEARDROP_STR,      /* event message */
00532             NULL);                   /* rule info ptr */
00533 
00534    f3stats.alerts++;
00535 }
00536 
00537 /**
00538  * Generate an event due to a fragment being too short, typcially based
00539  * on a non-last fragment that doesn't properly end on an 8-byte boundary
00540  *
00541  * @param context Current run context
00542  *
00543  * @return none
00544  */
00545 static INLINE void EventAnomShortFrag(Frag3Context *context)
00546 {
00547     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00548         return;
00549 
00550     SnortEventqAdd(GENERATOR_SPP_FRAG3,   /* GID */ 
00551             FRAG3_SHORT_FRAG,             /* SID */
00552             1,                            /* rev */
00553             0,                            /* classification enum */
00554             3,                            /* priority (low) */
00555             FRAG3_SHORT_FRAG_STR,         /* event message */
00556             NULL);                        /* rule info ptr */
00557 
00558    f3stats.alerts++;
00559    f3stats.anomalies++;
00560 }
00561 
00562 /**
00563  * This fragment's size will end after the already calculated reassembled
00564  * fragment end, as in a Bonk/Boink/etc attack.
00565  *
00566  * @param context Current run context
00567  *
00568  * @return none
00569  */
00570 static INLINE void EventAnomOversize(Frag3Context *context)
00571 {
00572     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00573         return;
00574 
00575     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */ 
00576             FRAG3_ANOMALY_OVERSIZE,  /* SID */
00577             1,                       /* rev */
00578             0,                       /* classification enum */
00579             3,                       /* priority (low) */
00580             FRAG3_ANOM_OVERSIZE_STR, /* event message */
00581             NULL);                   /* rule info ptr */
00582 
00583    f3stats.alerts++;
00584    f3stats.anomalies++;
00585 }
00586 
00587 /**
00588  * The current fragment will be inserted with a size of 0 bytes, that's
00589  * an anomaly if I've ever seen one.
00590  *
00591  * @param context Current run context
00592  *
00593  * @return none
00594  */
00595 static INLINE void EventAnomZeroFrag(Frag3Context *context)
00596 {
00597     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00598         return;
00599 
00600     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */ 
00601             FRAG3_ANOMALY_ZERO,      /* SID */
00602             1,                       /* rev */
00603             0,                       /* classification enum */
00604             3,                       /* priority (low) */
00605             FRAG3_ANOM_ZERO_STR,     /* event message */
00606             NULL);                   /* rule info ptr */
00607 
00608    f3stats.alerts++;
00609    f3stats.anomalies++;
00610 }
00611 
00612 /**
00613  * The reassembled packet will be bigger than 64k, generate an event.
00614  *
00615  * @param context Current run context
00616  *
00617  * @return none
00618  */
00619 static INLINE void EventAnomBadsizeLg(Frag3Context *context)
00620 {
00621     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00622         return;
00623 
00624     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */ 
00625             FRAG3_ANOMALY_BADSIZE_LG,   /* SID */
00626             1,                       /* rev */
00627             0,                       /* classification enum */
00628             3,                       /* priority (low) */
00629             FRAG3_ANOM_BADSIZE_LG_STR,  /* event message */
00630             NULL);                   /* rule info ptr */
00631 
00632    f3stats.alerts++;
00633    f3stats.anomalies++;
00634 }
00635 
00636 /**
00637  * Fragment size is negative after insertion (end < offset).
00638  *
00639  * @param context Current run context
00640  *
00641  * @return none
00642  */
00643 static INLINE void EventAnomBadsizeSm(Frag3Context *context)
00644 {
00645     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00646         return;
00647 
00648     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */ 
00649             FRAG3_ANOMALY_BADSIZE_SM,  /* SID */
00650             1,                         /* rev */
00651             0,                         /* classification enum */
00652             3,                         /* priority (low) */
00653             FRAG3_ANOM_BADSIZE_SM_STR, /* event message */
00654             NULL);                     /* rule info ptr */
00655 
00656    f3stats.alerts++;
00657    f3stats.anomalies++;
00658 }
00659 
00660 /**
00661  * There is an overlap with this fragment, someone is probably being naughty.
00662  *
00663  * @param context Current run context
00664  *
00665  * @return none
00666  */
00667 static INLINE void EventAnomOverlap(Frag3Context *context)
00668 {
00669     if(!(context->frag3_alerts & FRAG3_DETECT_ANOMALIES))
00670         return;
00671 
00672     SnortEventqAdd(GENERATOR_SPP_FRAG3,/* GID */ 
00673             FRAG3_ANOMALY_OVLP,   /* SID */
00674             1,                    /* rev */
00675             0,                    /* classification enum */
00676             3,                    /* priority (low) */
00677             FRAG3_ANOM_OVLP_STR,  /* event message */
00678             NULL);                /* rule info ptr */
00679 
00680    f3stats.alerts++;
00681    f3stats.anomalies++;
00682 }
00683 
00684 /**
00685  * Main setup function to regiser frag3 with the rest of Snort.
00686  *
00687  * @param none
00688  *
00689  * @return none
00690  */
00691 void SetupFrag3()
00692 {
00693     RegisterPreprocessor("frag3_global", Frag3GlobalInit);
00694     RegisterPreprocessor("frag3_engine", Frag3Init);
00695     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Preprocessor: frag3 is setup...\n"););
00696 }
00697 
00698 /**
00699  * Global init function, handles setting up the runtime hash table and 
00700  * memory management mode.
00701  *
00702  * @param args argument string to process for config data
00703  *
00704  * @return none
00705  */
00706 void Frag3GlobalInit(u_char *args)
00707 {
00708     Frag3Frag *tmp; /* for initializing the prealloc queue */
00709     unsigned int i;          /* counter */
00710 
00711     /*
00712      * setup default values
00713      */
00714     global_config.max_frags = DEFAULT_MAX_FRAGS;
00715     global_config.memcap = FRAG_MEMCAP;
00716     global_config.static_frags = 0;
00717     global_config.use_prealloc = 0;
00718 
00719     Frag3ParseGlobalArgs(args);
00720 
00721     /* 
00722      * we really only need one frag cache no matter how many different
00723      * contexts we have loaded
00724      */
00725     if(f_cache == NULL)
00726     {
00727         /* we keep FragTrackers in the hash table.. */
00728         int hashTableSize = (int) (global_config.max_frags * 1.4);
00729         int maxFragMem = global_config.max_frags * (
00730                             sizeof(FragTracker) + 
00731                             sizeof(SFXHASH_NODE) +
00732                             sizeof (FRAGKEY) +
00733                             sizeof(SFXHASH_NODE *));
00734         int tableMem = (hashTableSize + 1) * sizeof(SFXHASH_NODE *);
00735         int maxMem = maxFragMem + tableMem;
00736         f_cache = sfxhash_new(
00737                 hashTableSize,       /* number of hash buckets */
00738                 sizeof(FRAGKEY),     /* size of the key we're going to use */
00739                 sizeof(FragTracker), /* size of the storage node */
00740                 maxMem,              /* memcap for frag trackers */
00741                 1,                   /* use auto node recovery */
00742                 Frag3AutoFree,       /* anr free function */
00743                 Frag3UserFree,       /* user free function */
00744                 1);                  /* recycle node flag */
00745     }
00746 
00747     /*
00748      * can't proceed if we can't get a fragment cache
00749      */
00750     if(!f_cache)
00751     {
00752         LogMessage("WARNING: Unable to generate new sfxhash for frag3, "
00753                 "defragmentation disabled!\n");
00754         return;
00755     }
00756 
00757     /* 
00758      * user has decided to prealloc the node structs for performance 
00759      */
00760     if(global_config.static_frags)
00761     {
00762         for(i=0; i< global_config.static_frags; i++)
00763         {
00764             tmp = (Frag3Frag *) SnortAlloc(sizeof(Frag3Frag));
00765             tmp->fptr = (u_int8_t *) SnortAlloc(sizeof(u_int8_t) * snaplen);
00766             Frag3PreallocPush(tmp);
00767         }
00768 
00769         prealloc_nodes_in_use = 0;
00770     }
00771 
00772     /* 
00773      * preallocate the reassembled packet struct 
00774      */
00775     defrag_pkt = (Packet *)SnortAlloc(sizeof(Packet));
00776 
00777     /*
00778      * setup the reassembly pseudopacket
00779      */
00780     Frag3InitPkt();
00781 
00782     /* 
00783      * indicate that we've got a global config active 
00784      */
00785     global_init_complete = 1;
00786 
00787     /*
00788      * display the global config for the user
00789      */
00790     Frag3PrintGlobalConfig();
00791 
00792     return;
00793 }
00794 
00795 /**
00796  * Setup a frag3 engine context
00797  *
00798  * @param args list of configuration arguments
00799  *
00800  * @return none
00801  */
00802 void Frag3Init(u_char *args)
00803 {
00804     PreprocessFuncNode *pfn;    /* place to attach the runtime context */
00805     Frag3Context *context;      /* context pointer */ 
00806 
00807     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Initializing frag3\n"););
00808 
00809     context = (Frag3Context *) SnortAlloc(sizeof(Frag3Context));
00810 
00811     if(!global_init_complete)
00812     {
00813         LogMessage("[!] WARNING: Unable to configure frag3 engine!\n"
00814                 "Frag3 global config has not been established, "
00815                 "please issue a \"preprocessor frag3_global\" directive\n");
00816         return;
00817     }
00818 
00819     /*
00820      * setup default context config.  Thinking maybe we should go with 
00821      * FRAG_POLICY_FIRST or FRAG_POLICY_LINUX as the default instead of
00822      * BSD since Win32/Linux have a higher incidence of occurrence.  Anyone
00823      * with an opinion on the matter feel free to email me...
00824      */
00825     context->frag_policy = FRAG_POLICY_BSD;
00826     context->frag_timeout = FRAG_PRUNE_QUANTA; /* 60 seconds */
00827     context->ttl_limit = FRAG3_TTL_LIMIT;
00828     context->min_ttl = FRAG3_MIN_TTL;
00829     context->frag3_alerts = 0;
00830 
00831     /* 
00832      * the IpAddrSet struct is initialized in Frag3ParseArgs
00833      */
00834     context->bound_addrs = NULL;
00835 
00836     /*
00837      * parse the configuration for this engine
00838      */
00839     Frag3ParseArgs(args, context);
00840 
00841     /*
00842      * get me a preprocessor func node to attach the context
00843      */
00844     pfn = AddFuncToPreprocList(Frag3Defrag);
00845 
00846     pfn->context = (void *) context;
00847 
00848     if(!stats_registered)
00849     {
00850         AddFuncToCleanExitList(Frag3CleanExit, NULL);
00851         AddFuncToRestartList(Frag3Restart, NULL);
00852         stats_registered = 1;
00853     }
00854 
00855     /*
00856      * print this engine config
00857      */
00858     Frag3PrintEngineConfig(context);
00859 
00860     return;
00861 }
00862 
00863 /**
00864  * Config parser for global config.  
00865  *
00866  * @param args List of configuration parameters
00867  *
00868  * @return none
00869  */
00870 static void Frag3ParseGlobalArgs(u_char *args)
00871 {
00872     char **toks;
00873     int num_toks;
00874     int i;
00875     char *index;
00876     char **stoks = NULL;
00877     int s_toks;
00878 
00879     if(args != NULL && strlen(args) != 0)
00880     {
00881         toks = mSplit(args, ",", 12, &num_toks, 0);
00882 
00883         i=0;
00884 
00885         while(i < num_toks)
00886         {
00887             index = toks[i];
00888 
00889             while(isspace((int)*index)) index++;
00890 
00891             stoks = mSplit(index, " ", 4, &s_toks, 0);
00892 
00893             if(!strcasecmp(stoks[0], "max_frags"))
00894             {
00895                 if(isdigit((int)stoks[1][0]))
00896                 {
00897                     global_config.max_frags = atoi(stoks[1]);
00898                 }
00899                 else
00900                 {
00901                     LogMessage("WARNING %s(%d) => Bad max_frags in config "
00902                             "file, defaulting to %d frags\n", 
00903                             file_name, file_line, 
00904                             DEFAULT_MAX_FRAGS);
00905 
00906                     global_config.max_frags = DEFAULT_MAX_FRAGS;
00907                 }
00908 
00909             }
00910             else if(!strcasecmp(stoks[0], "memcap"))
00911             {
00912 #ifdef FRAG3_USE_MEMCAP
00913                 if(stoks[1] && isdigit((int)stoks[1][0]))
00914                 {
00915                     global_config.memcap = atoi(stoks[1]);
00916 
00917                     if(global_config.memcap < 16384)
00918                     {
00919                         LogMessage("WARNING %s(%d) => Ludicrous (<16k) memcap "
00920                                 "size, setting to default (%d bytes)\n", 
00921                                 file_name, file_line, FRAG_MEMCAP);
00922 
00923                         global_config.memcap = FRAG_MEMCAP;
00924                     }
00925                 }
00926                 else
00927                 {
00928                     LogMessage("WARNING %s(%d) => Bad memcap in config file, "
00929                             "defaulting to %u bytes\n", file_name, file_line, 
00930                             FRAG_MEMCAP);
00931 
00932                     global_config.memcap = FRAG_MEMCAP;
00933                 }
00934 
00935                 /* ok ok, it's really 9.375%, sue me */
00936                 ten_percent = ((global_config.memcap >> 5) + 
00937                                (global_config.memcap >> 6));
00938 #else
00939                 /* Use memcap to calculate prealloc_frag value */
00940                 int memcap;
00941                 if(stoks[1] && isdigit((int)stoks[1][0]))
00942                 {
00943                     memcap = atoi(stoks[1]);
00944 
00945                     if(memcap < 16384)
00946                     {
00947                         LogMessage("WARNING %s(%d) => Ludicrous (<16k) memcap "
00948                                 "size, setting to default (%d bytes)\n", 
00949                                 file_name, file_line, FRAG_MEMCAP);
00950 
00951                         memcap = FRAG_MEMCAP;
00952                     }
00953                 }
00954                 else
00955                 {
00956                     LogMessage("WARNING %s(%d) => Bad memcap in config file, "
00957                             "defaulting to %u bytes\n", file_name, file_line, 
00958                             FRAG_MEMCAP);
00959 
00960                     memcap = FRAG_MEMCAP;
00961                 }
00962 
00963                 global_config.static_frags = (u_int32_t)memcap /
00964                         (sizeof(Frag3Frag) + sizeof(u_int8_t) * snaplen) + 1;
00965                 global_config.use_prealloc = 1;
00966                 ten_percent = global_config.static_frags >> 5;
00967 #endif
00968             }
00969             else if(!strcasecmp(stoks[0], "prealloc_frags"))
00970             {
00971                 if(isdigit((int)stoks[1][0]))
00972                 {
00973                     global_config.static_frags = atoi(stoks[1]);
00974                     global_config.use_prealloc = 1;
00975 
00976                     //ten_percent = ((global_config.static_frags >> 5) + 
00977                     //        (global_config.static_frags >> 6));
00978                     ten_percent = global_config.static_frags >> 5;
00979                 }
00980                 else
00981                 {
00982                     LogMessage("WARNING %s(%d) => Bad prealloc_frags in config "
00983                             "file, defaulting to dynamic frag management\n",
00984                             file_name, file_line);
00985 
00986                     global_config.static_frags = 0;
00987                 }
00988             }
00989 
00990             mSplitFree(&stoks, s_toks);
00991 
00992             i++;
00993         }
00994         mSplitFree(&toks, num_toks);
00995     }
00996 
00997     return;
00998 }
00999 
01000 
01001 
01002 /**
01003  * Config parser for engine context config.  
01004  *
01005  * @param args List of configuration parameters
01006  *
01007  * @return none
01008  */
01009 static void Frag3ParseArgs(u_char *args, Frag3Context *context)
01010 {
01011     char **toks;
01012     int num_toks;
01013     int i;
01014     char *index;
01015 
01016     if(args == NULL || strlen(args) == 0)
01017     {
01018         return;
01019     }
01020     else
01021     {
01022         int increment;
01023         toks = mSplit(args, " ", 13, &num_toks, 0);
01024 
01025         i=0;
01026 
01027         while(i < num_toks)
01028         {
01029             increment = 1;
01030             index = toks[i];
01031 
01032             if(!strcasecmp(index, "timeout"))
01033             {
01034                 if(i+1 < num_toks && isdigit((int)toks[i+1][0]))
01035                 {
01036                     context->frag_timeout = atoi(toks[i+1]);
01037                     increment = 2;
01038                 }
01039                 else
01040                 {
01041                     LogMessage("WARNING %s(%d) => Bad timeout in config file, "
01042                             "defaulting to %d seconds\n", file_name, 
01043                             file_line, FRAG_PRUNE_QUANTA);
01044 
01045                     context->frag_timeout = FRAG_PRUNE_QUANTA;
01046                 }
01047             }
01048             else if(!strcasecmp(index, "ttl_limit"))
01049             {
01050                 if(i+1 >= num_toks || toks[i+1][0] == '\0')
01051                 {
01052                     FatalError("%s(%d) => ttl_limit requires an integer "
01053                             "argument\n", file_name,file_line);
01054                 }
01055 
01056                 if(isdigit((int)toks[i+1][0]))
01057                 {
01058                     context->ttl_limit = atoi(toks[i+1]);
01059                     increment = 2;
01060                 }
01061                 else
01062                 {
01063                     LogMessage("WARNING %s(%d) => Bad TTL Limit"
01064                             "size, setting to default (%d\n", file_name, 
01065                             file_line, FRAG3_TTL_LIMIT);
01066 
01067                     context->ttl_limit = FRAG3_TTL_LIMIT;
01068                 }
01069             }
01070             else if(!strcasecmp(index, "min_ttl"))
01071             {
01072                 if(i+1 >= num_toks || toks[i+1][0] == '\0')
01073                 {
01074                     FatalError("%s(%d) => min_ttl requires an integer "
01075                             "argument\n", file_name,file_line);
01076                 }
01077 
01078                 if(isdigit((int)toks[i+1][0]))
01079                 {
01080                     context->min_ttl = atoi(toks[i+1]);
01081                     increment = 2;
01082                 }
01083                 else
01084                 {
01085                     LogMessage("WARNING %s(%d) => Bad Min TTL "
01086                             "size, setting to default (%d\n", file_name, 
01087                             file_line, FRAG3_MIN_TTL);
01088 
01089                     context->min_ttl = FRAG3_MIN_TTL;
01090                 }
01091             }
01092             else if(!strcasecmp(index, "detect_anomalies"))
01093             {
01094                 context->frag3_alerts |= FRAG3_DETECT_ANOMALIES;
01095             }
01096             else if(!strcasecmp(index, "policy"))
01097             {
01098                 if (i+1 >= num_toks)
01099                     FatalError("%s(%d) => policy requires a policy "
01100                             "identifier argument\n", file_name, file_line);
01101 
01102                 if(!strcasecmp(toks[i+1], "bsd"))
01103                 {
01104                     context->frag_policy = FRAG_POLICY_BSD;
01105                 }
01106                 else if(!strcasecmp(toks[i+1], "bsd-right"))
01107                 {
01108                     context->frag_policy = FRAG_POLICY_BSD_RIGHT;
01109                 }
01110                 else if(!strcasecmp(toks[i+1], "linux"))
01111                 {
01112                     context->frag_policy = FRAG_POLICY_LINUX;
01113                 }
01114                 else if(!strcasecmp(toks[i+1], "first"))
01115                 {
01116                     context->frag_policy = FRAG_POLICY_FIRST;
01117                 }
01118                 else if(!strcasecmp(toks[i+1], "windows"))
01119                 {
01120                     context->frag_policy = FRAG_POLICY_WINDOWS;
01121                 }
01122                 else if(!strcasecmp(toks[i+1], "solaris"))
01123                 {
01124                     context->frag_policy = FRAG_POLICY_SOLARIS;
01125                 }
01126                 else if(!strcasecmp(toks[i+1], "last"))
01127                 {
01128                     context->frag_policy = FRAG_POLICY_LAST;
01129                 }
01130                 else
01131                 {
01132                     LogMessage("WARNING %s(%d) => Bad policy name \"%s\""
01133                             "reverting to FRAG_POLICY_BSD\n", 
01134                             file_name, file_line, toks[i+1]);
01135                 }
01136                 increment = 2;
01137             }
01138             else if(!strcasecmp(index, "bind_to"))
01139             {
01140                 if (i+1 < num_toks)
01141                 {
01142                     context->bound_addrs = IpAddrSetParse(toks[i+1]);
01143                     increment = 2;
01144                 }
01145                 else
01146                 {
01147                     FatalError("%s(%d) => bind_to requires an IP list or "
01148                             "CIDR block argument\n", file_name, file_line);
01149                 }
01150             }
01151 
01152             i += increment;
01153         }
01154 
01155         mSplitFree(&toks, num_toks);
01156 
01157         if(context->bound_addrs == NULL)
01158         {
01159             /* allocate and initializes the IpAddrSet at the same time 
01160              * set to "any"
01161              */
01162             context->bound_addrs = (IpAddrSet *) SnortAlloc(sizeof(IpAddrSet));
01163         }
01164     }
01165 
01166     return;
01167 }
01168 
01169 
01170 /**
01171  * Main runtime entry point for Frag3
01172  *
01173  * @param p Current packet to process.
01174  * @param context Context for this defrag engine
01175  *
01176  * @return none
01177  */
01178 void Frag3Defrag(Packet *p, void *context)
01179 {
01180     FRAGKEY fkey;           /* fragkey for this packet */
01181     FragTracker *ft;        /* FragTracker to process the packet on */
01182     Frag3Context *f3context = (Frag3Context *) context; /* engine context */
01183     int insert_return = 0;  /* return value from the insert function */
01184 
01185     /*
01186      * check to make sure this preprocessor should run
01187      */
01188     if( (p == NULL) || !(p->preprocessors & PP_FRAG3) ||
01189             p->iph == NULL || !p->frag_flag ||
01190             (p->csum_flags & CSE_IP) ||
01191             (p->packet_flags & PKT_REBUILT_FRAG))
01192     {
01193         return;
01194     }
01195 
01196     /* Ugly HACK -- if frag offset is 0 & UDP, let that packet go
01197      * through the rest of the system.  This results in the
01198      * first packet going through detection.  If we do see
01199      * the rest of the frags, the contents of that first frag
01200      * will go through again with the defrag'd (built) packet.
01201      */
01202     if ((p->frag_offset != 0) || (p->iph->ip_proto != IPPROTO_UDP))
01203     {
01204         /*
01205          * This packet is fragmented, will either be dropped
01206          * or payload included in a rebuilt packet later.  Don't
01207          * process it further.
01208          */
01209          p->preprocessors = 0;
01210          p->preprocessors |= PP_PORTSCAN2;
01211          do_detect = 0;
01212          otn_tmp = NULL;
01213     }
01214 
01215 #if 0
01216     /* 
01217      * fragments with IP options are bad, m'kay?
01218      */
01219     if(p->ip_options_len)
01220     {
01221         EventAnomIpOpts(f3context);
01222         f3stats.discards++;
01223         return;
01224     }
01225 #endif
01226 
01227     /*
01228      * pkt's not going to make it to the target, bail 
01229      */
01230     if(p->iph->ip_ttl < f3context->min_ttl)
01231     {
01232         LogMessage(
01233                 "[FRAG3] Fragment discarded due to low TTL "
01234                 "[0x%X->0x%X], TTL: %d  " "Offset: %d Length: %d\n", 
01235                 ntohl(p->iph->ip_src.s_addr), 
01236                 ntohl(p->iph->ip_dst.s_addr), 
01237                 p->iph->ip_ttl, p->frag_offset, 
01238                 p->dsize);
01239 
01240         f3stats.discards++;
01241         return;
01242     }
01243 
01244     /*
01245      * Does this engine context handle fragments to this IP address?
01246      */
01247     if(!IpAddrSetContains(f3context->bound_addrs, p->iph->ip_dst))
01248     {
01249         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01250                     "[FRAG3] Fragment ignored, not in IpAddrSet\n"););
01251         return;
01252     }
01253 
01254     f3stats.total++;
01255     UpdateIPFragStats(&(sfPerf.sfBase), p->pkth->caplen);
01256 
01257     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01258                 "\n++++++++++++++++++++++++++++++++++++++++++++++\n"););
01259     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01260                 "[**] [FRAG3] Inspecting fragment...\n"););
01261     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01262                 "[FRAG3] Got frag packet (mem use: %ld frag "
01263                 "trackers: %d  p->pkt_flags: 0x%X "
01264                 "prealloc nodes in use: %lu/%lu)\n", 
01265                 mem_in_use,
01266                 sfxhash_count(f_cache), 
01267                 p->packet_flags, prealloc_nodes_in_use, 
01268                 global_config.static_frags););
01269 
01270     /* zero the frag key */
01271     memset(&fkey, 0, sizeof(FRAGKEY));
01272 
01273 #if 0
01274     /*
01275      * Check the memcap and clear some space if we're over the memcap
01276      */
01277     if(mem_in_use > global_config.memcap)
01278     {
01279         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01280                     "memcap exceeded (%ld bytes in use), "
01281                     "calling Frag3Prune()\n", mem_in_use););
01282         Frag3Prune();
01283     }
01284 #endif
01285     pkttime = (struct timeval *) &p->pkth->ts;
01286 
01287     /* 
01288      * try to get the tracker that this frag should go with 
01289      */
01290     if((ft = Frag3GetTracker(p, &fkey)) == NULL)
01291     {
01292         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Adding New FragTracker...\n"););
01293 
01294         /* 
01295          * first frag for this packet, start a new tracker 
01296          */
01297         Frag3NewTracker(p, &fkey, f3context);
01298 
01299         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01300                     "[FRAG3] mem use: %ld frag "
01301                     "trackers: %d  prealloc "
01302                     "nodes in use: %lu/%lu\n", 
01303                     mem_in_use,
01304                     sfxhash_count(f_cache), 
01305                     prealloc_nodes_in_use, 
01306                     global_config.static_frags););
01307         /* 
01308          * all done, return control to Snort
01309          */
01310         return;
01311     }
01312 
01313     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Found frag tracker\n"););
01314 
01315     /*
01316      * insert the fragment into the FragTracker
01317      */
01318     if((insert_return = Frag3Insert(p, ft, &fkey, f3context)) != FRAG_INSERT_OK)
01319     {
01320         /*
01321          * we can pad this switch out for a variety of entertaining behaviors
01322          * later if we're so inclined
01323          */
01324         switch(insert_return)
01325         {
01326             case FRAG_INSERT_FAILED:
01327                 if(!pv.quiet_flag)
01328                 {
01329                     LogMessage("WARNING: Insert into Fraglist failed, "
01330                             "(offset: %u)\n", p->frag_offset);
01331                 }
01332                 return;
01333             case FRAG_INSERT_TTL:
01334                 LogMessage(
01335                         "[FRAG3] Fragment discarded due to large TTL Delta "
01336                         "[0x%X->0x%X], TTL: %d  orig TTL: %d "
01337                         "Offset: %d Length: %d\n", 
01338                         ntohl(p->iph->ip_src.s_addr), 
01339                         ntohl(p->iph->ip_dst.s_addr), 
01340                         p->iph->ip_ttl, ft->ttl, p->frag_offset, 
01341                         p->dsize);
01342                 f3stats.discards++;
01343                 return;
01344             case FRAG_INSERT_ATTACK:
01345             case FRAG_INSERT_ANOMALY:
01346                 f3stats.discards++;
01347                 return;
01348             case FRAG_INSERT_TIMEOUT:
01349 #ifdef DEBUG
01350                 if(!pv.quiet_flag)
01351                 {
01352                     LogMessage("WARNING: Insert into Fraglist failed due to timeout, "
01353                             "(offset: %u)\n", p->frag_offset);
01354                 }
01355 #endif
01356                 return;
01357             default:
01358                 break;
01359         }
01360     }
01361 
01362     p->fragtracker = (void *)ft;
01363 
01364     /* 
01365      * check to see if it's reassembly time 
01366      */
01367     if(Frag3IsComplete(ft))
01368     {
01369         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01370                     "[*] Fragment is complete, rebuilding!\n"););
01371 
01372         /* 
01373          * if the frag completes but it's bad we're just going to drop it
01374          * instead of wasting time on putting it back together
01375          */
01376         if(!(ft->frag_flags & FRAG_BAD))
01377         {
01378             Frag3Rebuild(ft, p);
01379 
01380             if ((p->frag_offset != 0) || (p->iph->ip_proto != IPPROTO_UDP))
01381             {
01382                 /* Need to reset some things here because the
01383                  * rebuilt packet will have reset the do_detect
01384                  * flag when it hits Preprocess.
01385                  */
01386                 do_detect = 0;
01387                 otn_tmp = NULL;
01388                 /* And unset the frag tracker for this packet since
01389                  * we're going to blow it away in a few usecs...
01390                  */
01391                 p->fragtracker = NULL;
01392             }
01393         }
01394 
01395         Frag3RemoveTracker(&fkey, ft);
01396 
01397     }
01398 
01399     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01400                 "[FRAG3] Dumped fragtracker (mem use: %ld frag "
01401                 "trackers: %d  prealloc "
01402                 "nodes in use: %lu/%lu)\n", 
01403                 mem_in_use,
01404                 sfxhash_count(f_cache), 
01405                 prealloc_nodes_in_use, 
01406                 global_config.static_frags););
01407 
01408     return;
01409 }
01410 
01411 /**
01412  * Check to see if a FragTracker has timed out
01413  *
01414  * @param current_time Time at this moment
01415  * @param start_time Time to compare current_time to
01416  * @param f3context Engine context
01417  *
01418  * @return status
01419  * @retval  FRAG_TIMEOUT Current time diff is greater than the current 
01420  *                       context's timeout value
01421  * @retval  FRAG_TIME_OK Current time diff is within the context's prune
01422  *                       window                      
01423  */
01424 static INLINE int CheckTimeout(struct timeval *current_time, 
01425         struct timeval *start_time, 
01426         Frag3Context *f3context)
01427 {
01428     struct timeval tv_diff; /* storage struct for the difference between 
01429                                current_time and start_time */
01430 
01431     TIMERSUB(current_time, start_time, &tv_diff);
01432     
01433     if(tv_diff.tv_sec >= f3context->frag_timeout)
01434     {
01435         return FRAG_TIMEOUT;
01436     }
01437 
01438     return FRAG_TIME_OK;
01439 }
01440 
01441 /**
01442  * Time-related expiration of fragments from the system.  Checks the current
01443  * FragTracker for timeout, then walks up the LRU list looking to see if 
01444  * anyone should have timed out.
01445  *
01446  * @param p Current packet (contains pointer to the current timestamp)
01447  * @param ft FragTracker to check for a timeout
01448  * @param fkey FragKey of the current FragTracker for sfxhash lookup
01449  * @param f3context Context of the defrag engine, contains the timeout value
01450  *
01451  * @return status
01452  * @retval FRAG_TRACKER_TIMEOUT The current FragTracker has timed out
01453  * @retval FRAG_OK The current FragTracker has not timed out
01454  */
01455 static int Frag3Expire(
01456         Packet *p, 
01457         FragTracker *ft, 
01458         FRAGKEY *fkey, 
01459         Frag3Context *f3context)
01460 {
01461 #if 0
01462     struct timeval *fttime;     /* FragTracker timestamp */
01463     struct timeval *pkttime;    /* packet timestamp */
01464     FragTracker *tmpft;         /* temp pointer for moving thru the LRU queue */
01465 #endif
01466 
01467     /*
01468      * Check the FragTracker that was passed in first
01469      */
01470     if(CheckTimeout(
01471                 pkttime,
01472                 &(ft)->frag_time, 
01473                 f3context) == FRAG_TIMEOUT)
01474     {
01475         /*
01476          * Oops, we've timed out, whack the FragTracker
01477          */
01478 #ifdef DEBUG_FRAG3
01479         if (DEBUG_FRAG & GetDebugLevel())
01480             LogMessage("(spp_frag3) Current Fragment dropped due to timeout! "
01481                 "[0x%08X->0x%08X ID: %d]\n", ft->sip, ft->dip, ft->id);
01482 #endif
01483 
01484         Frag3RemoveTracker(fkey, ft);
01485 
01486         f3stats.timeouts++;
01487         sfPerf.sfBase.iFragTimeouts++;
01488 
01489         return FRAG_TRACKER_TIMEOUT;
01490     }
01491 
01492 #if 0
01493     /*
01494      * This doesn't really need to be done here!!!
01495      * We'll blow them away when we prune for memory reasons.
01496      */
01497 
01498     /* 
01499      * The current FragTracker hasn't timed out, check the LRU FragTrackers to
01500      * see if any of them need to go.
01501      */
01502     if((tmpft = (FragTracker*)sfxhash_lru(f_cache)))
01503     {
01504         fttime = &tmpft->frag_time;
01505         pkttime = (struct timeval *) &p->pkth->ts;
01506 
01507         while(tmpft && CheckTimeout(pkttime,fttime,f3context)==FRAG_TIMEOUT)
01508         {
01509             LogMessage("(spp_frag3) Fragment dropped due to timeout! "
01510                     "[0x%08X->0x%08X ID: %d]\n", tmpft->sip, tmpft->dip, 
01511                     tmpft->id);
01512 
01513             sfxhash_free_node(f_cache, sfxhash_lru_node(f_cache));
01514 
01515             f3stats.timeouts++;
01516             sfPerf.sfBase.iFragTimeouts++;
01517 
01518             if((tmpft = (FragTracker*)(sfxhash_lru(f_cache))))
01519             {
01520                 fttime = &tmpft->frag_time;
01521             }
01522         }
01523     }
01524 #endif
01525 
01526     /*
01527      * set the current FragTracker's timeout on our way out the door...
01528      */
01529     /* XXX Uh, I shouldn't be doing this should I???? */
01530     //ft->frag_time.tv_sec = p->pkth->ts.tv_sec;
01531     //ft->frag_time.tv_usec = p->pkth->ts.tv_usec;
01532 
01533     return FRAG_OK;
01534 }
01535 
01536 /**
01537  * Check to see if we've got the first or last fragment on a FragTracker and
01538  * set the appropriate frag_flags
01539  *
01540  * @param p Packet to get the info from
01541  * @param ft FragTracker to set the flags on 
01542  *
01543  * @return none
01544  */
01545 static int INLINE Frag3CheckFirstLast(Packet *p, FragTracker *ft)
01546 {
01547     u_int16_t fragLength;
01548     int retVal = FRAG_FIRSTLAST_OK;
01549     u_int16_t endOfThisFrag;
01550 
01551 
01552     /* set the frag flag if this is the first fragment */
01553     if(p->mf && p->frag_offset == 0)
01554     {
01555         ft->frag_flags |= FRAG_GOT_FIRST;
01556 
01557         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got first frag\n"););
01558     }
01559     else if((!p->mf) && (p->frag_offset > 0)) /* set for last frag too */
01560     {
01561         /* Use the actual length here, because packet may have been
01562         * truncated.  Don't want to try to copy more than we actually
01563         * captured. */
01564         fragLength = p->actual_ip_len - IP_HLEN(p->iph) * 4;
01565         endOfThisFrag = (p->frag_offset << 3) + fragLength;
01566 
01567         if (ft->frag_flags & FRAG_GOT_LAST)
01568         {
01569             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got last frag again!\n"););
01570             switch (ft->context->frag_policy)
01571             {
01572                 case FRAG_POLICY_BSD:
01573                 case FRAG_POLICY_LINUX:
01574                 case FRAG_POLICY_BSD_RIGHT:
01575                 case FRAG_POLICY_LAST:
01576                 case FRAG_POLICY_WINDOWS:
01577                 case FRAG_POLICY_FIRST:
01578                     if (ft->calculated_size > endOfThisFrag)
01579                     {
01580                        /* Already have a 'last frag' with a higher
01581                         * end point.  Leave it as is.
01582                         *
01583                         * Some OS's do not respond at all -- we'll
01584                         * still try to rebuild anyway in that case,
01585                         * because there is really something wrong
01586                         * and we should look at it.
01587                         */
01588                         retVal = FRAG_LAST_DUPLICATE;
01589                     }
01590                     break;
01591                 case FRAG_POLICY_SOLARIS:
01592                     if (ft->calculated_size > endOfThisFrag)
01593                     {
01594                        /* Already have a 'last frag' with a higher
01595                         * end point.  Leave it as is.
01596                         *
01597                         * Some OS's do not respond at all -- we'll
01598                         * still try to rebuild anyway in that case,
01599                         * because there is really something wrong
01600                         * and we should look at it.
01601                         */
01602                         retVal = FRAG_LAST_DUPLICATE;
01603                     }
01604                     else
01605                     {
01606                         /* Solaris does some weird stuff here... */
01607                         /* Usually, Solaris takes the higher end point.
01608                          * But in one strange case (when it hasn't seen
01609                          * any frags beyond the existing last frag), it
01610                          * actually appends that new last frag to the
01611                          * end of the previous last frag, regardless of
01612                          * the offset.  Effectively, it adjusts the
01613                          * offset of the new last frag to immediately
01614                          * after the existing last frag.
01615                          */
01616                         /* XXX: how to handle that case? punt?  */
01617                         retVal = FRAG_LAST_OFFSET_ADJUST;
01618                     }
01619                     break;
01620             }
01621         }
01622 
01623         ft->frag_flags |= FRAG_GOT_LAST;
01624 
01625         /*
01626          * If this is the last frag (and we don't have a frag that already
01627          * extends beyond this one), set the size that we're expecting.
01628          */
01629         if ((ft->calculated_size < endOfThisFrag) &&
01630             (retVal != FRAG_LAST_OFFSET_ADJUST))
01631         {
01632             ft->calculated_size = endOfThisFrag;
01633 
01634             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got last frag, Bytes: %d, "
01635                     "Calculated size: %d\n",
01636                     ft->frag_bytes,
01637                     ft->calculated_size););
01638         }
01639     }
01640 
01641     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Frag Status: %s:%s\n", 
01642                 ft->frag_flags&FRAG_GOT_FIRST?"FIRST":"No FIRST", 
01643                 ft->frag_flags&FRAG_GOT_LAST?"LAST":"No LAST"););
01644     return retVal; 
01645 }
01646 
01647 /**
01648  * Lookup a FragTracker in the f_cache sfxhash table based on an input key
01649  *
01650  * @param p The current packet to get the key info from
01651  * @param fkey Pointer to a container for the FragKey
01652  *
01653  * @return Pointer to the FragTracker in the hash bucket or NULL if there is 
01654  *         no fragment in the hash bucket
01655  */
01656 static FragTracker *Frag3GetTracker(Packet *p, FRAGKEY *fkey)
01657 {
01658     FragTracker *returned; /* FragTracker ptr returned by the lookup */
01659 
01660     /* 
01661      * we have to setup the key first, downstream functions depend on
01662      * it being setup here
01663      */
01664     fkey->sip = p->iph->ip_src.s_addr;
01665     fkey->dip = p->iph->ip_dst.s_addr;
01666     fkey->id = p->iph->ip_id;
01667     fkey->proto = p->iph->ip_proto;
01668 
01669     /*
01670      * if the hash table is empty we're done
01671      */
01672     if(sfxhash_count(f_cache) == 0)
01673         return NULL;
01674 
01675     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01676                 "[*] Looking up FragTracker using key:\n"););
01677 
01678 #ifdef DEBUG_FRAG3
01679     PrintFragKey(fkey);
01680 #endif
01681 
01682     returned = (FragTracker *) sfxhash_find(f_cache, fkey);
01683 
01684     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01685                 "Frag3GetTracker returning %p for\n", returned););
01686 
01687     return returned;
01688 }
01689 
01690 /**
01691  * Handle IP Options in fragmented packets.
01692  *
01693  * @param ft Current frag tracker for this packet
01694  * @param p Current packet to check for options
01695  * @param context In case we get an anomaly
01696  *
01697  * @return status
01698  * @retval 0 on an error
01699  * @retval 1 on success
01700  */
01701 static int Frag3HandleIPOptions(FragTracker *ft,
01702                                 Packet *p)
01703 {
01704     unsigned int i = 0;          /* counter */
01705     if(p->frag_offset == 0)
01706     {
01707         /*
01708          * This is the first packet.  If it has IP options,
01709          * save them off, so we can set them on the reassembled packet.
01710          */
01711         if (p->ip_options_len)
01712         {
01713             ft->ip_options_len = p->ip_options_len;
01714             ft->ip_option_count = p->ip_option_count;
01715             ft->ip_options_data = SnortAlloc(p->ip_options_len);
01716             memcpy(ft->ip_options_data, p->ip_options_data, p->ip_options_len);
01717         }
01718     }
01719     else
01720     {
01721         /* check that options match those from other non-offset 0 packets */
01722 
01723         /* XXX: could check each individual option here, but that
01724          * would be performance ugly.  So, we'll just check that the
01725          * option counts match.  Alert if invalid, but still include in
01726          * reassembly.
01727          */
01728         if (ft->copied_ip_option_count)
01729         {
01730             if (ft->copied_ip_option_count != p->ip_option_count)
01731             {
01732                 EventAnomIpOpts(ft->context);
01733             }
01734         }
01735         else
01736         {
01737             ft->copied_ip_option_count = p->ip_option_count;
01738             for (i = 0;i< p->ip_option_count && i < IP_OPTMAX; i++)
01739             {
01740                 /* Is the high bit set?  If not, weird anomaly. */
01741                 if (!(p->ip_options[i].code & 0x80))
01742                     EventAnomIpOpts(ft->context);
01743             }
01744         }
01745     }
01746     return 1;
01747 }
01748 
01749 /**
01750  * Didn't find a FragTracker in the hash table, create a new one and put it
01751  * into the f_cache
01752  *
01753  * @param p Current packet to fill in FragTracker fields
01754  * @param fkey FragKey struct to use for table insertion
01755  *
01756  * @return status
01757  * @retval 0 on an error
01758  * @retval 1 on success
01759  */
01760 static int Frag3NewTracker(Packet *p, FRAGKEY *fkey, Frag3Context *f3context)
01761 {
01762     FragTracker *tmp;
01763     Frag3Frag *f = NULL;
01764     //int ret = 0;
01765     char *fragStart;
01766     u_int16_t fragLength;
01767     u_int16_t frag_end;
01768     SFXHASH_NODE *hnode;
01769 
01770     fragStart = (u_int8_t *)p->iph + IP_HLEN(p->iph) * 4;
01771     /* Use the actual length here, because packet may have been
01772      * truncated.  Don't want to try to copy more than we actually
01773      * captured. */
01774     fragLength = p->actual_ip_len - IP_HLEN(p->iph) * 4;
01775 #ifdef DEBUG
01776     if (p->actual_ip_len != ntohs(p->iph->ip_len))
01777     {
01778         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01779                "IP Actual Length (%d) != specified length (%d), "
01780                "truncated packet (%d)?\n",
01781                 p->actual_ip_len, ntohs(p->iph->ip_len), snaplen););
01782     }
01783 #endif
01784 
01785     /* Just to double check */
01786     if (fragLength > snaplen)
01787     {
01788         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01789                     "Overly large fragment %d 0x%x 0x%x %d\n",
01790                     fragLength, p->iph->ip_len, p->iph->ip_off,
01791                     p->frag_offset << 3););
01792 
01793         /* Ah, crap.  Return that tracker. */
01794         return 0;
01795     }
01796     /* Get a node from the hash table */
01797     hnode = sfxhash_get_node(f_cache, fkey);
01798     if (!hnode)
01799     {
01800         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01801                     "Frag3NewTracker: sfxhash_get_node() failed\n"););
01802 
01803         return 0;
01804     }
01805     else
01806     {
01807         if (hnode->data)
01808         {
01809             tmp = hnode->data;
01810             memset(tmp, 0, sizeof(FragTracker));
01811         }
01812         else
01813         {
01814             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01815                     "Frag3NewTracker: sfxhash_get_node() failed\n"););
01816 
01817             return 0;
01818         }
01819     }
01820 
01821     /* 
01822      * setup the frag tracker 
01823      */
01824     tmp->sip = fkey->sip;
01825     tmp->dip = fkey->dip;
01826     tmp->id = fkey->id;
01827     tmp->protocol = fkey->proto;
01828     tmp->ttl = p->iph->ip_ttl; /* store the first ttl we got */
01829     tmp->calculated_size = 0;
01830     tmp->alerted = 0;
01831     tmp->frag_flags = 0;
01832     tmp->frag_bytes = 0;
01833     tmp->frag_pkts = 0;
01834     tmp->frag_time.tv_sec = p->pkth->ts.tv_sec;
01835     tmp->frag_time.tv_usec = p->pkth->ts.tv_usec;
01836     tmp->alert_count = 0;
01837     tmp->ip_options_len = 0;
01838     tmp->ip_option_count = 0;
01839     tmp->ip_options_data = NULL;
01840     tmp->copied_ip_options_len = 0;
01841     tmp->copied_ip_option_count = 0;
01842     tmp->context = f3context;
01843     tmp->ordinal = 0;
01844 
01845     /* 
01846      * get our first fragment storage struct 
01847      */
01848     if(!global_config.use_prealloc)
01849     {
01850         if(mem_in_use > global_config.memcap)
01851         {
01852             if (Frag3Prune(tmp) == 0)
01853             {
01854                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01855                     "Frag3NewTracker: Pruning failed\n"););
01856 
01857                 return 0;
01858             }
01859         }
01860 
01861         f = (Frag3Frag *) SnortAlloc(sizeof(Frag3Frag));
01862         mem_in_use += sizeof(Frag3Frag);
01863 
01864         f->fptr = (u_int8_t *) SnortAlloc(fragLength);
01865         mem_in_use += fragLength;
01866     
01867 
01868     }
01869     else
01870     {
01871         while((f = Frag3PreallocPop()) == NULL)
01872         {
01873             if (Frag3Prune(tmp) == 0)
01874             {
01875                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01876                     "Frag3NewTracker: Pruning failed\n"););
01877 
01878                 return 0;
01879             }
01880         }
01881     }
01882 
01883     f3stats.fragnodes_created++;
01884     sfPerf.sfBase.iFragCreates++;
01885     sfPerf.sfBase.iCurrentFrags++;
01886     if (sfPerf.sfBase.iCurrentFrags > sfPerf.sfBase.iMaxFrags)
01887         sfPerf.sfBase.iMaxFrags = sfPerf.sfBase.iCurrentFrags;
01888 
01889     /* initialize the fragment list */
01890     tmp->fraglist = NULL;
01891 
01892     /*
01893      * setup the Frag3Frag struct with the current packet's data
01894      */
01895     memcpy(f->fptr, fragStart, fragLength);
01896 
01897     f->size = f->flen = fragLength;
01898     f->offset = p->frag_offset << 3;
01899     frag_end = f->offset + fragLength;
01900     f->ord = tmp->ordinal++;
01901     f->data = f->fptr;     /* ptr to adjusted start position */
01902     if (!p->mf)
01903     {
01904         f->last = 1;
01905     }
01906     else
01907     {
01908         /* 
01909          * all non-last frags are supposed to end on 8-byte boundries 
01910          */
01911         if(frag_end & 7)
01912         {
01913             /* 
01914              * bonk/boink/jolt/etc attack... 
01915              */
01916             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01917                         "[..] Short frag (Bonk, etc) attack!\n"););
01918 
01919             EventAnomShortFrag(f3context);
01920 
01921             /* don't return, might still be interesting... */
01922         }
01923 
01924         /* can't have non-full fragments... */
01925         frag_end &= ~7;
01926 
01927         /* Adjust len to take into account the jolting/non-full fragment. */
01928         f->size = frag_end - f->offset;
01929     }
01930 
01931     /* insert the fragment into the frag list */
01932     tmp->fraglist = f;
01933     tmp->fraglist_tail = f;
01934     tmp->fraglist_count = 1;  /* XXX: Are these duplciates? */
01935     tmp->frag_pkts = 1;
01936 
01937     /*
01938      * mark the FragTracker if this is the first/last frag
01939      */
01940     Frag3CheckFirstLast(p, tmp);
01941 
01942     tmp->frag_bytes += fragLength;
01943 
01944     Frag3HandleIPOptions(tmp, p);
01945 
01946     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
01947                 "[#] accumulated bytes on FragTracker: %d\n", 
01948                 tmp->frag_bytes););
01949 
01950     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01951                 "Initial fragment for tracker, ptr %p, offset %d, "
01952                 "size %d\n", f, f->offset, f->size););
01953 
01954 #ifdef DEBUG_FRAG3
01955     PrintFragKey(fkey);
01956 #endif 
01957 
01958     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01959                 "Calling sfxhash(add), overhead at %lu\n", 
01960                 f_cache->overhead_bytes););
01961 
01962 #if 0
01963     /* 
01964      * insert the frag tracker into the fragment hash 
01965      */
01966     if((ret = sfxhash_add(f_cache, fkey, &tmp)) != SFXHASH_OK)
01967     {
01968         if(ret == SFXHASH_INTABLE)
01969         {
01970             LogMessage("Key collision in sfxhash!\n");
01971         }
01972 
01973         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
01974                     "Frag3NewTracker: sfxhash_add() failed\n"););
01975 
01976         return 0;
01977     }
01978 #endif
01979 
01980     f3stats.fragtrackers_created++;
01981     pc.frag_trackers++;
01982 
01983     p->fragtracker = (void *)tmp;
01984 
01985     return 1;
01986 }
01987 
01988 /**
01989  * Handle the creation of the new frag node and list insertion.
01990  * Separating this from actually calculating the values.
01991  *
01992  * @param ft FragTracker to hold the packet
01993  * @param fragStart Pointer to start of the packet data
01994  * @param fragLength Length of packet data
01995  * @param len Length of this fragment
01996  * @param slide Adjustment to make to left side of data (for left overlaps)
01997  * @param trunc Adjustment to maek to right side of data (for right overlaps)
01998  * @param frag_offset Offset for this fragment
01999  * @prarm left FragNode prior to this one
02000  * @param retFrag this one after its inserted (returned)
02001  *
02002  * @return status
02003  * @retval FRAG_INSERT_FAILED Memory problem, insertion failed
02004  * @retval FRAG_INSERT_OK All okay
02005  */
02006 static int AddFragNode(FragTracker *ft,
02007                 Packet *p,
02008                 Frag3Context *f3context,
02009                 u_int8_t *fragStart,
02010                 int16_t fragLength,
02011                 char lastfrag,
02012                 int16_t len,
02013                 u_int16_t slide,
02014                 u_int16_t trunc,
02015                 u_int16_t frag_offset,
02016                 Frag3Frag *left,
02017                 Frag3Frag **retFrag)
02018 {
02019     Frag3Frag *newfrag = NULL;  /* new frag container */
02020     int16_t newSize = len - slide - trunc;
02021 
02022     if (newSize <= 0)
02023     {
02024         /* 
02025          * zero size frag
02026          */
02027         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02028             "zero size frag after left & right trimming "
02029             "(len: %d  slide: %d  trunc: %d)\n", 
02030             len, slide, trunc););
02031 
02032         f3stats.discards++;
02033 
02034 #ifdef DEBUG
02035         newfrag = ft->fraglist;
02036         while (newfrag)
02037         {
02038             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02039                    "Size: %d, offset: %d, len %d, "
02040                    "Prev: 0x%x, Next: 0x%x, This: 0x%x, Ord: %d, %s\n",
02041                    newfrag->size, newfrag->offset,
02042                    newfrag->flen, newfrag->prev,
02043                    newfrag->next, newfrag, newfrag->ord,
02044                    newfrag->last ? "Last":""););
02045             newfrag = newfrag->next;
02046         }
02047 #endif
02048 
02049         return FRAG_INSERT_ANOMALY;
02050     }
02051 
02052     /*
02053      * grab/generate a new frag node
02054      */
02055     if(!global_config.use_prealloc)
02056     {
02057         if(mem_in_use > global_config.memcap)
02058         {
02059             if (Frag3Prune(ft) == 0)
02060             {
02061                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02062                     "Frag3Insert: Pruning failed\n"););
02063 
02064                 return FRAG_INSERT_FAILED;
02065             }
02066         }
02067 
02068         /* 
02069          * build a frag struct to track this particular fragment 
02070          */
02071         newfrag = (Frag3Frag *) SnortAlloc(sizeof(Frag3Frag)); 
02072         mem_in_use += sizeof(Frag3Frag);
02073 
02074         /* 
02075          * allocate some space to hold the actual data 
02076          */
02077         newfrag->fptr = (u_int8_t*)SnortAlloc(fragLength);
02078         mem_in_use += fragLength;
02079     }
02080     else
02081     {
02082         /* 
02083          * fragments are preallocated, grab one from the list 
02084          */
02085         while((newfrag = Frag3PreallocPop()) == NULL)
02086         {
02087             if (Frag3Prune(ft) == 0)
02088             {
02089                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02090                     "Frag3Insert: Pruning failed\n"););
02091 
02092                 return FRAG_INSERT_FAILED;
02093             }
02094         }
02095 
02096         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02097                     "got newfrag (%p) from prealloc\n", newfrag););
02098     }
02099 
02100     f3stats.fragnodes_created++;
02101 
02102     newfrag->flen = fragLength;  
02103     memcpy(newfrag->fptr, fragStart, fragLength);
02104     newfrag->ord = ft->ordinal++;
02105 
02106     /* 
02107      * twiddle the frag values for overlaps
02108      */
02109     newfrag->data = newfrag->fptr + slide;
02110     newfrag->size = newSize;
02111     newfrag->offset = frag_offset;
02112     newfrag->last = lastfrag;
02113 
02114     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02115                 "[+] Adding new frag, offset %d, size %d\n"
02116                 "   nf->data = nf->fptr(%p) + slide (%d)\n"
02117                 "   nf->size = len(%d) - slide(%d) - trunc(%d)\n",
02118                 newfrag->offset, newfrag->size, newfrag->fptr,
02119                 slide, fragLength, slide, trunc););
02120 
02121     /*
02122      * insert the new frag into the list 
02123      */
02124     Frag3FraglistAddNode(ft, left, newfrag);
02125 
02126     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02127                 "[*] Inserted new frag %d@%d ptr %p data %p prv %p nxt %p\n", 
02128                 newfrag->size, newfrag->offset, newfrag, newfrag->data,
02129                 newfrag->prev, newfrag->next););
02130 
02131     /*
02132      * record the current size of the data in the fraglist
02133      */
02134     ft->frag_bytes += newfrag->size;
02135 
02136     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02137                 "[#] accumulated bytes on FragTracker %d, count"
02138                 " %d\n", ft->frag_bytes, ft->fraglist_count););
02139 
02140     *retFrag = newfrag;
02141     return FRAG_INSERT_OK;
02142 }
02143 
02144 /**
02145  * Duplicate a frag node and insert it into the list.
02146  *
02147  * @param ft FragTracker to hold the packet
02148  * @prarm left FragNode prior to this one (to be dup'd)
02149  * @param retFrag this one after its inserted (returned)
02150  *
02151  * @return status
02152  * @retval FRAG_INSERT_FAILED Memory problem, insertion failed
02153  * @retval FRAG_INSERT_OK All okay
02154  */
02155 static int DupFragNode(FragTracker *ft,
02156                 Frag3Frag *left,
02157                 Frag3Frag **retFrag)
02158 {
02159     Frag3Frag *newfrag = NULL;  /* new frag container */
02160 
02161     /*
02162      * grab/generate a new frag node
02163      */
02164     if(!global_config.use_prealloc)
02165     {
02166         if(mem_in_use > global_config.memcap)
02167         {
02168             if (Frag3Prune(ft) == 0)
02169             {
02170                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02171                     "Frag3Insert: Pruning failed\n"););
02172 
02173                 return FRAG_INSERT_FAILED;
02174             }
02175         }
02176 
02177         /* 
02178          * build a frag struct to track this particular fragment 
02179          */
02180         newfrag = (Frag3Frag *) SnortAlloc(sizeof(Frag3Frag)); 
02181         mem_in_use += sizeof(Frag3Frag);
02182 
02183         /* 
02184          * allocate some space to hold the actual data 
02185          */
02186         newfrag->fptr = (u_int8_t*)SnortAlloc(left->flen);
02187         mem_in_use += left->flen;
02188     }
02189     else
02190     {
02191         /* 
02192          * fragments are preallocated, grab one from the list 
02193          */
02194         while((newfrag = Frag3PreallocPop()) == NULL)
02195         {
02196             if (Frag3Prune(ft) == 0)
02197             {
02198                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02199                     "Frag3Insert: Pruning failed\n"););
02200 
02201                 return FRAG_INSERT_FAILED;
02202             }
02203         }
02204 
02205         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02206                     "got newfrag (%p) from prealloc\n", newfrag););
02207     }
02208 
02209     f3stats.fragnodes_created++;
02210 
02211     newfrag->ord = ft->ordinal++;
02212     /* 
02213      * twiddle the frag values for overlaps
02214      */
02215     newfrag->flen = left->flen;
02216     memcpy(newfrag->fptr, left->fptr, newfrag->flen);
02217     newfrag->data = newfrag->fptr + (left->data - left->fptr);
02218     newfrag->size = left->size;
02219     newfrag->offset = left->offset;
02220     newfrag->last = left->last;
02221 
02222     /*
02223      * insert the new frag into the list 
02224      */
02225     Frag3FraglistAddNode(ft, left, newfrag);
02226 
02227     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02228                 "[*] Inserted new frag %d@%d ptr %p data %p prv %p nxt %p\n", 
02229                 newfrag->size, newfrag->offset, newfrag, newfrag->data,
02230                 newfrag->prev, newfrag->next););
02231 
02232     /*
02233      * record the current size of the data in the fraglist
02234      */
02235     ft->frag_bytes += newfrag->size;
02236 
02237     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02238                 "[#] accumulated bytes on FragTracker %d, count"
02239                 " %d\n", ft->frag_bytes, ft->fraglist_count););
02240 
02241     *retFrag = newfrag;
02242     return FRAG_INSERT_OK;
02243 }
02244 
02245 /**
02246  * This is where the rubber hits the road.  Insert the new fragment's data 
02247  * into the current FragTracker's fraglist, doing anomaly detection and
02248  * handling overlaps in a target-based manner.
02249  *
02250  * @param p Current packet to insert
02251  * @param ft FragTracker to hold the packet
02252  * @param fkey FragKey with the current FragTracker's key info
02253  * @param f3context context of the current engine for target-based defrag info
02254  *
02255  * @return status
02256  * @retval FRAG_INSERT_TIMEOUT FragTracker has timed out and been dropped
02257  * @retval FRAG_INSERT_ATTACK  Attack detected during insertion
02258  * @retval FRAG_INSERT_ANOMALY Anomaly detected during insertion
02259  * @retval FRAG_INSERT_TTL Delta of TTL values beyond configured value
02260  * @retval FRAG_INSERT_OK Fragment has been inserted successfully
02261  */
02262 static int Frag3Insert(Packet *p, FragTracker *ft, FRAGKEY *fkey, 
02263         Frag3Context *f3context)
02264 {
02265     u_int16_t frag_offset;    /* calculated offset for this fragment */
02266     u_int16_t frag_end;       /* calculated end point for this fragment */
02267     int16_t trunc = 0;      /* we truncate off the tail */
02268     int32_t overlap = 0;    /* we overlap on either end of the frag */
02269     int16_t len = 0;        /* calculated size of the fragment */
02270     int16_t slide = 0;      /* slide up the front of the current frag */
02271     int done = 0;           /* flag for right-side overlap handling loop */
02272     int addthis = 1;           /* flag for right-side overlap handling loop */
02273     int i = 0;              /* counter */
02274     int delta = 0;
02275     int firstLastOk;
02276     int ret = FRAG_INSERT_OK;
02277     char lastfrag = 0;       /* Set to 1 when this is the 'last' frag */
02278     Frag3Frag *right = NULL; /* frag ptr for right-side overlap loop */
02279     Frag3Frag *newfrag = NULL;  /* new frag container */
02280     Frag3Frag *left = NULL;     /* left-side overlap fragment ptr */
02281     Frag3Frag *idx = NULL;      /* indexing fragment pointer for loops */
02282     Frag3Frag *dump_me = NULL;  /* frag ptr for complete overlaps to dump */
02283 
02284     u_int8_t *fragStart;
02285     int16_t fragLength;
02286     
02287     sfPerf.sfBase.iFragInserts++;
02288 
02289     /* 
02290      * check this fragtracker for expiration as well as 
02291      * the rest of the hash table
02292      */
02293     if(Frag3Expire(p, ft, fkey, f3context) == FRAG_TRACKER_TIMEOUT)
02294     {
02295         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02296                     "[..] Deleting fragtracker due to timeout!\n"););
02297 
02298         return FRAG_INSERT_TIMEOUT;
02299     }
02300 
02301     delta = abs(ft->ttl - p->iph->ip_ttl);
02302     if (delta > f3context->ttl_limit)
02303     {
02304         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02305                     "[..] Large TTL delta!\n"););
02306 
02307         return FRAG_INSERT_TTL;
02308     }
02309 
02310     /*
02311      * Check to see if this fragment is the first or last one and
02312      * set the appropriate flags and values in the FragTracker
02313      */
02314     firstLastOk = Frag3CheckFirstLast(p, ft);
02315 
02316     fragStart = (u_int8_t *)p->iph + IP_HLEN(p->iph) * 4;
02317     /* Use the actual length here, because packet may have been
02318      * truncated.  Don't want to try to copy more than we actually
02319      * captured. */
02320     len = fragLength = p->actual_ip_len - IP_HLEN(p->iph) * 4;
02321 #ifdef DEBUG
02322     if (p->actual_ip_len != ntohs(p->iph->ip_len))
02323     {
02324         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02325                "IP Actual Length (%d) != specified length (%d), "
02326                "truncated packet (%d)?\n",
02327                 p->actual_ip_len, ntohs(p->iph->ip_len), snaplen););
02328     }
02329 #endif    
02330 
02331     /*
02332      * setup local variables for tracking this frag
02333      */
02334     frag_offset = p->frag_offset << 3;
02335     /* Reset the offset to handle the weird Solaris case */
02336     if (firstLastOk == FRAG_LAST_OFFSET_ADJUST)
02337         frag_offset = (u_int16_t)ft->calculated_size;
02338     frag_end = frag_offset + fragLength;
02339 
02340     /* 
02341      * might have last frag...
02342      */
02343     if(!p->mf)
02344     {
02345         if ((frag_end > ft->calculated_size) &&
02346             (firstLastOk == FRAG_LAST_OFFSET_ADJUST))
02347         {
02348             ft->calculated_size = frag_end;
02349         }
02350 
02351         //    ft->frag_flags |= FRAG_GOT_LAST;
02352         //    ft->calculated_size = (p->frag_offset << 3) + fragLength;
02353         lastfrag = 1;
02354     }
02355     else
02356     {
02357         u_int16_t oldfrag_end;
02358         /* 
02359          * all non-last frags are supposed to end on 8-byte boundries 
02360          */
02361         if(frag_end & 7)
02362         {
02363             /* 
02364              * bonk/boink/jolt/etc attack... 
02365              */
02366             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02367                         "[..] Short frag (Bonk, etc) attack!\n"););
02368 
02369             EventAnomShortFrag(f3context);
02370 
02371             /* don't return, might still be interesting... */
02372         }
02373 
02374         /* can't have non-full fragments... */
02375         oldfrag_end = frag_end;
02376         frag_end &= ~7;
02377 
02378         /* Adjust len to take into account the jolting/non-full fragment. */
02379         len -= (oldfrag_end - frag_end);
02380 
02381         /*
02382          * if the end of this frag is greater than the max frag size we have a
02383          * problem
02384          */
02385         if(frag_end > ft->calculated_size)
02386         {
02387             if(ft->frag_flags & FRAG_GOT_LAST)
02388             {
02389                 /* oversize frag attack */
02390                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02391                             "[..] Oversize frag pkt!\n"););
02392 
02393                 EventAnomOversize(f3context);
02394 
02395                 return FRAG_INSERT_ANOMALY;
02396             }
02397             ft->calculated_size = frag_end;
02398         }
02399     }
02400 
02401     if(frag_end == frag_offset)
02402     {
02403         /* 
02404          * zero size frag... 
02405          */
02406         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02407                     "[..] Zero size frag!\n"););
02408 
02409         if(f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES)
02410         {
02411             EventAnomZeroFrag(f3context);
02412         }
02413 
02414         return FRAG_INSERT_ANOMALY;
02415     }
02416 
02417     if(ft->calculated_size > IP_MAXPACKET)
02418     {
02419         /* 
02420          * oversize pkt... 
02421          */
02422         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02423                     "[..] Oversize frag!\n"););
02424 
02425             EventAnomBadsizeLg(f3context);
02426 
02427         ft->frag_flags |= FRAG_BAD;
02428 
02429         return FRAG_INSERT_ANOMALY;
02430     }
02431 
02432     /* 
02433      * This may alert on bad options, but we still want to
02434      * insert the packet
02435      */
02436     Frag3HandleIPOptions(ft, p);
02437 
02438     ft->frag_pkts++;
02439 
02440     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02441                 "Walking frag list (%d nodes), new frag %d@%d\n",
02442                 ft->fraglist_count, fragLength, frag_offset););
02443 
02444     /* 
02445      * Need to figure out where in the frag list this frag should go
02446      * and who its neighbors are
02447      */
02448     for(idx = ft->fraglist; idx; idx = idx->next)
02449     {
02450         i++;
02451         right = idx;
02452 
02453         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02454                     "%d right o %d s %d ptr %p prv %p nxt %p\n", 
02455                     i, right->offset, right->size, right,
02456                     right->prev, right->next););
02457 
02458         if(right->offset >= frag_offset)
02459         {
02460             break;
02461         }
02462 
02463         left = right;
02464     }
02465 
02466     /* 
02467      * null things out if we walk to the end of the list 
02468      */
02469     if(idx == NULL) right = NULL;
02470 
02471     /* 
02472      * handle forward (left-side) overlaps... 
02473      */
02474     if(left)
02475     {
02476         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02477                     "Dealing with previous (left) frag %d@%d\n", 
02478                     left->size, left->offset););
02479 
02480         /*
02481          * generate the overlap of the current packet fragment 
02482          * over this left-side fragment
02483          */
02484         /* NOTE: If frag_offset is really large, overlap can be
02485          * negative because its stored as a 32bit int.
02486          */
02487         overlap = left->offset + left->size - frag_offset;
02488 
02489         if(overlap > 0)
02490         {
02491             if(frag_end < ft->calculated_size ||
02492                     ((ft->frag_flags & FRAG_GOT_LAST) && 
02493                      frag_end != ft->calculated_size))
02494             {
02495                 if (!p->mf)
02496                 {
02497                     /* 
02498                      * teardrop attack... 
02499                      */
02500                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02501                                 "[..] Teardrop attack!\n"););
02502 
02503                     EventAttackTeardrop(f3context);
02504 
02505                     ft->frag_flags |= FRAG_BAD;
02506 
02507                     return FRAG_INSERT_ATTACK;
02508                 }
02509             }
02510 
02511             f3stats.overlaps++;
02512 
02513             /*
02514              * Ok, we've got an overlap so we need to handle it.
02515              *
02516              * The target-based modes here match the data generated by 
02517              * Paxson's Active Mapping paper as do the policy types.
02518              */
02519             switch(f3context->frag_policy)
02520             {
02521                 /* 
02522                  * new frag gets moved around 
02523                  */
02524                 case FRAG_POLICY_LINUX:
02525                 case FRAG_POLICY_FIRST:
02526                 case FRAG_POLICY_WINDOWS:
02527                 case FRAG_POLICY_SOLARIS:
02528                 case FRAG_POLICY_BSD:
02529                     frag_offset += (int16_t)overlap;
02530                     slide = (int16_t)overlap;
02531 
02532                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02533                                 "left overlap, new frag moves: %d bytes, "
02534                                 "slide: %d\n", overlap, slide););
02535 
02536                     if(frag_end <= frag_offset)
02537                     {
02538                         /* 
02539                          * zero size frag
02540                          */
02541                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02542                                     "zero size frag"););
02543 
02544                         EventAnomZeroFrag(f3context);
02545 
02546                         return FRAG_INSERT_ANOMALY;
02547                     }
02548 
02549                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "left overlap, "
02550                                 "truncating new pkt (slide: %d)\n", slide););
02551 
02552                     break;
02553 
02554                     /* 
02555                      * new frag stays where it is, overlapee (existing frag) 
02556                      * gets whacked 
02557                      */
02558                 case FRAG_POLICY_BSD_RIGHT:
02559                     if ((f3context->frag_policy == FRAG_POLICY_BSD_RIGHT) &&
02560                              (left->offset + left->size >= frag_offset + len))
02561                     {
02562                         /* BSD-right (HP Printers) favor new fragments with lower/equal
02563                          * offset, EXCEPT when the existing fragment ends with at a
02564                          * higher/equal offset.
02565                          */
02566                         frag_offset += (int16_t)overlap;
02567                         slide = (int16_t)overlap;
02568                         goto left_overlap_last;
02569                     }
02570                     /* fall through */
02571                 case FRAG_POLICY_LAST:
02572                     if ((left->offset < frag_offset) && (left->offset + left->size > frag_offset + len))
02573                     {
02574                         /* The new frag is overlapped on both sides by an existing
02575                          * frag -- existing frag needs to be split and the new frag
02576                          * inserted in the middle.
02577                          * 
02578                          * Need to duplciate left.  Adjust that guys
02579                          * offset by + (frag_offset + len) and
02580                          * size by - (frag_offset + len - left->offset).
02581                          */
02582                         ret = DupFragNode(ft, left, &right);
02583                         if (ret != FRAG_INSERT_OK)
02584                         {
02585                             /* Some warning here,
02586                              * no, its done in AddFragNode */
02587                             return ret;
02588                         }
02589                         left->size -= (int16_t)overlap;
02590                         ft->frag_bytes -= (int16_t)overlap;
02591 
02592                         right->offset = frag_offset + len;
02593                         right->size -= (frag_offset + len - left->offset);
02594                         right->data += (frag_offset + len - left->offset);
02595                         ft->frag_bytes -= (frag_offset + len - left->offset);
02596                     }
02597                     else
02598                     {
02599                         left->size -= (int16_t)overlap;
02600                         ft->frag_bytes -= (int16_t)overlap;
02601                     }
02602 
02603 left_overlap_last:
02604                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] left overlap, "
02605                                 "truncating old pkt (offset: %d overlap: %d)\n",
02606                                 left->offset, overlap););
02607 
02608                     if (left->size <= 0)
02609                     {
02610                         dump_me = left;
02611 
02612                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
02613                                 "dumping old frag (offset: %d overlap: %d)\n", 
02614                                 dump_me->offset, overlap););
02615 
02616                         left = left->prev;
02617 
02618                         Frag3FraglistDeleteNode(ft, dump_me);
02619                     }
02620 
02621                     break;
02622             }
02623 
02624             /*
02625              * frag can't end before it begins...
02626              */
02627             if(frag_end < frag_offset)
02628             {
02629                 DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02630                             "frag_end < frag_offset!"););
02631 
02632                 if(f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES)
02633                 {
02634                     EventAnomBadsizeSm(f3context);
02635                 }
02636 
02637                 return FRAG_INSERT_ANOMALY;
02638             }
02639         }
02640         else
02641         {
02642             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "No left overlap!\n"););
02643         }
02644     }
02645 
02646     if ((u_int16_t)fragLength > snaplen)
02647     {
02648         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02649                     "Overly large fragment %d 0x%x 0x%x %d\n",
02650                     fragLength, p->iph->ip_len, p->iph->ip_off,
02651                     p->frag_offset << 3););
02652         return FRAG_INSERT_FAILED;
02653     }
02654 
02655     /* 
02656      * handle tail (right-side) overlaps
02657      *
02658      * We have to walk thru all the right side frags until the offset of the
02659      * existing frag is greater than the end of the new frag
02660      */
02661     while(right && (right->offset < frag_end) && !done)
02662     {
02663         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02664                     "Next (right)fragment %d@%d\n", 
02665                     right->size, right->offset););
02666 
02667 #ifdef DEBUG_FRAG3
02668         PrintFrag3Frag(right);
02669 #endif
02670         trunc = 0;
02671         overlap = frag_end - right->offset;
02672 
02673         if (overlap)
02674         {
02675             if(frag_end < ft->calculated_size ||
02676                     ((ft->frag_flags & FRAG_GOT_LAST) && 
02677                      frag_end != ft->calculated_size))
02678             {
02679                 if (!p->mf)
02680                 {
02681                     /* 
02682                      * teardrop attack... 
02683                      */
02684                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02685                                 "[..] Teardrop attack!\n"););
02686 
02687                     EventAttackTeardrop(f3context);
02688 
02689                     ft->frag_flags |= FRAG_BAD;
02690 
02691                     return FRAG_INSERT_ATTACK;
02692                 }
02693             }
02694         }
02695 
02696         /* 
02697          * partial right-side overlap, this will be the last frag to check 
02698          */
02699         if(overlap < right->size)
02700         {
02701             f3stats.overlaps++;
02702 
02703             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02704                         "Right-side overlap %d bytes\n", overlap););
02705 
02706             /* 
02707              * once again, target-based policy processing
02708              */
02709             switch(f3context->frag_policy)
02710             {
02711                 /* 
02712                  * existing fragment gets truncated 
02713                  */
02714                 case FRAG_POLICY_LAST:
02715                 case FRAG_POLICY_LINUX:
02716                 case FRAG_POLICY_BSD:
02717                     if ((f3context->frag_policy == FRAG_POLICY_BSD) &&
02718                         (right->offset == frag_offset))
02719                     {
02720                         slide = (int16_t)(right->offset + right->size - frag_offset);
02721                         frag_offset += (int16_t)slide;
02722                     }
02723                     else
02724                     {
02725                         right->offset += (int16_t)overlap;
02726                         right->data += (int16_t)overlap;
02727                         right->size -= (int16_t)overlap;
02728                         ft->frag_bytes -= (int16_t)overlap;
02729                     }
02730                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] right overlap, "
02731                                 "truncating old frag (offset: %d, "
02732                                 "overlap: %d)\n", right->offset, overlap);
02733                             DebugMessage(DEBUG_FRAG, 
02734                                 "Exiting right overlap loop...\n"););
02735                     if (right->size <= 0)
02736                     {
02737                         dump_me = right;
02738 
02739                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
02740                                 "dumping old frag (offset: %d overlap: %d)\n", 
02741                                 dump_me->offset, overlap););
02742 
02743                         right = right->next;
02744 
02745                         Frag3FraglistDeleteNode(ft, dump_me);
02746                     }
02747                     break;
02748 
02749                 /* 
02750                  * new frag gets truncated 
02751                  */
02752                 case FRAG_POLICY_FIRST:
02753                 case FRAG_POLICY_WINDOWS:
02754                 case FRAG_POLICY_SOLARIS:
02755                 case FRAG_POLICY_BSD_RIGHT:
02756                     trunc = (int16_t)overlap;
02757                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "[!!] right overlap, "
02758                                 "truncating new frag (offset: %d "
02759                                 "overlap: %d)\n", 
02760                                 right->offset, overlap);
02761                             DebugMessage(DEBUG_FRAG, 
02762                                 "Exiting right overlap loop...\n"););
02763                     break;
02764             }
02765 
02766             /*
02767              * all done, bail
02768              */
02769             done = 1;
02770         }
02771         else
02772         {
02773             /*
02774              * we've got a full overlap
02775              */
02776             if(f3context->frag3_alerts & FRAG3_DETECT_ANOMALIES)
02777             {
02778                 /* 
02779                  * retrans/full overlap
02780                  */
02781                 EventAnomOverlap(f3context);
02782                 f3stats.overlaps++;
02783             }
02784 
02785             /*
02786              * handle the overlap in a target-based manner
02787              */
02788             switch(f3context->frag_policy)
02789             {
02790                 /*
02791                  * overlap is treated differently if there is more
02792                  * data beyond the overlapped packet.
02793                  */
02794                 case FRAG_POLICY_WINDOWS:
02795                 case FRAG_POLICY_SOLARIS:
02796                 case FRAG_POLICY_BSD:
02797                     /*
02798                      * Old packet is overlapped on both sides...
02799                      * Drop the old packet.  This follows a
02800                      * POLICY_LAST model.
02801                      */
02802                     if ((frag_end > right->offset + right->size) &&
02803                         (frag_offset < right->offset))
02804                     {
02805                         dump_me = right;
02806                         ft->frag_bytes -= right->size;
02807 
02808                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
02809                                 "dumping old frag (offset: %d overlap: %d)\n", 
02810                                 dump_me->offset, overlap););
02811 
02812                         right = right->next;
02813 
02814                         Frag3FraglistDeleteNode(ft, dump_me);
02815                         break;
02816                     }
02817                     else
02818                     {
02819                         if ((f3context->frag_policy == FRAG_POLICY_SOLARIS) ||
02820                             (f3context->frag_policy == FRAG_POLICY_BSD))
02821                         {
02822                             /* SOLARIS & BSD only */
02823                             if ((frag_end == right->offset + right->size) &&
02824                                 (frag_offset < right->offset))
02825                             {
02826                                 /* If the frag overlaps an entire frag to the
02827                                  * right side of that frag, the old frag if
02828                                  * dumped -- this is a "policy last".
02829                                  */
02830                                 goto right_overlap_last;
02831                             }
02832                         }
02833                     }
02834                     /* Otherwise, treat it as a POLICY_FIRST,
02835                      * and trim accordingly. */
02836 
02837                     /* ie, fall through to the next case */
02838 
02839                 /* 
02840                  * overlap is rejected
02841                  */
02842                 case FRAG_POLICY_FIRST:
02843                     /* fix for bug 17823 */
02844                     if (right->offset == frag_offset)
02845                     {
02846                         slide = (int16_t)(right->offset + right->size - frag_offset);
02847                         frag_offset += (int16_t)slide;
02848                         left = right;
02849                         right = right->next;
02850                     }
02851                     else
02852                     {
02853                         trunc = (int16_t)overlap;
02854                     }
02855 
02856                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "right overlap, "
02857                                 "rejecting new overlap data (overlap: %d, "
02858                                 "trunc: %d)\n", overlap, trunc););
02859 
02860                     if (frag_end - trunc <= frag_offset)
02861                     {
02862                         /* 
02863                          * zero size frag
02864                          */
02865                         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02866                                     "zero size frag (len: %d  overlap: %d)\n", 
02867                                     fragLength, overlap););
02868 
02869                         f3stats.discards++;
02870 
02871                         return FRAG_INSERT_ANOMALY;
02872                     }
02873 
02874                     {
02875                         u_int16_t curr_end;
02876                         /* Full overlapping an already received packet
02877                          * and there are more packets beyond that fully
02878                          * overlapped one.
02879                          * Arrgh.  Need to insert this guy in chunks.
02880                          */
02881                         ret = AddFragNode(ft, p, f3context, fragStart, fragLength, 0, len,
02882                                 slide, trunc, frag_offset, left, &newfrag);
02883                         if (ret != FRAG_INSERT_OK)
02884                         {
02885                             /* Some warning here,
02886                              * no, its done in AddFragNode */
02887                             return ret;
02888                         }
02889 
02890                         curr_end = newfrag->offset + newfrag->size;
02891 
02892                         /* Find the next gap that this one might fill in */
02893                         while (right &&
02894                             (curr_end <= right->offset) &&
02895                             (right->offset < frag_end))
02896                         {
02897                             curr_end = right->offset + right->size;
02898                             left = right;
02899                             right = right->next;                            
02900                         }
02901 
02902                         if (right && (right->offset < frag_end))
02903                         {
02904                             /* Adjust offset to end of 'right' */
02905                             frag_offset = right->offset + right->size;
02906                             /* Not overlapping to the left anymore */
02907                             slide = 0;
02908                             /* Set 'left' so the next insert goes
02909                              * after the current 'right'
02910                              */
02911                             left = right;
02912                             /*
02913                              * Reset trunc, in case the next one kicks us
02914                              * out of the loop.  This packet will become the
02915                              * right-most entry so far.  Don't truncate any
02916                              * further.
02917                              */
02918                             trunc = 0;
02919                             if (right->next)
02920                                 continue;
02921                         }
02922 
02923                         if (curr_end < frag_end)
02924                         {
02925                             /* Insert this guy in his proper spot,
02926                              * adjust offset to the right-most endpoint
02927                              * we saw.
02928                              */
02929                             slide = left->offset + left->size - frag_offset;
02930                             frag_offset = curr_end;
02931                             trunc = 0;
02932                         }
02933                         else
02934                         {
02935                             addthis = 0;
02936                         }
02937                     }
02938                     break;
02939 
02940                     /* 
02941                      * retrans accepted, dump old frag 
02942                      */
02943 right_overlap_last:
02944                 case FRAG_POLICY_BSD_RIGHT:
02945                 case FRAG_POLICY_LAST:
02946                 case FRAG_POLICY_LINUX:
02947                     dump_me = right;
02948                     ft->frag_bytes -= right->size;
02949 
02950                     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "retrans, "
02951                                 "dumping old frag (offset: %d overlap: %d)\n", 
02952                                 dump_me->offset, overlap););
02953 
02954                     right = right->next;
02955 
02956                     Frag3FraglistDeleteNode(ft, dump_me);
02957 
02958                     break;
02959             }
02960         }
02961     }
02962 
02963     if (addthis)
02964     {
02965         ret = AddFragNode(ft, p, f3context, fragStart, fragLength, lastfrag, len,
02966                       slide, trunc, frag_offset, left, &newfrag);
02967     }
02968     else
02969     {
02970         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
02971                     "Fully truncated right overlap\n"););
02972     }
02973 
02974     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02975                 "Frag3Insert(): returning normally\n"););
02976 
02977     return ret;
02978 }
02979 
02980 /**
02981  * Check to see if a FragTracker has met all of its completion criteria
02982  *
02983  * @param ft FragTracker to check
02984  *
02985  * @return status
02986  * @retval 1 If the FragTracker is ready to be rebuilt
02987  * @retval 0 If the FragTracker hasn't fulfilled its completion criteria
02988  */
02989 static int INLINE Frag3IsComplete(FragTracker *ft)
02990 {
02991     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
02992                 "[$] Checking completion criteria\n"););
02993 
02994     /*
02995      * check to see if the first and last frags have arrived
02996      */
02997     if((ft->frag_flags & FRAG_GOT_FIRST) &&
02998             (ft->frag_flags & FRAG_GOT_LAST))
02999     {
03000         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03001                     "   Got First and Last frags\n"););
03002 
03003         /*
03004          * if we've accumulated enough data to match the calculated size
03005          * of the defragg'd packet, return 1
03006          */
03007         if(ft->frag_bytes == ft->calculated_size)
03008         {
03009             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03010                         "   [!] frag_bytes = calculated_size!\n"););
03011 
03012             sfPerf.sfBase.iFragCompletes++;
03013 
03014             return 1;
03015         }
03016 
03017         if (ft->frag_bytes > ft->calculated_size)
03018         {
03019             DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03020                         "   [!] frag_bytes > calculated_size!\n"););
03021 
03022             sfPerf.sfBase.iFragCompletes++;
03023 
03024             return 1;
03025         }
03026 
03027         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03028                     "   Calc size (%d) != frag bytes (%d)\n",
03029                     ft->calculated_size, ft->frag_bytes););
03030 
03031         /*
03032          * no dice
03033          */
03034         return 0;
03035     }
03036 
03037     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03038                 "   Missing First or Last frags (frag_flags: 0x%X)\n", 
03039                 ft->frag_flags););
03040 
03041     return 0;
03042 }
03043 
03044 /**
03045  * Reassemble the packet from the data in the FragTracker and reinject into
03046  * Snort's packet analysis system
03047  *
03048  * @param ft FragTracker to rebuild
03049  * @param p Packet to fill in pseudopacket IP structs
03050  *
03051  * @return none
03052  */
03053 static void Frag3Rebuild(FragTracker *ft, Packet *p)
03054 {
03055     u_int8_t *rebuild_ptr;  /* ptr to the start of the reassembly buffer */
03056     u_int8_t *rebuild_end;  /* ptr to the end of the reassembly buffer */
03057     Frag3Frag *frag;    /* frag pointer for managing fragments */
03058     u_int8_t new_ip_hlen = 0;
03059     u_int8_t save_ip_hlen = 0;
03060 
03061     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Rebuilding pkt [0x%X:%d  0x%X:%d]\n", 
03062                 p->iph->ip_src.s_addr, p->sp, 
03063                 p->iph->ip_dst.s_addr, p->dp);
03064             DebugMessage(DEBUG_FRAG, "Calculated size: %d\n", 
03065                 ft->calculated_size);
03066             DebugMessage(DEBUG_FRAG, "Frag Bytes: %d\n", ft->frag_bytes);
03067             );
03068 
03069     /* 
03070      * set the timestamps on the rebuild packet 
03071      * from the last packet of the frag 
03072      */
03073     defrag_pkt->pkth->ts.tv_sec = p->pkth->ts.tv_sec;
03074     defrag_pkt->pkth->ts.tv_usec = p->pkth->ts.tv_usec;
03075 
03076     /* 
03077      * set the pointer to the end of the rebuild packet
03078      */
03079     rebuild_end = defrag_pkt->pkt + DATASIZE;
03080 
03081     /*
03082      * If there are IP options for this reassembled frag, adjust
03083      * the IP Header length in the current packet here before
03084      * copying that into the rebuilt packet.
03085      */
03086     if (ft->ip_options_data && ft->ip_options_len)
03087     {
03088         save_ip_hlen = new_ip_hlen = IP_HLEN(p->iph);
03089         /*
03090          * New length is old length, less the options in this packet,
03091          * plus the options for the rebuilt fragment.  Option len
03092          * from packet & frag tracker are in bytes, header length
03093          * is in words, so shift it.
03094          */
03095         new_ip_hlen += (u_int8_t)((ft->ip_options_len - p->ip_options_len) >> 2);
03096         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03097                 "Adjusting IP Header from %d to %d bytes\n",
03098                 save_ip_hlen, new_ip_hlen););
03099         SET_IP_HLEN(p->iph, new_ip_hlen);
03100     }
03101 
03102     /* copy the packet data from the last packet of the frag */
03103     SafeMemcpy(defrag_pkt->pkt, p->pkt, ETHERNET_HEADER_LEN + sizeof(IPHdr),
03104             defrag_pkt->pkt, rebuild_end);
03105 
03106     /*
03107      * set the pointer to the beginning of the transport layer of the
03108      * rebuilt packet
03109      */
03110     rebuild_ptr = defrag_pkt->pkt + ETHERNET_HEADER_LEN + sizeof(IPHdr);
03111 
03112     /*
03113      * if there are IP options, copy those in as well
03114      */
03115     if (ft->ip_options_data && ft->ip_options_len)
03116     {
03117         SafeMemcpy(rebuild_ptr, ft->ip_options_data, ft->ip_options_len,
03118             rebuild_ptr, rebuild_end);
03119 
03120         /*
03121          * adjust the pointer to the beginning of the transport layer of the
03122          * rebuilt packet
03123          */
03124         rebuild_ptr += ft->ip_options_len;
03125 
03126         /*
03127          * Reset the current packet with its original IP Header length
03128          */
03129         SET_IP_HLEN(p->iph, save_ip_hlen);
03130     }
03131     else if (ft->copied_ip_options_len)
03132     {
03133         /* XXX: should we log a warning here?  there were IP options
03134          * copied across all fragments, EXCEPT the offset 0 fragment.
03135          */
03136     }
03137 
03138     /* 
03139      * reset the ip header pointer 
03140      */
03141     defrag_pkt->iph = (IPHdr *) (defrag_pkt->pkt + ETHERNET_HEADER_LEN);
03142 
03143     /* 
03144      * clear the packet fragment fields 
03145      */ 
03146     defrag_pkt->iph->ip_off = 0x0000;
03147     defrag_pkt->frag_flag = 0;
03148 
03149     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03150                 "[^^] Walking fraglist:\n"););
03151 
03152     /* 
03153      * walk the fragment list and rebuild the packet 
03154      */
03155     for(frag = ft->fraglist; frag; frag = frag->next)
03156     {
03157         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03158                     "   frag: %p\n"
03159                     "   frag->data: %p\n"
03160                     "   frag->offset: %d\n"
03161                     "   frag->size: %d\n"
03162                     "   frag->prev: %p\n"
03163                     "   frag->next: %p\n",
03164                     frag, frag->data, frag->offset, 
03165                     frag->size, frag->prev, frag->next););
03166 
03167         /*
03168          * We somehow got a frag that had data beyond the calculated
03169          * end. Don't want to include it.
03170          */
03171         if ((frag->offset + frag->size) > (u_int16_t)ft->calculated_size)
03172             continue;
03173 
03174         /* 
03175          * try to avoid buffer overflows...
03176          */
03177         if (frag->size)
03178             SafeMemcpy(rebuild_ptr+frag->offset, frag->data, frag->size, 
03179                 rebuild_ptr, rebuild_end);
03180 
03181     }
03182 
03183     /* 
03184      * set the new packet's capture length 
03185      */
03186     if((ETHERNET_HEADER_LEN + ft->calculated_size + sizeof(IPHdr)
03187                             + ft->ip_options_len) > 
03188             (IP_MAXPACKET-1))
03189     {
03190         /* don't let other pcap apps die when they process this file
03191          * -- yes this opens us up for 14 bytes at the end of the
03192          * giant packet.
03193          */
03194 #ifdef DONT_TRUNCATE
03195         defrag_pkt->pkth->caplen = IP_MAXPACKET - 1;
03196 #else /* DONT_TRUNCATE */
03197         defrag_pkt->pkth->caplen = ETHERNET_HEADER_LEN +
03198             ft->calculated_size + sizeof(IPHdr) + ft->ip_options_len ;
03199 #endif /* DONT_TRUNCATE */
03200     }
03201     else
03202     {
03203         defrag_pkt->pkth->caplen = ETHERNET_HEADER_LEN +
03204             ft->calculated_size + sizeof(IPHdr) + ft->ip_options_len;
03205     }
03206 
03207     defrag_pkt->pkth->len = defrag_pkt->pkth->caplen;
03208 
03209     /* 
03210      * set the ip dgm length 
03211      */
03212     defrag_pkt->iph->ip_len = htons((short)(defrag_pkt->pkth->len-ETHERNET_HEADER_LEN));
03213     defrag_pkt->actual_ip_len = ntohs(defrag_pkt->iph->ip_len);
03214 
03215     /* 
03216      * tell the rest of the system that this is a rebuilt fragment 
03217      */
03218     defrag_pkt->packet_flags = PKT_REBUILT_FRAG;
03219     defrag_pkt->frag_flag = 0;
03220     defrag_pkt->iph->ip_csum = 0;
03221 
03222     /* 
03223      * calculate the ip checksum for the packet 
03224      */
03225     defrag_pkt->iph->ip_csum  = 
03226         in_chksum_ip((u_int16_t *)defrag_pkt->iph, sizeof(IPHdr) + ft->ip_options_len);
03227 
03228     pc.rebuilt_frags++;
03229     sfPerf.sfBase.iFragFlushes++;
03230 
03231     /* 
03232      * process the packet through the detection engine 
03233      */
03234     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03235                 "Processing rebuilt packet:\n"););
03236 
03237     f3stats.reassembles++;
03238 
03239     UpdateIPReassStats(&(sfPerf.sfBase), defrag_pkt->pkth->caplen);
03240 
03241 #ifdef DEBUG_FRAG3
03242     /*
03243      * Note, that this won't print out the IP Options or any other
03244      * data that is established when the packet is decoded.
03245      */
03246     if (DEBUG_FRAG & GetDebugLevel())
03247     {
03248         ClearDumpBuf();
03249         printf("++++++++++++++++++Frag3 DEFRAG'd PACKET++++++++++++++\n");
03250         PrintIPPkt(stdout, defrag_pkt->iph->ip_proto, defrag_pkt);
03251         printf("++++++++++++++++++Frag3 DEFRAG'd PACKET++++++++++++++\n");
03252         ClearDumpBuf();
03253     }
03254 #endif
03255     ProcessPacket(NULL, defrag_pkt->pkth, defrag_pkt->pkt, ft);
03256 
03257     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03258                 "Done with rebuilt packet, marking rebuilt...\n"););
03259 
03260     ft->frag_flags = ft->frag_flags | FRAG_REBUILT;
03261 }
03262 
03263 
03264 /**
03265  * Initialize the packet data buffers for the reassembly pseudopacket
03266  *
03267  * @param none
03268  *
03269  * @return none
03270  */
03271 static void Frag3InitPkt()
03272 {
03273     /* 
03274      * allocate packet buffer 
03275      */
03276     defrag_pkt->pkth =  SnortAlloc(sizeof(SnortPktHeader));
03277     defrag_pkt->pkt = (u_int8_t *) SnortAlloc(DATASIZE + SPARC_TWIDDLE);
03278 
03279     /* 
03280      * kludge for alignment 
03281      */
03282     defrag_pkt->pkt += SPARC_TWIDDLE;
03283 
03284     if(defrag_pkt->pkth == NULL || defrag_pkt->pkt == NULL)
03285     {
03286         FatalError("Out of memory on Frag3InitPkt()\n");
03287     }
03288 }
03289 
03290 /**
03291  * Delete a Frag3Frag struct
03292  *
03293  * @param frag Fragment to delete
03294  *
03295  * @return none
03296  */
03297 static void Frag3DeleteFrag(Frag3Frag *frag)
03298 {
03299     /* 
03300      * delete the fragment either in prealloc or dynamic mode
03301      */
03302     if(!global_config.use_prealloc)
03303     {
03304         free(frag->fptr);
03305         mem_in_use -= frag->flen;
03306 
03307         free(frag);
03308         mem_in_use -= sizeof(Frag3Frag);
03309     }
03310     else
03311     {
03312         DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "o %d s %d ptr %p prv %p nxt %p\n", 
03313                     frag->offset, frag->size, frag, frag->prev, frag->next););
03314         Frag3PreallocPush(frag);
03315     }
03316 
03317     f3stats.fragnodes_released++;
03318 }
03319 
03320 /**
03321  * Delete the contents of a FragTracker, in this instance that just means to 
03322  * dump the fraglist.  The sfxhash system deletes the actual FragTracker mem.
03323  *
03324  * @param ft FragTracker to delete
03325  *
03326  * @return none
03327  */
03328 static void Frag3DeleteTracker(FragTracker *ft)
03329 {
03330     Frag3Frag *idx = ft->fraglist;  /* pointer to the fraglist to delete */
03331     Frag3Frag *dump_me = NULL;      /* ptr to the Frag3Frag element to drop */
03332 
03333     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03334                 "Frag3DeleteTracker %d nodes to dump\n", ft->fraglist_count);); 
03335 
03336     /*
03337      * delete all the nodes in a fraglist
03338      */
03339     while(idx)
03340     {
03341         dump_me = idx;
03342         idx = idx->next;
03343         Frag3DeleteFrag(dump_me);
03344     }
03345     if (ft->ip_options_data)
03346     {
03347         free(ft->ip_options_data);
03348         ft->ip_options_data = NULL;
03349     }
03350 
03351     return;
03352 }
03353 
03354 /**
03355  * Remove a FragTracker from the f_cache hash table
03356  *
03357  * @param key FragKey of the FragTracker to be removed
03358  * @param data unused in this function
03359  *
03360  * @return none
03361  */
03362 static void Frag3RemoveTracker(void *key, void *data)
03363 {
03364     /* 
03365      * sfxhash maintains its own self preservation stuff/node freeing stuff
03366      */
03367     if(sfxhash_remove(f_cache, key) != SFXHASH_OK)
03368     {
03369         ErrorMessage("sfxhash_remove() failed in frag3!\n");
03370     }
03371 
03372     return;
03373 }
03374 
03375 /**
03376  * This is the auto-node-release function that gets handed to the sfxhash table
03377  * at initialization.  Handles deletion of sfxhash table data members.
03378  *
03379  * @param key FragKey of the element to be freed
03380  * @param data unused in this implementation
03381  *
03382  * Now Returns 0 because we want to say, yes, delete that hash entry!!!
03383  */
03384 static int Frag3AutoFree(void *key, void *data)
03385 {
03386     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03387                 "Calling Frag3DeleteTracker()\n"););
03388 
03389     Frag3DeleteTracker((FragTracker *) data);
03390 
03391     sfPerf.sfBase.iFragDeletes++;
03392     sfPerf.sfBase.iFragAutoFrees++;
03393     sfPerf.sfBase.iCurrentFrags--;
03394     f3stats.fragtrackers_autoreleased++;
03395 
03396     return 0;
03397 }
03398 
03399 /**
03400  * This is the user free function that gets handed to the sfxhash table
03401  * at initialization.  Handles deletion of sfxhash table data members.
03402  *
03403  * @param key FragKey of the element to be freed
03404  * @param data unused in this implementation
03405  *
03406  * Now Returns 0 because we want to say, yes, delete that hash entry!!!
03407  */
03408 static int Frag3UserFree(void *key, void *data)
03409 {
03410     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, 
03411                 "Calling Frag3DeleteTracker()\n"););
03412 
03413     Frag3DeleteTracker((FragTracker *) data);
03414 
03415     sfPerf.sfBase.iFragDeletes++;
03416     sfPerf.sfBase.iCurrentFrags--;
03417     f3stats.fragtrackers_released++;
03418 
03419     return 0;
03420 }
03421 
03422 /**
03423  * This function gets called either when we run out of prealloc nodes or when
03424  * the memcap is exceeded.  Its job is to free memory up in frag3 by deleting
03425  * old/stale data.  Currently implemented using a simple LRU pruning
03426  * technique, could probably benefit from having some sort of tail selection
03427  * randomization added to it.  Additonally, right now when we hit the wall we
03428  * try to drop at least enough memory to satisfy the "ten_percent" value.
03429  * Hopefully that's not too aggressive, salt to taste!
03430  *
03431  * @param none
03432  *
03433  * @return none
03434  */
03435 static int Frag3Prune(FragTracker *not_me)
03436 {
03437     SFXHASH_NODE *hnode;
03438     int found_this = 0;
03439     int pruned = 0;
03440 #ifdef DEBUG
03441     /* Use these to print out whether the frag tracker has
03442      * expired or not.
03443      */
03444     FragTracker *ft;
03445     struct timeval *fttime;     /* FragTracker timestamp */
03446 #endif
03447 
03448     sfPerf.sfBase.iFragFaults++;
03449     f3stats.prunes++;
03450 
03451     if(!global_config.use_prealloc)
03452     {
03453         //while(mem_in_use > (global_config.memcap-ten_percent))
03454         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03455                     "(spp_frag3) Frag3Prune: Pruning by memcap! "););
03456         while((mem_in_use > global_config.memcap) ||
03457               (f_cache->count > (global_config.max_frags - 5)))
03458         {
03459             hnode = sfxhash_lru_node(f_cache);
03460             if (hnode && hnode->data == not_me)
03461             {
03462                 if (found_this)
03463                 {
03464                     /* Uh, problem... we've gone through the entire list */
03465                     LogMessage("(spp_frag3) Frag3Prune: Pruning by memcap - empty list! ");
03466                     return pruned;
03467                 }
03468                 sfxhash_gmovetofront(f_cache, hnode);
03469                 found_this = 1;
03470                 continue;
03471             }
03472 #ifdef DEBUG
03473             ft = hnode->data;
03474             fttime = &(ft->frag_time);
03475 
03476             if (CheckTimeout(pkttime,fttime,ft->context)==FRAG_TIMEOUT)
03477             {
03478                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (timeout)! "
03479                     "[0x%08X->0x%08X ID: %d Count: %d]\n", ft->sip, ft->dip, 
03480                     ft->id, ft->fraglist_count);
03481                 f3stats.timeouts++;
03482                 sfPerf.sfBase.iFragTimeouts++;
03483             }
03484             else
03485             {
03486                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (memory)! "
03487                     "[0x%08X->0x%08X ID: %d Count: %d]\n", ft->sip, ft->dip, 
03488                     ft->id, ft->fraglist_count);
03489             }
03490 #endif
03491             Frag3RemoveTracker(hnode->key, hnode->data);
03492             //sfPerf.sfBase.iFragDeletes++;
03493             //f3stats.fragtrackers_released++;
03494             pruned++;
03495         }
03496     }
03497     else
03498     {
03499         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03500                     "(spp_frag3) Frag3Prune: Pruning by prealloc! "););
03501         while(prealloc_nodes_in_use>(global_config.static_frags-ten_percent))
03502         {
03503             hnode = sfxhash_lru_node(f_cache);
03504             if (hnode && hnode->data == not_me)
03505             {
03506                 if (found_this)
03507                 {
03508                     /* Uh, problem... we've gone through the entire list */
03509                     LogMessage("(spp_frag3) Frag3Prune: Pruning by prealloc - empty list! ");
03510                     return pruned;
03511                 }
03512                 sfxhash_gmovetofront(f_cache, hnode);
03513                 found_this = 1;
03514                 continue;
03515             }
03516 
03517 #ifdef DEBUG
03518             ft = hnode->data;
03519             fttime = &(ft->frag_time);
03520 
03521             if (CheckTimeout(pkttime,fttime,ft->context)==FRAG_TIMEOUT)
03522             {
03523                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (timeout)! "
03524                     "[0x%08X->0x%08X ID: %d Count: %d]\n", ft->sip, ft->dip, 
03525                     ft->id, ft->fraglist_count);
03526                 f3stats.timeouts++;
03527                 sfPerf.sfBase.iFragTimeouts++;
03528             }
03529             else
03530             {
03531                 LogMessage("(spp_frag3) Frag3Prune: Fragment dropped (memory)! "
03532                     "[0x%08X->0x%08X ID: %d Count: %d]\n", ft->sip, ft->dip, 
03533                     ft->id, ft->fraglist_count);
03534             }
03535 #endif
03536 
03537             Frag3RemoveTracker(hnode->key, hnode->data);
03538             //sfPerf.sfBase.iFragDeletes++;
03539             //f3stats.fragtrackers_released++;
03540             pruned++;
03541         }
03542     }
03543 
03544     DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03545                 "(spp_frag3) Frag3Prune: Pruned %d nodes\n", pruned););
03546     return pruned;
03547 }
03548 
03549 /**
03550  * Print out the frag stats from this run
03551  *
03552  * @param none
03553  *
03554  * @return none
03555  */
03556 void Frag3PrintStats()
03557 {
03558     LogMessage("Frag3 statistics:\n");
03559     LogMessage("        Total Fragments: %lu\n", f3stats.total);
03560     LogMessage("      Frags Reassembled: %lu\n", f3stats.reassembles);
03561     LogMessage("               Discards: %lu\n", f3stats.discards);
03562     LogMessage("          Memory Faults: %lu\n", f3stats.prunes);
03563     LogMessage("               Timeouts: %lu\n", f3stats.timeouts);
03564     LogMessage("               Overlaps: %lu\n", f3stats.overlaps);
03565     LogMessage("              Anomalies: %lu\n", f3stats.anomalies);
03566     LogMessage("                 Alerts: %lu\n", f3stats.alerts);
03567     LogMessage("     FragTrackers Added: %lu\n", f3stats.fragtrackers_created);
03568     LogMessage("    FragTrackers Dumped: %lu\n", f3stats.fragtrackers_released);
03569     LogMessage("FragTrackers Auto Freed: %lu\n", f3stats.fragtrackers_autoreleased);
03570     LogMessage("    Frag Nodes Inserted: %lu\n", f3stats.fragnodes_created);
03571     LogMessage("     Frag Nodes Deleted: %lu\n", f3stats.fragnodes_released);
03572 
03573     LogMessage("===================================================="
03574             "===========================\n");
03575 }
03576 
03577 /**
03578  * Basic restart function required by preprocessors
03579  */
03580 void Frag3Restart(int signal, void *foo)
03581 {
03582     Frag3PrintStats();
03583     return;
03584 }
03585 
03586 /**
03587  * CleanExit func required by preprocessors
03588  */
03589 void Frag3CleanExit(int signal, void *foo)
03590 {
03591     Frag3PrintStats();
03592 
03593     //sfxhash_delete(f_cache);
03594     //f_cache = NULL;
03595 
03596     return;
03597 }
03598 
03599 /**
03600  * Get a node from the prealloc_list
03601  *
03602  * @return pointer to a Frag3Frag preallocated structure or NULL if the list
03603  * is empty
03604  */
03605 static INLINE Frag3Frag *Frag3PreallocPop()
03606 {
03607     Frag3Frag *node;
03608 
03609     if(prealloc_frag_list)
03610     {
03611         node = prealloc_frag_list;
03612         prealloc_frag_list = prealloc_frag_list->next; 
03613         if (prealloc_frag_list)
03614         {
03615             prealloc_frag_list->prev = NULL;
03616         }
03617         else
03618         {
03619             DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03620                         "Using last prealloc frag node\n"););
03621         }
03622         node->next = NULL;
03623         node->prev = NULL;
03624         node->offset = 0;
03625         node->size = 0;
03626         node->flen = 0;
03627         node->last = 0;
03628     }
03629     else
03630     {
03631         return NULL;
03632     }
03633 
03634     if (!node->fptr)
03635     {
03636         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03637                         "Frag3Frag fptr is NULL!\n"););
03638     }
03639 
03640     prealloc_nodes_in_use++;
03641     return node;
03642 }
03643 
03644 /** 
03645  * Put a prealloc node back into the prealloc_cache pool
03646  *
03647  * @param node Prealloc node to place back in the pool
03648  *
03649  * @return none
03650  */
03651 static INLINE void Frag3PreallocPush(Frag3Frag *node)
03652 {
03653     if (!prealloc_frag_list)
03654     {
03655         node->next = NULL;
03656         node->prev = NULL;
03657     }
03658     else
03659     {
03660         node->next = prealloc_frag_list;
03661         node->prev = NULL;
03662         prealloc_frag_list->prev = node;
03663     }
03664 
03665     prealloc_frag_list = node;
03666     node->data = NULL;
03667     if (!node->fptr)
03668     {
03669         DEBUG_WRAP(DebugMessage(DEBUG_FRAG,
03670                         "Frag3Frag fptr is NULL!\n"););
03671     }
03672 
03673     prealloc_nodes_in_use--;
03674     return;
03675 }
03676 
03677 /**
03678  * Plug a Frag3Frag into the fraglist of a FragTracker
03679  *
03680  * @param ft FragTracker to put the new node into
03681  * @param prev ptr to preceeding Frag3Frag in fraglist
03682  * @param next ptr to following Frag3Frag in fraglist
03683  * @param node ptr to node to put in list
03684  *
03685  * @return none
03686  */
03687 static INLINE void Frag3FraglistAddNode(FragTracker *ft, Frag3Frag *prev, 
03688         Frag3Frag *node) 
03689 {
03690     if(prev)
03691     {
03692         node->next = prev->next;
03693         node->prev = prev;
03694         prev->next = node;
03695         if (node->next)
03696             node->next->prev = node;
03697         else
03698             ft->fraglist_tail = node;
03699     }
03700     else
03701     {
03702         node->next = ft->fraglist;
03703         if (node->next)
03704             node->next->prev = node;
03705         else
03706             ft->fraglist_tail = node;
03707         ft->fraglist = node;
03708     }
03709 
03710     ft->fraglist_count++;
03711     return;
03712 }
03713 
03714 /**
03715  * Delete a Frag3Frag from a fraglist
03716  *
03717  * @param ft FragTracker to delete the frag from
03718  * @param node node to be deleted
03719  *
03720  * @return none
03721  */
03722 static INLINE void Frag3FraglistDeleteNode(FragTracker *ft, Frag3Frag *node)
03723 {
03724     DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Deleting list node %p (p %p n %p)\n",
03725                 node, node->prev, node->next););
03726 
03727     if(node->prev)
03728         node->prev->next = node->next;
03729     else
03730         ft->fraglist = node->next;
03731 
03732     if(node->next)
03733         node->next->prev = node->prev;
03734     else
03735         ft->fraglist_tail = node->prev;
03736 
03737     Frag3DeleteFrag(node);
03738     ft->fraglist_count--;
03739 }
03740 
03741 /*
03742 **  
03743 **  NAME
03744 **    fpAddFragAlert::
03745 **
03746 **  DESCRIPTION
03747 **    This function flags an alert per frag tracker.
03748 **
03749 **  FORMAL INPUTS
03750 **    Packet *     - the packet to inspect
03751 **    OTNX *       - the rule that generated the alert
03752 **
03753 **  FORMAL OUTPUTS
03754 **    int - 0 if not flagged
03755 **          1 if flagged
03756 **
03757 */
03758 int fpAddFragAlert(Packet *p, OTNX *otnx)
03759 {
03760     FragTracker *ft = p->fragtracker;
03761 
03762     if ( !ft )
03763         return 0;
03764 
03765     if ( !otnx )
03766         return 0;
03767 
03768     if ( !otnx->otn )
03769         return 0;
03770 
03771     /* Only track a certain number of alerts per session */
03772     if ( ft->alert_count >= MAX_FRAG_ALERTS )
03773         return 0;
03774 
03775     ft->alert_gid[ft->alert_count] = otnx->otn->sigInfo.generator;
03776     ft->alert_sid[ft->alert_count] = otnx->otn->sigInfo.id;
03777     ft->alert_count++;
03778 
03779     return 1;
03780 }
03781 
03782 /*
03783 **  
03784 **  NAME
03785 **    fpFragAlerted::
03786 **
03787 **  DESCRIPTION
03788 **    This function indicates whether or not an alert has been generated previously
03789 **    in this session, but only if this is a rebuilt packet.
03790 **
03791 **  FORMAL INPUTS
03792 **    Packet *     - the packet to inspect
03793 **    OTNX *       - the rule that generated the alert
03794 **
03795 **  FORMAL OUTPUTS
03796 **    int - 0 if alert NOT previously generated
03797 **          1 if alert previously generated
03798 **
03799 */
03800 int fpFragAlerted(Packet *p, OTNX *otnx)
03801 {
03802     FragTracker *ft = p->fragtracker;
03803     SigInfo *si = &otnx->otn->sigInfo;
03804     int      i;
03805 
03806     if ( !ft )
03807         return 0;
03808 
03809     for ( i = 0; i < ft->alert_count; i++ )
03810     {
03811         /*  If this is a rebuilt packet and we've seen this alert before, return
03812          *  that we have previously alerted on a non-rebuilt packet.
03813          */
03814         if ( (p->packet_flags & PKT_REBUILT_FRAG)
03815                 && ft->alert_gid[i] == si->generator && ft->alert_sid[i] == si->id )
03816         {
03817             return 1;
03818         }
03819     }
03820 
03821     return 0;
03822 }
03823 

Generated on Sun May 14 14:51:16 2006 by  doxygen 1.4.2