suricata
detect-engine-threshold.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2024 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \defgroup threshold Thresholding
20  *
21  * This feature is used to reduce the number of logged alerts for noisy rules.
22  * This can be tuned to significantly reduce false alarms, and it can also be
23  * used to write a newer breed of rules. Thresholding commands limit the number
24  * of times a particular event is logged during a specified time interval.
25  *
26  * @{
27  */
28 
29 /**
30  * \file
31  *
32  * \author Breno Silva <breno.silva@gmail.com>
33  * \author Victor Julien <victor@inliniac.net>
34  *
35  * Threshold part of the detection engine.
36  */
37 
38 #include "suricata-common.h"
39 #include "detect.h"
40 #include "flow.h"
41 
42 #include "detect-parse.h"
43 #include "detect-engine.h"
45 #include "detect-engine-address.h"
47 
48 #include "util-misc.h"
49 #include "util-time.h"
50 #include "util-error.h"
51 #include "util-debug.h"
52 #include "action-globals.h"
53 #include "util-validate.h"
54 
55 #include "util-hash.h"
56 #include "util-thash.h"
57 #include "util-hash-lookup3.h"
58 #include "counters.h"
59 
60 static SC_ATOMIC_DECLARE(uint64_t, threshold_bitmap_alloc_fail);
61 static SC_ATOMIC_DECLARE(uint64_t, threshold_bitmap_memuse);
62 
63 /* UNITTESTS-only test seam to force allocation failure and query counters */
64 #ifdef UNITTESTS
65 void ThresholdForceAllocFail(int v);
66 uint64_t ThresholdGetBitmapMemuse(void);
67 uint64_t ThresholdGetBitmapAllocFail(void);
68 
69 static int g_threshold_force_alloc_fail = 0;
70 
72 {
73  g_threshold_force_alloc_fail = v;
74 }
75 
77 {
78  return SC_ATOMIC_GET(threshold_bitmap_memuse);
79 }
80 
82 {
83  return SC_ATOMIC_GET(threshold_bitmap_alloc_fail);
84 }
85 #endif
86 
87 /* bitmap settings for exact distinct counting of 16-bit ports */
88 #define DF_PORT_BITMAP_SIZE (65536u / 8u)
89 #define DF_PORT_BYTE_IDX(p) ((uint32_t)((p) >> 3))
90 #define DF_PORT_BIT_MASK(p) ((uint8_t)(1u << ((p)&7u)))
91 
92 struct Thresholds {
94 } ctx;
95 
96 static int ThresholdsInit(struct Thresholds *t);
97 static void ThresholdsDestroy(struct Thresholds *t);
98 
99 static uint64_t ThresholdBitmapAllocFailCounter(void)
100 {
101  return SC_ATOMIC_GET(threshold_bitmap_alloc_fail);
102 }
103 
104 static uint64_t ThresholdBitmapMemuseCounter(void)
105 {
106  return SC_ATOMIC_GET(threshold_bitmap_memuse);
107 }
108 
109 static uint64_t ThresholdMemuseCounter(void)
110 {
111  if (ctx.thash == NULL)
112  return 0;
113  return SC_ATOMIC_GET(ctx.thash->memuse);
114 }
115 
116 static uint64_t ThresholdMemcapCounter(void)
117 {
118  if (ctx.thash == NULL)
119  return 0;
120  return SC_ATOMIC_GET(ctx.thash->config.memcap);
121 }
122 
123 void ThresholdInit(void)
124 {
125  SC_ATOMIC_INIT(threshold_bitmap_alloc_fail);
126  SC_ATOMIC_INIT(threshold_bitmap_memuse);
127  ThresholdsInit(&ctx);
128 }
129 
131 {
132  StatsRegisterGlobalCounter("detect.thresholds.memuse", ThresholdMemuseCounter);
133  StatsRegisterGlobalCounter("detect.thresholds.memcap", ThresholdMemcapCounter);
134  StatsRegisterGlobalCounter("detect.thresholds.bitmap_memuse", ThresholdBitmapMemuseCounter);
136  "detect.thresholds.bitmap_alloc_fail", ThresholdBitmapAllocFailCounter);
137 }
138 
140 {
141  ThresholdsDestroy(&ctx);
142 }
143 
144 #define SID 0
145 #define GID 1
146 #define REV 2
147 #define TRACK 3
148 #define TENANT 4
149 
150 typedef struct ThresholdEntry_ {
151  uint32_t key[5];
152 
153  SCTime_t tv_timeout; /**< Timeout for new_action (for rate_filter)
154  its not "seconds", that define the time interval */
155  uint32_t seconds; /**< Event seconds */
156  uint32_t current_count; /**< Var for count control */
157 
158  union {
159  struct {
160  uint32_t next_value;
162  struct {
163  SCTime_t tv1; /**< Var for time control */
164  Address addr; /* used for src/dst/either tracking */
165  Address addr2; /* used for both tracking */
166  /* distinct counting state (for detection_filter unique_on ports) */
167  uint8_t *distinct_bitmap_union; /* 8192 bytes (65536 bits) */
168  };
169  };
170 
172 
173 static int ThresholdEntrySet(void *dst, void *src)
174 {
175  const ThresholdEntry *esrc = src;
176  ThresholdEntry *edst = dst;
177  memset(edst, 0, sizeof(*edst));
178  *edst = *esrc;
179  return 0;
180 }
181 
182 static void ThresholdDistinctInit(ThresholdEntry *te, const DetectThresholdData *td)
183 {
184  if (td->type != TYPE_DETECTION || td->unique_on == DF_UNIQUE_NONE) {
185  return;
186  }
187  DEBUG_VALIDATE_BUG_ON(td->seconds == 0);
188 
189  const uint32_t bitmap_size = DF_PORT_BITMAP_SIZE;
190  te->current_count = 0;
191 #ifdef UNITTESTS
192  if (g_threshold_force_alloc_fail) {
193  SC_ATOMIC_ADD(threshold_bitmap_alloc_fail, 1);
194  te->distinct_bitmap_union = NULL;
195  return;
196  }
197 #endif
198  /* Check memcap before allocating bitmap.
199  * Bitmap memory is bounded by detect.thresholds.memcap via thash.
200  * Note: if ctx.thash is NULL (e.g. init failed or unittests), we bypass
201  * the memcap check but still attempt allocation unless forced to fail. */
202  if (ctx.thash != NULL && !THASH_CHECK_MEMCAP(ctx.thash, bitmap_size)) {
203  SC_ATOMIC_ADD(threshold_bitmap_alloc_fail, 1);
204  te->distinct_bitmap_union = NULL;
205  return;
206  }
207 
208  te->distinct_bitmap_union = SCCalloc(1, bitmap_size);
209  if (te->distinct_bitmap_union == NULL) {
210  SC_ATOMIC_ADD(threshold_bitmap_alloc_fail, 1);
211  } else {
212  /* Track bitmap memory in thash memuse for proper accounting */
213  if (ctx.thash != NULL) {
214  (void)SC_ATOMIC_ADD(ctx.thash->memuse, bitmap_size);
215  }
216  SC_ATOMIC_ADD(threshold_bitmap_memuse, bitmap_size);
217  }
218 }
219 
220 static void ThresholdDistinctReset(ThresholdEntry *te)
221 {
222  const uint32_t bitmap_size = DF_PORT_BITMAP_SIZE;
223  if (te->distinct_bitmap_union) {
224  memset(te->distinct_bitmap_union, 0x00, bitmap_size);
225  }
226  te->current_count = 0;
227 }
228 
229 static inline void ThresholdDistinctAddPort(ThresholdEntry *te, uint16_t port)
230 {
231  const uint32_t byte_index = DF_PORT_BYTE_IDX(port);
232  const uint8_t bit_mask = DF_PORT_BIT_MASK(port);
233  if (te->distinct_bitmap_union) {
234  bool already = (te->distinct_bitmap_union[byte_index] & bit_mask);
235  if (!already) {
236  te->distinct_bitmap_union[byte_index] =
237  (uint8_t)(te->distinct_bitmap_union[byte_index] | bit_mask);
238  te->current_count++;
239  }
240  }
241 }
242 
243 static void ThresholdEntryFree(void *ptr)
244 {
245  if (ptr == NULL)
246  return;
247 
248  ThresholdEntry *e = ptr;
249  if (e->distinct_bitmap_union) {
250  const uint32_t bitmap_size = DF_PORT_BITMAP_SIZE;
251  /* Decrement bitmap memory from thash memuse */
252  if (ctx.thash != NULL) {
253  (void)SC_ATOMIC_SUB(ctx.thash->memuse, bitmap_size);
254  }
255  SC_ATOMIC_SUB(threshold_bitmap_memuse, bitmap_size);
257  e->distinct_bitmap_union = NULL;
258  }
259 }
260 
261 static inline uint32_t HashAddress(const Address *a)
262 {
263  uint32_t key;
264 
265  if (a->family == AF_INET) {
266  key = a->addr_data32[0];
267  } else if (a->family == AF_INET6) {
268  key = hashword(a->addr_data32, 4, 0);
269  } else
270  key = 0;
271 
272  return key;
273 }
274 
275 static inline int CompareAddress(const Address *a, const Address *b)
276 {
277  if (a->family == b->family) {
278  switch (a->family) {
279  case AF_INET:
280  return (a->addr_data32[0] == b->addr_data32[0]);
281  case AF_INET6:
282  return CMP_ADDR(a, b);
283  }
284  }
285  return 0;
286 }
287 
288 static uint32_t ThresholdEntryHash(uint32_t seed, void *ptr)
289 {
290  const ThresholdEntry *e = ptr;
291  uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), seed);
292  switch (e->key[TRACK]) {
293  case TRACK_BOTH:
294  hash += HashAddress(&e->addr2);
295  /* fallthrough */
296  case TRACK_SRC:
297  case TRACK_DST:
298  hash += HashAddress(&e->addr);
299  break;
300  }
301  return hash;
302 }
303 
304 static bool ThresholdEntryCompare(void *a, void *b)
305 {
306  const ThresholdEntry *e1 = a;
307  const ThresholdEntry *e2 = b;
308  SCLogDebug("sid1: %u sid2: %u", e1->key[SID], e2->key[SID]);
309 
310  if (memcmp(e1->key, e2->key, sizeof(e1->key)) != 0)
311  return false;
312  switch (e1->key[TRACK]) {
313  case TRACK_BOTH:
314  if (!(CompareAddress(&e1->addr2, &e2->addr2)))
315  return false;
316  /* fallthrough */
317  case TRACK_SRC:
318  case TRACK_DST:
319  if (!(CompareAddress(&e1->addr, &e2->addr)))
320  return false;
321  break;
322  }
323  return true;
324 }
325 
326 static bool ThresholdEntryExpire(void *data, const SCTime_t ts)
327 {
328  const ThresholdEntry *e = data;
329  const SCTime_t entry = SCTIME_ADD_SECS(e->tv1, e->seconds);
330  if (SCTIME_CMP_GT(ts, entry)) {
331  return true;
332  }
333  return false;
334 }
335 
336 static int ThresholdsInit(struct Thresholds *t)
337 {
338  uint32_t hashsize = 16384;
339  uint64_t memcap = 16 * 1024 * 1024;
340 
341  const char *str;
342  if (SCConfGet("detect.thresholds.memcap", &str) == 1) {
343  if (ParseSizeStringU64(str, &memcap) < 0) {
344  SCLogError("Error parsing detect.thresholds.memcap from conf file - %s", str);
345  return -1;
346  }
347  }
348 
349  intmax_t value = 0;
350  if ((SCConfGetInt("detect.thresholds.hash-size", &value)) == 1) {
351  if (value < 256 || value > INT_MAX) {
352  SCLogError("'detect.thresholds.hash-size' value %" PRIiMAX
353  " out of range. Valid range 256-2147483647.",
354  value);
355  return -1;
356  }
357  hashsize = (uint32_t)value;
358  }
359 
360  t->thash = THashInit("thresholds", sizeof(ThresholdEntry), ThresholdEntrySet,
361  ThresholdEntryFree, ThresholdEntryHash, ThresholdEntryCompare, ThresholdEntryExpire,
362  NULL, 0, memcap, hashsize);
363  if (t->thash == NULL) {
364  SCLogError("failed to initialize thresholds hash table");
365  return -1;
366  }
367  return 0;
368 }
369 
370 static void ThresholdsDestroy(struct Thresholds *t)
371 {
372  if (t->thash) {
373  THashShutdown(t->thash);
374  }
375 }
376 
377 uint32_t ThresholdsExpire(const SCTime_t ts)
378 {
379  return THashExpire(ctx.thash, ts);
380 }
381 
382 #define TC_ADDRESS 0
383 #define TC_SID 1
384 #define TC_GID 2
385 #define TC_REV 3
386 #define TC_TENANT 4
387 
388 typedef struct ThresholdCacheItem {
389  int8_t track; // by_src/by_dst
390  int8_t ipv;
391  int8_t retval;
392  uint32_t key[5];
396 
397 static thread_local HashTable *threshold_cache_ht = NULL;
398 
399 thread_local uint64_t cache_lookup_cnt = 0;
400 thread_local uint64_t cache_lookup_notinit = 0;
401 thread_local uint64_t cache_lookup_nosupport = 0;
402 thread_local uint64_t cache_lookup_miss_expired = 0;
403 thread_local uint64_t cache_lookup_miss = 0;
404 thread_local uint64_t cache_lookup_hit = 0;
405 thread_local uint64_t cache_housekeeping_check = 0;
406 thread_local uint64_t cache_housekeeping_expired = 0;
407 
408 static void DumpCacheStats(void)
409 {
410  SCLogPerf("threshold thread cache stats: cnt:%" PRIu64 " notinit:%" PRIu64 " nosupport:%" PRIu64
411  " miss_expired:%" PRIu64 " miss:%" PRIu64 " hit:%" PRIu64
412  ", housekeeping: checks:%" PRIu64 ", expired:%" PRIu64,
416 }
417 
418 /* rbtree for expiry handling */
419 
420 static int ThresholdCacheTreeCompareFunc(ThresholdCacheItem *a, ThresholdCacheItem *b)
421 {
422  if (SCTIME_CMP_GTE(a->expires_at, b->expires_at)) {
423  return 1;
424  } else {
425  return -1;
426  }
427 }
428 
429 RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem);
430 RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
431 RB_GENERATE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
432 thread_local struct THRESHOLD_CACHE threshold_cache_tree;
433 thread_local uint64_t threshold_cache_housekeeping_ts = 0;
434 
435 static void ThresholdCacheExpire(SCTime_t now)
436 {
437  ThresholdCacheItem *iter, *safe = NULL;
438  int cnt = 0;
440 
441  RB_FOREACH_SAFE (iter, THRESHOLD_CACHE, &threshold_cache_tree, safe) {
443 
444  if (SCTIME_CMP_LT(iter->expires_at, now)) {
445  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, iter);
446  HashTableRemove(threshold_cache_ht, iter, 0);
447  SCLogDebug("iter %p expired", iter);
449  }
450 
451  if (++cnt > 1)
452  break;
453  }
454 }
455 
456 /* hash table for threshold look ups */
457 
458 static uint32_t ThresholdCacheHashFunc(HashTable *ht, void *data, uint16_t datalen)
459 {
460  ThresholdCacheItem *e = data;
461  uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), 0) * (e->ipv + e->track);
462  hash = hash % ht->array_size;
463  return hash;
464 }
465 
466 static char ThresholdCacheHashCompareFunc(
467  void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
468 {
469  ThresholdCacheItem *tci1 = data1;
470  ThresholdCacheItem *tci2 = data2;
471  return tci1->ipv == tci2->ipv && tci1->track == tci2->track &&
472  memcmp(tci1->key, tci2->key, sizeof(tci1->key)) == 0;
473 }
474 
475 static void ThresholdCacheHashFreeFunc(void *data)
476 {
477  SCFree(data);
478 }
479 
480 /// \brief Thread local cache
481 static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, const uint32_t sid,
482  const uint32_t gid, const uint32_t rev, SCTime_t expires)
483 {
484  if (!threshold_cache_ht) {
485  threshold_cache_ht = HashTableInit(256, ThresholdCacheHashFunc,
486  ThresholdCacheHashCompareFunc, ThresholdCacheHashFreeFunc);
487  }
488 
489  uint32_t addr;
490  if (track == TRACK_SRC) {
491  addr = p->src.addr_data32[0];
492  } else if (track == TRACK_DST) {
493  addr = p->dst.addr_data32[0];
494  } else {
495  return -1;
496  }
497 
498  ThresholdCacheItem lookup = {
499  .track = track,
500  .ipv = 4,
501  .retval = retval,
502  .key[TC_ADDRESS] = addr,
503  .key[TC_SID] = sid,
504  .key[TC_GID] = gid,
505  .key[TC_REV] = rev,
506  .key[TC_TENANT] = p->tenant_id,
507  .expires_at = expires,
508  };
509  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
510  if (!found) {
511  ThresholdCacheItem *n = SCCalloc(1, sizeof(*n));
512  if (n) {
513  n->track = track;
514  n->ipv = 4;
515  n->retval = retval;
516  n->key[TC_ADDRESS] = addr;
517  n->key[TC_SID] = sid;
518  n->key[TC_GID] = gid;
519  n->key[TC_REV] = rev;
520  n->key[TC_TENANT] = p->tenant_id;
521  n->expires_at = expires;
522 
523  if (HashTableAdd(threshold_cache_ht, n, 0) == 0) {
524  ThresholdCacheItem *r = THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, n);
525  DEBUG_VALIDATE_BUG_ON(r != NULL); // duplicate; should be impossible
526  (void)r; // only used by DEBUG_VALIDATE_BUG_ON
527  return 1;
528  }
529  SCFree(n);
530  }
531  return -1;
532  } else {
533  found->expires_at = expires;
534  found->retval = retval;
535 
536  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
537  THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, found);
538  return 1;
539  }
540 }
541 
542 /** \brief Check Thread local thresholding cache
543  * \note only supports IPv4
544  * \retval -1 cache miss - not found
545  * \retval -2 cache miss - found but expired
546  * \retval -3 error - cache not initialized
547  * \retval -4 error - unsupported tracker
548  * \retval ret cached return code
549  */
550 static int CheckCache(const Packet *p, const int8_t track, const uint32_t sid, const uint32_t gid,
551  const uint32_t rev)
552 {
554 
555  if (!threshold_cache_ht) {
557  return -3; // error cache initialized
558  }
559 
560  uint32_t addr;
561  if (track == TRACK_SRC) {
562  addr = p->src.addr_data32[0];
563  } else if (track == TRACK_DST) {
564  addr = p->dst.addr_data32[0];
565  } else {
567  return -4; // error tracker not unsupported
568  }
569 
571  ThresholdCacheExpire(p->ts);
572  }
573 
574  ThresholdCacheItem lookup = {
575  .track = track,
576  .ipv = 4,
577  .key[TC_ADDRESS] = addr,
578  .key[TC_SID] = sid,
579  .key[TC_GID] = gid,
580  .key[TC_REV] = rev,
581  .key[TC_TENANT] = p->tenant_id,
582  };
583  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
584  if (found) {
585  if (SCTIME_CMP_GT(p->ts, found->expires_at)) {
586  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
587  HashTableRemove(threshold_cache_ht, found, 0);
589  return -2; // cache miss - found but expired
590  }
592  return found->retval;
593  }
595  return -1; // cache miss - not found
596 }
597 
599 {
600  if (threshold_cache_ht) {
601  HashTableFree(threshold_cache_ht);
602  threshold_cache_ht = NULL;
603  }
605  DumpCacheStats();
606 }
607 
608 /**
609  * \brief Return next DetectThresholdData for signature
610  *
611  * \param sig Signature pointer
612  * \param psm Pointer to a Signature Match pointer
613  * \param list List to return data from
614  *
615  * \retval tsh Return the threshold data from signature or NULL if not found
616  */
618  const Signature *sig, const SigMatchData **psm, int list)
619 {
620  const SigMatchData *smd = NULL;
621  const DetectThresholdData *tsh = NULL;
622 
623  if (sig == NULL)
624  return NULL;
625 
626  if (*psm == NULL) {
627  smd = sig->sm_arrays[list];
628  } else {
629  /* Iteration in progress, using provided value */
630  smd = *psm;
631  }
632 
633  while (1) {
634  if (smd->type == DETECT_THRESHOLD || smd->type == DETECT_DETECTION_FILTER) {
635  tsh = (DetectThresholdData *)smd->ctx;
636 
637  if (smd->is_last) {
638  *psm = NULL;
639  } else {
640  *psm = smd + 1;
641  }
642  return tsh;
643  }
644 
645  if (smd->is_last) {
646  break;
647  }
648  smd++;
649  }
650  *psm = NULL;
651  return NULL;
652 }
653 
654 typedef struct FlowThresholdEntryList_ {
658 
659 static void FlowThresholdEntryListFree(FlowThresholdEntryList *list)
660 {
661  for (FlowThresholdEntryList *i = list; i != NULL;) {
663  SCFree(i);
664  i = next;
665  }
666 }
667 
668 /** struct for storing per flow thresholds. This will be stored in the Flow::flowvar list, so it
669  * needs to follow the GenericVar header format. */
670 typedef struct FlowVarThreshold_ {
671  uint16_t type;
672  uint8_t pad[6];
673  struct GenericVar_ *next;
676 
677 void FlowThresholdVarFree(void *ptr)
678 {
679  FlowVarThreshold *t = ptr;
680  FlowThresholdEntryListFree(t->thresholds);
681  SCFree(t);
682 }
683 
684 static FlowVarThreshold *FlowThresholdVarGet(Flow *f)
685 {
686  if (f == NULL)
687  return NULL;
688 
689  for (GenericVar *gv = f->flowvar; gv != NULL; gv = gv->next) {
690  if (gv->type == DETECT_THRESHOLD)
691  return (FlowVarThreshold *)gv;
692  }
693 
694  return NULL;
695 }
696 
697 static ThresholdEntry *ThresholdFlowLookupEntry(
698  Flow *f, uint32_t sid, uint32_t gid, uint32_t rev, uint32_t tenant_id)
699 {
700  FlowVarThreshold *t = FlowThresholdVarGet(f);
701  if (t == NULL)
702  return NULL;
703 
704  for (FlowThresholdEntryList *e = t->thresholds; e != NULL; e = e->next) {
705  if (e->threshold.key[SID] == sid && e->threshold.key[GID] == gid &&
706  e->threshold.key[REV] == rev && e->threshold.key[TENANT] == tenant_id) {
707  return &e->threshold;
708  }
709  }
710  return NULL;
711 }
712 
713 static int AddEntryToFlow(Flow *f, FlowThresholdEntryList *e, SCTime_t packet_time)
714 {
715  DEBUG_VALIDATE_BUG_ON(e == NULL);
716 
717  FlowVarThreshold *t = FlowThresholdVarGet(f);
718  if (t == NULL) {
719  t = SCCalloc(1, sizeof(*t));
720  if (t == NULL) {
721  return -1;
722  }
723  t->type = DETECT_THRESHOLD;
725  }
726 
727  e->next = t->thresholds;
728  t->thresholds = e;
729  return 0;
730 }
731 
732 static int ThresholdHandlePacketSuppress(
733  Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid)
734 {
735  int ret = 0;
736  DetectAddress *m = NULL;
737  switch (td->track) {
738  case TRACK_DST:
739  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
740  SCLogDebug("TRACK_DST");
741  break;
742  case TRACK_SRC:
743  m = DetectAddressLookupInHead(&td->addrs, &p->src);
744  SCLogDebug("TRACK_SRC");
745  break;
746  /* suppress if either src or dst is a match on the suppress
747  * address list */
748  case TRACK_EITHER:
749  m = DetectAddressLookupInHead(&td->addrs, &p->src);
750  if (m == NULL) {
751  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
752  }
753  break;
754  case TRACK_RULE:
755  case TRACK_FLOW:
756  default:
757  SCLogError("track mode %d is not supported", td->track);
758  break;
759  }
760  if (m == NULL)
761  ret = 1;
762  else
763  ret = 2; /* suppressed but still need actions */
764 
765  return ret;
766 }
767 
768 static inline void RateFilterSetAction(PacketAlert *pa, uint8_t new_action)
769 {
770  switch (new_action) {
771  case TH_ACTION_ALERT:
773  pa->action = ACTION_ALERT;
774  break;
775  case TH_ACTION_DROP:
777  pa->action = (ACTION_DROP | ACTION_ALERT);
778  break;
779  case TH_ACTION_REJECT:
782  break;
783  case TH_ACTION_PASS:
785  pa->action = ACTION_PASS;
786  break;
787  default:
788  /* Weird, leave the default action */
789  break;
790  }
791 }
792 
793 /** \internal
794  * \brief Apply the multiplier and return the new value.
795  * If it would overflow the uint32_t we return UINT32_MAX.
796  */
797 static uint32_t BackoffCalcNextValue(const uint32_t cur, const uint32_t m)
798 {
799  /* goal is to see if cur * m would overflow uint32_t */
800  if (unlikely(UINT32_MAX / m < cur)) {
801  return UINT32_MAX;
802  }
803  return cur * m;
804 }
805 
806 /**
807  * \retval 2 silent match (no alert but apply actions)
808  * \retval 1 normal match
809  * \retval 0 no match
810  */
811 static int ThresholdSetup(const DetectThresholdData *td, ThresholdEntry *te, const Packet *p,
812  const uint32_t sid, const uint32_t gid, const uint32_t rev)
813 {
814  te->key[SID] = sid;
815  te->key[GID] = gid;
816  te->key[REV] = rev;
817  te->key[TRACK] = td->track;
818  te->key[TENANT] = p->tenant_id;
819 
820  te->seconds = td->seconds;
821  te->current_count = 1;
822 
823  switch (td->type) {
824  case TYPE_BACKOFF:
825  te->backoff.next_value = td->count;
826  break;
827  default:
828  te->tv1 = p->ts;
830  ThresholdDistinctInit(te, td);
831  /* If unique_on is enabled, we must add the current packet's port to the bitmap.
832  * ThresholdDistinctInit resets current_count to 0, so we must add the port
833  * or restore the count if allocation failed. */
834  if (td->type == TYPE_DETECTION && td->unique_on != DF_UNIQUE_NONE) {
835  if (te->distinct_bitmap_union) {
836  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
837  ThresholdDistinctAddPort(te, port);
838  } else {
839  /* Allocation failed (or test mode), fallback to classic counting.
840  * We must set current_count to 1 for this first packet. */
841  te->current_count = 1;
842  }
843  }
844  break;
845  }
846 
847  switch (td->type) {
848  case TYPE_LIMIT:
849  case TYPE_RATE:
850  return 1;
851  case TYPE_THRESHOLD:
852  case TYPE_BOTH:
853  if (td->count == 1)
854  return 1;
855  return 0;
856  case TYPE_BACKOFF:
857  if (td->count == 1) {
858  te->backoff.next_value =
859  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
860  return 1;
861  }
862  return 0;
863  case TYPE_DETECTION:
864  return 0;
865  }
866  return 0;
867 }
868 
869 static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThresholdData *td,
870  ThresholdEntry *te,
871  const Packet *p, // ts only? - cache too
872  const uint32_t sid, const uint32_t gid, const uint32_t rev, PacketAlert *pa)
873 {
874  int ret = 0;
875  const SCTime_t packet_time = p->ts;
876  const SCTime_t entry = SCTIME_ADD_SECS(te->tv1, td->seconds);
877  switch (td->type) {
878  case TYPE_LIMIT:
879  SCLogDebug("limit");
880 
881  if (SCTIME_CMP_LTE(p->ts, entry)) {
882  te->current_count++;
883 
884  if (te->current_count <= td->count) {
885  ret = 1;
886  } else {
887  ret = 2;
888 
889  if (PacketIsIPv4(p)) {
890  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
891  }
892  }
893  } else {
894  /* entry expired, reset */
895  te->tv1 = p->ts;
896  te->current_count = 1;
897  ret = 1;
898  }
899  break;
900  case TYPE_THRESHOLD:
901  if (SCTIME_CMP_LTE(p->ts, entry)) {
902  te->current_count++;
903 
904  if (te->current_count >= td->count) {
905  ret = 1;
906  te->current_count = 0;
907  }
908  } else {
909  te->tv1 = p->ts;
910  te->current_count = 1;
911  }
912  break;
913  case TYPE_BOTH:
914  if (SCTIME_CMP_LTE(p->ts, entry)) {
915  /* within time limit */
916 
917  te->current_count++;
918  if (te->current_count == td->count) {
919  ret = 1;
920  } else if (te->current_count > td->count) {
921  /* silent match */
922  ret = 2;
923 
924  if (PacketIsIPv4(p)) {
925  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
926  }
927  }
928  } else {
929  /* expired, so reset */
930  te->tv1 = p->ts;
931  te->current_count = 1;
932 
933  /* if we have a limit of 1, this is a match */
934  if (te->current_count == td->count) {
935  ret = 1;
936  }
937  }
938  break;
939  case TYPE_DETECTION: {
940  SCLogDebug("detection_filter");
941 
942  if (SCTIME_CMP_LTE(p->ts, entry)) {
943  /* within timeout */
944  if (td->unique_on != DF_UNIQUE_NONE && te->distinct_bitmap_union) {
945  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
946  ThresholdDistinctAddPort(te, port);
947  if (te->current_count > td->count) {
948  ret = 1;
949  }
950  } else {
951  te->current_count++;
952  if (te->current_count > td->count) {
953  ret = 1;
954  }
955  }
956  } else {
957  /* expired, reset to new window starting now */
958  te->tv1 = p->ts;
959  ThresholdDistinctReset(te);
960 
961  /* record current packet's distinct port as the first in the new window */
962  if (td->unique_on != DF_UNIQUE_NONE && te->distinct_bitmap_union) {
963  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
964  ThresholdDistinctAddPort(te, port);
965  } else {
966  te->current_count = 1;
967  }
968  }
969  break;
970  }
971  case TYPE_RATE: {
972  SCLogDebug("rate_filter");
973  const uint8_t original_action = pa->action;
974  ret = 1;
975  /* Check if we have a timeout enabled, if so,
976  * we still matching (and enabling the new_action) */
978  if ((SCTIME_SECS(packet_time) - SCTIME_SECS(te->tv_timeout)) > td->timeout) {
979  /* Ok, we are done, timeout reached */
981  } else {
982  /* Already matching */
983  RateFilterSetAction(pa, td->new_action);
984  }
985  } else {
986  /* Update the matching state with the timeout interval */
987  if (SCTIME_CMP_LTE(packet_time, entry)) {
988  te->current_count++;
989  if (te->current_count > td->count) {
990  /* Then we must enable the new action by setting a
991  * timeout */
992  te->tv_timeout = packet_time;
993  RateFilterSetAction(pa, td->new_action);
994  }
995  } else {
996  te->tv1 = packet_time;
997  te->current_count = 1;
998  }
999  }
1000  if (de_ctx->RateFilterCallback && original_action != pa->action) {
1001  pa->action = de_ctx->RateFilterCallback(p, sid, gid, rev, original_action,
1003  if (pa->action == original_action) {
1004  /* Reset back to original action, clear modified flag. */
1006  }
1007  }
1008  break;
1009  }
1010  case TYPE_BACKOFF:
1011  SCLogDebug("backoff");
1012 
1013  if (te->current_count < UINT32_MAX) {
1014  te->current_count++;
1015  if (te->backoff.next_value == te->current_count) {
1016  te->backoff.next_value =
1017  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
1018  SCLogDebug("te->backoff.next_value %u", te->backoff.next_value);
1019  ret = 1;
1020  } else {
1021  ret = 2;
1022  }
1023  } else {
1024  /* if count reaches UINT32_MAX, we just silent match on the rest of the flow */
1025  ret = 2;
1026  }
1027  break;
1028  }
1029  return ret;
1030 }
1031 
1032 static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, struct Thresholds *tctx,
1033  const Packet *p, const Signature *s, const DetectThresholdData *td, PacketAlert *pa)
1034 {
1035  /* fast track for count 1 threshold */
1036  if (td->count == 1 && td->type == TYPE_THRESHOLD) {
1037  return 1;
1038  }
1039 
1040  ThresholdEntry lookup;
1041  memset(&lookup, 0, sizeof(lookup));
1042  lookup.key[SID] = s->id;
1043  lookup.key[GID] = s->gid;
1044  lookup.key[REV] = s->rev;
1045  lookup.key[TRACK] = td->track;
1046  lookup.key[TENANT] = p->tenant_id;
1047  if (td->track == TRACK_SRC) {
1048  COPY_ADDRESS(&p->src, &lookup.addr);
1049  } else if (td->track == TRACK_DST) {
1050  COPY_ADDRESS(&p->dst, &lookup.addr);
1051  } else if (td->track == TRACK_BOTH) {
1052  /* make sure lower ip address is first */
1053  if (PacketIsIPv4(p)) {
1054  if (SCNtohl(p->src.addr_data32[0]) < SCNtohl(p->dst.addr_data32[0])) {
1055  COPY_ADDRESS(&p->src, &lookup.addr);
1056  COPY_ADDRESS(&p->dst, &lookup.addr2);
1057  } else {
1058  COPY_ADDRESS(&p->dst, &lookup.addr);
1059  COPY_ADDRESS(&p->src, &lookup.addr2);
1060  }
1061  } else {
1062  if (AddressIPv6Lt(&p->src, &p->dst)) {
1063  COPY_ADDRESS(&p->src, &lookup.addr);
1064  COPY_ADDRESS(&p->dst, &lookup.addr2);
1065  } else {
1066  COPY_ADDRESS(&p->dst, &lookup.addr);
1067  COPY_ADDRESS(&p->src, &lookup.addr2);
1068  }
1069  }
1070  }
1071 
1072  struct THashDataGetResult res = THashGetFromHash(tctx->thash, &lookup);
1073  if (res.data) {
1074  SCLogDebug("found %p, is_new %s", res.data, BOOL2STR(res.is_new));
1075  int r;
1076  ThresholdEntry *te = res.data->data;
1077  if (res.is_new) {
1078  // new threshold, set up
1079  r = ThresholdSetup(td, te, p, s->id, s->gid, s->rev);
1080  } else {
1081  // existing, check/update
1082  r = ThresholdCheckUpdate(de_ctx, td, te, p, s->id, s->gid, s->rev, pa);
1083  }
1084 
1085  (void)THashDecrUsecnt(res.data);
1086  THashDataUnlock(res.data);
1087  return r;
1088  }
1089  return 0; // TODO error?
1090 }
1091 
1092 /**
1093  * \retval 2 silent match (no alert but apply actions)
1094  * \retval 1 normal match
1095  * \retval 0 no match
1096  */
1097 static int ThresholdHandlePacketFlow(const DetectEngineCtx *de_ctx, Flow *f, Packet *p,
1098  const DetectThresholdData *td, uint32_t sid, uint32_t gid, uint32_t rev, PacketAlert *pa)
1099 {
1100  int ret = 0;
1101  ThresholdEntry *found = ThresholdFlowLookupEntry(f, sid, gid, rev, p->tenant_id);
1102  SCLogDebug("found %p sid %u gid %u rev %u", found, sid, gid, rev);
1103 
1104  if (found == NULL) {
1105  FlowThresholdEntryList *new = SCCalloc(1, sizeof(*new));
1106  if (new == NULL)
1107  return 0;
1108 
1109  // new threshold, set up
1110  ret = ThresholdSetup(td, &new->threshold, p, sid, gid, rev);
1111 
1112  if (AddEntryToFlow(f, new, p->ts) == -1) {
1113  SCFree(new);
1114  return 0;
1115  }
1116  } else {
1117  // existing, check/update
1118  ret = ThresholdCheckUpdate(de_ctx, td, found, p, sid, gid, rev, pa);
1119  }
1120  return ret;
1121 }
1122 
1123 /**
1124  * \brief Make the threshold logic for signatures
1125  *
1126  * \param de_ctx Detection Context
1127  * \param tsh_ptr Threshold element
1128  * \param p Packet structure
1129  * \param s Signature structure
1130  *
1131  * \retval 2 silent match (no alert but apply actions)
1132  * \retval 1 alert on this event
1133  * \retval 0 do not alert on this event
1134  */
1136  const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa)
1137 {
1138  SCEnter();
1139 
1140  int ret = 0;
1141  if (td == NULL) {
1142  SCReturnInt(0);
1143  }
1144 
1145  if (td->type == TYPE_SUPPRESS) {
1146  ret = ThresholdHandlePacketSuppress(p, td, s->id, s->gid);
1147  } else if (td->track == TRACK_SRC) {
1148  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
1149  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
1150  if (cache_ret >= 0) {
1151  SCReturnInt(cache_ret);
1152  }
1153  }
1154 
1155  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1156  } else if (td->track == TRACK_DST) {
1157  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
1158  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
1159  if (cache_ret >= 0) {
1160  SCReturnInt(cache_ret);
1161  }
1162  }
1163 
1164  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1165  } else if (td->track == TRACK_BOTH) {
1166  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1167  } else if (td->track == TRACK_RULE) {
1168  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1169  } else if (td->track == TRACK_FLOW) {
1170  if (p->flow) {
1171  ret = ThresholdHandlePacketFlow(de_ctx, p->flow, p, td, s->id, s->gid, s->rev, pa);
1172  }
1173  }
1174 
1175  SCReturnInt(ret);
1176 }
1177 
1178 /**
1179  * @}
1180  */
TRACK_BOTH
#define TRACK_BOTH
Definition: detect-threshold.h:39
SID
#define SID
Definition: detect-engine-threshold.c:144
DetectThresholdData_::timeout
uint32_t timeout
Definition: detect-threshold.h:68
ThresholdEntry_::tv_timeout
SCTime_t tv_timeout
Definition: detect-engine-threshold.c:153
StatsRegisterGlobalCounter
StatsCounterGlobalId StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1094
ts
uint64_t ts
Definition: source-erf-file.c:55
GenericVarAppend
void GenericVarAppend(GenericVar **list, GenericVar *gv)
Definition: util-var.c:98
cache_lookup_notinit
thread_local uint64_t cache_lookup_notinit
Definition: detect-engine-threshold.c:400
detect-engine.h
FlowVarThreshold_
Definition: detect-engine-threshold.c:670
THashDataGetResult::data
THashData * data
Definition: util-thash.h:192
hashword
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:172
DF_PORT_BITMAP_SIZE
#define DF_PORT_BITMAP_SIZE
Definition: detect-engine-threshold.c:88
SCTIME_CMP_NEQ
#define SCTIME_CMP_NEQ(a, b)
Definition: util-time.h:107
FlowVarThreshold_::next
struct GenericVar_ * next
Definition: detect-engine-threshold.c:673
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
Thresholds::thash
THashTableContext * thash
Definition: detect-engine-threshold.c:93
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
ThresholdEntry
struct ThresholdEntry_ ThresholdEntry
ACTION_PASS
#define ACTION_PASS
Definition: action-globals.h:34
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
TYPE_BACKOFF
#define TYPE_BACKOFF
Definition: detect-threshold.h:33
TRACK
#define TRACK
Definition: detect-engine-threshold.c:147
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:168
GID
#define GID
Definition: detect-engine-threshold.c:145
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:191
ThresholdCacheItem
struct ThresholdCacheItem ThresholdCacheItem
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:366
TC_GID
#define TC_GID
Definition: detect-engine-threshold.c:384
RB_PROTOTYPE
RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc)
DetectThresholdData_::count
uint32_t count
Definition: detect-threshold.h:63
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:367
Thresholds
Definition: detect-engine-threshold.c:92
action-globals.h
Flow_
Flow data structure.
Definition: flow.h:347
util-hash.h
ctx
struct Thresholds ctx
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
SCConfGet
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:351
TYPE_LIMIT
#define TYPE_LIMIT
Definition: detect-threshold.h:27
TRACK_DST
#define TRACK_DST
Definition: detect-detection-filter.c:44
HashTable_
Definition: util-hash.h:35
DetectThresholdData_::new_action
uint8_t new_action
Definition: detect-threshold.h:67
FlowVarThreshold_::pad
uint8_t pad[6]
Definition: detect-engine-threshold.c:672
Address_
Definition: decode.h:112
DetectThresholdData_::multiplier
uint32_t multiplier
Definition: detect-threshold.h:70
TH_ACTION_ALERT
#define TH_ACTION_ALERT
Definition: detect-threshold.h:43
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:730
m
SCMutex m
Definition: flow-hash.h:6
ThresholdCacheItem
Definition: detect-engine-threshold.c:388
FlowThresholdEntryList_::threshold
ThresholdEntry threshold
Definition: detect-engine-threshold.c:656
SigMatchData_
Data needed for Match()
Definition: detect.h:364
SigMatchData_::type
uint16_t type
Definition: detect.h:365
TC_ADDRESS
#define TC_ADDRESS
Definition: detect-engine-threshold.c:382
ThresholdRegisterGlobalCounters
void ThresholdRegisterGlobalCounters(void)
Definition: detect-engine-threshold.c:130
DetectAddressLookupInHead
DetectAddress * DetectAddressLookupInHead(const DetectAddressHead *gh, Address *a)
Find the group matching address in a group head.
Definition: detect-engine-address.c:1799
HashTableFree
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
Definition: util-hash.c:100
DetectThresholdData_::unique_on
enum DetectThresholdUniqueOn unique_on
Definition: detect-threshold.h:71
DetectThresholdData_::type
uint8_t type
Definition: detect-threshold.h:65
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
PacketAlert_::action
uint8_t action
Definition: decode.h:250
Signature_::gid
uint32_t gid
Definition: detect.h:713
TC_TENANT
#define TC_TENANT
Definition: detect-engine-threshold.c:386
FlowThresholdEntryList_::next
struct FlowThresholdEntryList_ * next
Definition: detect-engine-threshold.c:655
FlowThresholdEntryList_
Definition: detect-engine-threshold.c:654
ThresholdForceAllocFail
void ThresholdForceAllocFail(int v)
Definition: detect-engine-threshold.c:71
counters.h
ThresholdGetBitmapAllocFail
uint64_t ThresholdGetBitmapAllocFail(void)
Definition: detect-engine-threshold.c:81
TRACK_RULE
#define TRACK_RULE
Definition: detect-threshold.h:37
RB_INIT
#define RB_INIT(root)
Definition: tree.h:308
util-debug.h
TRACK_FLOW
#define TRACK_FLOW
Definition: detect-threshold.h:40
ThresholdEntry_::seconds
uint32_t seconds
Definition: detect-engine-threshold.c:155
GenericVar_::next
struct GenericVar_ * next
Definition: util-var.h:57
util-error.h
REV
#define REV
Definition: detect-engine-threshold.c:146
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
TYPE_RATE
#define TYPE_RATE
Definition: detect-threshold.h:31
FlowThresholdEntryList
struct FlowThresholdEntryList_ FlowThresholdEntryList
DetectEngineThreadCtx_
Definition: detect.h:1244
Packet_::ts
SCTime_t ts
Definition: decode.h:555
DETECT_THRESHOLD
@ DETECT_THRESHOLD
Definition: detect-engine-register.h:58
THashTableContext_
Definition: util-thash.h:141
ThresholdEntry_::next_value
uint32_t next_value
Definition: detect-engine-threshold.c:160
TH_ACTION_PASS
#define TH_ACTION_PASS
Definition: detect-threshold.h:45
SCConfGetInt
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:415
ThresholdEntry_::current_count
uint32_t current_count
Definition: detect-engine-threshold.c:156
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:542
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:182
detect.h
Packet_::sp
Port sp
Definition: decode.h:508
HashTableRemove
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Remove an item from the hash table.
Definition: util-hash.c:166
util-time.h
ThresholdDestroy
void ThresholdDestroy(void)
Definition: detect-engine-threshold.c:139
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:120
TYPE_BOTH
#define TYPE_BOTH
Definition: detect-threshold.h:28
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:341
SC_ATOMIC_DECLARE
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
Definition: util-atomic.h:280
THashDataGetResult
Definition: util-thash.h:191
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:501
TRACK_EITHER
#define TRACK_EITHER
Definition: detect-threshold.h:38
SCTime_t
Definition: util-time.h:40
cache_lookup_miss_expired
thread_local uint64_t cache_lookup_miss_expired
Definition: detect-engine-threshold.c:402
ThresholdCacheItem::ipv
int8_t ipv
Definition: detect-engine-threshold.c:390
DetectEngineCtx_::RateFilterCallback
SCDetectRateFilterFunc RateFilterCallback
Definition: detect.h:1147
FlowVarThreshold_::thresholds
FlowThresholdEntryList * thresholds
Definition: detect-engine-threshold.c:674
cache_housekeeping_expired
thread_local uint64_t cache_housekeeping_expired
Definition: detect-engine-threshold.c:406
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:480
DetectThresholdData_::track
uint8_t track
Definition: detect-threshold.h:66
ThresholdEntry_
Definition: detect-engine-threshold.c:150
ThresholdEntry_::backoff
struct ThresholdEntry_::@61::@63 backoff
THashShutdown
void THashShutdown(THashTableContext *ctx)
shutdown the flow engine
Definition: util-thash.c:354
SCTIME_CMP_LT
#define SCTIME_CMP_LT(a, b)
Definition: util-time.h:105
PacketAlert_::flags
uint8_t flags
Definition: decode.h:251
ThresholdEntry_::tv1
SCTime_t tv1
Definition: detect-engine-threshold.c:163
TH_ACTION_REJECT
#define TH_ACTION_REJECT
Definition: detect-threshold.h:48
THashData_::data
void * data
Definition: util-thash.h:92
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
Packet_::flow
struct Flow_ * flow
Definition: decode.h:546
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:661
CMP_ADDR
#define CMP_ADDR(a1, a2)
Definition: decode.h:222
suricata-common.h
DetectThresholdData_
Definition: detect-threshold.h:62
cache_lookup_hit
thread_local uint64_t cache_lookup_hit
Definition: detect-engine-threshold.c:404
GenericVar_
Definition: util-var.h:53
DF_PORT_BIT_MASK
#define DF_PORT_BIT_MASK(p)
Definition: detect-engine-threshold.c:90
TYPE_SUPPRESS
#define TYPE_SUPPRESS
Definition: detect-threshold.h:32
TC_SID
#define TC_SID
Definition: detect-engine-threshold.c:383
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
DetectEngineCtx_::rate_filter_callback_arg
void * rate_filter_callback_arg
Definition: detect.h:1150
threshold_cache_housekeeping_ts
thread_local uint64_t threshold_cache_housekeeping_ts
Definition: detect-engine-threshold.c:433
TH_ACTION_DROP
#define TH_ACTION_DROP
Definition: detect-threshold.h:44
Signature_::rev
uint32_t rev
Definition: detect.h:714
ThresholdEntry_::addr2
Address addr2
Definition: detect-engine-threshold.c:165
THashGetFromHash
struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:637
cache_lookup_nosupport
thread_local uint64_t cache_lookup_nosupport
Definition: detect-engine-threshold.c:401
hashsize
#define hashsize(n)
Definition: util-hash-lookup3.h:40
util-hash-lookup3.h
detect-engine-address-ipv6.h
ThresholdCacheItem::track
int8_t track
Definition: detect-engine-threshold.c:389
THashDecrUsecnt
#define THashDecrUsecnt(h)
Definition: util-thash.h:170
SigGetThresholdTypeIter
const DetectThresholdData * SigGetThresholdTypeIter(const Signature *sig, const SigMatchData **psm, int list)
Return next DetectThresholdData for signature.
Definition: detect-engine-threshold.c:617
util-validate.h
ThresholdGetBitmapMemuse
uint64_t ThresholdGetBitmapMemuse(void)
Definition: detect-engine-threshold.c:76
SCTIME_CMP_GT
#define SCTIME_CMP_GT(a, b)
Definition: util-time.h:104
TYPE_THRESHOLD
#define TYPE_THRESHOLD
Definition: detect-threshold.h:29
DETECT_DETECTION_FILTER
@ DETECT_DETECTION_FILTER
Definition: detect-engine-register.h:120
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:123
PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED
#define PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED
Definition: decode.h:274
ThresholdCacheItem::expires_at
SCTime_t expires_at
Definition: detect-engine-threshold.c:393
str
#define str(s)
Definition: suricata-common.h:308
cache_lookup_cnt
thread_local uint64_t cache_lookup_cnt
Definition: detect-engine-threshold.c:399
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
ThresholdEntry_::distinct_bitmap_union
uint8_t * distinct_bitmap_union
Definition: detect-engine-threshold.c:167
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SCNtohl
#define SCNtohl(x)
Definition: suricata-common.h:430
AddressIPv6Lt
int AddressIPv6Lt(const Address *a, const Address *b)
Compares 2 ipv6 addresses and returns if the first address(a) is less than the second address(b) or n...
Definition: detect-engine-address-ipv6.c:52
SCTIME_CMP_GTE
#define SCTIME_CMP_GTE(a, b)
Definition: util-time.h:103
Signature_::id
uint32_t id
Definition: detect.h:712
ThresholdEntry_::key
uint32_t key[5]
Definition: detect-engine-threshold.c:151
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
Signature_
Signature container.
Definition: detect.h:667
FlowVarThreshold_::type
uint16_t type
Definition: detect-engine-threshold.c:671
ThresholdEntry_::addr
Address addr
Definition: detect-engine-threshold.c:164
DF_UNIQUE_NONE
@ DF_UNIQUE_NONE
Definition: detect-threshold.h:52
RB_GENERATE
RB_GENERATE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc)
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
THashDataGetResult::is_new
bool is_new
Definition: util-thash.h:193
RB_ENTRY
#define RB_ENTRY(type)
Definition: tree.h:314
cache_housekeeping_check
thread_local uint64_t cache_housekeeping_check
Definition: detect-engine-threshold.c:405
Address_::family
char family
Definition: decode.h:113
Packet_::dst
Address dst
Definition: decode.h:506
THashInit
THashTableContext * THashInit(const char *cnf_prefix, uint32_t data_size, int(*DataSet)(void *, void *), void(*DataFree)(void *), uint32_t(*DataHash)(uint32_t, void *), bool(*DataCompare)(void *, void *), bool(*DataExpired)(void *, SCTime_t), uint32_t(*DataSize)(void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
Definition: util-thash.c:302
TRACK_SRC
#define TRACK_SRC
Definition: detect-detection-filter.c:45
PacketAlert_
Definition: decode.h:248
THashExpire
uint32_t THashExpire(THashTableContext *ctx, const SCTime_t ts)
expire data from the hash Walk the hash table and remove data that is exprired according to the DataE...
Definition: util-thash.c:442
DF_UNIQUE_SRC_PORT
@ DF_UNIQUE_SRC_PORT
Definition: detect-threshold.h:53
ThresholdCacheThreadFree
void ThresholdCacheThreadFree(void)
Definition: detect-engine-threshold.c:598
DetectThresholdData_::seconds
uint32_t seconds
Definition: detect-threshold.h:64
threshold_cache_tree
thread_local struct THRESHOLD_CACHE threshold_cache_tree
Definition: detect-engine-threshold.c:432
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
PacketAlertThreshold
int PacketAlertThreshold(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa)
Make the threshold logic for signatures.
Definition: detect-engine-threshold.c:1135
util-misc.h
COPY_ADDRESS
#define COPY_ADDRESS(a, b)
Definition: decode.h:127
flow.h
util-thash.h
SCTIME_INITIALIZER
#define SCTIME_INITIALIZER
Definition: util-time.h:51
SCTIME_ADD_SECS
#define SCTIME_ADD_SECS(ts, s)
Definition: util-time.h:64
Packet_::dp
Port dp
Definition: decode.h:516
TENANT
#define TENANT
Definition: detect-engine-threshold.c:148
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
ThresholdCacheItem::retval
int8_t retval
Definition: detect-engine-threshold.c:391
DF_PORT_BYTE_IDX
#define DF_PORT_BYTE_IDX(p)
Definition: detect-engine-threshold.c:89
FlowThresholdVarFree
void FlowThresholdVarFree(void *ptr)
Definition: detect-engine-threshold.c:677
ThresholdInit
void ThresholdInit(void)
Definition: detect-engine-threshold.c:123
THASH_CHECK_MEMCAP
#define THASH_CHECK_MEMCAP(ctx, size)
check if a memory alloc would fit in the memcap
Definition: util-thash.h:164
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
SCTIME_CMP_LTE
#define SCTIME_CMP_LTE(a, b)
Definition: util-time.h:106
ThresholdCacheItem::key
uint32_t key[5]
Definition: detect-engine-threshold.c:392
detect-engine-address.h
Packet_::src
Address src
Definition: decode.h:505
detect-engine-threshold.h
ThresholdsExpire
uint32_t ThresholdsExpire(const SCTime_t ts)
Definition: detect-engine-threshold.c:377
TC_REV
#define TC_REV
Definition: detect-engine-threshold.c:385
cache_lookup_miss
thread_local uint64_t cache_lookup_miss
Definition: detect-engine-threshold.c:403
TYPE_DETECTION
#define TYPE_DETECTION
Definition: detect-threshold.h:30
THashTableContext_::config
THashConfig config
Definition: util-thash.h:151
RB_HEAD
RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem)
FlowVarThreshold
struct FlowVarThreshold_ FlowVarThreshold
DetectThresholdData_::addrs
DetectAddressHead addrs
Definition: detect-threshold.h:73