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