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