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  return SCTIME_CMP_GT(ts, entry);
331 }
332 
333 static int ThresholdsInit(struct Thresholds *t)
334 {
335  uint32_t hashsize = 16384;
336  uint64_t memcap = 16 * 1024 * 1024;
337 
338  const char *str;
339  if (SCConfGet("detect.thresholds.memcap", &str) == 1) {
340  if (ParseSizeStringU64(str, &memcap) < 0) {
341  SCLogError("Error parsing detect.thresholds.memcap from conf file - %s", str);
342  return -1;
343  }
344  }
345 
346  intmax_t value = 0;
347  if ((SCConfGetInt("detect.thresholds.hash-size", &value)) == 1) {
348  if (value < 256 || value > INT_MAX) {
349  SCLogError("'detect.thresholds.hash-size' value %" PRIiMAX
350  " out of range. Valid range 256-2147483647.",
351  value);
352  return -1;
353  }
354  hashsize = (uint32_t)value;
355  }
356 
357  t->thash = THashInit("thresholds", sizeof(ThresholdEntry), ThresholdEntrySet,
358  ThresholdEntryFree, ThresholdEntryHash, ThresholdEntryCompare, ThresholdEntryExpire,
359  NULL, 0, memcap, hashsize);
360  if (t->thash == NULL) {
361  SCLogError("failed to initialize thresholds hash table");
362  return -1;
363  }
364  return 0;
365 }
366 
367 static void ThresholdsDestroy(struct Thresholds *t)
368 {
369  if (t->thash) {
370  THashShutdown(t->thash);
371  }
372 }
373 
374 uint32_t ThresholdsExpire(const SCTime_t ts)
375 {
376  return THashExpire(ctx.thash, ts);
377 }
378 
379 #define TC_ADDRESS 0
380 #define TC_SID 1
381 #define TC_GID 2
382 #define TC_REV 3
383 #define TC_TENANT 4
384 
385 typedef struct ThresholdCacheItem {
386  int8_t track; // by_src/by_dst
387  int8_t ipv;
388  int8_t retval;
389  uint32_t key[5];
393 
394 static thread_local HashTable *threshold_cache_ht = NULL;
395 
396 thread_local uint64_t cache_lookup_cnt = 0;
397 thread_local uint64_t cache_lookup_notinit = 0;
398 thread_local uint64_t cache_lookup_nosupport = 0;
399 thread_local uint64_t cache_lookup_miss_expired = 0;
400 thread_local uint64_t cache_lookup_miss = 0;
401 thread_local uint64_t cache_lookup_hit = 0;
402 thread_local uint64_t cache_housekeeping_check = 0;
403 thread_local uint64_t cache_housekeeping_expired = 0;
404 
405 static void DumpCacheStats(void)
406 {
407  SCLogPerf("threshold thread cache stats: cnt:%" PRIu64 " notinit:%" PRIu64 " nosupport:%" PRIu64
408  " miss_expired:%" PRIu64 " miss:%" PRIu64 " hit:%" PRIu64
409  ", housekeeping: checks:%" PRIu64 ", expired:%" PRIu64,
413 }
414 
415 /* rbtree for expiry handling */
416 
417 static int ThresholdCacheTreeCompareFunc(ThresholdCacheItem *a, ThresholdCacheItem *b)
418 {
419  if (SCTIME_CMP_GTE(a->expires_at, b->expires_at)) {
420  return 1;
421  } else {
422  return -1;
423  }
424 }
425 
426 RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem);
427 RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
428 RB_GENERATE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
429 thread_local struct THRESHOLD_CACHE threshold_cache_tree;
430 thread_local uint64_t threshold_cache_housekeeping_ts = 0;
431 
432 static void ThresholdCacheExpire(SCTime_t now)
433 {
434  ThresholdCacheItem *iter, *safe = NULL;
435  int cnt = 0;
437 
438  RB_FOREACH_SAFE (iter, THRESHOLD_CACHE, &threshold_cache_tree, safe) {
440 
441  if (SCTIME_CMP_LT(iter->expires_at, now)) {
442  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, iter);
443  HashTableRemove(threshold_cache_ht, iter, 0);
444  SCLogDebug("iter %p expired", iter);
446  }
447 
448  if (++cnt > 1)
449  break;
450  }
451 }
452 
453 /* hash table for threshold look ups */
454 
455 static uint32_t ThresholdCacheHashFunc(HashTable *ht, void *data, uint16_t datalen)
456 {
457  ThresholdCacheItem *e = data;
458  uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), 0) * (e->ipv + e->track);
459  hash = hash % ht->array_size;
460  return hash;
461 }
462 
463 static char ThresholdCacheHashCompareFunc(
464  void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
465 {
466  ThresholdCacheItem *tci1 = data1;
467  ThresholdCacheItem *tci2 = data2;
468  return tci1->ipv == tci2->ipv && tci1->track == tci2->track &&
469  memcmp(tci1->key, tci2->key, sizeof(tci1->key)) == 0;
470 }
471 
472 static void ThresholdCacheHashFreeFunc(void *data)
473 {
474  SCFree(data);
475 }
476 
477 /// \brief Thread local cache
478 static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, const uint32_t sid,
479  const uint32_t gid, const uint32_t rev, SCTime_t expires)
480 {
481  if (!threshold_cache_ht) {
482  threshold_cache_ht = HashTableInit(256, ThresholdCacheHashFunc,
483  ThresholdCacheHashCompareFunc, ThresholdCacheHashFreeFunc);
484  }
485 
486  uint32_t addr;
487  if (track == TRACK_SRC) {
488  addr = p->src.addr_data32[0];
489  } else if (track == TRACK_DST) {
490  addr = p->dst.addr_data32[0];
491  } else {
492  return -1;
493  }
494 
495  ThresholdCacheItem lookup = {
496  .track = track,
497  .ipv = 4,
498  .retval = retval,
499  .key[TC_ADDRESS] = addr,
500  .key[TC_SID] = sid,
501  .key[TC_GID] = gid,
502  .key[TC_REV] = rev,
503  .key[TC_TENANT] = p->tenant_id,
504  .expires_at = expires,
505  };
506  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
507  if (!found) {
508  ThresholdCacheItem *n = SCCalloc(1, sizeof(*n));
509  if (n) {
510  n->track = track;
511  n->ipv = 4;
512  n->retval = retval;
513  n->key[TC_ADDRESS] = addr;
514  n->key[TC_SID] = sid;
515  n->key[TC_GID] = gid;
516  n->key[TC_REV] = rev;
517  n->key[TC_TENANT] = p->tenant_id;
518  n->expires_at = expires;
519 
520  if (HashTableAdd(threshold_cache_ht, n, 0) == 0) {
521  ThresholdCacheItem *r = THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, n);
522  DEBUG_VALIDATE_BUG_ON(r != NULL); // duplicate; should be impossible
523  (void)r; // only used by DEBUG_VALIDATE_BUG_ON
524  return 1;
525  }
526  SCFree(n);
527  }
528  return -1;
529  } else {
530  found->expires_at = expires;
531  found->retval = retval;
532 
533  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
534  THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, found);
535  return 1;
536  }
537 }
538 
539 /** \brief Check Thread local thresholding cache
540  * \note only supports IPv4
541  * \retval -1 cache miss - not found
542  * \retval -2 cache miss - found but expired
543  * \retval -3 error - cache not initialized
544  * \retval -4 error - unsupported tracker
545  * \retval ret cached return code
546  */
547 static int CheckCache(const Packet *p, const int8_t track, const uint32_t sid, const uint32_t gid,
548  const uint32_t rev)
549 {
551 
552  if (!threshold_cache_ht) {
554  return -3; // error cache initialized
555  }
556 
557  uint32_t addr;
558  if (track == TRACK_SRC) {
559  addr = p->src.addr_data32[0];
560  } else if (track == TRACK_DST) {
561  addr = p->dst.addr_data32[0];
562  } else {
564  return -4; // error tracker not unsupported
565  }
566 
568  ThresholdCacheExpire(p->ts);
569  }
570 
571  ThresholdCacheItem lookup = {
572  .track = track,
573  .ipv = 4,
574  .key[TC_ADDRESS] = addr,
575  .key[TC_SID] = sid,
576  .key[TC_GID] = gid,
577  .key[TC_REV] = rev,
578  .key[TC_TENANT] = p->tenant_id,
579  };
580  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
581  if (found) {
582  if (SCTIME_CMP_GT(p->ts, found->expires_at)) {
583  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
584  HashTableRemove(threshold_cache_ht, found, 0);
586  return -2; // cache miss - found but expired
587  }
589  return found->retval;
590  }
592  return -1; // cache miss - not found
593 }
594 
596 {
597  if (threshold_cache_ht) {
598  HashTableFree(threshold_cache_ht);
599  threshold_cache_ht = NULL;
600  }
602  DumpCacheStats();
603 }
604 
605 /**
606  * \brief Return next DetectThresholdData for signature
607  *
608  * \param sig Signature pointer
609  * \param psm Pointer to a Signature Match pointer
610  * \param list List to return data from
611  *
612  * \retval tsh Return the threshold data from signature or NULL if not found
613  */
615  const Signature *sig, const SigMatchData **psm, int list)
616 {
617  const SigMatchData *smd = NULL;
618  const DetectThresholdData *tsh = NULL;
619 
620  if (sig == NULL)
621  return NULL;
622 
623  if (*psm == NULL) {
624  smd = sig->sm_arrays[list];
625  } else {
626  /* Iteration in progress, using provided value */
627  smd = *psm;
628  }
629 
630  while (1) {
631  if (smd->type == DETECT_THRESHOLD || smd->type == DETECT_DETECTION_FILTER) {
632  tsh = (DetectThresholdData *)smd->ctx;
633 
634  if (smd->is_last) {
635  *psm = NULL;
636  } else {
637  *psm = smd + 1;
638  }
639  return tsh;
640  }
641 
642  if (smd->is_last) {
643  break;
644  }
645  smd++;
646  }
647  *psm = NULL;
648  return NULL;
649 }
650 
651 typedef struct FlowThresholdEntryList_ {
655 
656 static void FlowThresholdEntryListFree(FlowThresholdEntryList *list)
657 {
658  for (FlowThresholdEntryList *i = list; i != NULL;) {
660  SCFree(i);
661  i = next;
662  }
663 }
664 
665 /** struct for storing per flow thresholds. This will be stored in the Flow::flowvar list, so it
666  * needs to follow the GenericVar header format. */
667 typedef struct FlowVarThreshold_ {
668  uint16_t type;
669  uint8_t pad[6];
670  struct GenericVar_ *next;
673 
674 void FlowThresholdVarFree(void *ptr)
675 {
676  FlowVarThreshold *t = ptr;
677  FlowThresholdEntryListFree(t->thresholds);
678  SCFree(t);
679 }
680 
681 static FlowVarThreshold *FlowThresholdVarGet(Flow *f)
682 {
683  if (f == NULL)
684  return NULL;
685 
686  for (GenericVar *gv = f->flowvar; gv != NULL; gv = gv->next) {
687  if (gv->type == DETECT_THRESHOLD)
688  return (FlowVarThreshold *)gv;
689  }
690 
691  return NULL;
692 }
693 
694 static ThresholdEntry *ThresholdFlowLookupEntry(
695  Flow *f, uint32_t sid, uint32_t gid, uint32_t rev, uint32_t tenant_id)
696 {
697  FlowVarThreshold *t = FlowThresholdVarGet(f);
698  if (t == NULL)
699  return NULL;
700 
701  for (FlowThresholdEntryList *e = t->thresholds; e != NULL; e = e->next) {
702  if (e->threshold.key[SID] == sid && e->threshold.key[GID] == gid &&
703  e->threshold.key[REV] == rev && e->threshold.key[TENANT] == tenant_id) {
704  return &e->threshold;
705  }
706  }
707  return NULL;
708 }
709 
710 static int AddEntryToFlow(Flow *f, FlowThresholdEntryList *e, SCTime_t packet_time)
711 {
712  DEBUG_VALIDATE_BUG_ON(e == NULL);
713 
714  FlowVarThreshold *t = FlowThresholdVarGet(f);
715  if (t == NULL) {
716  t = SCCalloc(1, sizeof(*t));
717  if (t == NULL) {
718  return -1;
719  }
720  t->type = DETECT_THRESHOLD;
722  }
723 
724  e->next = t->thresholds;
725  t->thresholds = e;
726  return 0;
727 }
728 
729 static int ThresholdHandlePacketSuppress(
730  Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid)
731 {
732  int ret = 0;
733  DetectAddress *m = NULL;
734  switch (td->track) {
735  case TRACK_DST:
736  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
737  SCLogDebug("TRACK_DST");
738  break;
739  case TRACK_SRC:
740  m = DetectAddressLookupInHead(&td->addrs, &p->src);
741  SCLogDebug("TRACK_SRC");
742  break;
743  /* suppress if either src or dst is a match on the suppress
744  * address list */
745  case TRACK_EITHER:
746  m = DetectAddressLookupInHead(&td->addrs, &p->src);
747  if (m == NULL) {
748  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
749  }
750  break;
751  case TRACK_RULE:
752  case TRACK_FLOW:
753  default:
754  SCLogError("track mode %d is not supported", td->track);
755  break;
756  }
757  if (m == NULL)
758  ret = 1;
759  else
760  ret = 2; /* suppressed but still need actions */
761 
762  return ret;
763 }
764 
765 static inline void RateFilterSetAction(PacketAlert *pa, uint8_t new_action)
766 {
767  switch (new_action) {
768  case TH_ACTION_ALERT:
770  pa->action = ACTION_ALERT;
771  break;
772  case TH_ACTION_DROP:
774  pa->action = (ACTION_DROP | ACTION_ALERT);
775  break;
776  case TH_ACTION_REJECT:
779  break;
780  case TH_ACTION_PASS:
782  pa->action = ACTION_PASS;
783  break;
784  default:
785  /* Weird, leave the default action */
786  break;
787  }
788 }
789 
790 /** \internal
791  * \brief Apply the multiplier and return the new value.
792  * If it would overflow the uint32_t we return UINT32_MAX.
793  */
794 static uint32_t BackoffCalcNextValue(const uint32_t cur, const uint32_t m)
795 {
796  /* goal is to see if cur * m would overflow uint32_t */
797  if (unlikely(UINT32_MAX / m < cur)) {
798  return UINT32_MAX;
799  }
800  return cur * m;
801 }
802 
803 /**
804  * \retval 2 silent match (no alert but apply actions)
805  * \retval 1 normal match
806  * \retval 0 no match
807  */
808 static int ThresholdSetup(const DetectThresholdData *td, ThresholdEntry *te, const Packet *p,
809  const uint32_t sid, const uint32_t gid, const uint32_t rev)
810 {
811  te->key[SID] = sid;
812  te->key[GID] = gid;
813  te->key[REV] = rev;
814  te->key[TRACK] = td->track;
815  te->key[TENANT] = p->tenant_id;
816 
817  te->seconds = td->seconds;
818  te->current_count = 1;
819 
820  switch (td->type) {
821  case TYPE_BACKOFF:
822  te->backoff.next_value = td->count;
823  break;
824  default:
825  te->tv1 = p->ts;
827  ThresholdDistinctInit(te, td);
828  /* If unique_on is enabled, we must add the current packet's port to the bitmap.
829  * ThresholdDistinctInit resets current_count to 0, so we must add the port
830  * or restore the count if allocation failed. */
831  if (td->type == TYPE_DETECTION && td->unique_on != DF_UNIQUE_NONE) {
832  if (te->distinct_bitmap_union) {
833  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
834  ThresholdDistinctAddPort(te, port);
835  } else {
836  /* Allocation failed (or test mode), fallback to classic counting.
837  * We must set current_count to 1 for this first packet. */
838  te->current_count = 1;
839  }
840  }
841  break;
842  }
843 
844  switch (td->type) {
845  case TYPE_LIMIT:
846  case TYPE_RATE:
847  return 1;
848  case TYPE_THRESHOLD:
849  case TYPE_BOTH:
850  if (td->count == 1)
851  return 1;
852  return 0;
853  case TYPE_BACKOFF:
854  if (td->count == 1) {
855  te->backoff.next_value =
856  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
857  return 1;
858  }
859  return 0;
860  case TYPE_DETECTION:
861  return 0;
862  }
863  return 0;
864 }
865 
866 static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThresholdData *td,
867  ThresholdEntry *te,
868  const Packet *p, // ts only? - cache too
869  const uint32_t sid, const uint32_t gid, const uint32_t rev, PacketAlert *pa)
870 {
871  int ret = 0;
872  const SCTime_t packet_time = p->ts;
873  const SCTime_t entry = SCTIME_ADD_SECS(te->tv1, td->seconds);
874  switch (td->type) {
875  case TYPE_LIMIT:
876  SCLogDebug("limit");
877 
878  if (SCTIME_CMP_LTE(p->ts, entry)) {
879  te->current_count++;
880 
881  if (te->current_count <= td->count) {
882  ret = 1;
883  } else {
884  ret = 2;
885 
886  if (PacketIsIPv4(p)) {
887  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
888  }
889  }
890  } else {
891  /* entry expired, reset */
892  te->tv1 = p->ts;
893  te->current_count = 1;
894  ret = 1;
895  }
896  break;
897  case TYPE_THRESHOLD:
898  if (SCTIME_CMP_LTE(p->ts, entry)) {
899  te->current_count++;
900 
901  if (te->current_count >= td->count) {
902  ret = 1;
903  te->current_count = 0;
904  }
905  } else {
906  te->tv1 = p->ts;
907  te->current_count = 1;
908  }
909  break;
910  case TYPE_BOTH:
911  if (SCTIME_CMP_LTE(p->ts, entry)) {
912  /* within time limit */
913 
914  te->current_count++;
915  if (te->current_count == td->count) {
916  ret = 1;
917  } else if (te->current_count > td->count) {
918  /* silent match */
919  ret = 2;
920 
921  if (PacketIsIPv4(p)) {
922  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
923  }
924  }
925  } else {
926  /* expired, so reset */
927  te->tv1 = p->ts;
928  te->current_count = 1;
929 
930  /* if we have a limit of 1, this is a match */
931  if (te->current_count == td->count) {
932  ret = 1;
933  }
934  }
935  break;
936  case TYPE_DETECTION: {
937  SCLogDebug("detection_filter");
938 
939  if (SCTIME_CMP_LTE(p->ts, entry)) {
940  /* within timeout */
941  if (td->unique_on != DF_UNIQUE_NONE && te->distinct_bitmap_union) {
942  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
943  ThresholdDistinctAddPort(te, port);
944  if (te->current_count > td->count) {
945  ret = 1;
946  }
947  } else {
948  te->current_count++;
949  if (te->current_count > td->count) {
950  ret = 1;
951  }
952  }
953  } else {
954  /* expired, reset to new window starting now */
955  te->tv1 = p->ts;
956  ThresholdDistinctReset(te);
957 
958  /* record current packet's distinct port as the first in the new window */
959  if (td->unique_on != DF_UNIQUE_NONE && te->distinct_bitmap_union) {
960  uint16_t port = (td->unique_on == DF_UNIQUE_SRC_PORT) ? p->sp : p->dp;
961  ThresholdDistinctAddPort(te, port);
962  } else {
963  te->current_count = 1;
964  }
965  }
966  break;
967  }
968  case TYPE_RATE: {
969  SCLogDebug("rate_filter");
970  const uint8_t original_action = pa->action;
971  ret = 1;
972  /* Check if we have a timeout enabled, if so,
973  * we still matching (and enabling the new_action) */
975  if ((SCTIME_SECS(packet_time) - SCTIME_SECS(te->tv_timeout)) > td->timeout) {
976  /* Ok, we are done, timeout reached */
978  } else {
979  /* Already matching */
980  RateFilterSetAction(pa, td->new_action);
981  }
982  } else {
983  /* Update the matching state with the timeout interval */
984  if (SCTIME_CMP_LTE(packet_time, entry)) {
985  te->current_count++;
986  if (te->current_count > td->count) {
987  /* Then we must enable the new action by setting a
988  * timeout */
989  te->tv_timeout = packet_time;
990  RateFilterSetAction(pa, td->new_action);
991  }
992  } else {
993  te->tv1 = packet_time;
994  te->current_count = 1;
995  }
996  }
997  if (de_ctx->RateFilterCallback && original_action != pa->action) {
998  pa->action = de_ctx->RateFilterCallback(p, sid, gid, rev, original_action,
1000  if (pa->action == original_action) {
1001  /* Reset back to original action, clear modified flag. */
1003  }
1004  }
1005  break;
1006  }
1007  case TYPE_BACKOFF:
1008  SCLogDebug("backoff");
1009 
1010  if (te->current_count < UINT32_MAX) {
1011  te->current_count++;
1012  if (te->backoff.next_value == te->current_count) {
1013  te->backoff.next_value =
1014  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
1015  SCLogDebug("te->backoff.next_value %u", te->backoff.next_value);
1016  ret = 1;
1017  } else {
1018  ret = 2;
1019  }
1020  } else {
1021  /* if count reaches UINT32_MAX, we just silent match on the rest of the flow */
1022  ret = 2;
1023  }
1024  break;
1025  }
1026  return ret;
1027 }
1028 
1029 static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, struct Thresholds *tctx,
1030  const Packet *p, const Signature *s, const DetectThresholdData *td, PacketAlert *pa)
1031 {
1032  /* fast track for count 1 threshold */
1033  if (td->count == 1 && td->type == TYPE_THRESHOLD) {
1034  return 1;
1035  }
1036 
1037  ThresholdEntry lookup;
1038  memset(&lookup, 0, sizeof(lookup));
1039  lookup.key[SID] = s->id;
1040  lookup.key[GID] = s->gid;
1041  lookup.key[REV] = s->rev;
1042  lookup.key[TRACK] = td->track;
1043  lookup.key[TENANT] = p->tenant_id;
1044  if (td->track == TRACK_SRC) {
1045  COPY_ADDRESS(&p->src, &lookup.addr);
1046  } else if (td->track == TRACK_DST) {
1047  COPY_ADDRESS(&p->dst, &lookup.addr);
1048  } else if (td->track == TRACK_BOTH) {
1049  /* make sure lower ip address is first */
1050  if (PacketIsIPv4(p)) {
1051  if (SCNtohl(p->src.addr_data32[0]) < SCNtohl(p->dst.addr_data32[0])) {
1052  COPY_ADDRESS(&p->src, &lookup.addr);
1053  COPY_ADDRESS(&p->dst, &lookup.addr2);
1054  } else {
1055  COPY_ADDRESS(&p->dst, &lookup.addr);
1056  COPY_ADDRESS(&p->src, &lookup.addr2);
1057  }
1058  } else {
1059  if (AddressIPv6Lt(&p->src, &p->dst)) {
1060  COPY_ADDRESS(&p->src, &lookup.addr);
1061  COPY_ADDRESS(&p->dst, &lookup.addr2);
1062  } else {
1063  COPY_ADDRESS(&p->dst, &lookup.addr);
1064  COPY_ADDRESS(&p->src, &lookup.addr2);
1065  }
1066  }
1067  }
1068 
1069  struct THashDataGetResult res = THashGetFromHash(tctx->thash, &lookup);
1070  if (res.data) {
1071  SCLogDebug("found %p, is_new %s", res.data, BOOL2STR(res.is_new));
1072  int r;
1073  ThresholdEntry *te = res.data->data;
1074  if (res.is_new) {
1075  // new threshold, set up
1076  r = ThresholdSetup(td, te, p, s->id, s->gid, s->rev);
1077  } else {
1078  // existing, check/update
1079  r = ThresholdCheckUpdate(de_ctx, td, te, p, s->id, s->gid, s->rev, pa);
1080  }
1081 
1082  (void)THashDecrUsecnt(res.data);
1083  THashDataUnlock(res.data);
1084  return r;
1085  }
1086  return 0; // TODO error?
1087 }
1088 
1089 /**
1090  * \retval 2 silent match (no alert but apply actions)
1091  * \retval 1 normal match
1092  * \retval 0 no match
1093  */
1094 static int ThresholdHandlePacketFlow(const DetectEngineCtx *de_ctx, Flow *f, Packet *p,
1095  const DetectThresholdData *td, uint32_t sid, uint32_t gid, uint32_t rev, PacketAlert *pa)
1096 {
1097  int ret = 0;
1098  ThresholdEntry *found = ThresholdFlowLookupEntry(f, sid, gid, rev, p->tenant_id);
1099  SCLogDebug("found %p sid %u gid %u rev %u", found, sid, gid, rev);
1100 
1101  if (found == NULL) {
1102  FlowThresholdEntryList *new = SCCalloc(1, sizeof(*new));
1103  if (new == NULL)
1104  return 0;
1105 
1106  // new threshold, set up
1107  ret = ThresholdSetup(td, &new->threshold, p, sid, gid, rev);
1108 
1109  if (AddEntryToFlow(f, new, p->ts) == -1) {
1110  SCFree(new);
1111  return 0;
1112  }
1113  } else {
1114  // existing, check/update
1115  ret = ThresholdCheckUpdate(de_ctx, td, found, p, sid, gid, rev, pa);
1116  }
1117  return ret;
1118 }
1119 
1120 /**
1121  * \brief Make the threshold logic for signatures
1122  *
1123  * \param de_ctx Detection Context
1124  * \param tsh_ptr Threshold element
1125  * \param p Packet structure
1126  * \param s Signature structure
1127  *
1128  * \retval 2 silent match (no alert but apply actions)
1129  * \retval 1 alert on this event
1130  * \retval 0 do not alert on this event
1131  */
1133  const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa)
1134 {
1135  SCEnter();
1136 
1137  int ret = 0;
1138  if (td == NULL) {
1139  SCReturnInt(0);
1140  }
1141 
1142  if (td->type == TYPE_SUPPRESS) {
1143  ret = ThresholdHandlePacketSuppress(p, td, s->id, s->gid);
1144  } else if (td->track == TRACK_SRC) {
1145  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
1146  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
1147  if (cache_ret >= 0) {
1148  SCReturnInt(cache_ret);
1149  }
1150  }
1151 
1152  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1153  } else if (td->track == TRACK_DST) {
1154  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
1155  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
1156  if (cache_ret >= 0) {
1157  SCReturnInt(cache_ret);
1158  }
1159  }
1160 
1161  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1162  } else if (td->track == TRACK_BOTH) {
1163  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1164  } else if (td->track == TRACK_RULE) {
1165  ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa);
1166  } else if (td->track == TRACK_FLOW) {
1167  if (p->flow) {
1168  ret = ThresholdHandlePacketFlow(de_ctx, p->flow, p, td, s->id, s->gid, s->rev, pa);
1169  }
1170  }
1171 
1172  SCReturnInt(ret);
1173 }
1174 
1175 /**
1176  * @}
1177  */
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:1092
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:397
detect-engine.h
FlowVarThreshold_
Definition: detect-engine-threshold.c:667
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:670
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:367
TC_GID
#define TC_GID
Definition: detect-engine-threshold.c:381
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:368
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:937
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:669
Address_
Definition: decode.h:113
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:735
m
SCMutex m
Definition: flow-hash.h:6
ThresholdCacheItem
Definition: detect-engine-threshold.c:385
FlowThresholdEntryList_::threshold
ThresholdEntry threshold
Definition: detect-engine-threshold.c:653
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigMatchData_::type
uint16_t type
Definition: detect.h:366
TC_ADDRESS
#define TC_ADDRESS
Definition: detect-engine-threshold.c:379
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:1795
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:251
Signature_::gid
uint32_t gid
Definition: detect.h:718
TC_TENANT
#define TC_TENANT
Definition: detect-engine-threshold.c:383
FlowThresholdEntryList_::next
struct FlowThresholdEntryList_ * next
Definition: detect-engine-threshold.c:652
FlowThresholdEntryList_
Definition: detect-engine-threshold.c:651
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:1252
Packet_::ts
SCTime_t ts
Definition: decode.h:559
DETECT_THRESHOLD
@ DETECT_THRESHOLD
Definition: detect-engine-register.h:60
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:512
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:505
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:399
ThresholdCacheItem::ipv
int8_t ipv
Definition: detect-engine-threshold.c:387
DetectEngineCtx_::RateFilterCallback
SCDetectRateFilterFunc RateFilterCallback
Definition: detect.h:1155
FlowVarThreshold_::thresholds
FlowThresholdEntryList * thresholds
Definition: detect-engine-threshold.c:671
cache_housekeeping_expired
thread_local uint64_t cache_housekeeping_expired
Definition: detect-engine-threshold.c:403
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:482
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:252
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:553
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:665
CMP_ADDR
#define CMP_ADDR(a1, a2)
Definition: decode.h:223
suricata-common.h
DetectThresholdData_
Definition: detect-threshold.h:62
cache_lookup_hit
thread_local uint64_t cache_lookup_hit
Definition: detect-engine-threshold.c:401
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:380
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:1158
threshold_cache_housekeeping_ts
thread_local uint64_t threshold_cache_housekeeping_ts
Definition: detect-engine-threshold.c:430
TH_ACTION_DROP
#define TH_ACTION_DROP
Definition: detect-threshold.h:44
Signature_::rev
uint32_t rev
Definition: detect.h:719
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:398
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:386
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:614
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:123
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:124
PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED
#define PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED
Definition: decode.h:275
ThresholdCacheItem::expires_at
SCTime_t expires_at
Definition: detect-engine-threshold.c:390
str
#define str(s)
Definition: suricata-common.h:308
cache_lookup_cnt
thread_local uint64_t cache_lookup_cnt
Definition: detect-engine-threshold.c:396
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:717
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:672
FlowVarThreshold_::type
uint16_t type
Definition: detect-engine-threshold.c:668
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:402
Address_::family
char family
Definition: decode.h:114
Packet_::dst
Address dst
Definition: decode.h:510
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:249
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:595
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:429
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:1132
util-misc.h
COPY_ADDRESS
#define COPY_ADDRESS(a, b)
Definition: decode.h:128
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:520
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:388
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:674
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:389
detect-engine-address.h
Packet_::src
Address src
Definition: decode.h:509
detect-engine-threshold.h
ThresholdsExpire
uint32_t ThresholdsExpire(const SCTime_t ts)
Definition: detect-engine-threshold.c:374
TC_REV
#define TC_REV
Definition: detect-engine-threshold.c:382
cache_lookup_miss
thread_local uint64_t cache_lookup_miss
Definition: detect-engine-threshold.c:400
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