suricata
util-threshold-config.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2023 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  * \ingroup threshold
20  * @{
21  */
22 
23 /**
24  * \file
25  *
26  * \author Breno Silva Pinto <breno.silva@gmail.com>
27  *
28  * Implements Threshold support
29  */
30 
31 #include "suricata-common.h"
32 
33 #include "action-globals.h"
34 #include "host.h"
35 #include "ippair.h"
36 
37 #include "detect.h"
38 #include "detect-engine.h"
39 #include "detect-engine-address.h"
41 #include "detect-threshold.h"
42 #include "detect-parse.h"
43 #include "detect-engine-build.h"
44 
45 #include "conf.h"
46 #include "util-threshold-config.h"
47 #include "util-unittest.h"
48 #include "util-unittest-helper.h"
49 #include "util-byte.h"
50 #include "util-time.h"
51 #include "util-debug.h"
52 #include "util-fmemopen.h"
53 
54 typedef enum ThresholdRuleType {
60 
61 #ifdef UNITTESTS
62 /* File descriptor for unittests */
63 static FILE *g_ut_threshold_fp = NULL;
64 #endif
65 
66 /* common base for all options */
67 #define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$"
68 
69 #define DETECT_THRESHOLD_REGEX \
70  "^,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src|by_both|by_rule|by_" \
71  "flow)\\s*," \
72  "\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$"
73 
74 /* TODO: "apply_to" */
75 #define DETECT_RATE_REGEX \
76  "^,\\s*track\\s*(by_dst|by_src|by_both|by_rule|by_flow)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*" \
77  "seconds\\s*(\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*" \
78  "timeout\\s*(\\d+)\\s*$"
79 
80 /*
81  * suppress has two form:
82  * suppress gen_id 0, sig_id 0, track by_dst, ip 10.88.0.14
83  * suppress gen_id 1, sig_id 2000328
84  * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10
85 */
86 #define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$"
87 
88 /* Default path for the threshold.config file */
89 #if defined OS_WIN32 || defined __CYGWIN__
90 #define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\threshold.config"
91 #else
92 #define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config"
93 #endif
94 
95 static DetectParseRegex *regex_base = NULL;
96 static DetectParseRegex *regex_threshold = NULL;
97 static DetectParseRegex *regex_rate = NULL;
98 static DetectParseRegex *regex_suppress = NULL;
99 
100 static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd);
101 
103 {
104  regex_base = DetectSetupPCRE2(DETECT_BASE_REGEX, 0);
105  if (regex_base == NULL) {
106  FatalError("classification base regex setup failed");
107  }
108  regex_threshold = DetectSetupPCRE2(DETECT_THRESHOLD_REGEX, 0);
109  if (regex_threshold == NULL) {
110  FatalError("classification threshold regex setup failed");
111  }
112  regex_rate = DetectSetupPCRE2(DETECT_RATE_REGEX, 0);
113  if (regex_rate == NULL) {
114  FatalError("classification rate_filter regex setup failed");
115  }
116  regex_suppress = DetectSetupPCRE2(DETECT_SUPPRESS_REGEX, 0);
117  if (regex_suppress == NULL) {
118  FatalError("classification suppress regex setup failed");
119  }
120 }
121 
122 /**
123  * \brief Returns the path for the Threshold Config file. We check if we
124  * can retrieve the path from the yaml conf file. If it is not present,
125  * return the default path for the threshold file which is
126  * "./threshold.config".
127  *
128  * \retval log_filename Pointer to a string containing the path for the
129  * Threshold Config file.
130  */
131 static const char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx)
132 {
133  const char *log_filename = NULL;
134 
135  if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) {
136  char config_value[256];
137  snprintf(config_value, sizeof(config_value),
138  "%s.threshold-file", de_ctx->config_prefix);
139 
140  /* try loading prefix setting, fall back to global if that
141  * fails. */
142  if (ConfGet(config_value, &log_filename) != 1) {
143  if (ConfGet("threshold-file", &log_filename) != 1) {
144  log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH;
145  }
146  }
147  } else {
148  if (ConfGet("threshold-file", &log_filename) != 1) {
149  log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH;
150  }
151  }
152  return log_filename;
153 }
154 
155 /**
156  * \brief Inits the context to be used by the Threshold Config parsing API.
157  *
158  * This function initializes the hash table to be used by the Detection
159  * Engine Context to hold the data from the threshold.config file,
160  * obtains the file desc to parse the threshold.config file, and
161  * inits the regex used to parse the lines from threshold.config
162  * file.
163  *
164  * \param de_ctx Pointer to the Detection Engine Context.
165  *
166  * \retval 0 On success.
167  * \retval -1 On failure.
168  */
170 {
171  const char *filename = NULL;
172  int ret = 0;
173 #ifndef UNITTESTS
174  FILE *fd = NULL;
175 #else
176  FILE *fd = g_ut_threshold_fp;
177  if (fd == NULL) {
178 #endif
179  filename = SCThresholdConfGetConfFilename(de_ctx);
180  if ( (fd = fopen(filename, "r")) == NULL) {
181  SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno));
182  SCThresholdConfDeInitContext(de_ctx, fd);
183  return 0;
184  }
185 #ifdef UNITTESTS
186  }
187 #endif
188 
189  if (SCThresholdConfParseFile(de_ctx, fd) < 0) {
190  SCLogWarning("Error loading threshold configuration from %s", filename);
191  SCThresholdConfDeInitContext(de_ctx, fd);
192  /* maintain legacy behavior so no errors unless config testing */
193  if (SCRunmodeGet() == RUNMODE_CONF_TEST) {
194  ret = -1;
195  }
196  return ret;
197  }
198  SCThresholdConfDeInitContext(de_ctx, fd);
199 
200 #ifdef UNITTESTS
201  g_ut_threshold_fp = NULL;
202 #endif
203  SCLogDebug("Global thresholding options defined");
204  return 0;
205 }
206 
207 /**
208  * \brief Releases resources used by the Threshold Config API.
209  *
210  * \param de_ctx Pointer to the Detection Engine Context.
211  * \param fd Pointer to file descriptor.
212  */
213 static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd)
214 {
215  if (fd != NULL)
216  fclose(fd);
217 }
218 
219 /** \internal
220  * \brief setup suppress rules
221  * \retval 0 ok
222  * \retval -1 error
223  */
224 static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
225  uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count,
226  uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action,
227  const char *th_ip)
228 {
229  Signature *s = NULL;
230  DetectThresholdData *de = NULL;
231 
232  BUG_ON(parsed_type != TYPE_SUPPRESS);
233 
234  DetectThresholdData *orig_de = NULL;
235  if (parsed_track != TRACK_RULE) {
236  orig_de = SCCalloc(1, sizeof(DetectThresholdData));
237  if (unlikely(orig_de == NULL))
238  goto error;
239 
240  orig_de->type = TYPE_SUPPRESS;
241  orig_de->track = parsed_track;
242  orig_de->count = parsed_count;
243  orig_de->seconds = parsed_seconds;
244  orig_de->new_action = parsed_new_action;
245  orig_de->timeout = parsed_timeout;
246  if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &orig_de->addrs, (char *)th_ip) <
247  0) {
248  SCLogError("failed to parse %s", th_ip);
249  goto error;
250  }
251  }
252 
253  /* Install it */
254  if (id == 0 && gid == 0) {
255  if (parsed_track == TRACK_RULE) {
256  SCLogWarning("suppressing all rules");
257  }
258 
259  /* update each sig with our suppress info */
260  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
261  /* tag the rule as noalert */
262  if (parsed_track == TRACK_RULE) {
263  s->action &= ~ACTION_ALERT;
264  continue;
265  }
266 
267  de = DetectThresholdDataCopy(orig_de);
268  if (unlikely(de == NULL))
269  goto error;
270 
272  DETECT_SM_LIST_SUPPRESS) == NULL) {
273  goto error;
274  }
275  }
276  } else if (id == 0 && gid > 0) {
277  if (parsed_track == TRACK_RULE) {
278  SCLogWarning("suppressing all rules with gid %" PRIu32, gid);
279  }
280  /* set up suppression for each signature with a matching gid */
281  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
282  if (s->gid != gid)
283  continue;
284 
285  /* tag the rule as noalert */
286  if (parsed_track == TRACK_RULE) {
287  s->action &= ~ACTION_ALERT;
288  continue;
289  }
290 
291  de = DetectThresholdDataCopy(orig_de);
292  if (unlikely(de == NULL))
293  goto error;
294 
296  DETECT_SM_LIST_SUPPRESS) == NULL) {
297  goto error;
298  }
299  }
300  } else if (id > 0 && gid == 0) {
301  SCLogError("Can't use a event config that has "
302  "sid > 0 and gid == 0. Please fix this "
303  "in your threshold.config file");
304  goto error;
305  } else {
306  s = SigFindSignatureBySidGid(de_ctx, id, gid);
307  if (s == NULL) {
308  SCLogWarning("can't suppress sid "
309  "%" PRIu32 ", gid %" PRIu32 ": unknown rule",
310  id, gid);
311  } else {
312  if (parsed_track == TRACK_RULE) {
313  s->action &= ~ACTION_ALERT;
314  goto end;
315  }
316 
317  de = DetectThresholdDataCopy(orig_de);
318  if (unlikely(de == NULL))
319  goto error;
320 
322  DETECT_SM_LIST_SUPPRESS) == NULL) {
323  goto error;
324  }
325  }
326  }
327 
328 end:
329  if (orig_de != NULL) {
330  DetectAddressHeadCleanup(&orig_de->addrs);
331  SCFree(orig_de);
332  }
333  return 0;
334 error:
335  if (orig_de != NULL) {
336  DetectAddressHeadCleanup(&orig_de->addrs);
337  SCFree(orig_de);
338  }
339  if (de != NULL) {
340  DetectAddressHeadCleanup(&de->addrs);
341  SCFree(de);
342  }
343  return -1;
344 }
345 
346 /** \internal
347  * \brief setup suppress rules
348  * \retval 0 ok
349  * \retval -1 error
350  */
351 static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
352  uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, uint32_t parsed_seconds,
353  uint32_t parsed_timeout, uint8_t parsed_new_action)
354 {
355  Signature *s = NULL;
356  SigMatch *sm = NULL;
357  DetectThresholdData *de = NULL;
358 
359  BUG_ON(parsed_type == TYPE_SUPPRESS);
360 
361  /* Install it */
362  if (id == 0 && gid == 0) {
363  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
365  if (sm != NULL) {
366  SCLogWarning("signature sid:%" PRIu32 " has "
367  "an event var set. The signature event var is "
368  "given precedence over the threshold.conf one. "
369  "We'll change this in the future though.",
370  s->id);
371  continue;
372  }
373 
376  if (sm != NULL) {
377  SCLogWarning("signature sid:%" PRIu32 " has "
378  "an event var set. The signature event var is "
379  "given precedence over the threshold.conf one. "
380  "We'll change this in the future though.",
381  s->id);
382  continue;
383  }
384 
385  de = SCCalloc(1, sizeof(DetectThresholdData));
386  if (unlikely(de == NULL))
387  goto error;
388 
389  de->type = parsed_type;
390  de->track = parsed_track;
391  de->count = parsed_count;
392  de->seconds = parsed_seconds;
393  de->new_action = parsed_new_action;
394  de->timeout = parsed_timeout;
395 
396  uint16_t smtype = DETECT_THRESHOLD;
397  if (parsed_type == TYPE_RATE)
398  smtype = DETECT_DETECTION_FILTER;
399 
401  de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) {
402  goto error;
403  }
404  }
405 
406  } else if (id == 0 && gid > 0) {
407  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
408  if (s->gid == gid) {
411  if (sm != NULL) {
412  SCLogWarning("signature sid:%" PRIu32 " has "
413  "an event var set. The signature event var is "
414  "given precedence over the threshold.conf one. "
415  "We'll change this in the future though.",
416  id);
417  continue;
418  }
419 
420  de = SCCalloc(1, sizeof(DetectThresholdData));
421  if (unlikely(de == NULL))
422  goto error;
423 
424  de->type = parsed_type;
425  de->track = parsed_track;
426  de->count = parsed_count;
427  de->seconds = parsed_seconds;
428  de->new_action = parsed_new_action;
429  de->timeout = parsed_timeout;
430 
431  uint16_t smtype = DETECT_THRESHOLD;
432  if (parsed_type == TYPE_RATE)
433  smtype = DETECT_DETECTION_FILTER;
434 
435  if (SigMatchAppendSMToList(de_ctx, s, smtype, (SigMatchCtx *)de,
436  DETECT_SM_LIST_THRESHOLD) == NULL) {
437  goto error;
438  }
439  }
440  }
441  } else if (id > 0 && gid == 0) {
442  SCLogError("Can't use a event config that has "
443  "sid > 0 and gid == 0. Please fix this "
444  "in your threshold.conf file");
445  } else {
446  s = SigFindSignatureBySidGid(de_ctx, id, gid);
447  if (s == NULL) {
448  SCLogWarning("can't suppress sid "
449  "%" PRIu32 ", gid %" PRIu32 ": unknown rule",
450  id, gid);
451  } else {
452  if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD &&
453  parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT)
454  {
457  if (sm != NULL) {
458  SCLogWarning("signature sid:%" PRIu32 " has "
459  "a threshold set. The signature event var is "
460  "given precedence over the threshold.conf one. "
461  "Bug #425.",
462  s->id);
463  goto end;
464  }
465 
468  if (sm != NULL) {
469  SCLogWarning("signature sid:%" PRIu32 " has "
470  "a detection_filter set. The signature event var is "
471  "given precedence over the threshold.conf one. "
472  "Bug #425.",
473  s->id);
474  goto end;
475  }
476 
477  /* replace threshold on sig if we have a global override for it */
478  } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) {
481  if (sm != NULL) {
483  SigMatchFree(de_ctx, sm);
484  }
485  }
486 
487  de = SCCalloc(1, sizeof(DetectThresholdData));
488  if (unlikely(de == NULL))
489  goto error;
490 
491  de->type = parsed_type;
492  de->track = parsed_track;
493  de->count = parsed_count;
494  de->seconds = parsed_seconds;
495  de->new_action = parsed_new_action;
496  de->timeout = parsed_timeout;
497 
498  uint16_t smtype = DETECT_THRESHOLD;
499  if (parsed_type == TYPE_RATE)
500  smtype = DETECT_DETECTION_FILTER;
501 
503  de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) {
504  goto error;
505  }
506  }
507  }
508 end:
509  return 0;
510 error:
511  if (de != NULL) {
512  DetectAddressHeadCleanup(&de->addrs);
513  SCFree(de);
514  }
515  return -1;
516 }
517 
518 static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint32_t *ret_id,
519  uint32_t *ret_gid, uint8_t *ret_parsed_type, uint8_t *ret_parsed_track,
520  uint32_t *ret_parsed_count, uint32_t *ret_parsed_seconds, uint32_t *ret_parsed_timeout,
521  uint8_t *ret_parsed_new_action, char **ret_th_ip)
522 {
523  char th_rule_type[32];
524  char th_gid[16];
525  char th_sid[16];
526  const char *rule_extend = NULL;
527  char th_type[16] = "";
528  char th_track[16] = "";
529  char th_count[16] = "";
530  char th_seconds[16] = "";
531  char th_new_action[16] = "";
532  char th_timeout[16] = "";
533  const char *th_ip = NULL;
534 
535  uint8_t parsed_type = 0;
536  uint8_t parsed_track = 0;
537  uint8_t parsed_new_action = 0;
538  uint32_t parsed_count = 0;
539  uint32_t parsed_seconds = 0;
540  uint32_t parsed_timeout = 0;
541 
542  int ret = 0;
543  uint32_t id = 0, gid = 0;
544  ThresholdRuleType rule_type;
545 
546  if (de_ctx == NULL)
547  return -1;
548 
549  pcre2_match_data *regex_base_match = NULL;
550  ret = DetectParsePcreExec(regex_base, &regex_base_match, rawstr, 0, 0);
551  if (ret < 4) {
552  SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rawstr);
553  pcre2_match_data_free(regex_base_match);
554  goto error;
555  }
556 
557  /* retrieve the classtype name */
558  size_t copylen = sizeof(th_rule_type);
559  ret = pcre2_substring_copy_bynumber(
560  regex_base_match, 1, (PCRE2_UCHAR8 *)th_rule_type, &copylen);
561  if (ret < 0) {
562  SCLogError("pcre2_substring_copy_bynumber failed");
563  pcre2_match_data_free(regex_base_match);
564  goto error;
565  }
566 
567  /* retrieve the classtype name */
568  copylen = sizeof(th_gid);
569  ret = pcre2_substring_copy_bynumber(regex_base_match, 2, (PCRE2_UCHAR8 *)th_gid, &copylen);
570  if (ret < 0) {
571  SCLogError("pcre2_substring_copy_bynumber failed");
572  pcre2_match_data_free(regex_base_match);
573  goto error;
574  }
575 
576  copylen = sizeof(th_sid);
577  ret = pcre2_substring_copy_bynumber(regex_base_match, 3, (PCRE2_UCHAR8 *)th_sid, &copylen);
578  if (ret < 0) {
579  SCLogError("pcre2_substring_copy_bynumber failed");
580  pcre2_match_data_free(regex_base_match);
581  goto error;
582  }
583 
584  /* Use "get" for heap allocation */
585  ret = pcre2_substring_get_bynumber(
586  regex_base_match, 4, (PCRE2_UCHAR8 **)&rule_extend, &copylen);
587  if (ret < 0) {
588  SCLogError("pcre2_substring_get_bynumber failed");
589  pcre2_match_data_free(regex_base_match);
590  goto error;
591  }
592  pcre2_match_data_free(regex_base_match);
593  regex_base_match = NULL;
594 
595  /* get type of rule */
596  if (strcasecmp(th_rule_type,"event_filter") == 0) {
597  rule_type = THRESHOLD_TYPE_EVENT_FILTER;
598  } else if (strcasecmp(th_rule_type,"threshold") == 0) {
599  rule_type = THRESHOLD_TYPE_THRESHOLD;
600  } else if (strcasecmp(th_rule_type,"rate_filter") == 0) {
601  rule_type = THRESHOLD_TYPE_RATE;
602  } else if (strcasecmp(th_rule_type,"suppress") == 0) {
603  rule_type = THRESHOLD_TYPE_SUPPRESS;
604  } else {
605  SCLogError("rule type %s is unknown", th_rule_type);
606  goto error;
607  }
608 
609  /* get end of rule */
610  switch(rule_type) {
613  if (strlen(rule_extend) > 0) {
614  pcre2_match_data *match = NULL;
615 
616  ret = DetectParsePcreExec(regex_threshold, &match, rule_extend, 0, 0);
617  if (ret < 4) {
618  SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
619  rule_extend);
620  pcre2_match_data_free(match);
621  goto error;
622  }
623 
624  copylen = sizeof(th_type);
625  ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_type, &copylen);
626  if (ret < 0) {
627  SCLogError("pcre2_substring_copy_bynumber failed");
628  pcre2_match_data_free(match);
629  goto error;
630  }
631 
632  copylen = sizeof(th_track);
633  ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_track, &copylen);
634  if (ret < 0) {
635  SCLogError("pcre2_substring_copy_bynumber failed");
636  pcre2_match_data_free(match);
637  goto error;
638  }
639 
640  copylen = sizeof(th_count);
641  ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_count, &copylen);
642  if (ret < 0) {
643  SCLogError("pcre2_substring_copy_bynumber failed");
644  pcre2_match_data_free(match);
645  goto error;
646  }
647 
648  copylen = sizeof(th_seconds);
649  ret = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)th_seconds, &copylen);
650  if (ret < 0) {
651  SCLogError("pcre2_substring_copy_bynumber failed");
652  pcre2_match_data_free(match);
653  goto error;
654  }
655  pcre2_match_data_free(match);
656 
657  if (strcasecmp(th_type,"limit") == 0)
658  parsed_type = TYPE_LIMIT;
659  else if (strcasecmp(th_type,"both") == 0)
660  parsed_type = TYPE_BOTH;
661  else if (strcasecmp(th_type,"threshold") == 0)
662  parsed_type = TYPE_THRESHOLD;
663  else {
664  SCLogError("limit type not supported: %s", th_type);
665  goto error;
666  }
667  } else {
668  SCLogError("rule invalid: %s", rawstr);
669  goto error;
670  }
671  break;
673  if (strlen(rule_extend) > 0) {
674  pcre2_match_data *match = NULL;
675  ret = DetectParsePcreExec(regex_suppress, &match, rule_extend, 0, 0);
676  if (ret < 2) {
677  SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
678  rule_extend);
679  pcre2_match_data_free(match);
680  goto error;
681  }
682  /* retrieve the track mode */
683  copylen = sizeof(th_seconds);
684  ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, &copylen);
685  if (ret < 0) {
686  SCLogError("pcre2_substring_copy_bynumber failed");
687  pcre2_match_data_free(match);
688  goto error;
689  }
690  /* retrieve the IP; use "get" for heap allocation */
691  ret = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&th_ip, &copylen);
692  if (ret < 0) {
693  SCLogError("pcre2_substring_get_bynumber failed");
694  pcre2_match_data_free(match);
695  goto error;
696  }
697  pcre2_match_data_free(match);
698  } else {
699  parsed_track = TRACK_RULE;
700  }
701  parsed_type = TYPE_SUPPRESS;
702  break;
703  case THRESHOLD_TYPE_RATE:
704  if (strlen(rule_extend) > 0) {
705  pcre2_match_data *match = NULL;
706  ret = DetectParsePcreExec(regex_rate, &match, rule_extend, 0, 0);
707  if (ret < 5) {
708  SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret,
709  rule_extend);
710  pcre2_match_data_free(match);
711  goto error;
712  }
713 
714  copylen = sizeof(th_track);
715  ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, &copylen);
716  if (ret < 0) {
717  SCLogError("pcre2_substring_copy_bynumber failed");
718  pcre2_match_data_free(match);
719  goto error;
720  }
721 
722  copylen = sizeof(th_count);
723  ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_count, &copylen);
724  if (ret < 0) {
725  SCLogError("pcre2_substring_copy_bynumber failed");
726  pcre2_match_data_free(match);
727  goto error;
728  }
729 
730  copylen = sizeof(th_seconds);
731  ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_seconds, &copylen);
732  if (ret < 0) {
733  SCLogError("pcre2_substring_copy_bynumber failed");
734  pcre2_match_data_free(match);
735  goto error;
736  }
737 
738  copylen = sizeof(th_new_action);
739  ret = pcre2_substring_copy_bynumber(
740  match, 4, (PCRE2_UCHAR8 *)th_new_action, &copylen);
741  if (ret < 0) {
742  SCLogError("pcre2_substring_copy_bynumber failed");
743  pcre2_match_data_free(match);
744  goto error;
745  }
746 
747  copylen = sizeof(th_timeout);
748  ret = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)th_timeout, &copylen);
749  if (ret < 0) {
750  SCLogError("pcre2_substring_copy_bynumber failed");
751  pcre2_match_data_free(match);
752  goto error;
753  }
754  pcre2_match_data_free(match);
755 
756  /* TODO: implement option "apply_to" */
757 
758  if (StringParseUint32(&parsed_timeout, 10, sizeof(th_timeout), th_timeout) <= 0) {
759  goto error;
760  }
761 
762  /* Get the new action to take */
763  if (strcasecmp(th_new_action, "alert") == 0)
764  parsed_new_action = TH_ACTION_ALERT;
765  if (strcasecmp(th_new_action, "drop") == 0)
766  parsed_new_action = TH_ACTION_DROP;
767  if (strcasecmp(th_new_action, "pass") == 0)
768  parsed_new_action = TH_ACTION_PASS;
769  if (strcasecmp(th_new_action, "reject") == 0)
770  parsed_new_action = TH_ACTION_REJECT;
771  if (strcasecmp(th_new_action, "log") == 0) {
772  SCLogInfo("log action for rate_filter not supported yet");
773  parsed_new_action = TH_ACTION_LOG;
774  }
775  if (strcasecmp(th_new_action, "sdrop") == 0) {
776  SCLogInfo("sdrop action for rate_filter not supported yet");
777  parsed_new_action = TH_ACTION_SDROP;
778  }
779  parsed_type = TYPE_RATE;
780  } else {
781  SCLogError("rule invalid: %s", rawstr);
782  goto error;
783  }
784  break;
785  }
786 
787  switch (rule_type) {
788  /* This part is common to threshold/event_filter/rate_filter */
791  case THRESHOLD_TYPE_RATE:
792  if (strcasecmp(th_track,"by_dst") == 0)
793  parsed_track = TRACK_DST;
794  else if (strcasecmp(th_track,"by_src") == 0)
795  parsed_track = TRACK_SRC;
796  else if (strcasecmp(th_track, "by_both") == 0) {
797  parsed_track = TRACK_BOTH;
798  }
799  else if (strcasecmp(th_track,"by_rule") == 0)
800  parsed_track = TRACK_RULE;
801  else if (strcasecmp(th_track, "by_flow") == 0)
802  parsed_track = TRACK_FLOW;
803  else {
804  SCLogError("Invalid track parameter %s in %s", th_track, rawstr);
805  goto error;
806  }
807 
808  if (StringParseUint32(&parsed_count, 10, sizeof(th_count), th_count) <= 0) {
809  goto error;
810  }
811  if (parsed_count == 0) {
812  SCLogError("rate filter count should be > 0");
813  goto error;
814  }
815 
816  if (StringParseUint32(&parsed_seconds, 10, sizeof(th_seconds), th_seconds) <= 0) {
817  goto error;
818  }
819 
820  break;
822  /* need to get IP if extension is provided */
823  if (strcmp("", th_track) != 0) {
824  if (strcasecmp(th_track,"by_dst") == 0)
825  parsed_track = TRACK_DST;
826  else if (strcasecmp(th_track,"by_src") == 0)
827  parsed_track = TRACK_SRC;
828  else if (strcasecmp(th_track,"by_either") == 0) {
829  parsed_track = TRACK_EITHER;
830  }
831  else {
832  SCLogError("Invalid track parameter %s in %s", th_track, rule_extend);
833  goto error;
834  }
835  }
836  break;
837  }
838 
839  if (StringParseUint32(&id, 10, sizeof(th_sid), th_sid) <= 0) {
840  goto error;
841  }
842 
843  if (StringParseUint32(&gid, 10, sizeof(th_gid), th_gid) <= 0) {
844  goto error;
845  }
846 
847  *ret_id = id;
848  *ret_gid = gid;
849  *ret_parsed_type = parsed_type;
850  *ret_parsed_track = parsed_track;
851  *ret_parsed_new_action = parsed_new_action;
852  *ret_parsed_count = parsed_count;
853  *ret_parsed_seconds = parsed_seconds;
854  *ret_parsed_timeout = parsed_timeout;
855  *ret_th_ip = NULL;
856  if (th_ip != NULL) {
857  *ret_th_ip = (char *)th_ip;
858  }
859  pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend);
860  return 0;
861 
862 error:
863  if (rule_extend != NULL) {
864  pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend);
865  }
866  if (th_ip != NULL) {
867  pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
868  }
869  return -1;
870 }
871 
872 /**
873  * \brief Parses a line from the threshold file and applies it to the
874  * detection engine
875  *
876  * \param rawstr Pointer to the string to be parsed.
877  * \param de_ctx Pointer to the Detection Engine Context.
878  *
879  * \retval 0 On success.
880  * \retval -1 On failure.
881  */
882 static int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx)
883 {
884  uint8_t parsed_type = 0;
885  uint8_t parsed_track = 0;
886  uint8_t parsed_new_action = 0;
887  uint32_t parsed_count = 0;
888  uint32_t parsed_seconds = 0;
889  uint32_t parsed_timeout = 0;
890  char *th_ip = NULL;
891  uint32_t id = 0, gid = 0;
892 
893  int r = ParseThresholdRule(de_ctx, rawstr, &id, &gid, &parsed_type, &parsed_track,
894  &parsed_count, &parsed_seconds, &parsed_timeout, &parsed_new_action, &th_ip);
895  if (r < 0)
896  goto error;
897 
898  if (parsed_type == TYPE_SUPPRESS) {
899  r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track,
900  parsed_count, parsed_seconds, parsed_timeout, parsed_new_action,
901  th_ip);
902  } else {
903  r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track, parsed_count,
904  parsed_seconds, parsed_timeout, parsed_new_action);
905  }
906  if (r < 0) {
907  goto error;
908  }
909 
910  pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
911  return 0;
912 error:
913  if (th_ip != NULL)
914  pcre2_substring_free((PCRE2_UCHAR8 *)th_ip);
915  return -1;
916 }
917 
918 /**
919  * \brief Checks if a string is a comment or a blank line.
920  *
921  * Comments lines are lines of the following format -
922  * "# This is a comment string" or
923  * " # This is a comment string".
924  *
925  * \param line String that has to be checked
926  *
927  * \retval 1 On the argument string being a comment or blank line
928  * \retval 0 Otherwise
929  */
930 static int SCThresholdConfIsLineBlankOrComment(char *line)
931 {
932  while (*line != '\0') {
933  /* we have a comment */
934  if (*line == '#')
935  return 1;
936 
937  /* this line is neither a comment line, nor a blank line */
938  if (!isspace((unsigned char)*line))
939  return 0;
940 
941  line++;
942  }
943 
944  /* we have a blank line */
945  return 1;
946 }
947 
948 /**
949  * \brief Checks if the rule is multiline, by searching an ending slash
950  *
951  * \param line String that has to be checked
952  *
953  * \retval the position of the slash making it multiline
954  * \retval 0 Otherwise
955  */
956 static int SCThresholdConfLineIsMultiline(char *line)
957 {
958  int flag = 0;
959  char *rline = line;
960  int len = strlen(line);
961 
962  while (line < rline + len && *line != '\n') {
963  /* we have a comment */
964  if (*line == '\\')
965  flag = line - rline;
966  else
967  if (!isspace((unsigned char)*line))
968  flag = 0;
969 
970  line++;
971  }
972 
973  /* we have a blank line */
974  return flag;
975 }
976 
977 /**
978  * \brief Parses the Threshold Config file
979  *
980  * \param de_ctx Pointer to the Detection Engine Context.
981  * \param fd Pointer to file descriptor.
982  */
984 {
985  char line[8192] = "";
986  int rule_num = 0;
987 
988  /* position of "\", on multiline rules */
989  int esc_pos = 0;
990 
991  if (fp == NULL)
992  return -1;
993 
994  while (fgets(line + esc_pos, (int)sizeof(line) - esc_pos, fp) != NULL) {
995  if (SCThresholdConfIsLineBlankOrComment(line)) {
996  continue;
997  }
998 
999  esc_pos = SCThresholdConfLineIsMultiline(line);
1000  if (esc_pos == 0) {
1001  if (SCThresholdConfAddThresholdtype(line, de_ctx) < 0) {
1003  return -1;
1004  } else {
1005  SCLogDebug("Adding threshold.config rule num %" PRIu32 "( %s )", rule_num, line);
1006  rule_num++;
1007  }
1008  }
1009  }
1010 
1011  if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0)
1012  SCLogInfo("tenant id %d: Threshold config parsed: %d rule(s) found", de_ctx->tenant_id,
1013  rule_num);
1014  else
1015  SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num);
1016  return 0;
1017 }
1018 
1019 #ifdef UNITTESTS
1020 #include "detect-engine-alert.h"
1021 #include "packet.h"
1022 #include "action-globals.h"
1023 
1024 /**
1025  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1026  *
1027  * \retval fd Pointer to file descriptor.
1028  */
1029 static FILE *SCThresholdConfGenerateValidDummyFD01(void)
1030 {
1031  FILE *fd = NULL;
1032  const char *buffer =
1033  "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n"
1034  "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n"
1035  "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds 60\n";
1036 
1037  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1038  if (fd == NULL)
1039  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1040 
1041  return fd;
1042 }
1043 
1044 /**
1045  * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options.
1046  * For testing purposes.
1047  *
1048  * \retval fd Pointer to file descriptor.
1049  */
1050 static FILE *SCThresholdConfGenerateInvalidDummyFD02(void)
1051 {
1052  FILE *fd;
1053  const char *buffer =
1054  "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count 100, seconds 60\n";
1055 
1056  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1057  if (fd == NULL)
1058  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1059 
1060  return fd;
1061 }
1062 
1063 /**
1064  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1065  *
1066  * \retval fd Pointer to file descriptor.
1067  */
1068 static FILE *SCThresholdConfGenerateValidDummyFD03(void)
1069 {
1070  FILE *fd;
1071  const char *buffer =
1072  "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count 100, seconds 60\n";
1073 
1074  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1075  if (fd == NULL)
1076  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1077 
1078  return fd;
1079 }
1080 
1081 /**
1082  * \brief Creates a dummy threshold file, with all valid options, but
1083  * with split rules (multiline), for testing purposes.
1084  *
1085  * \retval fd Pointer to file descriptor.
1086  */
1087 static FILE *SCThresholdConfGenerateValidDummyFD04(void)
1088 {
1089  FILE *fd = NULL;
1090  const char *buffer =
1091  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n"
1092  "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n"
1093  "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\n";
1094 
1095  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1096  if (fd == NULL)
1097  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1098 
1099  return fd;
1100 }
1101 
1102 /**
1103  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1104  *
1105  * \retval fd Pointer to file descriptor.
1106  */
1107 static FILE *SCThresholdConfGenerateValidDummyFD05(void)
1108 {
1109  FILE *fd = NULL;
1110  const char *buffer =
1111  "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n"
1112  "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n"
1113  "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1114  "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, seconds 60, new_action reject, timeout 21\n";
1115 
1116  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1117  if (fd == NULL)
1118  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1119 
1120  return fd;
1121 }
1122 
1123 /**
1124  * \brief Creates a dummy threshold file, with all valid options, but
1125  * with split rules (multiline), for testing purposes.
1126  *
1127  * \retval fd Pointer to file descriptor.
1128  */
1129 static FILE *SCThresholdConfGenerateValidDummyFD06(void)
1130 {
1131  FILE *fd = NULL;
1132  const char *buffer =
1133  "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n"
1134  "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n"
1135  "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1136  "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, \\\nseconds 60, new_action reject, timeout 21\n";
1137 
1138  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1139  if (fd == NULL)
1140  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1141 
1142  return fd;
1143 }
1144 
1145 /**
1146  * \brief Creates a dummy threshold file, with all valid options, but
1147  * with split rules (multiline), for testing purposes.
1148  *
1149  * \retval fd Pointer to file descriptor.
1150  */
1151 static FILE *SCThresholdConfGenerateValidDummyFD07(void)
1152 {
1153  FILE *fd = NULL;
1154  const char *buffer =
1155  "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n"
1156  "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n";
1157 
1158  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1159  if (fd == NULL)
1160  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1161 
1162  return fd;
1163 }
1164 
1165 /**
1166  * \brief Creates a dummy threshold file, for testing rate_filter, track by_rule
1167  *
1168  * \retval fd Pointer to file descriptor.
1169  */
1170 static FILE *SCThresholdConfGenerateValidDummyFD08(void)
1171 {
1172  FILE *fd = NULL;
1173  const char *buffer =
1174  "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n";
1175 
1176  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1177  if (fd == NULL)
1178  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1179 
1180  return fd;
1181 }
1182 
1183 /**
1184  * \brief Creates a dummy threshold file, with all valid options, but
1185  * with split rules (multiline), for testing purposes.
1186  *
1187  * \retval fd Pointer to file descriptor.
1188  */
1189 static FILE *SCThresholdConfGenerateValidDummyFD09(void)
1190 {
1191  FILE *fd = NULL;
1192  const char *buffer =
1193  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n"
1194  "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n"
1195  "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n";
1196 
1197  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1198  if (fd == NULL)
1199  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1200 
1201  return fd;
1202 }
1203 
1204 /**
1205  * \brief Creates a dummy threshold file, with all valid options, but
1206  * with split rules (multiline), for testing purposes.
1207  *
1208  * \retval fd Pointer to file descriptor.
1209  */
1210 static FILE *SCThresholdConfGenerateValidDummyFD10(void)
1211 {
1212  FILE *fd = NULL;
1213  const char *buffer =
1214  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n"
1215  "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n"
1216  "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n";
1217 
1218  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1219  if (fd == NULL)
1220  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1221 
1222  return fd;
1223 }
1224 
1225 /**
1226  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1227  *
1228  * \retval fd Pointer to file descriptor.
1229  */
1230 static FILE *SCThresholdConfGenerateValidDummyFD11(void)
1231 {
1232  FILE *fd = NULL;
1233  const char *buffer =
1234  "suppress gen_id 1, sig_id 10000\n"
1235  "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
1236 
1237  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1238  if (fd == NULL)
1239  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1240 
1241  return fd;
1242 }
1243 
1244 /**
1245  * \test Check if the threshold file is loaded and well parsed
1246  *
1247  * \retval 1 on success
1248  * \retval 0 on failure
1249  */
1250 static int SCThresholdConfTest01(void)
1251 {
1254  de_ctx->flags |= DE_QUIET;
1255 
1257  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1258  FAIL_IF_NULL(sig);
1259 
1260  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1261  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1262  FAIL_IF_NULL(g_ut_threshold_fp);
1264 
1266  DETECT_THRESHOLD, -1);
1267  FAIL_IF_NULL(m);
1268 
1270  FAIL_IF_NULL(de);
1271 
1272  FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1274  PASS;
1275 }
1276 
1277 /**
1278  * \test Check if the threshold file is loaded and well parsed
1279  *
1280  * \retval 1 on success
1281  * \retval 0 on failure
1282  */
1283 static int SCThresholdConfTest02(void)
1284 {
1287  de_ctx->flags |= DE_QUIET;
1288 
1290  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)");
1291  FAIL_IF_NULL(sig);
1292 
1293  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1294  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1295  FAIL_IF_NULL(g_ut_threshold_fp);
1297 
1299  DETECT_THRESHOLD, -1);
1300  FAIL_IF_NULL(m);
1301 
1303  FAIL_IF_NULL(de);
1304 
1305  FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60);
1307  PASS;
1308 }
1309 
1310 /**
1311  * \test Check if the threshold file is loaded and well parsed
1312  *
1313  * \retval 1 on success
1314  * \retval 0 on failure
1315  */
1316 static int SCThresholdConfTest03(void)
1317 {
1320  de_ctx->flags |= DE_QUIET;
1321 
1323  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1324  FAIL_IF_NULL(sig);
1325 
1326  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1327  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1328  FAIL_IF_NULL(g_ut_threshold_fp);
1330 
1332  DETECT_THRESHOLD, -1);
1333  FAIL_IF_NULL(m);
1334 
1336  FAIL_IF_NULL(de);
1337 
1338  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1340  PASS;
1341 }
1342 
1343 /**
1344  * \test Check if the threshold file is loaded and well parsed
1345  *
1346  * \retval 1 on success
1347  * \retval 0 on failure
1348  */
1349 static int SCThresholdConfTest04(void)
1350 {
1353  de_ctx->flags |= DE_QUIET;
1354 
1356  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1357  FAIL_IF_NULL(sig);
1358 
1359  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1360  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD02();
1361  FAIL_IF_NULL(g_ut_threshold_fp);
1363 
1365  DETECT_THRESHOLD, -1);
1367 
1369  PASS;
1370 }
1371 
1372 /**
1373  * \test Check if the threshold file is loaded and well parsed
1374  *
1375  * \retval 1 on success
1376  * \retval 0 on failure
1377  */
1378 static int SCThresholdConfTest05(void)
1379 {
1382  de_ctx->flags |= DE_QUIET;
1383 
1385  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)");
1386  FAIL_IF_NULL(sig);
1388  "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)");
1389  FAIL_IF_NULL(sig);
1390 
1392  "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)");
1393  FAIL_IF_NULL(sig);
1394 
1395  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1396  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03();
1397  FAIL_IF_NULL(g_ut_threshold_fp);
1399 
1400  Signature *s = de_ctx->sig_list;
1402  DETECT_THRESHOLD, -1);
1403  FAIL_IF_NULL(m);
1404  FAIL_IF_NULL(m->ctx);
1406  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1407 
1408  s = de_ctx->sig_list->next;
1410  DETECT_THRESHOLD, -1);
1411  FAIL_IF_NULL(m);
1412  FAIL_IF_NULL(m->ctx);
1413  de = (DetectThresholdData *)m->ctx;
1414  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1415 
1416  s = de_ctx->sig_list->next->next;
1418  DETECT_THRESHOLD, -1);
1419  FAIL_IF_NULL(m);
1420  FAIL_IF_NULL(m->ctx);
1421  de = (DetectThresholdData *)m->ctx;
1422  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1423 
1424  PASS;
1425 }
1426 
1427 /**
1428  * \test Check if the threshold file is loaded and well parsed
1429  *
1430  * \retval 1 on success
1431  * \retval 0 on failure
1432  */
1433 static int SCThresholdConfTest06(void)
1434 {
1437  de_ctx->flags |= DE_QUIET;
1438 
1440  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1441  FAIL_IF_NULL(sig);
1442 
1443  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1444  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04();
1445  FAIL_IF_NULL(g_ut_threshold_fp);
1447 
1449  DETECT_THRESHOLD, -1);
1450  FAIL_IF_NULL(m);
1451 
1453  FAIL_IF_NULL(de);
1454  FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1455 
1457  PASS;
1458 }
1459 
1460 /**
1461  * \test Check if the rate_filter rules are loaded and well parsed
1462  *
1463  * \retval 1 on success
1464  * \retval 0 on failure
1465  */
1466 static int SCThresholdConfTest07(void)
1467 {
1470  de_ctx->flags |= DE_QUIET;
1471 
1473  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1474  FAIL_IF_NULL(sig);
1475 
1476  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1477  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05();
1478  FAIL_IF_NULL(g_ut_threshold_fp);
1480 
1483  FAIL_IF_NULL(m);
1484 
1486  FAIL_IF_NULL(de);
1487  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1488 
1490  PASS;
1491 }
1492 
1493 /**
1494  * \test Check if the rate_filter rules are loaded and well parsed
1495  * with multilines
1496  *
1497  * \retval 1 on success
1498  * \retval 0 on failure
1499  */
1500 static int SCThresholdConfTest08(void)
1501 {
1504  de_ctx->flags |= DE_QUIET;
1505 
1507  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1508  FAIL_IF_NULL(sig);
1509 
1510  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1511  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06();
1512  FAIL_IF_NULL(g_ut_threshold_fp);
1514 
1517  FAIL_IF_NULL(m);
1518 
1520  FAIL_IF_NULL(de);
1521  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1522 
1524  PASS;
1525 }
1526 
1527 /**
1528  * \test Check if the rate_filter rules work
1529  *
1530  * \retval 1 on success
1531  * \retval 0 on failure
1532  */
1533 static int SCThresholdConfTest09(void)
1534 {
1535  ThreadVars th_v;
1536  memset(&th_v, 0, sizeof(th_v));
1537 
1538  ThresholdInit();
1539 
1540  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1541  FAIL_IF_NULL(p);
1542 
1543  DetectEngineThreadCtx *det_ctx = NULL;
1544 
1547  de_ctx->flags |= DE_QUIET;
1548 
1550  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1551  FAIL_IF_NULL(s);
1552 
1553  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1554  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07();
1555  FAIL_IF_NULL(g_ut_threshold_fp);
1557 
1559  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1560 
1561  p->ts = TimeGet();
1562  p->alerts.cnt = 0;
1563  p->action = 0;
1564  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1565  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1566  p->alerts.cnt = 0;
1567  p->action = 0;
1568  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1569  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1570  p->alerts.cnt = 0;
1571  p->action = 0;
1572  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1573  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1574 
1576  p->ts = TimeGet();
1577 
1578  p->alerts.cnt = 0;
1579  p->action = 0;
1580  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1581  FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1582 
1584  p->ts = TimeGet();
1585 
1586  p->alerts.cnt = 0;
1587  p->action = 0;
1588  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1589  FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1590 
1592  p->ts = TimeGet();
1593 
1594  p->alerts.cnt = 0;
1595  p->action = 0;
1596  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1597  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1598 
1599  p->alerts.cnt = 0;
1600  p->action = 0;
1601  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1602  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1603 
1604  UTHFreePacket(p);
1605  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1607  ThresholdDestroy();
1608  PASS;
1609 }
1610 
1611 /**
1612  * \test Check if the rate_filter rules work with track by_rule
1613  *
1614  * \retval 1 on success
1615  * \retval 0 on failure
1616  */
1617 static int SCThresholdConfTest10(void)
1618 {
1619  ThresholdInit();
1620 
1621  /* Create two different packets falling to the same rule, and
1622  * because count:3, we should drop on match #4.
1623  */
1624  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1625  "172.26.0.2", "172.26.0.11");
1626  FAIL_IF_NULL(p1);
1627  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1628  "172.26.0.1", "172.26.0.10");
1629  FAIL_IF_NULL(p2);
1630 
1631  ThreadVars th_v;
1632  memset(&th_v, 0, sizeof(th_v));
1633 
1636  de_ctx->flags |= DE_QUIET;
1637  DetectEngineThreadCtx *det_ctx = NULL;
1638 
1640  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1641  FAIL_IF_NULL(s);
1642 
1643  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1644  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08();
1645  FAIL_IF_NULL(g_ut_threshold_fp);
1647 
1649  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1650  p1->ts = TimeGet();
1651  p2->ts = p1->ts;
1652 
1653  /* All should be alerted, none dropped */
1654  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1655  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1656  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1657  p1->action = 0;
1658  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1659  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
1660  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1661  p2->action = 0;
1662  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1663  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1664  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1665  p1->action = 0;
1666 
1667  /* Match #4 should be dropped*/
1668  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1669  FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
1670  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1671  p2->action = 0;
1672 
1674  p1->ts = TimeGet();
1675 
1676  /* Still dropped because timeout not expired */
1677  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1678  FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
1679  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1680  p1->action = 0;
1681 
1683  p1->ts = TimeGet();
1684 
1685  /* Not dropped because timeout expired */
1686  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1687  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1688  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1689 #if 0
1690  /* Ensure that a Threshold entry was installed at the sig */
1691  FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->num]);
1692 #endif
1693  UTHFreePacket(p1);
1694  UTHFreePacket(p2);
1695  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1697  ThresholdDestroy();
1698  PASS;
1699 }
1700 
1701 /**
1702  * \test Check if the rate_filter rules work
1703  *
1704  * \retval 1 on success
1705  * \retval 0 on failure
1706  */
1707 static int SCThresholdConfTest11(void)
1708 {
1709  ThresholdInit();
1710 
1711  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1712  FAIL_IF_NULL(p);
1713 
1714  ThreadVars th_v;
1715  memset(&th_v, 0, sizeof(th_v));
1716 
1719  de_ctx->flags |= DE_QUIET;
1720  DetectEngineThreadCtx *det_ctx = NULL;
1721 
1723  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1724  FAIL_IF_NULL(s);
1726  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1727  FAIL_IF_NULL(s);
1729  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1730  FAIL_IF_NULL(s);
1731 
1732  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1733  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09();
1734  FAIL_IF_NULL(g_ut_threshold_fp);
1736 
1738  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1739 
1740  p->ts = TimeGet();
1741 
1742  int alerts10 = 0;
1743  int alerts11 = 0;
1744  int alerts12 = 0;
1745 
1746  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1747  alerts10 += PacketAlertCheck(p, 10);
1748  alerts11 += PacketAlertCheck(p, 11);
1749  alerts12 += PacketAlertCheck(p, 12);
1750  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1751  alerts10 += PacketAlertCheck(p, 10);
1752  alerts11 += PacketAlertCheck(p, 11);
1753  alerts12 += PacketAlertCheck(p, 12);
1754  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1755  alerts10 += PacketAlertCheck(p, 10);
1756  alerts11 += PacketAlertCheck(p, 11);
1757  alerts12 += PacketAlertCheck(p, 12);
1758  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1759  alerts10 += PacketAlertCheck(p, 10);
1760  alerts11 += PacketAlertCheck(p, 11);
1761  alerts12 += PacketAlertCheck(p, 12);
1762  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1763  alerts10 += PacketAlertCheck(p, 10);
1764  alerts11 += PacketAlertCheck(p, 11);
1765  alerts12 += PacketAlertCheck(p, 12);
1766 
1767  TimeSetIncrementTime(100);
1768  p->ts = TimeGet();
1769 
1770  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1771  alerts10 += PacketAlertCheck(p, 10);
1772  alerts11 += PacketAlertCheck(p, 11);
1773 
1775  p->ts = TimeGet();
1776 
1777  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1778  alerts10 += PacketAlertCheck(p, 10);
1779  alerts11 += PacketAlertCheck(p, 11);
1780  alerts12 += PacketAlertCheck(p, 12);
1781  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1782  alerts10 += PacketAlertCheck(p, 10);
1783  alerts11 += PacketAlertCheck(p, 11);
1784  alerts12 += PacketAlertCheck(p, 12);
1785  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1786  alerts10 += PacketAlertCheck(p, 10);
1787  alerts11 += PacketAlertCheck(p, 11);
1788  alerts12 += PacketAlertCheck(p, 12);
1789  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1790  alerts10 += PacketAlertCheck(p, 10);
1791  alerts11 += PacketAlertCheck(p, 11);
1792  alerts12 += PacketAlertCheck(p, 12);
1793 
1794  FAIL_IF_NOT(alerts10 == 4);
1795  /* One on the first interval, another on the second */
1796  FAIL_IF_NOT(alerts11 == 2);
1797  FAIL_IF_NOT(alerts12 == 2);
1798 
1799  UTHFreePacket(p);
1800  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1802  ThresholdDestroy();
1803  PASS;
1804 }
1805 
1806 /**
1807  * \test Check if the rate_filter rules work
1808  *
1809  * \retval 1 on success
1810  * \retval 0 on failure
1811  */
1812 static int SCThresholdConfTest12(void)
1813 {
1814  ThresholdInit();
1815 
1816  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1817  FAIL_IF_NULL(p);
1818 
1819  ThreadVars th_v;
1820  memset(&th_v, 0, sizeof(th_v));
1821 
1824  de_ctx->flags |= DE_QUIET;
1825  DetectEngineThreadCtx *det_ctx = NULL;
1826 
1828  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1829  FAIL_IF_NULL(s);
1831  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1832  FAIL_IF_NULL(s);
1834  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1835  FAIL_IF_NULL(s);
1836 
1837  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1838  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10();
1839  FAIL_IF_NULL(g_ut_threshold_fp);
1841 
1843  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1844 
1845  p->ts = TimeGet();
1846 
1847  int alerts10 = 0;
1848  int alerts11 = 0;
1849  int alerts12 = 0;
1850 
1851  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1852  alerts10 += PacketAlertCheck(p, 10);
1853  alerts11 += PacketAlertCheck(p, 11);
1854  alerts12 += PacketAlertCheck(p, 12);
1855  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1856  alerts10 += PacketAlertCheck(p, 10);
1857  alerts11 += PacketAlertCheck(p, 11);
1858  alerts12 += PacketAlertCheck(p, 12);
1859  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1860  alerts10 += PacketAlertCheck(p, 10);
1861  alerts11 += PacketAlertCheck(p, 11);
1862  alerts12 += PacketAlertCheck(p, 12);
1863  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1864  alerts10 += PacketAlertCheck(p, 10);
1865  alerts11 += PacketAlertCheck(p, 11);
1866  alerts12 += PacketAlertCheck(p, 12);
1867  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1868  alerts10 += PacketAlertCheck(p, 10);
1869  alerts11 += PacketAlertCheck(p, 11);
1870  alerts12 += PacketAlertCheck(p, 12);
1871 
1872  TimeSetIncrementTime(100);
1873  p->ts = TimeGet();
1874 
1875  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1876  alerts10 += PacketAlertCheck(p, 10);
1877  alerts11 += PacketAlertCheck(p, 11);
1878 
1880  p->ts = TimeGet();
1881 
1882  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1883  alerts10 += PacketAlertCheck(p, 10);
1884  alerts11 += PacketAlertCheck(p, 11);
1885  alerts12 += PacketAlertCheck(p, 12);
1886  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1887  alerts10 += PacketAlertCheck(p, 10);
1888  alerts11 += PacketAlertCheck(p, 11);
1889  alerts12 += PacketAlertCheck(p, 12);
1890  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1891  alerts10 += PacketAlertCheck(p, 10);
1892  alerts11 += PacketAlertCheck(p, 11);
1893  alerts12 += PacketAlertCheck(p, 12);
1894  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1895  alerts10 += PacketAlertCheck(p, 10);
1896  alerts11 += PacketAlertCheck(p, 11);
1897  alerts12 += PacketAlertCheck(p, 12);
1898 
1899  FAIL_IF_NOT(alerts10 == 10);
1900  /* One on the first interval, another on the second */
1901  FAIL_IF_NOT(alerts11 == 1);
1902  FAIL_IF_NOT(alerts12 == 1);
1903 
1904  UTHFreePacket(p);
1905  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1907  ThresholdDestroy();
1908  PASS;
1909 }
1910 
1911 /**
1912  * \test Check if the threshold file is loaded and well parsed
1913  *
1914  * \retval 1 on success
1915  * \retval 0 on failure
1916  */
1917 static int SCThresholdConfTest13(void)
1918 {
1921  de_ctx->flags |= DE_QUIET;
1922 
1924  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1925  FAIL_IF_NULL(sig);
1926 
1927  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1928  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1929  FAIL_IF_NULL(g_ut_threshold_fp);
1931 
1934  FAIL_IF_NULL(m);
1935 
1937  FAIL_IF_NULL(de);
1938  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
1939 
1941  PASS;
1942 }
1943 
1944 /**
1945  * \test Check if the suppress rules work
1946  *
1947  * \retval 1 on success
1948  * \retval 0 on failure
1949  */
1950 static int SCThresholdConfTest14(void)
1951 {
1952  ThresholdInit();
1953 
1954  Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
1955  "192.168.0.100", 1234, 24);
1956  FAIL_IF_NULL(p1);
1957  Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
1958  "192.168.0.100", 1234, 24);
1959  FAIL_IF_NULL(p2);
1960 
1961  DetectEngineThreadCtx *det_ctx = NULL;
1964  de_ctx->flags |= DE_QUIET;
1965 
1967  "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)");
1968  FAIL_IF_NULL(sig);
1970  "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)");
1971  FAIL_IF_NULL(sig);
1973  "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)");
1974  FAIL_IF_NULL(sig);
1975 
1976  ThreadVars th_v;
1977  memset(&th_v, 0, sizeof(th_v));
1978 
1979  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1980  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1981  FAIL_IF_NULL(g_ut_threshold_fp);
1983 
1985  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1986 
1987  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1988  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1989 
1990  FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0);
1991  FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1);
1992  FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1);
1993  FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0);
1994 
1995  UTHFreePacket(p1);
1996  UTHFreePacket(p2);
1997 
1998  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2000 
2001  ThresholdDestroy();
2002  PASS;
2003 }
2004 
2005 /**
2006  * \test Check if the suppress rules work
2007  *
2008  * \retval 1 on success
2009  * \retval 0 on failure
2010  */
2011 static int SCThresholdConfTest15(void)
2012 {
2013  ThresholdInit();
2014 
2015  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2016  "192.168.0.100", 1234, 24);
2017  FAIL_IF_NULL(p);
2018 
2019  ThreadVars th_v;
2020  memset(&th_v, 0, sizeof(th_v));
2021 
2022  DetectEngineThreadCtx *det_ctx = NULL;
2025  de_ctx->flags |= DE_QUIET;
2026 
2028  "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)");
2029  FAIL_IF_NULL(sig);
2030 
2031  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2032  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2033  FAIL_IF_NULL(g_ut_threshold_fp);
2035 
2037  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2038 
2039  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2040 
2041  /* 10000 shouldn't match */
2042  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2043  /* however, it should have set the drop flag */
2044  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2045 
2046  UTHFreePacket(p);
2047  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2049  ThresholdDestroy();
2050  PASS;
2051 }
2052 
2053 /**
2054  * \test Check if the suppress rules work
2055  *
2056  * \retval 1 on success
2057  * \retval 0 on failure
2058  */
2059 static int SCThresholdConfTest16(void)
2060 {
2061  ThresholdInit();
2062 
2063  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
2064  "192.168.0.100", 1234, 24);
2065  FAIL_IF_NULL(p);
2066 
2067  ThreadVars th_v;
2068  memset(&th_v, 0, sizeof(th_v));
2069 
2070  DetectEngineThreadCtx *det_ctx = NULL;
2073  de_ctx->flags |= DE_QUIET;
2074 
2076  "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)");
2077  FAIL_IF_NULL(sig);
2078 
2079  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2080  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2081  FAIL_IF_NULL(g_ut_threshold_fp);
2083 
2085  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2086 
2087  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2088 
2089  FAIL_IF(PacketAlertCheck(p, 1000) != 0);
2090  /* however, it should have set the drop flag */
2091  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2092 
2093  UTHFreePacket(p);
2094  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2096  ThresholdDestroy();
2097  PASS;
2098 }
2099 
2100 /**
2101  * \test Check if the suppress rules work - ip only rule
2102  *
2103  * \retval 1 on success
2104  * \retval 0 on failure
2105  */
2106 static int SCThresholdConfTest17(void)
2107 {
2108  ThresholdInit();
2109 
2110  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2111  "192.168.0.100", 1234, 24);
2112  FAIL_IF_NULL(p);
2113 
2114  ThreadVars th_v;
2115  memset(&th_v, 0, sizeof(th_v));
2116 
2117  DetectEngineThreadCtx *det_ctx = NULL;
2120  de_ctx->flags |= DE_QUIET;
2121 
2123  "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)");
2124  FAIL_IF_NULL(sig);
2125 
2126  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2127  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2128  FAIL_IF_NULL(g_ut_threshold_fp);
2130 
2132  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2133 
2134  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2135 
2136  /* 10000 shouldn't match */
2137  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2138  /* however, it should have set the drop flag */
2139  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2140 
2141  UTHFreePacket(p);
2142  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2144  ThresholdDestroy();
2145  PASS;
2146 }
2147 
2148 /**
2149  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2150  *
2151  * \retval fd Pointer to file descriptor.
2152  */
2153 static FILE *SCThresholdConfGenerateInvalidDummyFD12(void)
2154 {
2155  FILE *fd = NULL;
2156  const char *buffer =
2157  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"
2158  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n";
2159 
2160  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2161  if (fd == NULL)
2162  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2163 
2164  return fd;
2165 }
2166 
2167 /**
2168  * \test Check if the suppress rule parsing handles errors correctly
2169  *
2170  * \retval 1 on success
2171  * \retval 0 on failure
2172  */
2173 static int SCThresholdConfTest18(void)
2174 {
2175  ThresholdInit();
2178  de_ctx->flags |= DE_QUIET;
2179 
2181  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2182  FAIL_IF_NULL(s);
2183  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2184  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12();
2185  FAIL_IF_NULL(g_ut_threshold_fp);
2188 
2192  FAIL_IF_NULL(de);
2193  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2194 
2196  ThresholdDestroy();
2197  PASS;
2198 }
2199 
2200 /**
2201  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2202  *
2203  * \retval fd Pointer to file descriptor.
2204  */
2205 static FILE *SCThresholdConfGenerateInvalidDummyFD13(void)
2206 {
2207  FILE *fd = NULL;
2208  const char *buffer =
2209  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"
2210  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n";
2211 
2212  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2213  if (fd == NULL)
2214  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2215 
2216  return fd;
2217 }
2218 
2219 /**
2220  * \test Check if the suppress rule parsing handles errors correctly
2221  *
2222  * \retval 1 on success
2223  * \retval 0 on failure
2224  */
2225 static int SCThresholdConfTest19(void)
2226 {
2227  ThresholdInit();
2230  de_ctx->flags |= DE_QUIET;
2232  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2233  FAIL_IF_NULL(s);
2234  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2235  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13();
2236  FAIL_IF_NULL(g_ut_threshold_fp);
2242  FAIL_IF_NULL(de);
2243  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2245  ThresholdDestroy();
2246  PASS;
2247 }
2248 
2249 /**
2250  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2251  *
2252  * \retval fd Pointer to file descriptor.
2253  */
2254 static FILE *SCThresholdConfGenerateValidDummyFD20(void)
2255 {
2256  FILE *fd = NULL;
2257  const char *buffer =
2258  "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n"
2259  "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n"
2260  "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
2261 
2262  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2263  if (fd == NULL)
2264  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2265 
2266  return fd;
2267 }
2268 
2269 /**
2270  * \test Check if the threshold file is loaded and well parsed
2271  *
2272  * \retval 1 on success
2273  * \retval 0 on failure
2274  */
2275 static int SCThresholdConfTest20(void)
2276 {
2277  ThresholdInit();
2280  de_ctx->flags |= DE_QUIET;
2282  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)");
2283  FAIL_IF_NULL(s);
2284  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2285  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2286  FAIL_IF_NULL(g_ut_threshold_fp);
2290 
2293  FAIL_IF_NULL(de);
2294  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2295  FAIL_IF(smd->is_last);
2296 
2297  smd++;
2298  de = (DetectThresholdData *)smd->ctx;
2299  FAIL_IF_NULL(de);
2300  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2301  FAIL_IF(smd->is_last);
2302 
2303  smd++;
2304  de = (DetectThresholdData *)smd->ctx;
2305  FAIL_IF_NULL(de);
2306  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2307  FAIL_IF_NOT(smd->is_last);
2308 
2310  ThresholdDestroy();
2311  PASS;
2312 }
2313 
2314 /**
2315  * \test Check if the threshold file is loaded and well parsed, and applied
2316  * correctly to a rule with thresholding
2317  *
2318  * \retval 1 on success
2319  * \retval 0 on failure
2320  */
2321 static int SCThresholdConfTest21(void)
2322 {
2323  ThresholdInit();
2326  de_ctx->flags |= DE_QUIET;
2328  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
2329  FAIL_IF_NULL(s);
2330  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2331  FAIL_IF_NULL(g_ut_threshold_fp);
2335 
2338  FAIL_IF_NULL(de);
2339  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2340  FAIL_IF(smd->is_last);
2341 
2342  smd++;
2343  de = (DetectThresholdData *)smd->ctx;
2344  FAIL_IF_NULL(de);
2345  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2346  FAIL_IF(smd->is_last);
2347 
2348  smd++;
2349  de = (DetectThresholdData *)smd->ctx;
2350  FAIL_IF_NULL(de);
2351  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2352  FAIL_IF_NOT(smd->is_last);
2353 
2355  ThresholdDestroy();
2356  PASS;
2357 }
2358 
2359 /**
2360 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2361 *
2362 * \retval fd Pointer to file descriptor.
2363 */
2364 static FILE *SCThresholdConfGenerateValidDummyFD22(void)
2365 {
2366  FILE *fd = NULL;
2367  const char *buffer =
2368  "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, new_action drop, timeout 6\n";
2369 
2370  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2371  if (fd == NULL)
2372  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2373 
2374  return fd;
2375 }
2376 
2377 /**
2378  * \test Check if the rate_filter rules work with track by_both
2379  *
2380  * \retval 1 on success
2381  * \retval 0 on failure
2382  */
2383 static int SCThresholdConfTest22(void)
2384 {
2385  ThreadVars th_v;
2386  memset(&th_v, 0, sizeof(th_v));
2387 
2388  ThresholdInit();
2389 
2390  /* This packet will cause rate_filter */
2391  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2392  FAIL_IF_NULL(p1);
2393 
2394  /* Should not be filtered for different destination */
2395  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2");
2396  FAIL_IF_NULL(p2);
2397 
2398  /* Should not be filtered when both src and dst the same */
2399  Packet *p3 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1");
2400  FAIL_IF_NULL(p3);
2401 
2402  DetectEngineThreadCtx *det_ctx = NULL;
2403 
2406  de_ctx->flags |= DE_QUIET;
2407 
2409  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2410  FAIL_IF_NULL(sig);
2411 
2412  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2413  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22();
2414  FAIL_IF_NULL(g_ut_threshold_fp);
2416 
2418  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2419 
2420  p1->ts = TimeGet();
2421  p2->ts = p3->ts = p1->ts;
2422 
2423  /* All should be alerted, none dropped */
2424  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2425  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2426  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2427 
2428  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2429  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2430  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2431 
2432  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2433  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2434  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2435 
2436  p1->action = p2->action = p3->action = 0;
2437 
2439  p1->ts = TimeGet();
2440  p2->ts = p3->ts = p1->ts;
2441 
2442  /* p1 still shouldn't be dropped after 2nd alert */
2443  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2444  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2445  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2446 
2447  p1->action = 0;
2448 
2450  p1->ts = TimeGet();
2451  p2->ts = p3->ts = p1->ts;
2452 
2453  /* All should be alerted, only p1 must be dropped due to rate_filter*/
2454  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2455  FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
2456  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2457 
2458  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2459  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2460  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2461 
2462  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2463  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2464  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2465 
2466  p1->action = p2->action = p3->action = 0;
2467 
2469  p1->ts = TimeGet();
2470  p2->ts = p3->ts = p1->ts;
2471 
2472  /* All should be alerted, none dropped (because timeout expired) */
2473  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2474  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2475  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2476 
2477  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2478  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2479  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2480 
2481  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2482  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2483  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2484 
2485  UTHFreePacket(p3);
2486  UTHFreePacket(p2);
2487  UTHFreePacket(p1);
2488 
2489  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2491  ThresholdDestroy();
2492  PASS;
2493 }
2494 
2495 /**
2496 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2497 *
2498 * \retval fd Pointer to file descriptor.
2499 */
2500 static FILE *SCThresholdConfGenerateValidDummyFD23(void)
2501 {
2502  FILE *fd = NULL;
2503  const char *buffer =
2504  "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, new_action drop, timeout 6\n";
2505 
2506  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2507  if (fd == NULL)
2508  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2509 
2510  return fd;
2511 }
2512 
2513 /**
2514  * \test Check if the rate_filter by_both work when similar packets
2515  * going in opposite direction
2516  *
2517  * \retval 1 on success
2518  * \retval 0 on failure
2519  */
2520 static int SCThresholdConfTest23(void)
2521 {
2522  ThreadVars th_v;
2523  memset(&th_v, 0, sizeof(th_v));
2524 
2525  ThresholdInit();
2526 
2527  /* Create two packets between same addresses in opposite direction */
2528  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2529  FAIL_IF_NULL(p1);
2530 
2531  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1");
2532  FAIL_IF_NULL(p2);
2533 
2534  DetectEngineThreadCtx *det_ctx = NULL;
2535 
2538  de_ctx->flags |= DE_QUIET;
2539 
2541  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2542  FAIL_IF_NULL(sig);
2543 
2544  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2545  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23();
2546  FAIL_IF_NULL(g_ut_threshold_fp);
2548 
2550  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2551 
2552  p1->ts = TimeGet();
2553  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2554  /* First packet should be alerted, not dropped */
2555  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2556  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2557 
2559  p2->ts = TimeGet();
2560  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2561 
2562  /* Second packet should be dropped because it considered as "the same pair"
2563  and rate_filter count reached*/
2564  FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
2565  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2566 
2567  UTHFreePacket(p2);
2568  UTHFreePacket(p1);
2569 
2570  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2572  ThresholdDestroy();
2573  PASS;
2574 }
2575 #endif /* UNITTESTS */
2576 
2577 /**
2578  * \brief This function registers unit tests for Classification Config API.
2579  */
2581 {
2582 #ifdef UNITTESTS
2583  UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01);
2584  UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02);
2585  UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03);
2586  UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04);
2587  UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05);
2588  UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06);
2589  UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07);
2590  UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08);
2591  UtRegisterTest("SCThresholdConfTest09 - rate_filter",
2592  SCThresholdConfTest09);
2593  UtRegisterTest("SCThresholdConfTest10 - rate_filter",
2594  SCThresholdConfTest10);
2595  UtRegisterTest("SCThresholdConfTest11 - event_filter",
2596  SCThresholdConfTest11);
2597  UtRegisterTest("SCThresholdConfTest12 - event_filter",
2598  SCThresholdConfTest12);
2599  UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13);
2600  UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14);
2601  UtRegisterTest("SCThresholdConfTest15 - suppress drop",
2602  SCThresholdConfTest15);
2603  UtRegisterTest("SCThresholdConfTest16 - suppress drop",
2604  SCThresholdConfTest16);
2605  UtRegisterTest("SCThresholdConfTest17 - suppress drop",
2606  SCThresholdConfTest17);
2607 
2608  UtRegisterTest("SCThresholdConfTest18 - suppress parsing",
2609  SCThresholdConfTest18);
2610  UtRegisterTest("SCThresholdConfTest19 - suppress parsing",
2611  SCThresholdConfTest19);
2612  UtRegisterTest("SCThresholdConfTest20 - suppress parsing",
2613  SCThresholdConfTest20);
2614  UtRegisterTest("SCThresholdConfTest21 - suppress parsing",
2615  SCThresholdConfTest21);
2616  UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both",
2617  SCThresholdConfTest22);
2618  UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite",
2619  SCThresholdConfTest23);
2620 
2621 #endif /* UNITTESTS */
2622 }
2623 
2624 /**
2625  * @}
2626  */
TRACK_BOTH
#define TRACK_BOTH
Definition: detect-threshold.h:39
util-byte.h
DetectThresholdData_::timeout
uint32_t timeout
Definition: detect-threshold.h:61
host.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
ippair.h
detect-engine.h
SigMatchRemoveSMFromList
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
Definition: detect-parse.c:530
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SCRunmodeGet
int SCRunmodeGet(void)
Get the current run mode.
Definition: suricata.c:260
DetectAddressParse
int DetectAddressParse(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, const char *str)
Parses an address group sent as a character string and updates the DetectAddressHead sent as the argu...
Definition: detect-engine-address.c:1394
util-fmemopen.h
SigMatchFree
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:337
DetectParseRegex
Definition: detect-parse.h:62
Signature_::num
SigIntId num
Definition: detect.h:615
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
DETECT_SUPPRESS_REGEX
#define DETECT_SUPPRESS_REGEX
Definition: util-threshold-config.c:86
SigMatchData_::is_last
bool is_last
Definition: detect.h:360
DetectAddressHeadCleanup
void DetectAddressHeadCleanup(DetectAddressHead *gh)
Cleans a DetectAddressHead. The functions frees the address group heads(ipv4 and ipv6) inside the Det...
Definition: detect-engine-address.c:1476
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:267
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:141
DetectThresholdData_::count
uint32_t count
Definition: detect-threshold.h:56
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:361
action-globals.h
Packet_::action
uint8_t action
Definition: decode.h:578
DetectSetupPCRE2
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
Definition: detect-parse.c:2721
DETECT_SM_LIST_THRESHOLD
@ DETECT_SM_LIST_THRESHOLD
Definition: detect.h:130
UTHBuildPacketSrcDst
Packet * UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst)
UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs and defaulting ports.
Definition: util-unittest-helper.c:400
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:843
TYPE_LIMIT
#define TYPE_LIMIT
Definition: detect-threshold.h:27
TH_ACTION_SDROP
#define TH_ACTION_SDROP
Definition: detect-threshold.h:47
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2623
TRACK_DST
#define TRACK_DST
Definition: detect-detection-filter.c:43
DetectThresholdData_::new_action
uint8_t new_action
Definition: detect-threshold.h:60
DE_QUIET
#define DE_QUIET
Definition: detect.h:323
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:359
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1950
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:656
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:2645
m
SCMutex m
Definition: flow-hash.h:6
SCFmemopen
#define SCFmemopen
Definition: util-fmemopen.h:52
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:2591
SCThresholdConfInitContext
int SCThresholdConfInitContext(DetectEngineCtx *de_ctx)
Inits the context to be used by the Threshold Config parsing API.
Definition: util-threshold-config.c:169
UTHBuildPacketReal
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
Definition: util-unittest-helper.c:260
SigMatchData_
Data needed for Match()
Definition: detect.h:358
SCThresholdConfGlobalInit
void SCThresholdConfGlobalInit(void)
Definition: util-threshold-config.c:102
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:589
util-unittest.h
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
DetectThresholdData_::type
uint8_t type
Definition: detect-threshold.h:58
DetectGetLastSMByListId
SigMatch * DetectGetLastSMByListId(const Signature *s, int list_id,...)
Returns the sm with the largest index (added last) from the list passed to us as an id.
Definition: detect-parse.c:701
DETECT_BASE_REGEX
#define DETECT_BASE_REGEX
Definition: util-threshold-config.c:67
Signature_::gid
uint32_t gid
Definition: detect.h:639
Signature_::next
struct Signature_ * next
Definition: detect.h:675
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
TRACK_RULE
#define TRACK_RULE
Definition: detect-threshold.h:37
THRESHOLD_TYPE_RATE
@ THRESHOLD_TYPE_RATE
Definition: util-threshold-config.c:57
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
TRACK_FLOW
#define TRACK_FLOW
Definition: detect-threshold.h:40
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
TYPE_RATE
#define TYPE_RATE
Definition: detect-threshold.h:31
RUNMODE_CONF_TEST
@ RUNMODE_CONF_TEST
Definition: runmodes.h:52
DetectEngineThreadCtx_
Definition: detect.h:1098
Packet_::ts
SCTime_t ts
Definition: decode.h:524
DETECT_THRESHOLD
@ DETECT_THRESHOLD
Definition: detect-engine-register.h:61
SigFindSignatureBySidGid
Signature * SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint32_t gid)
Find a specific signature by sid and gid.
Definition: detect-engine-build.c:79
de
uint8_t de
Definition: app-layer-htp.c:563
TH_ACTION_PASS
#define TH_ACTION_PASS
Definition: detect-threshold.h:45
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3365
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
util-time.h
ThresholdDestroy
void ThresholdDestroy(void)
Definition: detect-engine-threshold.c:71
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
TYPE_BOTH
#define TYPE_BOTH
Definition: detect-threshold.h:28
Signature_::action
uint8_t action
Definition: detect.h:618
TimeSetIncrementTime
void TimeSetIncrementTime(uint32_t tv_sec)
increment the time in the engine
Definition: util-time.c:180
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:476
detect-engine-build.h
TimeGet
SCTime_t TimeGet(void)
Definition: util-time.c:152
TRACK_EITHER
#define TRACK_EITHER
Definition: detect-threshold.h:38
detect-engine-alert.h
conf.h
ThresholdRuleType
ThresholdRuleType
Definition: util-threshold-config.c:54
THRESHOLD_TYPE_EVENT_FILTER
@ THRESHOLD_TYPE_EVENT_FILTER
Definition: util-threshold-config.c:55
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2145
DetectThresholdData_::track
uint8_t track
Definition: detect-threshold.h:59
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:965
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:344
TH_ACTION_REJECT
#define TH_ACTION_REJECT
Definition: detect-threshold.h:48
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
TH_ACTION_LOG
#define TH_ACTION_LOG
Definition: detect-threshold.h:46
suricata-common.h
DetectThresholdData_
Definition: detect-threshold.h:55
TYPE_SUPPRESS
#define TYPE_SUPPRESS
Definition: detect-threshold.h:32
packet.h
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3592
TH_ACTION_DROP
#define TH_ACTION_DROP
Definition: detect-threshold.h:44
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:851
TYPE_THRESHOLD
#define TYPE_THRESHOLD
Definition: detect-threshold.h:29
DETECT_DETECTION_FILTER
@ DETECT_DETECTION_FILTER
Definition: detect-engine-register.h:121
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
UTHFreePacket
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:467
Signature_::id
uint32_t id
Definition: detect.h:638
detect-parse.h
Signature_
Signature container.
Definition: detect.h:603
SigMatch_
a single match condition for a signature
Definition: detect.h:349
THRESHOLD_CONF_DEF_CONF_FILEPATH
#define THRESHOLD_CONF_DEF_CONF_FILEPATH
Definition: util-threshold-config.c:92
detect-threshold.h
SCThresholdConfRegisterTests
void SCThresholdConfRegisterTests(void)
This function registers unit tests for Classification Config API.
Definition: util-threshold-config.c:2580
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2584
TRACK_SRC
#define TRACK_SRC
Definition: detect-detection-filter.c:44
SigMatchAppendSMToList
SigMatch * SigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:437
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:845
DetectThresholdData_::seconds
uint32_t seconds
Definition: detect-threshold.h:57
THRESHOLD_TYPE_THRESHOLD
@ THRESHOLD_TYPE_THRESHOLD
Definition: util-threshold-config.c:56
THRESHOLD_TYPE_SUPPRESS
@ THRESHOLD_TYPE_SUPPRESS
Definition: util-threshold-config.c:58
SCThresholdConfParseFile
int SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fp)
Parses the Threshold Config file.
Definition: util-threshold-config.c:983
DETECT_THRESHOLD_REGEX
#define DETECT_THRESHOLD_REGEX
Definition: util-threshold-config.c:69
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::tenant_id
uint32_t tenant_id
Definition: detect.h:849
DetectThresholdDataCopy
DetectThresholdData * DetectThresholdDataCopy(DetectThresholdData *de)
Make a deep-copy of an extant DetectTHresholdData object.
Definition: detect-threshold.c:343
ThresholdInit
void ThresholdInit(void)
Definition: detect-engine-threshold.c:66
DETECT_SM_LIST_SUPPRESS
@ DETECT_SM_LIST_SUPPRESS
Definition: detect.h:129
detect-engine-address.h
util-threshold-config.h
detect-engine-threshold.h
DETECT_RATE_REGEX
#define DETECT_RATE_REGEX
Definition: util-threshold-config.c:75
DetectThresholdData_::addrs
DetectAddressHead addrs
Definition: detect-threshold.h:64