1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2003-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 /*
21 * sfthd.cc author Marc Norton
22 *
23 * An Abstracted Event Thresholding System
24 *
25 * 3/5/07 - man - fixed memory leak in global config to limit
26 * of one gid=0, or multiple gid!=0 but not both.
27 * Boris Lytochkin found it.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "sfthd.h"
35
36 #include <cassert>
37
38 #include "hash/ghash.h"
39 #include "hash/hash_defs.h"
40 #include "hash/xhash.h"
41 #include "main/thread.h"
42 #include "sfip/sf_ipvar.h"
43 #include "utils/dyn_array.h"
44 #include "utils/sflsq.h"
45 #include "utils/util.h"
46
47 using namespace snort;
48
49 // Debug Printing
50 //#define THD_DEBUG
51
52 THREAD_LOCAL EventFilterStats event_filter_stats;
53
sfthd_new_hash(unsigned nbytes,size_t key,size_t data)54 XHash* sfthd_new_hash(unsigned nbytes, size_t key, size_t data)
55 {
56 size_t size = key + data;
57 int nrows;
58
59 /* Calc max ip nodes for this memory */
60 if ( nbytes < size )
61 nbytes = size;
62 nrows = nbytes / size;
63
64 return new XHash(nrows, key, data, nbytes);
65 }
66
67 /*!
68 Create a threshold table, initialize the threshold system,
69 and optionally limit it's memory usage.
70
71 @param nbytes maximum memory to use for thresholding objects, in bytes.
72
73 @return THD_STRUCT*
74 @retval 0 error
75 @retval !0 valid THD_STRUCT
76 */
77
sfthd_local_new(unsigned bytes)78 XHash* sfthd_local_new(unsigned bytes)
79 {
80 XHash* local_hash =
81 sfthd_new_hash(bytes,
82 sizeof(THD_IP_NODE_KEY),
83 sizeof(THD_IP_NODE));
84
85 #ifdef THD_DEBUG
86 if ( !local_hash )
87 printf("Could not allocate the sfxhash table\n");
88 #endif
89
90 return local_hash;
91 }
92
sfthd_global_new(unsigned bytes)93 XHash* sfthd_global_new(unsigned bytes)
94 {
95 XHash* global_hash =
96 sfthd_new_hash(bytes,
97 sizeof(THD_IP_GNODE_KEY),
98 sizeof(THD_IP_NODE));
99
100 #ifdef THD_DEBUG
101 if ( !global_hash )
102 printf("Could not allocate the sfxhash table\n");
103 #endif
104
105 return global_hash;
106 }
107
sfthd_new(unsigned lbytes,unsigned gbytes)108 THD_STRUCT* sfthd_new(unsigned lbytes, unsigned gbytes)
109 {
110 THD_STRUCT* thd;
111
112 /* Create the THD struct */
113 thd = (THD_STRUCT*)snort_calloc(sizeof(THD_STRUCT));
114
115 /* Create hash table for all of the local IP Nodes */
116 thd->ip_nodes = sfthd_local_new(lbytes);
117 if ( !thd->ip_nodes )
118 {
119 #ifdef THD_DEBUG
120 printf("Could not allocate the sfxhash table\n");
121 #endif
122 snort_free(thd);
123 return nullptr;
124 }
125
126 if ( gbytes == 0 )
127 return thd;
128
129 /* Create hash table for all of the global IP Nodes */
130 thd->ip_gnodes = sfthd_global_new(gbytes);
131 if ( !thd->ip_gnodes )
132 {
133 #ifdef THD_DEBUG
134 printf("Could not allocate the sfxhash table\n");
135 #endif
136 delete thd->ip_nodes;
137 snort_free(thd);
138 return nullptr;
139 }
140
141 return thd;
142 }
143
sfthd_objs_new()144 ThresholdObjects* sfthd_objs_new()
145 {
146 return (ThresholdObjects*)snort_calloc(sizeof(ThresholdObjects));
147 }
148
sfthd_node_free(THD_NODE * sfthd_node)149 void sfthd_node_free(THD_NODE* sfthd_node)
150 {
151 if ( !sfthd_node )
152 return;
153
154 if ( sfthd_node->ip_address )
155 sfvar_free(sfthd_node->ip_address);
156
157 snort_free(sfthd_node);
158 }
159
sfthd_node_free(void * node)160 static void sfthd_node_free(void* node)
161 { sfthd_node_free((THD_NODE*)node); }
162
sfthd_objs_free(ThresholdObjects * thd_objs)163 void sfthd_objs_free(ThresholdObjects* thd_objs)
164 {
165 if (thd_objs == nullptr)
166 return;
167
168 for (int i = 0; i < THD_MAX_GENID; i++)
169 {
170 if ( thd_objs->sfthd_array[i] )
171 delete thd_objs->sfthd_array[i];
172 }
173
174 for (PolicyId policy_id = 0; policy_id < thd_objs->numPoliciesAllocated; policy_id++)
175 {
176 if ( !thd_objs->sfthd_garray[policy_id] )
177 continue;
178
179 if ( thd_objs->sfthd_garray[policy_id][0] )
180 {
181 sfthd_node_free(thd_objs->sfthd_garray[policy_id][0]);
182
183 /* Free any individuals */
184 for (int i = 0; i < THD_MAX_GENID; i++)
185 {
186 if ( thd_objs->sfthd_garray[policy_id][i] !=
187 thd_objs->sfthd_garray[policy_id][0] )
188 {
189 sfthd_node_free(thd_objs->sfthd_garray[policy_id][i]);
190 }
191 }
192 }
193 else
194 {
195 /* Anything other GID will be allocated individually */
196 for (int i = 1; i < THD_MAX_GENID; i++)
197 {
198 if ( thd_objs->sfthd_garray[policy_id][i] )
199 sfthd_node_free(thd_objs->sfthd_garray[policy_id][i]);
200 }
201 }
202
203 snort_free(thd_objs->sfthd_garray[policy_id]);
204 }
205
206 if ( thd_objs->sfthd_garray )
207 snort_free(thd_objs->sfthd_garray);
208
209 snort_free(thd_objs);
210 }
211
sfthd_item_free(void * item)212 static void sfthd_item_free(void* item)
213 {
214 THD_ITEM* sfthd_item = (THD_ITEM*)item;
215 sflist_free_all(sfthd_item->sfthd_node_list, sfthd_node_free);
216 snort_free(sfthd_item);
217 }
218
sfthd_free(THD_STRUCT * thd)219 void sfthd_free(THD_STRUCT* thd)
220 {
221 if (thd == nullptr)
222 return;
223
224 if ( thd->ip_nodes )
225 delete thd->ip_nodes;
226
227 if ( thd->ip_gnodes )
228 delete thd->ip_gnodes;
229
230 snort_free(thd);
231 }
232
sfthd_create_rule_threshold(int id,int tracking,int type,int count,unsigned int seconds)233 THD_NODE* sfthd_create_rule_threshold(int id,
234 int tracking,
235 int type,
236 int count,
237 unsigned int seconds)
238 {
239 THD_NODE* sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE));
240
241 sfthd_node->thd_id = id;
242 sfthd_node->tracking = tracking;
243 sfthd_node->type = type;
244 sfthd_node->count = count;
245 sfthd_node->seconds = seconds;
246
247 return sfthd_node;
248 }
249
250 /*!
251 Add a permanent threshold object to the threshold table. Multiple
252 objects may be defined for each gen_id and sig_id pair. Internally
253 a unique threshold id is generated for each pair.
254
255 Threshold objects track the number of events seen during the time
256 interval specified by seconds. Depending on the type of threshold
257 object and the count value, the thresholding object determines if
258 the current event should be logged or dropped.
259
260 @param thd Threshold object from sfthd_new()
261 @param gen_id Generator id
262 @param sig_id Signature id
263 @param tracking Selects tracking by src ip or by dst ip
264 @param type Thresholding type: Limit, Threshold, or Limit+Threshold, Suppress
265 @param priority Assigns a relative priority to this object, higher numbers imply higher priority
266
267 @param count Number of events
268 @param seconds Time duration over which this threshold object acts.
269 @param ip IP address, for suppression
270 @param ip-mask IP mask, applied with ip_mask, for suppression
271
272 @return integer
273 @retval 0 successfully added the thresholding object
274 @retval !0 failed
275
276 */
sfthd_create_threshold_local(SnortConfig *,ThresholdObjects * thd_objs,THD_NODE * config,PolicyId policy_id)277 static int sfthd_create_threshold_local(
278 SnortConfig*, ThresholdObjects* thd_objs, THD_NODE* config, PolicyId policy_id)
279 {
280 GHash* sfthd_hash;
281 THD_ITEM* sfthd_item;
282 THD_NODE* sfthd_node;
283 tThdItemKey key;
284
285 if (thd_objs == nullptr )
286 return -1;
287
288 if ( config->gen_id >= THD_MAX_GENID )
289 return -1;
290
291 /* Check for an existing 'gen_id' entry, if none found create one. */
292 if (thd_objs->sfthd_array[config->gen_id] == nullptr)
293 {
294 int nrows;
295
296 if ( config->gen_id == 1 ) /* patmatch rules gen_id, many rules */
297 {
298 nrows= THD_GEN_ID_1_ROWS;
299 }
300 else /* other gen_id's */
301 {
302 nrows= THD_GEN_ID_ROWS;
303 }
304
305 /* Create the hash table for this gen_id */
306 sfthd_hash = new GHash(nrows, sizeof(tThdItemKey), false, sfthd_item_free);
307 thd_objs->sfthd_array[config->gen_id] = sfthd_hash;
308 }
309 else
310 {
311 /* Get the hash table for this gen_id */
312 sfthd_hash = thd_objs->sfthd_array[config->gen_id];
313 }
314
315 if (sfthd_hash == nullptr)
316 return -2;
317
318 key.sig_id = config->sig_id;
319 key.policyId = policy_id;
320
321 /* Check if sig_id is already in the table - if not allocate and add it */
322 sfthd_item = (THD_ITEM*)sfthd_hash->find((void*)&key);
323 if ( !sfthd_item )
324 {
325 /* Create the sfthd_item hash node data */
326 sfthd_item = (THD_ITEM*)snort_calloc(sizeof(THD_ITEM));
327
328 sfthd_item->gen_id = config->gen_id;
329 sfthd_item->sig_id = config->sig_id;
330 sfthd_item->policyId = policy_id;
331 sfthd_item->sfthd_node_list = sflist_new();
332
333 if (!sfthd_item->sfthd_node_list)
334 {
335 snort_free(sfthd_item);
336 return -4;
337 }
338
339 /* Add the sfthd_item to the hash table */
340 if ( sfthd_hash->insert((void*)&key, sfthd_item) )
341 {
342 sflist_free(sfthd_item->sfthd_node_list);
343 snort_free(sfthd_item);
344 return -5;
345 }
346 }
347
348 /*
349 * Test that we only have one Limit/Threshold/Both Object at the tail,
350 * we can have multiple suppression nodes at the head
351 */
352 if ( sfthd_item->sfthd_node_list->count > 0 )
353 {
354 THD_NODE* p;
355 if ( !sfthd_item->sfthd_node_list->tail)
356 {
357 /* can you say paranoid- if there is a count, there should be a tail */
358 return -10;
359 }
360 p = (THD_NODE*)sfthd_item->sfthd_node_list->tail->ndata;
361 if (p) /* just to be safe- if there is a tail, there is is node data */
362 {
363 if ( p->type != THD_TYPE_SUPPRESS && config->type != THD_TYPE_SUPPRESS )
364 {
365 #ifdef THD_DEBUG
366 printf("THD_DEBUG: Could not add a 2nd Threshold object, "
367 "you can only have 1 per sid: gid=%u, sid=%u\n",
368 config->gen_id, config->sig_id);
369 #endif
370 /* cannot add more than one threshold per sid in
371 version 3.0, wait for 3.2 and CIDR blocks */
372 return THD_TOO_MANY_THDOBJ;
373 }
374 }
375 }
376
377 /* Create a THD_NODE for this THD_ITEM (Object) */
378 sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE));
379
380 /* Limit priorities to force suppression nodes to highest priority */
381 if ( config->priority >= THD_PRIORITY_SUPPRESS )
382 {
383 config->priority = THD_PRIORITY_SUPPRESS - 1;
384 }
385
386 /* Copy the node parameters */
387 sfthd_node->thd_id = config->thd_id;
388 sfthd_node->gen_id = config->gen_id;
389 sfthd_node->sig_id = config->sig_id;
390 sfthd_node->tracking = config->tracking; /* by_src, by_dst */
391 sfthd_node->type = config->type;
392 sfthd_node->priority = config->priority;
393 sfthd_node->count = config->count;
394 sfthd_node->seconds = config->seconds;
395 sfthd_node->ip_address= config->ip_address;
396
397 if ( config->type == THD_TYPE_SUPPRESS )
398 {
399 sfthd_node->priority = THD_PRIORITY_SUPPRESS;
400 }
401
402 /*
403 add the sfthd_node using priority to determine where in the list
404 it belongs
405
406 3.0 we can have only 1 threshold object but several suppression objects
407 plus a single threshold object is ok. Blocking multiple threshold
408 objects is done above.
409
410 Suppressions have the highest priority and are at the front of the
411 list, the tail node is either a suppression node or the only pure
412 thresholding node.
413 */
414 {
415 SF_LNODE* lnode;
416 NODE_DATA ndata;
417
418 /* Walk the list and insert based on priorities if suppress */
419 for ( ndata = sflist_first(sfthd_item->sfthd_node_list, &lnode);
420 ndata;
421 ndata = sflist_next(&lnode) )
422 {
423 THD_NODE* sfthd_n = (THD_NODE*)ndata;
424
425 /* check if the new node is higher priority */
426 if ( sfthd_node->priority > sfthd_n->priority )
427 {
428 /* insert before current node */
429 #ifdef THD_DEBUG
430 printf("Threshold node added after based on priority\n"); fflush(stdout);
431 #endif
432 sflist_add_before(sfthd_item->sfthd_node_list,lnode,sfthd_node);
433 return 0;
434 }
435
436 /* last node, just insert it here */
437 if ( !lnode->next )
438 {
439 /* if last node, insert at end of list */
440 #ifdef THD_DEBUG
441 printf("Threshold node added to tail\n"); fflush(stdout);
442 #endif
443 sflist_add_tail(sfthd_item->sfthd_node_list,sfthd_node);
444 return 0;
445 }
446 }
447 }
448
449 /*
450 sfthd_node list is empty - add as head node
451 */
452 assert(!sfthd_item->sfthd_node_list->count);
453 {
454 #ifdef THD_DEBUG
455 printf("Threshold node added to head of list\n"); fflush(stdout);
456 #endif
457 sflist_add_head(sfthd_item->sfthd_node_list,sfthd_node);
458 }
459
460 return 0;
461 }
462
463 /*
464 */
sfthd_create_threshold_global(SnortConfig *,ThresholdObjects * thd_objs,THD_NODE * config,PolicyId policy_id)465 static int sfthd_create_threshold_global(
466 SnortConfig*, ThresholdObjects* thd_objs, THD_NODE* config, PolicyId policy_id)
467 {
468 THD_NODE* sfthd_node;
469
470 if (thd_objs == nullptr)
471 return -1;
472
473 if (thd_objs->sfthd_garray[policy_id] == nullptr)
474 {
475 thd_objs->sfthd_garray[policy_id] =
476 (THD_NODE**)(snort_calloc(THD_MAX_GENID, sizeof(THD_NODE*)));
477 }
478
479 if ((config->gen_id == 0) &&
480 (thd_objs->sfthd_garray[policy_id][config->gen_id] != nullptr))
481 {
482 return THD_TOO_MANY_THDOBJ;
483 }
484 /* Reset the current threshold */
485 if (thd_objs->sfthd_garray[policy_id][config->gen_id] ==
486 thd_objs->sfthd_garray[policy_id][0])
487 {
488 thd_objs->sfthd_garray[policy_id][config->gen_id] = nullptr;
489 }
490 else if (thd_objs->sfthd_garray[policy_id][config->gen_id])
491 {
492 return THD_TOO_MANY_THDOBJ;
493 }
494
495 sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE));
496
497 /* Copy the node parameters */
498 sfthd_node->thd_id = config->thd_id;
499 sfthd_node->gen_id = config->gen_id;
500 sfthd_node->sig_id = config->sig_id; /* -1 for global thresholds */
501 sfthd_node->tracking = config->tracking; /* by_src, by_dst */
502 sfthd_node->type = config->type;
503 sfthd_node->priority = config->priority;
504 sfthd_node->count = config->count;
505 sfthd_node->seconds = config->seconds;
506 sfthd_node->ip_address = config->ip_address;
507
508 /* need a hash of these where
509 * key=[gen_id,sig_id] => THD_GNODE_KEY
510 * data = THD_NODE's
511 */
512 if (config->gen_id == 0) /* do em all */
513 {
514 int i;
515
516 for (i = 0; i < THD_MAX_GENID; i++)
517 {
518 /* only assign if there wasn't a value */
519 if (thd_objs->sfthd_garray[policy_id][i] == nullptr)
520 {
521 thd_objs->sfthd_garray[policy_id][i] = sfthd_node;
522 }
523 }
524 }
525 else
526 {
527 thd_objs->sfthd_garray[policy_id][config->gen_id] = sfthd_node;
528 }
529
530 #ifdef THD_DEBUG
531 printf("THD_DEBUG-GLOBAL: created global threshold object "
532 "for gen_id=%u\n",config->gen_id);
533 fflush(stdout);
534 #endif
535
536 return 0;
537 }
538
539 /*!
540 Add a permanent threshold object to the threshold table. Multiple
541 objects may be defined for each gen_id and sig_id pair. Internally
542 a unique threshold id is generated for each pair.
543
544 Threshold objects track the number of events seen during the time
545 interval specified by seconds. Depending on the type of threshold
546 object and the count value, the thresholding object determines if
547 the current event should be logged or dropped.
548
549 @param thd Threshold object from sfthd_new()
550 @param gen_id Generator id
551 @param sig_id Signature id
552 @param tracking Selects tracking by src ip or by dst ip
553 @param type Thresholding type: Limit, Threshold, or Limit+Threshold, Suppress
554 @param priority Assigns a relative priority to this object, higher numbers imply higher priority
555
556 @param count Number of events
557 @param seconds Time duration over which this threshold object acts.
558 @param ip IP address, for suppression
559 @param ip-mask IP mask, applied with ip_mask, for suppression
560
561 @return integer
562 @retval 0 successfully added the thresholding object
563 @retval !0 failed
564
565 --- Local and Global Thresholding is setup here ---
566
567 */
sfthd_create_threshold(SnortConfig * sc,ThresholdObjects * thd_objs,unsigned gen_id,unsigned sig_id,int tracking,int type,int priority,int count,int seconds,sfip_var_t * ip_address,PolicyId policy_id)568 int sfthd_create_threshold(
569 SnortConfig* sc,
570 ThresholdObjects* thd_objs,
571 unsigned gen_id,
572 unsigned sig_id,
573 int tracking,
574 int type,
575 int priority,
576 int count,
577 int seconds,
578 sfip_var_t* ip_address, PolicyId policy_id)
579 {
580 //allocate memory fpr sfthd_array if needed.
581 THD_NODE sfthd_node;
582 memset(&sfthd_node, 0, sizeof(sfthd_node));
583
584 thd_objs->count++;
585
586 sfthd_node.thd_id = thd_objs->count; /* produce a unique thd_id for this node */
587 sfthd_node.gen_id = gen_id;
588 sfthd_node.sig_id = sig_id;
589 sfthd_node.tracking = tracking; /* by_src, by_dst */
590 sfthd_node.type = type;
591 sfthd_node.priority = priority;
592 sfthd_node.count = count;
593 sfthd_node.seconds = seconds;
594 sfthd_node.ip_address= ip_address;
595
596 // FIXIT-L convert to std::vector
597 sfDynArrayCheckBounds ((void**)&thd_objs->sfthd_garray, policy_id,
598 &thd_objs->numPoliciesAllocated);
599
600 if (thd_objs->sfthd_garray[policy_id] == nullptr)
601 {
602 thd_objs->sfthd_garray[policy_id] =
603 (THD_NODE**)snort_calloc(THD_MAX_GENID, sizeof(THD_NODE*));
604 }
605
606 if ( sig_id == 0 )
607 {
608 return sfthd_create_threshold_global(sc, thd_objs, &sfthd_node, policy_id);
609 }
610
611 if ( gen_id == 0 )
612 return -1;
613
614 return sfthd_create_threshold_local(sc, thd_objs, &sfthd_node, policy_id);
615 }
616
617 #ifdef THD_DEBUG
printIP(unsigned u,char * buf,unsigned len)618 static char* printIP(unsigned u, char* buf, unsigned len)
619 {
620 SnortSnprintf(buf, len, "%d.%d.%d.%d", (u>>24)&0xff, (u>>16)&0xff, (u>>8)&0xff, u&0xff);
621 return s;
622 }
623
624 #endif
625
sfthd_test_rule(XHash * rule_hash,THD_NODE * sfthd_node,const SfIp * sip,const SfIp * dip,long curtime,PolicyId policy_id)626 int sfthd_test_rule(XHash* rule_hash, THD_NODE* sfthd_node,
627 const SfIp* sip, const SfIp* dip, long curtime, PolicyId policy_id)
628 {
629 if ((rule_hash == nullptr) || (sfthd_node == nullptr))
630 return 0;
631
632 int status = sfthd_test_local(rule_hash, sfthd_node, sip, dip, curtime, policy_id);
633
634 return (status < -1) ? 1 : status;
635 }
636
sfthd_test_suppress(THD_NODE * sfthd_node,const SfIp * ip)637 static inline int sfthd_test_suppress(
638 THD_NODE* sfthd_node,
639 const SfIp* ip)
640 {
641 if ( !sfthd_node->ip_address ||
642 sfvar_ip_in(sfthd_node->ip_address, ip) )
643 {
644 #ifdef THD_DEBUG
645 printf("THD_DEBUG: SUPPRESS NODE, do not log events with this IP\n");
646 fflush(stdout);
647 #endif
648 /* Don't log, and stop looking( event's to this address
649 * for this gen_id+sig_id) */
650 return -1;
651 }
652 return 1; /* Keep looking for other suppressors */
653 }
654
655 /*
656 * Do the appropriate test for the Threshold Object Type
657 */
sfthd_test_non_suppress(THD_NODE * sfthd_node,THD_IP_NODE * sfthd_ip_node,time_t curtime)658 static inline int sfthd_test_non_suppress(
659 THD_NODE* sfthd_node,
660 THD_IP_NODE* sfthd_ip_node,
661 time_t curtime)
662 {
663 unsigned dt;
664
665 if ( sfthd_node->type == THD_TYPE_DETECT )
666 {
667 #ifdef THD_DEBUG
668 printf("\n...Detect Test\n");
669 fflush(stdout);
670 #endif
671 dt = (unsigned)(curtime - sfthd_ip_node->tstart);
672
673 if ( dt >= sfthd_node->seconds )
674 { /* reset */
675 sfthd_ip_node->tstart = curtime;
676 if ( (unsigned)(curtime - sfthd_ip_node->tlast) > sfthd_node->seconds )
677 sfthd_ip_node->prev = 0;
678 else
679 sfthd_ip_node->prev = sfthd_ip_node->count - 1;
680 sfthd_ip_node->count = 1;
681 }
682 sfthd_ip_node->tlast = curtime;
683
684 #ifdef THD_DEBUG
685 printf("...dt=%u, sfthd_node->seconds=%u\n",dt, sfthd_node->seconds);
686 printf("...sfthd_ip_node->count=%u, sfthd_node->count=%d\n",
687 sfthd_ip_node->count,sfthd_node->count);
688 fflush(stdout);
689 #endif
690 if ( (int)sfthd_ip_node->count > sfthd_node->count ||
691 (int)sfthd_ip_node->prev > sfthd_node->count )
692 {
693 return 0; /* Log it, stop looking: log all > 'count' events */
694 }
695
696 /* Don't Log yet, don't keep looking:
697 * already logged our limit, don't log this sid */
698 return -2;
699 }
700 if ( sfthd_node->type == THD_TYPE_LIMIT )
701 {
702 #ifdef THD_DEBUG
703 printf("\n...Limit Test\n");
704 fflush(stdout);
705 #endif
706 dt = (unsigned)(curtime - sfthd_ip_node->tstart);
707
708 if ( dt >= sfthd_node->seconds )
709 { /* reset */
710 sfthd_ip_node->tstart = curtime;
711 sfthd_ip_node->count = 1;
712 }
713
714 #ifdef THD_DEBUG
715 printf("...dt=%u, sfthd_node->seconds=%u\n",dt, sfthd_node->seconds);
716 printf("...sfthd_ip_node->count=%u, sfthd_node->count=%d\n",
717 sfthd_ip_node->count,sfthd_node->count);
718 fflush(stdout);
719 #endif
720 if ( (int)sfthd_ip_node->count <= sfthd_node->count )
721 {
722 return 0; /* Log it, stop looking: only log the 1st 'count' events */
723 }
724
725 /* Don't Log yet, don't keep looking:
726 * already logged our limit, don't log this sid */
727 return -2;
728 }
729 else if ( sfthd_node->type == THD_TYPE_THRESHOLD )
730 {
731 #ifdef THD_DEBUG
732 printf("\n...Threshold Test\n");
733 fflush(stdout);
734 #endif
735 dt = (unsigned)(curtime - sfthd_ip_node->tstart);
736 if ( dt >= sfthd_node->seconds )
737 {
738 sfthd_ip_node->tstart = curtime;
739 sfthd_ip_node->count = 1;
740 }
741 if ( (int)sfthd_ip_node->count >= sfthd_node->count )
742 {
743 /* reset */
744 sfthd_ip_node->count = 0;
745 sfthd_ip_node->tstart= curtime;
746 return 0; /* Log it, stop looking */
747 }
748 return -2; /* don't log yet */
749 }
750 else if ( sfthd_node->type == THD_TYPE_BOTH )
751 {
752 #ifdef THD_DEBUG
753 printf("\n...Threshold+Limit Test\n");
754 fflush(stdout);
755 #endif
756 dt = (unsigned)(curtime - sfthd_ip_node->tstart);
757 if ( dt >= sfthd_node->seconds )
758 {
759 sfthd_ip_node->tstart = curtime;
760 sfthd_ip_node->count = 1;
761
762 /* Don't Log yet, keep looking:
763 * only log after we reach count, which must be > '1' */
764 return -2;
765 }
766 else
767 {
768 if ( (int)sfthd_ip_node->count >= sfthd_node->count )
769 {
770 if ( (int)sfthd_ip_node->count > sfthd_node->count )
771 {
772 /* don't log it, stop looking:
773 * log once per time interval - than block it */
774 return -2;
775 }
776 /* Log it, stop looking:
777 * log the 1st event we see past 'count' events */
778 return 0;
779 }
780 else /* Block it from logging */
781 {
782 /* don't log it, stop looking:
783 * we must see at least count events 1st */
784 return -2;
785 }
786 }
787 }
788
789 #ifdef THD_DEBUG
790 printf("THD_DEBUG: You should not be here...\n");
791 fflush(stdout);
792 #endif
793
794 return 0; /* should not get here, so log it just to be safe */
795 }
796
797 /*!
798 *
799 * Find/Test/Add an event against a single threshold object.
800 * Events without thresholding objects are automatically loggable.
801 *
802 * @param thd Threshold table pointer
803 * @param sfthd_node Permanent Thresholding Object
804 * @param sip Event/Packet Src IP address- should be host ordered for comparison
805 * @param dip Event/Packet Dst IP address
806 * @param curtime Current Event/Packet time in seconds
807 *
808 * @return integer
809 * @retval 0 : Event is loggable
810 * @retval >0 : Event should not be logged, try next thd object
811 * @retval <0 : Event should never be logged to this user! Suppressed Event+IP
812 *
813 */
sfthd_test_local(XHash * local_hash,THD_NODE * sfthd_node,const SfIp * sip,const SfIp * dip,time_t curtime,PolicyId policy_id)814 int sfthd_test_local(
815 XHash* local_hash,
816 THD_NODE* sfthd_node,
817 const SfIp* sip,
818 const SfIp* dip,
819 time_t curtime,
820 PolicyId policy_id)
821 {
822 THD_IP_NODE_KEY key;
823 THD_IP_NODE data,* sfthd_ip_node;
824 const SfIp* ip;
825
826 #ifdef THD_DEBUG
827 char buf[24];
828 printf("THD_DEBUG: Key THD_NODE IP=%s,",
829 printIP((unsigned)sfthd_node->ip_address, buf, sizeof(buf)) );
830 printf(" MASK=%s\n", printIP((unsigned)sfthd_node->ip_mask, buf, sizeof(buf)) );
831 printf("THD_DEBUG: PKT SIP=%s\n", printIP((unsigned)sip, buf, sizeof(buf)) );
832 printf("THD_DEBUG: PKT DIP=%s\n", printIP((unsigned)dip, buf, sizeof(buf)) );
833 fflush(stdout);
834 #endif
835
836 /* -1 means don't do any limit or thresholding */
837 if ( sfthd_node->count == THD_NO_THRESHOLD)
838 {
839 #ifdef THD_DEBUG
840 printf("\n...No Threshold applied for this object\n");
841 fflush(stdout);
842 #endif
843 return 0;
844 }
845
846 /*
847 * Get The correct IP
848 */
849 if (sfthd_node->tracking == THD_TRK_SRC)
850 ip = sip;
851 else
852 ip = dip;
853
854 /*
855 * Check for and test Suppression of this event to this IP
856 */
857 if ( sfthd_node->type == THD_TYPE_SUPPRESS )
858 {
859 #ifdef THD_DEBUG
860 printf("THD_DEBUG: SUPPRESS NODE Testing...\n"); fflush(stdout);
861 #endif
862 return sfthd_test_suppress(sfthd_node, ip);
863 }
864
865 /*
866 * Go on and do standard thresholding
867 */
868
869 /* Set up the key */
870 key.policyId = policy_id;
871 key.ip = *ip;
872 key.thd_id = sfthd_node->thd_id;
873 key.padding = 0;
874
875 /* Set up a new data element */
876 data.count = 1;
877 data.prev = 0;
878 data.tstart = data.tlast = curtime; /* Event time */
879
880 /*
881 * Check for any Permanent sig_id objects for this gen_id or add this one ...
882 */
883 int status = local_hash->insert((void*)&key, &data);
884 if (status == HASH_INTABLE)
885 {
886 /* Already in the table */
887 sfthd_ip_node = (THD_IP_NODE*)local_hash->get_user_data();
888
889 /* Increment the event count */
890 sfthd_ip_node->count++;
891 }
892 else if (status == HASH_NOMEM)
893 {
894 event_filter_stats.xhash_nomem_peg_local++;
895 return 1;
896 }
897 else if (status != HASH_OK)
898 {
899 /* hash error */
900 return 1; /* check the next threshold object */
901 }
902 else
903 {
904 /* Was not in the table - it was added - work with our copy of the data */
905 sfthd_ip_node = &data;
906 }
907
908 return sfthd_test_non_suppress(sfthd_node, sfthd_ip_node, curtime);
909 }
910
911 /*
912 * Test a global thresholding object
913 */
sfthd_test_global(XHash * global_hash,THD_NODE * sfthd_node,unsigned sig_id,const SfIp * sip,const SfIp * dip,time_t curtime,PolicyId policy_id)914 static inline int sfthd_test_global(
915 XHash* global_hash,
916 THD_NODE* sfthd_node,
917 unsigned sig_id, /* from current event */
918 const SfIp* sip, /* " */
919 const SfIp* dip, /* " */
920 time_t curtime,
921 PolicyId policy_id)
922 {
923 THD_IP_GNODE_KEY key;
924 THD_IP_NODE data;
925 THD_IP_NODE* sfthd_ip_node;
926 const SfIp* ip;
927
928 #ifdef THD_DEBUG
929 char buf[24];
930 printf("THD_DEBUG: Global THD_NODE IP=%s,",
931 printIP((unsigned)sfthd_node->ip_address, buf, sizeof(buf)) );
932 printf(" MASK=%s\n", printIP((unsigned)sfthd_node->ip_mask, buf, sizeof(buf)) );
933 printf("THD_DEBUG: PKT SIP=%s\n", printIP((unsigned)sip, buf, sizeof(buf)) );
934 printf("THD_DEBUG: PKT DIP=%s\n", printIP((unsigned)dip, buf, sizeof(buf)) );
935 fflush(stdout);
936 #endif
937
938 /* -1 means don't do any limit or thresholding */
939 if ( sfthd_node->count == THD_NO_THRESHOLD)
940 {
941 #ifdef THD_DEBUG
942 printf("\n...No Threshold applied for this object\n");
943 fflush(stdout);
944 #endif
945 return 0;
946 }
947
948 /* Get The correct IP */
949 if (sfthd_node->tracking == THD_TRK_SRC)
950 ip = sip;
951 else
952 ip = dip;
953
954 /* Check for and test Suppression of this event to this IP */
955 if ( sfthd_node->type == THD_TYPE_SUPPRESS )
956 {
957 #ifdef THD_DEBUG
958 printf("THD_DEBUG: G-SUPPRESS NODE Testing...\n"); fflush(stdout);
959 #endif
960 return sfthd_test_suppress(sfthd_node, ip);
961 }
962
963 /*
964 * Go on and do standard thresholding
965 */
966
967 /* Set up the key */
968 key.ip = *ip;
969 key.gen_id = sfthd_node->gen_id;
970 key.sig_id = sig_id;
971 key.policyId = policy_id;
972 key.padding = 0;
973
974 /* Set up a new data element */
975 data.count = 1;
976 data.prev = 0;
977 data.tstart = data.tlast = curtime; /* Event time */
978
979 /* Check for any Permanent sig_id objects for this gen_id or add this one ... */
980 int status = global_hash->insert((void*)&key, &data);
981 if (status == HASH_INTABLE)
982 {
983 /* Already in the table */
984 sfthd_ip_node = (THD_IP_NODE*)global_hash->get_user_data();
985
986 /* Increment the event count */
987 sfthd_ip_node->count++;
988 }
989 else if (status == HASH_NOMEM)
990 {
991 event_filter_stats.xhash_nomem_peg_global++;
992 return 1;
993 }
994 else if (status != HASH_OK)
995 {
996 /* hash error */
997 return 1; /* check the next threshold object */
998 }
999 else
1000 {
1001 /* Was not in the table - it was added - work with our copy of the data */
1002 sfthd_ip_node = &data;
1003 }
1004
1005 return sfthd_test_non_suppress(sfthd_node, sfthd_ip_node, curtime);
1006 }
1007
1008 /*!
1009 *
1010 * Test a an event against the threshold database.
1011 * Events without thresholding objects are automatically
1012 * loggable.
1013 *
1014 * @param thd Threshold table pointer
1015 * @param gen_id Generator Id from the event
1016 * @param sig_id Signature Id from the event
1017 * @param sip Event/Packet Src IP address
1018 * @param dip Event/Packet Dst IP address
1019 * @param curtime Current Event/Packet time
1020 *
1021 * @return integer
1022 * @retval 0 : Event is loggable
1023 * @retval !0 : Event should not be logged (-1 suppressed, 1 filtered)
1024 *
1025 */
sfthd_test_threshold(ThresholdObjects * thd_objs,THD_STRUCT * thd,unsigned gen_id,unsigned sig_id,const SfIp * sip,const SfIp * dip,long curtime,PolicyId policy_id)1026 int sfthd_test_threshold(
1027 ThresholdObjects* thd_objs,
1028 THD_STRUCT* thd,
1029 unsigned gen_id,
1030 unsigned sig_id,
1031 const SfIp* sip,
1032 const SfIp* dip,
1033 long curtime,
1034 PolicyId policy_id)
1035 {
1036 tThdItemKey key;
1037 GHash* sfthd_hash;
1038 THD_ITEM* sfthd_item;
1039 THD_NODE* sfthd_node;
1040 THD_NODE* g_thd_node = nullptr;
1041 #ifdef THD_DEBUG
1042 int cnt;
1043 #endif
1044
1045 if ((thd_objs == nullptr) || (thd == nullptr))
1046 return 0;
1047
1048 #ifdef THD_DEBUG
1049 printf("sfthd_test_threshold...\n"); fflush(stdout);
1050 #endif
1051
1052 if ( gen_id >= THD_MAX_GENID )
1053 {
1054 #ifdef THD_DEBUG
1055 printf("THD_DEBUG: invalid gen_id=%u\n",gen_id);
1056 fflush(stdout);
1057 #endif
1058 return 0; /* bogus gen_id */
1059 }
1060
1061 /*
1062 * Get the hash table for this gen_id
1063 */
1064 sfthd_hash = thd_objs->sfthd_array[gen_id];
1065 if (sfthd_hash == nullptr)
1066 {
1067 #ifdef THD_DEBUG
1068 printf("THD_DEBUG: no hash table entry for gen_id=%u\n",gen_id);
1069 fflush(stdout);
1070 #endif
1071 goto global_test;
1072 /* return 0; */ /* no threshold objects for this gen_id, log it ! */
1073 }
1074
1075 key.sig_id = sig_id;
1076 key.policyId = policy_id;
1077 /*
1078 * Check for any Permanent sig_id objects for this gen_id
1079 */
1080 sfthd_item = (THD_ITEM*)sfthd_hash->find((void*)&key);
1081 if (sfthd_item == nullptr)
1082 {
1083 #ifdef THD_DEBUG
1084 printf("THD_DEBUG: no THD objects for gen_id=%u, sig_id=%u\n",gen_id,sig_id);
1085 fflush(stdout);
1086 #endif
1087 /* no matching permanent sig_id objects so, log it ! */
1088 goto global_test;
1089 }
1090
1091 /* No List of Threshold objects - bail and log it */
1092 if (sfthd_item->sfthd_node_list == nullptr)
1093 {
1094 goto global_test;
1095 }
1096
1097 /* For each permanent thresholding object, test/add/update the thd object
1098 We maintain a list of thd objects for each gen_id+sig_id
1099 each object has it's own unique thd_id
1100 Suppression nodes have a very high priority, so they are tested 1st */
1101 #ifdef THD_DEBUG
1102 cnt=0;
1103 #endif
1104 SF_LNODE* cursor;
1105
1106 for (sfthd_node = (THD_NODE*)sflist_first(sfthd_item->sfthd_node_list, &cursor);
1107 sfthd_node != nullptr;
1108 sfthd_node = (THD_NODE*)sflist_next(&cursor))
1109 {
1110 #ifdef THD_DEBUG
1111 cnt++;
1112 printf("THD_DEBUG: gen_id=%u sig_id=%u testing thd_id=%d thd_type=%d\n",
1113 gen_id, sig_id, sfthd_node->thd_id, sfthd_node->type);
1114 fflush(stdout);
1115 #endif
1116 /*
1117 * Test SUPPRESSION and THRESHOLDING
1118 */
1119 int status = sfthd_test_local(thd->ip_nodes, sfthd_node, sip, dip, curtime, policy_id);
1120
1121 if ( status < 0 ) /* -1 == Don't log and stop looking */
1122 {
1123 #ifdef THD_DEBUG
1124 printf("THD_DEBUG: gen_id=%u sig_id=%u, UnLoggable %d\n\n",gen_id, sig_id,cnt);
1125 fflush(stdout);
1126 #endif
1127 return (status < -1) ? 1 : -1; /* !0 == Don't log it*/
1128 }
1129 else if ( status == 0 ) /* Log it and stop looking */
1130 {
1131 #ifdef THD_DEBUG
1132 printf("THD_DEBUG: gen_id=%u sig_id=%u tested %d THD_NODE's, "
1133 "Loggable\n\n",sfthd_item->gen_id, sfthd_item->sig_id,cnt);
1134 fflush(stdout);
1135 #endif
1136 return 0; /* 0 == Log the event */
1137 }
1138 /* status > 0 : Log it later but Keep looking
1139 * check the next threshold object for a blocking action ...
1140 */
1141 }
1142
1143 /*
1144 * Test for a global threshold object
1145 * we're here cause there were no threshold objects for this gen_id/sig_id pair
1146 */
1147 global_test:
1148
1149 #ifdef THD_DEBUG
1150 printf("THD_DEBUG-GLOBAL: doing global object test\n");
1151 #endif
1152
1153 if (thd_objs->sfthd_garray && thd_objs->sfthd_garray[policy_id])
1154 {
1155 g_thd_node = thd_objs->sfthd_garray[policy_id][gen_id];
1156 }
1157
1158 if ( g_thd_node )
1159 {
1160 int status = sfthd_test_global(thd->ip_gnodes, g_thd_node, sig_id,
1161 sip, dip, curtime, policy_id);
1162
1163 if ( status < 0 ) /* -1 == Don't log and stop looking */
1164 {
1165 #ifdef THD_DEBUG
1166 printf("THD_DEBUG-GLOBAL: gen_id=%u sig_id=%u THD_NODE's, "
1167 "UnLoggable\n\n",gen_id, sig_id);
1168 fflush(stdout);
1169 #endif
1170 return (status < -1) ? 1 : -1; /* !0 == Don't log it*/
1171 }
1172
1173 /* Log it ! */
1174 #ifdef THD_DEBUG
1175 printf("THD_DEBUG-GLOBAL: gen_id=%u sig_id=%u THD_NODE's, "
1176 "Loggable\n\n",gen_id, sig_id);
1177 fflush(stdout);
1178 #endif
1179 }
1180 else
1181 {
1182 #ifdef THD_DEBUG
1183 printf("THD_DEBUG-GLOBAL: no Global THD Object for gen_id=%u, "
1184 "sig_id=%u\n\n",gen_id, sig_id);
1185 fflush(stdout);
1186 #endif
1187 }
1188
1189 return 0; /* Default: Log it if we did not block the logging action */
1190 }
1191
1192 #ifdef THD_DEBUG
1193 /*!
1194 * A function to print the thresholding objects to stdout.
1195 *
1196 */
sfthd_show_objects(ThresholdObjects * thd_objs)1197 int sfthd_show_objects(ThresholdObjects* thd_objs)
1198 {
1199 THD_ITEM* sfthd_item;
1200 THD_NODE* sfthd_node;
1201 unsigned gen_id;
1202 GHashNode* item_hash_node;
1203
1204 for (gen_id=0; gen_id < THD_MAX_GENID; gen_id++ )
1205 {
1206 GHash* sfthd_hash = thd_objs->sfthd_array[gen_id];
1207
1208 if ( !sfthd_hash )
1209 continue;
1210
1211 printf("...GEN_ID = %u\n",gen_id);
1212
1213 for (item_hash_node = sfthd_hash->ghash_findfirst();
1214 item_hash_node != 0;
1215 item_hash_node = sfthd_hash->ghash_findnext() )
1216 {
1217 /* Check for any Permanent sig_id objects for this gen_id */
1218 sfthd_item = (THD_ITEM*)item_hash_node->data;
1219
1220 printf(".....GEN_ID = %u, SIG_ID = %u, Policy = %u\n",gen_id,sfthd_item->sig_id,
1221 sfthd_item->policyId);
1222
1223 /* For each permanent thresholding object, test/add/update the thd object
1224 We maintain a list of thd objects for each gen_id+sig_id
1225 each object has it's own unique thd_id */
1226 SF_LNODE* cursor;
1227
1228 for ( sfthd_node = (THD_NODE*)sflist_first(sfthd_item->sfthd_node_list, &cursor);
1229 sfthd_node != 0;
1230 sfthd_node = (THD_NODE*)sflist_next(&cursor) )
1231 {
1232 printf(".........THD_ID =%d\n",sfthd_node->thd_id);
1233
1234 if ( sfthd_node->type == THD_TYPE_SUPPRESS )
1235 printf(".........type =Suppress\n");
1236 if ( sfthd_node->type == THD_TYPE_LIMIT )
1237 printf(".........type =Limit\n");
1238 if ( sfthd_node->type == THD_TYPE_THRESHOLD )
1239 printf(".........type =Threshold\n");
1240 if ( sfthd_node->type == THD_TYPE_BOTH )
1241 printf(".........type =Both\n");
1242
1243 printf(".........tracking=%d\n",sfthd_node->tracking);
1244 printf(".........priority=%d\n",sfthd_node->priority);
1245
1246 if ( sfthd_node->type == THD_TYPE_SUPPRESS )
1247 {
1248 printf(".........ip =%s\n",
1249 sfthd_node->ip_address.ntoa());
1250 printf(".........mask =%d\n",
1251 sfthd_node->ip_address.bits);
1252 printf(".........not_flag=%d\n",sfthd_node->ip_mask);
1253 }
1254 else
1255 {
1256 printf(".........count =%d\n",sfthd_node->count);
1257 printf(".........seconds =%u\n",sfthd_node->seconds);
1258 }
1259 }
1260 }
1261 }
1262
1263 return 0;
1264 }
1265
1266 #endif // THD_DEBUG
1267