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