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 
59 struct Thresholds {
61 } ctx;
62 
63 static int ThresholdsInit(struct Thresholds *t);
64 static void ThresholdsDestroy(struct Thresholds *t);
65 
66 void ThresholdInit(void)
67 {
68  ThresholdsInit(&ctx);
69 }
70 
71 void ThresholdDestroy(void)
72 {
73  ThresholdsDestroy(&ctx);
74 }
75 
76 #define SID 0
77 #define GID 1
78 #define REV 2
79 #define TRACK 3
80 #define TENANT 4
81 
82 typedef struct ThresholdEntry_ {
83  uint32_t key[5];
84 
85  uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter)
86  its not "seconds", that define the time interval */
87  uint32_t seconds; /**< Event seconds */
88  uint32_t current_count; /**< Var for count control */
89 
90  union {
91  struct {
92  uint32_t next_value;
94  struct {
95  SCTime_t tv1; /**< Var for time control */
96  Address addr; /* used for src/dst/either tracking */
97  Address addr2; /* used for both tracking */
98  };
99  };
100 
102 
103 static int ThresholdEntrySet(void *dst, void *src)
104 {
105  const ThresholdEntry *esrc = src;
106  ThresholdEntry *edst = dst;
107  memset(edst, 0, sizeof(*edst));
108  *edst = *esrc;
109  return 0;
110 }
111 
112 static void ThresholdEntryFree(void *ptr)
113 {
114  // nothing to free, base data is part of hash
115 }
116 
117 static inline uint32_t HashAddress(const Address *a)
118 {
119  uint32_t key;
120 
121  if (a->family == AF_INET) {
122  key = a->addr_data32[0];
123  } else if (a->family == AF_INET6) {
124  key = hashword(a->addr_data32, 4, 0);
125  } else
126  key = 0;
127 
128  return key;
129 }
130 
131 static inline int CompareAddress(const Address *a, const Address *b)
132 {
133  if (a->family == b->family) {
134  switch (a->family) {
135  case AF_INET:
136  return (a->addr_data32[0] == b->addr_data32[0]);
137  case AF_INET6:
138  return CMP_ADDR(a, b);
139  }
140  }
141  return 0;
142 }
143 
144 static uint32_t ThresholdEntryHash(uint32_t seed, void *ptr)
145 {
146  const ThresholdEntry *e = ptr;
147  uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), seed);
148  switch (e->key[TRACK]) {
149  case TRACK_BOTH:
150  hash += HashAddress(&e->addr2);
151  /* fallthrough */
152  case TRACK_SRC:
153  case TRACK_DST:
154  hash += HashAddress(&e->addr);
155  break;
156  }
157  return hash;
158 }
159 
160 static bool ThresholdEntryCompare(void *a, void *b)
161 {
162  const ThresholdEntry *e1 = a;
163  const ThresholdEntry *e2 = b;
164  SCLogDebug("sid1: %u sid2: %u", e1->key[SID], e2->key[SID]);
165 
166  if (memcmp(e1->key, e2->key, sizeof(e1->key)) != 0)
167  return false;
168  switch (e1->key[TRACK]) {
169  case TRACK_BOTH:
170  if (!(CompareAddress(&e1->addr2, &e2->addr2)))
171  return false;
172  /* fallthrough */
173  case TRACK_SRC:
174  case TRACK_DST:
175  if (!(CompareAddress(&e1->addr, &e2->addr)))
176  return false;
177  break;
178  }
179  return true;
180 }
181 
182 static bool ThresholdEntryExpire(void *data, const SCTime_t ts)
183 {
184  const ThresholdEntry *e = data;
185  const SCTime_t entry = SCTIME_ADD_SECS(e->tv1, e->seconds);
186  if (SCTIME_CMP_GT(ts, entry)) {
187  return true;
188  }
189  return false;
190 }
191 
192 static int ThresholdsInit(struct Thresholds *t)
193 {
194  uint32_t hashsize = 16384;
195  uint64_t memcap = 16 * 1024 * 1024;
196 
197  const char *str;
198  if (ConfGet("detect.thresholds.memcap", &str) == 1) {
199  if (ParseSizeStringU64(str, &memcap) < 0) {
200  SCLogError("Error parsing detect.thresholds.memcap from conf file - %s", str);
201  return -1;
202  }
203  }
204 
205  intmax_t value = 0;
206  if ((ConfGetInt("detect.thresholds.hash-size", &value)) == 1) {
207  if (value < 256 || value > INT_MAX) {
208  SCLogError("'detect.thresholds.hash-size' value %" PRIiMAX
209  " out of range. Valid range 256-2147483647.",
210  value);
211  return -1;
212  }
213  hashsize = (uint32_t)value;
214  }
215 
216  t->thash = THashInit("thresholds", sizeof(ThresholdEntry), ThresholdEntrySet,
217  ThresholdEntryFree, ThresholdEntryHash, ThresholdEntryCompare, ThresholdEntryExpire,
218  NULL, 0, memcap, hashsize);
219  if (t->thash == NULL) {
220  SCLogError("failed to initialize thresholds hash table");
221  return -1;
222  }
223  return 0;
224 }
225 
226 static void ThresholdsDestroy(struct Thresholds *t)
227 {
228  if (t->thash) {
229  THashShutdown(t->thash);
230  }
231 }
232 
233 uint32_t ThresholdsExpire(const SCTime_t ts)
234 {
235  return THashExpire(ctx.thash, ts);
236 }
237 
238 #define TC_ADDRESS 0
239 #define TC_SID 1
240 #define TC_GID 2
241 #define TC_REV 3
242 #define TC_TENANT 4
243 
244 typedef struct ThresholdCacheItem {
245  int8_t track; // by_src/by_dst
246  int8_t ipv;
247  int8_t retval;
248  uint32_t key[5];
252 
253 static thread_local HashTable *threshold_cache_ht = NULL;
254 
255 thread_local uint64_t cache_lookup_cnt = 0;
256 thread_local uint64_t cache_lookup_notinit = 0;
257 thread_local uint64_t cache_lookup_nosupport = 0;
258 thread_local uint64_t cache_lookup_miss_expired = 0;
259 thread_local uint64_t cache_lookup_miss = 0;
260 thread_local uint64_t cache_lookup_hit = 0;
261 thread_local uint64_t cache_housekeeping_check = 0;
262 thread_local uint64_t cache_housekeeping_expired = 0;
263 
264 static void DumpCacheStats(void)
265 {
266  SCLogPerf("threshold thread cache stats: cnt:%" PRIu64 " notinit:%" PRIu64 " nosupport:%" PRIu64
267  " miss_expired:%" PRIu64 " miss:%" PRIu64 " hit:%" PRIu64
268  ", housekeeping: checks:%" PRIu64 ", expired:%" PRIu64,
272 }
273 
274 /* rbtree for expiry handling */
275 
276 static int ThresholdCacheTreeCompareFunc(ThresholdCacheItem *a, ThresholdCacheItem *b)
277 {
278  if (SCTIME_CMP_GTE(a->expires_at, b->expires_at)) {
279  return 1;
280  } else {
281  return -1;
282  }
283 }
284 
285 RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem);
286 RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
287 RB_GENERATE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc);
288 thread_local struct THRESHOLD_CACHE threshold_cache_tree;
289 thread_local uint64_t threshold_cache_housekeeping_ts = 0;
290 
291 static void ThresholdCacheExpire(SCTime_t now)
292 {
293  ThresholdCacheItem *iter, *safe = NULL;
294  int cnt = 0;
296 
297  RB_FOREACH_SAFE (iter, THRESHOLD_CACHE, &threshold_cache_tree, safe) {
299 
300  if (SCTIME_CMP_LT(iter->expires_at, now)) {
301  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, iter);
302  HashTableRemove(threshold_cache_ht, iter, 0);
303  SCLogDebug("iter %p expired", iter);
305  }
306 
307  if (++cnt > 1)
308  break;
309  }
310 }
311 
312 /* hash table for threshold look ups */
313 
314 static uint32_t ThresholdCacheHashFunc(HashTable *ht, void *data, uint16_t datalen)
315 {
316  ThresholdCacheItem *e = data;
317  uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), 0) * (e->ipv + e->track);
318  hash = hash % ht->array_size;
319  return hash;
320 }
321 
322 static char ThresholdCacheHashCompareFunc(
323  void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
324 {
325  ThresholdCacheItem *tci1 = data1;
326  ThresholdCacheItem *tci2 = data2;
327  return tci1->ipv == tci2->ipv && tci1->track == tci2->track &&
328  memcmp(tci1->key, tci2->key, sizeof(tci1->key)) == 0;
329 }
330 
331 static void ThresholdCacheHashFreeFunc(void *data)
332 {
333  SCFree(data);
334 }
335 
336 /// \brief Thread local cache
337 static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, const uint32_t sid,
338  const uint32_t gid, const uint32_t rev, SCTime_t expires)
339 {
340  if (!threshold_cache_ht) {
341  threshold_cache_ht = HashTableInit(256, ThresholdCacheHashFunc,
342  ThresholdCacheHashCompareFunc, ThresholdCacheHashFreeFunc);
343  }
344 
345  uint32_t addr;
346  if (track == TRACK_SRC) {
347  addr = p->src.addr_data32[0];
348  } else if (track == TRACK_DST) {
349  addr = p->dst.addr_data32[0];
350  } else {
351  return -1;
352  }
353 
354  ThresholdCacheItem lookup = {
355  .track = track,
356  .ipv = 4,
357  .retval = retval,
358  .key[TC_ADDRESS] = addr,
359  .key[TC_SID] = sid,
360  .key[TC_GID] = gid,
361  .key[TC_REV] = rev,
362  .key[TC_TENANT] = p->tenant_id,
363  .expires_at = expires,
364  };
365  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
366  if (!found) {
367  ThresholdCacheItem *n = SCCalloc(1, sizeof(*n));
368  if (n) {
369  n->track = track;
370  n->ipv = 4;
371  n->retval = retval;
372  n->key[TC_ADDRESS] = addr;
373  n->key[TC_SID] = sid;
374  n->key[TC_GID] = gid;
375  n->key[TC_REV] = rev;
376  n->key[TC_TENANT] = p->tenant_id;
377  n->expires_at = expires;
378 
379  if (HashTableAdd(threshold_cache_ht, n, 0) == 0) {
380  ThresholdCacheItem *r = THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, n);
381  DEBUG_VALIDATE_BUG_ON(r != NULL); // duplicate; should be impossible
382  (void)r; // only used by DEBUG_VALIDATE_BUG_ON
383  return 1;
384  }
385  SCFree(n);
386  }
387  return -1;
388  } else {
389  found->expires_at = expires;
390  found->retval = retval;
391 
392  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
393  THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, found);
394  return 1;
395  }
396 }
397 
398 /** \brief Check Thread local thresholding cache
399  * \note only supports IPv4
400  * \retval -1 cache miss - not found
401  * \retval -2 cache miss - found but expired
402  * \retval -3 error - cache not initialized
403  * \retval -4 error - unsupported tracker
404  * \retval ret cached return code
405  */
406 static int CheckCache(const Packet *p, const int8_t track, const uint32_t sid, const uint32_t gid,
407  const uint32_t rev)
408 {
410 
411  if (!threshold_cache_ht) {
413  return -3; // error cache initialized
414  }
415 
416  uint32_t addr;
417  if (track == TRACK_SRC) {
418  addr = p->src.addr_data32[0];
419  } else if (track == TRACK_DST) {
420  addr = p->dst.addr_data32[0];
421  } else {
423  return -4; // error tracker not unsupported
424  }
425 
427  ThresholdCacheExpire(p->ts);
428  }
429 
430  ThresholdCacheItem lookup = {
431  .track = track,
432  .ipv = 4,
433  .key[TC_ADDRESS] = addr,
434  .key[TC_SID] = sid,
435  .key[TC_GID] = gid,
436  .key[TC_REV] = rev,
437  .key[TC_TENANT] = p->tenant_id,
438  };
439  ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0);
440  if (found) {
441  if (SCTIME_CMP_GT(p->ts, found->expires_at)) {
442  THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found);
443  HashTableRemove(threshold_cache_ht, found, 0);
445  return -2; // cache miss - found but expired
446  }
448  return found->retval;
449  }
451  return -1; // cache miss - not found
452 }
453 
455 {
456  if (threshold_cache_ht) {
457  HashTableFree(threshold_cache_ht);
458  threshold_cache_ht = NULL;
459  }
461  DumpCacheStats();
462 }
463 
464 /**
465  * \brief Return next DetectThresholdData for signature
466  *
467  * \param sig Signature pointer
468  * \param psm Pointer to a Signature Match pointer
469  * \param list List to return data from
470  *
471  * \retval tsh Return the threshold data from signature or NULL if not found
472  */
474  const Signature *sig, const SigMatchData **psm, int list)
475 {
476  const SigMatchData *smd = NULL;
477  const DetectThresholdData *tsh = NULL;
478 
479  if (sig == NULL)
480  return NULL;
481 
482  if (*psm == NULL) {
483  smd = sig->sm_arrays[list];
484  } else {
485  /* Iteration in progress, using provided value */
486  smd = *psm;
487  }
488 
489  while (1) {
490  if (smd->type == DETECT_THRESHOLD || smd->type == DETECT_DETECTION_FILTER) {
491  tsh = (DetectThresholdData *)smd->ctx;
492 
493  if (smd->is_last) {
494  *psm = NULL;
495  } else {
496  *psm = smd + 1;
497  }
498  return tsh;
499  }
500 
501  if (smd->is_last) {
502  break;
503  }
504  smd++;
505  }
506  *psm = NULL;
507  return NULL;
508 }
509 
510 typedef struct FlowThresholdEntryList_ {
514 
515 static void FlowThresholdEntryListFree(FlowThresholdEntryList *list)
516 {
517  for (FlowThresholdEntryList *i = list; i != NULL;) {
519  SCFree(i);
520  i = next;
521  }
522 }
523 
524 /** struct for storing per flow thresholds. This will be stored in the Flow::flowvar list, so it
525  * needs to follow the GenericVar header format. */
526 typedef struct FlowVarThreshold_ {
527  uint8_t type;
528  uint8_t pad[7];
529  struct GenericVar_ *next;
532 
533 void FlowThresholdVarFree(void *ptr)
534 {
535  FlowVarThreshold *t = ptr;
536  FlowThresholdEntryListFree(t->thresholds);
537  SCFree(t);
538 }
539 
540 static FlowVarThreshold *FlowThresholdVarGet(Flow *f)
541 {
542  if (f == NULL)
543  return NULL;
544 
545  for (GenericVar *gv = f->flowvar; gv != NULL; gv = gv->next) {
546  if (gv->type == DETECT_THRESHOLD)
547  return (FlowVarThreshold *)gv;
548  }
549 
550  return NULL;
551 }
552 
553 static ThresholdEntry *ThresholdFlowLookupEntry(
554  Flow *f, uint32_t sid, uint32_t gid, uint32_t rev, uint32_t tenant_id)
555 {
556  FlowVarThreshold *t = FlowThresholdVarGet(f);
557  if (t == NULL)
558  return NULL;
559 
560  for (FlowThresholdEntryList *e = t->thresholds; e != NULL; e = e->next) {
561  if (e->threshold.key[SID] == sid && e->threshold.key[GID] == gid &&
562  e->threshold.key[REV] == rev && e->threshold.key[TENANT] == tenant_id) {
563  return &e->threshold;
564  }
565  }
566  return NULL;
567 }
568 
569 static int AddEntryToFlow(Flow *f, FlowThresholdEntryList *e, SCTime_t packet_time)
570 {
571  DEBUG_VALIDATE_BUG_ON(e == NULL);
572 
573  FlowVarThreshold *t = FlowThresholdVarGet(f);
574  if (t == NULL) {
575  t = SCCalloc(1, sizeof(*t));
576  if (t == NULL) {
577  return -1;
578  }
579  t->type = DETECT_THRESHOLD;
581  }
582 
583  e->next = t->thresholds;
584  t->thresholds = e;
585  return 0;
586 }
587 
588 static int ThresholdHandlePacketSuppress(Packet *p,
589  const DetectThresholdData *td, uint32_t sid, uint32_t gid)
590 {
591  int ret = 0;
592  DetectAddress *m = NULL;
593  switch (td->track) {
594  case TRACK_DST:
595  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
596  SCLogDebug("TRACK_DST");
597  break;
598  case TRACK_SRC:
599  m = DetectAddressLookupInHead(&td->addrs, &p->src);
600  SCLogDebug("TRACK_SRC");
601  break;
602  /* suppress if either src or dst is a match on the suppress
603  * address list */
604  case TRACK_EITHER:
605  m = DetectAddressLookupInHead(&td->addrs, &p->src);
606  if (m == NULL) {
607  m = DetectAddressLookupInHead(&td->addrs, &p->dst);
608  }
609  break;
610  case TRACK_RULE:
611  case TRACK_FLOW:
612  default:
613  SCLogError("track mode %d is not supported", td->track);
614  break;
615  }
616  if (m == NULL)
617  ret = 1;
618  else
619  ret = 2; /* suppressed but still need actions */
620 
621  return ret;
622 }
623 
624 static inline void RateFilterSetAction(PacketAlert *pa, uint8_t new_action)
625 {
626  switch (new_action) {
627  case TH_ACTION_ALERT:
629  pa->action = ACTION_ALERT;
630  break;
631  case TH_ACTION_DROP:
633  pa->action = ACTION_DROP;
634  break;
635  case TH_ACTION_REJECT:
637  pa->action = (ACTION_REJECT | ACTION_DROP);
638  break;
639  case TH_ACTION_PASS:
641  pa->action = ACTION_PASS;
642  break;
643  default:
644  /* Weird, leave the default action */
645  break;
646  }
647 }
648 
649 /** \internal
650  * \brief Apply the multiplier and return the new value.
651  * If it would overflow the uint32_t we return UINT32_MAX.
652  */
653 static uint32_t BackoffCalcNextValue(const uint32_t cur, const uint32_t m)
654 {
655  /* goal is to see if cur * m would overflow uint32_t */
656  if (unlikely(UINT32_MAX / m < cur)) {
657  return UINT32_MAX;
658  }
659  return cur * m;
660 }
661 
662 /**
663  * \retval 2 silent match (no alert but apply actions)
664  * \retval 1 normal match
665  * \retval 0 no match
666  */
667 static int ThresholdSetup(const DetectThresholdData *td, ThresholdEntry *te,
668  const SCTime_t packet_time, const uint32_t sid, const uint32_t gid, const uint32_t rev,
669  const uint32_t tenant_id)
670 {
671  te->key[SID] = sid;
672  te->key[GID] = gid;
673  te->key[REV] = rev;
674  te->key[TRACK] = td->track;
675  te->key[TENANT] = tenant_id;
676 
677  te->seconds = td->seconds;
678  te->current_count = 1;
679 
680  switch (td->type) {
681  case TYPE_BACKOFF:
682  te->backoff.next_value = td->count;
683  break;
684  default:
685  te->tv1 = packet_time;
686  te->tv_timeout = 0;
687  break;
688  }
689 
690  switch (td->type) {
691  case TYPE_LIMIT:
692  case TYPE_RATE:
693  return 1;
694  case TYPE_THRESHOLD:
695  case TYPE_BOTH:
696  if (td->count == 1)
697  return 1;
698  return 0;
699  case TYPE_BACKOFF:
700  if (td->count == 1) {
701  te->backoff.next_value =
702  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
703  return 1;
704  }
705  return 0;
706  case TYPE_DETECTION:
707  return 0;
708  }
709  return 0;
710 }
711 
712 static int ThresholdCheckUpdate(const DetectThresholdData *td, ThresholdEntry *te,
713  const Packet *p, // ts only? - cache too
714  const uint32_t sid, const uint32_t gid, const uint32_t rev, PacketAlert *pa)
715 {
716  int ret = 0;
717  const SCTime_t packet_time = p->ts;
718  const SCTime_t entry = SCTIME_ADD_SECS(te->tv1, td->seconds);
719  switch (td->type) {
720  case TYPE_LIMIT:
721  SCLogDebug("limit");
722 
723  if (SCTIME_CMP_LTE(p->ts, entry)) {
724  te->current_count++;
725 
726  if (te->current_count <= td->count) {
727  ret = 1;
728  } else {
729  ret = 2;
730 
731  if (PacketIsIPv4(p)) {
732  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
733  }
734  }
735  } else {
736  /* entry expired, reset */
737  te->tv1 = p->ts;
738  te->current_count = 1;
739  ret = 1;
740  }
741  break;
742  case TYPE_THRESHOLD:
743  if (SCTIME_CMP_LTE(p->ts, entry)) {
744  te->current_count++;
745 
746  if (te->current_count >= td->count) {
747  ret = 1;
748  te->current_count = 0;
749  }
750  } else {
751  te->tv1 = p->ts;
752  te->current_count = 1;
753  }
754  break;
755  case TYPE_BOTH:
756  if (SCTIME_CMP_LTE(p->ts, entry)) {
757  /* within time limit */
758 
759  te->current_count++;
760  if (te->current_count == td->count) {
761  ret = 1;
762  } else if (te->current_count > td->count) {
763  /* silent match */
764  ret = 2;
765 
766  if (PacketIsIPv4(p)) {
767  SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry);
768  }
769  }
770  } else {
771  /* expired, so reset */
772  te->tv1 = p->ts;
773  te->current_count = 1;
774 
775  /* if we have a limit of 1, this is a match */
776  if (te->current_count == td->count) {
777  ret = 1;
778  }
779  }
780  break;
781  case TYPE_DETECTION:
782  SCLogDebug("detection_filter");
783 
784  if (SCTIME_CMP_LTE(p->ts, entry)) {
785  /* within timeout */
786  te->current_count++;
787  if (te->current_count > td->count) {
788  ret = 1;
789  }
790  } else {
791  /* expired, reset */
792  te->tv1 = p->ts;
793  te->current_count = 1;
794  }
795  break;
796  case TYPE_RATE:
797  SCLogDebug("rate_filter");
798  ret = 1;
799  /* Check if we have a timeout enabled, if so,
800  * we still matching (and enabling the new_action) */
801  if (te->tv_timeout != 0) {
802  if ((SCTIME_SECS(packet_time) - te->tv_timeout) > td->timeout) {
803  /* Ok, we are done, timeout reached */
804  te->tv_timeout = 0;
805  } else {
806  /* Already matching */
807  RateFilterSetAction(pa, td->new_action);
808  }
809  } else {
810  /* Update the matching state with the timeout interval */
811  if (SCTIME_CMP_LTE(packet_time, entry)) {
812  te->current_count++;
813  if (te->current_count > td->count) {
814  /* Then we must enable the new action by setting a
815  * timeout */
816  te->tv_timeout = SCTIME_SECS(packet_time);
817  RateFilterSetAction(pa, td->new_action);
818  }
819  } else {
820  te->tv1 = packet_time;
821  te->current_count = 1;
822  }
823  }
824  break;
825  case TYPE_BACKOFF:
826  SCLogDebug("backoff");
827 
828  if (te->current_count < UINT32_MAX) {
829  te->current_count++;
830  if (te->backoff.next_value == te->current_count) {
831  te->backoff.next_value =
832  BackoffCalcNextValue(te->backoff.next_value, td->multiplier);
833  SCLogDebug("te->backoff.next_value %u", te->backoff.next_value);
834  ret = 1;
835  } else {
836  ret = 2;
837  }
838  } else {
839  /* if count reaches UINT32_MAX, we just silent match on the rest of the flow */
840  ret = 2;
841  }
842  break;
843  }
844  return ret;
845 }
846 
847 static int ThresholdGetFromHash(struct Thresholds *tctx, const Packet *p, const Signature *s,
848  const DetectThresholdData *td, PacketAlert *pa)
849 {
850  /* fast track for count 1 threshold */
851  if (td->count == 1 && td->type == TYPE_THRESHOLD) {
852  return 1;
853  }
854 
855  ThresholdEntry lookup;
856  memset(&lookup, 0, sizeof(lookup));
857  lookup.key[SID] = s->id;
858  lookup.key[GID] = s->gid;
859  lookup.key[REV] = s->rev;
860  lookup.key[TRACK] = td->track;
861  lookup.key[TENANT] = p->tenant_id;
862  if (td->track == TRACK_SRC) {
863  COPY_ADDRESS(&p->src, &lookup.addr);
864  } else if (td->track == TRACK_DST) {
865  COPY_ADDRESS(&p->dst, &lookup.addr);
866  } else if (td->track == TRACK_BOTH) {
867  /* make sure lower ip address is first */
868  if (PacketIsIPv4(p)) {
869  if (SCNtohl(p->src.addr_data32[0]) < SCNtohl(p->dst.addr_data32[0])) {
870  COPY_ADDRESS(&p->src, &lookup.addr);
871  COPY_ADDRESS(&p->dst, &lookup.addr2);
872  } else {
873  COPY_ADDRESS(&p->dst, &lookup.addr);
874  COPY_ADDRESS(&p->src, &lookup.addr2);
875  }
876  } else {
877  if (AddressIPv6Lt(&p->src, &p->dst)) {
878  COPY_ADDRESS(&p->src, &lookup.addr);
879  COPY_ADDRESS(&p->dst, &lookup.addr2);
880  } else {
881  COPY_ADDRESS(&p->dst, &lookup.addr);
882  COPY_ADDRESS(&p->src, &lookup.addr2);
883  }
884  }
885  }
886 
887  struct THashDataGetResult res = THashGetFromHash(tctx->thash, &lookup);
888  if (res.data) {
889  SCLogDebug("found %p, is_new %s", res.data, BOOL2STR(res.is_new));
890  int r;
891  ThresholdEntry *te = res.data->data;
892  if (res.is_new) {
893  // new threshold, set up
894  r = ThresholdSetup(td, te, p->ts, s->id, s->gid, s->rev, p->tenant_id);
895  } else {
896  // existing, check/update
897  r = ThresholdCheckUpdate(td, te, p, s->id, s->gid, s->rev, pa);
898  }
899 
900  (void)THashDecrUsecnt(res.data);
901  THashDataUnlock(res.data);
902  return r;
903  }
904  return 0; // TODO error?
905 }
906 
907 /**
908  * \retval 2 silent match (no alert but apply actions)
909  * \retval 1 normal match
910  * \retval 0 no match
911  */
912 static int ThresholdHandlePacketFlow(Flow *f, Packet *p, const DetectThresholdData *td,
913  uint32_t sid, uint32_t gid, uint32_t rev, PacketAlert *pa)
914 {
915  int ret = 0;
916  ThresholdEntry *found = ThresholdFlowLookupEntry(f, sid, gid, rev, p->tenant_id);
917  SCLogDebug("found %p sid %u gid %u rev %u", found, sid, gid, rev);
918 
919  if (found == NULL) {
920  FlowThresholdEntryList *new = SCCalloc(1, sizeof(*new));
921  if (new == NULL)
922  return 0;
923 
924  // new threshold, set up
925  ret = ThresholdSetup(td, &new->threshold, p->ts, sid, gid, rev, p->tenant_id);
926 
927  if (AddEntryToFlow(f, new, p->ts) == -1) {
928  SCFree(new);
929  return 0;
930  }
931  } else {
932  // existing, check/update
933  ret = ThresholdCheckUpdate(td, found, p, sid, gid, rev, pa);
934  }
935  return ret;
936 }
937 
938 /**
939  * \brief Make the threshold logic for signatures
940  *
941  * \param de_ctx Detection Context
942  * \param tsh_ptr Threshold element
943  * \param p Packet structure
944  * \param s Signature structure
945  *
946  * \retval 2 silent match (no alert but apply actions)
947  * \retval 1 alert on this event
948  * \retval 0 do not alert on this event
949  */
951  const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa)
952 {
953  SCEnter();
954 
955  int ret = 0;
956  if (td == NULL) {
957  SCReturnInt(0);
958  }
959 
960  if (td->type == TYPE_SUPPRESS) {
961  ret = ThresholdHandlePacketSuppress(p,td,s->id,s->gid);
962  } else if (td->track == TRACK_SRC) {
963  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
964  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
965  if (cache_ret >= 0) {
966  SCReturnInt(cache_ret);
967  }
968  }
969 
970  ret = ThresholdGetFromHash(&ctx, p, s, td, pa);
971  } else if (td->track == TRACK_DST) {
972  if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) {
973  int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev);
974  if (cache_ret >= 0) {
975  SCReturnInt(cache_ret);
976  }
977  }
978 
979  ret = ThresholdGetFromHash(&ctx, p, s, td, pa);
980  } else if (td->track == TRACK_BOTH) {
981  ret = ThresholdGetFromHash(&ctx, p, s, td, pa);
982  } else if (td->track == TRACK_RULE) {
983  ret = ThresholdGetFromHash(&ctx, p, s, td, pa);
984  } else if (td->track == TRACK_FLOW) {
985  if (p->flow) {
986  ret = ThresholdHandlePacketFlow(p->flow, p, td, s->id, s->gid, s->rev, pa);
987  }
988  }
989 
990  SCReturnInt(ret);
991 }
992 
993 /**
994  * @}
995  */
TRACK_BOTH
#define TRACK_BOTH
Definition: detect-threshold.h:39
SID
#define SID
Definition: detect-engine-threshold.c:76
DetectThresholdData_::timeout
uint32_t timeout
Definition: detect-threshold.h:61
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
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:256
detect-engine.h
FlowVarThreshold_
Definition: detect-engine-threshold.c:526
THashDataGetResult::data
THashData * data
Definition: util-thash.h:191
hashword
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:172
FlowVarThreshold_::next
struct GenericVar_ * next
Definition: detect-engine-threshold.c:529
Thresholds::thash
THashTableContext * thash
Definition: detect-engine-threshold.c:60
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:79
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:165
GID
#define GID
Definition: detect-engine-threshold.c:77
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
ThresholdCacheItem
struct ThresholdCacheItem ThresholdCacheItem
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:360
TC_GID
#define TC_GID
Definition: detect-engine-threshold.c:240
RB_PROTOTYPE
RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc)
DetectThresholdData_::count
uint32_t count
Definition: detect-threshold.h:56
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:361
Thresholds
Definition: detect-engine-threshold.c:59
action-globals.h
Flow_
Flow data structure.
Definition: flow.h:356
util-hash.h
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:841
TYPE_LIMIT
#define TYPE_LIMIT
Definition: detect-threshold.h:27
TRACK_DST
#define TRACK_DST
Definition: detect-detection-filter.c:43
HashTable_
Definition: util-hash.h:35
DetectThresholdData_::new_action
uint8_t new_action
Definition: detect-threshold.h:60
Address_
Definition: decode.h:114
DetectThresholdData_::multiplier
uint32_t multiplier
Definition: detect-threshold.h:63
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:654
m
SCMutex m
Definition: flow-hash.h:6
ThresholdCacheItem
Definition: detect-engine-threshold.c:244
FlowThresholdEntryList_::threshold
ThresholdEntry threshold
Definition: detect-engine-threshold.c:512
SigMatchData_
Data needed for Match()
Definition: detect.h:358
ThresholdEntry_::backoff
struct ThresholdEntry_::@58::@60 backoff
SigMatchData_::type
uint16_t type
Definition: detect.h:359
ThresholdEntry_::tv_timeout
uint32_t tv_timeout
Definition: detect-engine-threshold.c:85
TC_ADDRESS
#define TC_ADDRESS
Definition: detect-engine-threshold.c:238
DetectAddressLookupInHead
DetectAddress * DetectAddressLookupInHead(const DetectAddressHead *gh, Address *a)
Find the group matching address in a group head.
Definition: detect-engine-address.c:1798
HashTableFree
void HashTableFree(HashTable *ht)
Definition: util-hash.c:78
DetectThresholdData_::type
uint8_t type
Definition: detect-threshold.h:58
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
PacketAlert_::action
uint8_t action
Definition: decode.h:247
Signature_::gid
uint32_t gid
Definition: detect.h:637
TC_TENANT
#define TC_TENANT
Definition: detect-engine-threshold.c:242
FlowThresholdEntryList_::next
struct FlowThresholdEntryList_ * next
Definition: detect-engine-threshold.c:511
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
FlowThresholdEntryList_
Definition: detect-engine-threshold.c:510
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:87
GenericVar_::next
struct GenericVar_ * next
Definition: util-var.h:54
util-error.h
REV
#define REV
Definition: detect-engine-threshold.c:78
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
TYPE_RATE
#define TYPE_RATE
Definition: detect-threshold.h:31
FlowThresholdEntryList
struct FlowThresholdEntryList_ FlowThresholdEntryList
DetectEngineThreadCtx_
Definition: detect.h:1093
Packet_::ts
SCTime_t ts
Definition: decode.h:527
DETECT_THRESHOLD
@ DETECT_THRESHOLD
Definition: detect-engine-register.h:59
THashTableContext_
Definition: util-thash.h:141
ThresholdEntry_::next_value
uint32_t next_value
Definition: detect-engine-threshold.c:92
TH_ACTION_PASS
#define TH_ACTION_PASS
Definition: detect-threshold.h:45
ThresholdEntry_::current_count
uint32_t current_count
Definition: detect-engine-threshold.c:88
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:527
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:183
detect.h
HashTableRemove
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:142
util-time.h
ThresholdDestroy
void ThresholdDestroy(void)
Definition: detect-engine-threshold.c:71
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:104
TYPE_BOTH
#define TYPE_BOTH
Definition: detect-threshold.h:28
THashDataGetResult
Definition: util-thash.h:190
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:479
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:258
ThresholdCacheItem::ipv
int8_t ipv
Definition: detect-engine-threshold.c:246
PacketAlertThreshold
int PacketAlertThreshold(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:950
FlowVarThreshold_::thresholds
FlowThresholdEntryList * thresholds
Definition: detect-engine-threshold.c:530
cache_housekeeping_expired
thread_local uint64_t cache_housekeeping_expired
Definition: detect-engine-threshold.c:262
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:491
DetectThresholdData_::track
uint8_t track
Definition: detect-threshold.h:59
ThresholdEntry_
Definition: detect-engine-threshold.c:82
THashShutdown
void THashShutdown(THashTableContext *ctx)
shutdown the flow engine
Definition: util-thash.c:358
SCTIME_CMP_LT
#define SCTIME_CMP_LT(a, b)
Definition: util-time.h:105
PacketAlert_::flags
uint8_t flags
Definition: decode.h:248
ThresholdEntry_::tv1
SCTime_t tv1
Definition: detect-engine-threshold.c:95
PACKET_ALERT_RATE_FILTER_MODIFIED
#define PACKET_ALERT_RATE_FILTER_MODIFIED
Definition: decode.h:263
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:518
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:640
CMP_ADDR
#define CMP_ADDR(a1, a2)
Definition: decode.h:224
suricata-common.h
DetectThresholdData_
Definition: detect-threshold.h:55
cache_lookup_hit
thread_local uint64_t cache_lookup_hit
Definition: detect-engine-threshold.c:260
GenericVar_
Definition: util-var.h:50
TYPE_SUPPRESS
#define TYPE_SUPPRESS
Definition: detect-threshold.h:32
TC_SID
#define TC_SID
Definition: detect-engine-threshold.c:239
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:230
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
threshold_cache_housekeeping_ts
thread_local uint64_t threshold_cache_housekeeping_ts
Definition: detect-engine-threshold.c:289
TH_ACTION_DROP
#define TH_ACTION_DROP
Definition: detect-threshold.h:44
Signature_::rev
uint32_t rev
Definition: detect.h:638
ThresholdEntry_::addr2
Address addr2
Definition: detect-engine-threshold.c:97
THashGetFromHash
struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:618
cache_lookup_nosupport
thread_local uint64_t cache_lookup_nosupport
Definition: detect-engine-threshold.c:257
FlowVarThreshold_::pad
uint8_t pad[7]
Definition: detect-engine-threshold.c:528
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:245
THashDecrUsecnt
#define THashDecrUsecnt(h)
Definition: util-thash.h:169
SigGetThresholdTypeIter
const DetectThresholdData * SigGetThresholdTypeIter(const Signature *sig, const SigMatchData **psm, int list)
Return next DetectThresholdData for signature.
Definition: detect-engine-threshold.c:473
util-validate.h
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:118
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:178
ThresholdCacheItem::expires_at
SCTime_t expires_at
Definition: detect-engine-threshold.c:249
str
#define str(s)
Definition: suricata-common.h:291
cache_lookup_cnt
thread_local uint64_t cache_lookup_cnt
Definition: detect-engine-threshold.c:255
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SCNtohl
#define SCNtohl(x)
Definition: suricata-common.h:413
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:636
ThresholdEntry_::key
uint32_t key[5]
Definition: detect-engine-threshold.c:83
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
Signature_
Signature container.
Definition: detect.h:601
ThresholdEntry_::addr
Address addr
Definition: detect-engine-threshold.c:96
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:192
RB_ENTRY
#define RB_ENTRY(type)
Definition: tree.h:314
FlowVarThreshold_::type
uint8_t type
Definition: detect-engine-threshold.c:527
cache_housekeeping_check
thread_local uint64_t cache_housekeeping_check
Definition: detect-engine-threshold.c:261
Address_::family
char family
Definition: decode.h:115
Packet_::dst
Address dst
Definition: decode.h:484
TRACK_SRC
#define TRACK_SRC
Definition: detect-detection-filter.c:44
PacketAlert_
Definition: decode.h:245
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:427
THashInit
THashTableContext * THashInit(const char *cnf_prefix, size_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
ThresholdCacheThreadFree
void ThresholdCacheThreadFree(void)
Definition: detect-engine-threshold.c:454
DetectThresholdData_::seconds
uint32_t seconds
Definition: detect-threshold.h:57
threshold_cache_tree
thread_local struct THRESHOLD_CACHE threshold_cache_tree
Definition: detect-engine-threshold.c:288
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
util-misc.h
COPY_ADDRESS
#define COPY_ADDRESS(a, b)
Definition: decode.h:129
flow.h
util-thash.h
SCTIME_ADD_SECS
#define SCTIME_ADD_SECS(ts, s)
Definition: util-time.h:64
TENANT
#define TENANT
Definition: detect-engine-threshold.c:80
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
ThresholdCacheItem::retval
int8_t retval
Definition: detect-engine-threshold.c:247
FlowThresholdVarFree
void FlowThresholdVarFree(void *ptr)
Definition: detect-engine-threshold.c:533
ThresholdInit
void ThresholdInit(void)
Definition: detect-engine-threshold.c:66
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:248
detect-engine-address.h
Packet_::src
Address src
Definition: decode.h:483
detect-engine-threshold.h
ThresholdsExpire
uint32_t ThresholdsExpire(const SCTime_t ts)
Definition: detect-engine-threshold.c:233
TC_REV
#define TC_REV
Definition: detect-engine-threshold.c:241
cache_lookup_miss
thread_local uint64_t cache_lookup_miss
Definition: detect-engine-threshold.c:259
TYPE_DETECTION
#define TYPE_DETECTION
Definition: detect-threshold.h:30
RB_HEAD
RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem)
FlowVarThreshold
struct FlowVarThreshold_ FlowVarThreshold
DetectThresholdData_::addrs
DetectAddressHead addrs
Definition: detect-threshold.h:64