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