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