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  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) {
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 (SCSigMatchAppendSMToList(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) {
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  size_t len = strlen(line);
961 
962  while (line < rline + len && *line != '\n') {
963  /* we have a comment */
964  if (*line == '\\')
965  flag = (int)(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 
1425  PASS;
1426 }
1427 
1428 /**
1429  * \test Check if the threshold file is loaded and well parsed
1430  *
1431  * \retval 1 on success
1432  * \retval 0 on failure
1433  */
1434 static int SCThresholdConfTest06(void)
1435 {
1438  de_ctx->flags |= DE_QUIET;
1439 
1441  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1442  FAIL_IF_NULL(sig);
1443 
1444  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1445  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04();
1446  FAIL_IF_NULL(g_ut_threshold_fp);
1448 
1450  DETECT_THRESHOLD, -1);
1451  FAIL_IF_NULL(m);
1452 
1454  FAIL_IF_NULL(de);
1455  FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1456 
1458  PASS;
1459 }
1460 
1461 /**
1462  * \test Check if the rate_filter rules are loaded and well parsed
1463  *
1464  * \retval 1 on success
1465  * \retval 0 on failure
1466  */
1467 static int SCThresholdConfTest07(void)
1468 {
1471  de_ctx->flags |= DE_QUIET;
1472 
1474  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1475  FAIL_IF_NULL(sig);
1476 
1477  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1478  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05();
1479  FAIL_IF_NULL(g_ut_threshold_fp);
1481 
1484  FAIL_IF_NULL(m);
1485 
1487  FAIL_IF_NULL(de);
1488  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1489 
1491  PASS;
1492 }
1493 
1494 /**
1495  * \test Check if the rate_filter rules are loaded and well parsed
1496  * with multilines
1497  *
1498  * \retval 1 on success
1499  * \retval 0 on failure
1500  */
1501 static int SCThresholdConfTest08(void)
1502 {
1505  de_ctx->flags |= DE_QUIET;
1506 
1508  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1509  FAIL_IF_NULL(sig);
1510 
1511  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1512  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06();
1513  FAIL_IF_NULL(g_ut_threshold_fp);
1515 
1518  FAIL_IF_NULL(m);
1519 
1521  FAIL_IF_NULL(de);
1522  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1523 
1525  PASS;
1526 }
1527 
1528 /**
1529  * \test Check if the rate_filter rules work
1530  *
1531  * \retval 1 on success
1532  * \retval 0 on failure
1533  */
1534 static int SCThresholdConfTest09(void)
1535 {
1536  ThreadVars th_v;
1537  memset(&th_v, 0, sizeof(th_v));
1538 
1539  ThresholdInit();
1540 
1541  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1542  FAIL_IF_NULL(p);
1543 
1544  DetectEngineThreadCtx *det_ctx = NULL;
1545 
1548  de_ctx->flags |= DE_QUIET;
1549 
1551  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1552  FAIL_IF_NULL(s);
1553 
1554  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1555  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07();
1556  FAIL_IF_NULL(g_ut_threshold_fp);
1558 
1560  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1561 
1562  p->ts = TimeGet();
1563  p->alerts.cnt = 0;
1564  p->action = 0;
1565  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1566  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1567  p->alerts.cnt = 0;
1568  p->action = 0;
1569  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1570  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1571  p->alerts.cnt = 0;
1572  p->action = 0;
1573  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1574  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1575 
1577  p->ts = TimeGet();
1578 
1579  p->alerts.cnt = 0;
1580  p->action = 0;
1581  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1582  FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1583 
1585  p->ts = TimeGet();
1586 
1587  p->alerts.cnt = 0;
1588  p->action = 0;
1589  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1590  FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP)));
1591 
1593  p->ts = TimeGet();
1594 
1595  p->alerts.cnt = 0;
1596  p->action = 0;
1597  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1598  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1599 
1600  p->alerts.cnt = 0;
1601  p->action = 0;
1602  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1603  FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP));
1604 
1605  UTHFreePacket(p);
1606  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1608  ThresholdDestroy();
1609  StatsThreadCleanup(&th_v);
1610  PASS;
1611 }
1612 
1613 /**
1614  * \test Check if the rate_filter rules work with track by_rule
1615  *
1616  * \retval 1 on success
1617  * \retval 0 on failure
1618  */
1619 static int SCThresholdConfTest10(void)
1620 {
1621  ThresholdInit();
1622 
1623  /* Create two different packets falling to the same rule, and
1624  * because count:3, we should drop on match #4.
1625  */
1626  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1627  "172.26.0.2", "172.26.0.11");
1628  FAIL_IF_NULL(p1);
1629  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1630  "172.26.0.1", "172.26.0.10");
1631  FAIL_IF_NULL(p2);
1632 
1633  ThreadVars th_v;
1634  memset(&th_v, 0, sizeof(th_v));
1635 
1638  de_ctx->flags |= DE_QUIET;
1639  DetectEngineThreadCtx *det_ctx = NULL;
1640 
1642  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1643  FAIL_IF_NULL(s);
1644 
1645  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1646  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08();
1647  FAIL_IF_NULL(g_ut_threshold_fp);
1649 
1651  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1652  p1->ts = TimeGet();
1653  p2->ts = p1->ts;
1654 
1655  /* All should be alerted, none dropped */
1656  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1657  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1658  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1659  p1->action = 0;
1660  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1661  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
1662  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1663  p2->action = 0;
1664  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1665  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1666  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1667  p1->action = 0;
1668 
1669  /* Match #4 should be dropped*/
1670  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1671  FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
1672  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1673  p2->action = 0;
1674 
1676  p1->ts = TimeGet();
1677 
1678  /* Still dropped because timeout not expired */
1679  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1680  FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
1681  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1682  p1->action = 0;
1683 
1685  p1->ts = TimeGet();
1686 
1687  /* Not dropped because timeout expired */
1688  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1689  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
1690  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1691 #if 0
1692  /* Ensure that a Threshold entry was installed at the sig */
1693  FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->iid]);
1694 #endif
1695  UTHFreePacket(p1);
1696  UTHFreePacket(p2);
1697  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1699  ThresholdDestroy();
1700  StatsThreadCleanup(&th_v);
1701  PASS;
1702 }
1703 
1704 /**
1705  * \test Check if the rate_filter rules work
1706  *
1707  * \retval 1 on success
1708  * \retval 0 on failure
1709  */
1710 static int SCThresholdConfTest11(void)
1711 {
1712  ThresholdInit();
1713 
1714  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1715  FAIL_IF_NULL(p);
1716 
1717  ThreadVars th_v;
1718  memset(&th_v, 0, sizeof(th_v));
1719 
1722  de_ctx->flags |= DE_QUIET;
1723  DetectEngineThreadCtx *det_ctx = NULL;
1724 
1726  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1727  FAIL_IF_NULL(s);
1729  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1730  FAIL_IF_NULL(s);
1732  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1733  FAIL_IF_NULL(s);
1734 
1735  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1736  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09();
1737  FAIL_IF_NULL(g_ut_threshold_fp);
1739 
1741  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1742 
1743  p->ts = TimeGet();
1744 
1745  int alerts10 = 0;
1746  int alerts11 = 0;
1747  int alerts12 = 0;
1748 
1749  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1750  alerts10 += PacketAlertCheck(p, 10);
1751  alerts11 += PacketAlertCheck(p, 11);
1752  alerts12 += PacketAlertCheck(p, 12);
1753  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1754  alerts10 += PacketAlertCheck(p, 10);
1755  alerts11 += PacketAlertCheck(p, 11);
1756  alerts12 += PacketAlertCheck(p, 12);
1757  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1758  alerts10 += PacketAlertCheck(p, 10);
1759  alerts11 += PacketAlertCheck(p, 11);
1760  alerts12 += PacketAlertCheck(p, 12);
1761  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1762  alerts10 += PacketAlertCheck(p, 10);
1763  alerts11 += PacketAlertCheck(p, 11);
1764  alerts12 += PacketAlertCheck(p, 12);
1765  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1766  alerts10 += PacketAlertCheck(p, 10);
1767  alerts11 += PacketAlertCheck(p, 11);
1768  alerts12 += PacketAlertCheck(p, 12);
1769 
1770  TimeSetIncrementTime(100);
1771  p->ts = TimeGet();
1772 
1773  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1774  alerts10 += PacketAlertCheck(p, 10);
1775  alerts11 += PacketAlertCheck(p, 11);
1776 
1778  p->ts = TimeGet();
1779 
1780  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1781  alerts10 += PacketAlertCheck(p, 10);
1782  alerts11 += PacketAlertCheck(p, 11);
1783  alerts12 += PacketAlertCheck(p, 12);
1784  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1785  alerts10 += PacketAlertCheck(p, 10);
1786  alerts11 += PacketAlertCheck(p, 11);
1787  alerts12 += PacketAlertCheck(p, 12);
1788  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1789  alerts10 += PacketAlertCheck(p, 10);
1790  alerts11 += PacketAlertCheck(p, 11);
1791  alerts12 += PacketAlertCheck(p, 12);
1792  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1793  alerts10 += PacketAlertCheck(p, 10);
1794  alerts11 += PacketAlertCheck(p, 11);
1795  alerts12 += PacketAlertCheck(p, 12);
1796 
1797  FAIL_IF_NOT(alerts10 == 4);
1798  /* One on the first interval, another on the second */
1799  FAIL_IF_NOT(alerts11 == 2);
1800  FAIL_IF_NOT(alerts12 == 2);
1801 
1802  UTHFreePacket(p);
1803  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1805  ThresholdDestroy();
1806  StatsThreadCleanup(&th_v);
1807  PASS;
1808 }
1809 
1810 /**
1811  * \test Check if the rate_filter rules work
1812  *
1813  * \retval 1 on success
1814  * \retval 0 on failure
1815  */
1816 static int SCThresholdConfTest12(void)
1817 {
1818  ThresholdInit();
1819 
1820  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1821  FAIL_IF_NULL(p);
1822 
1823  ThreadVars th_v;
1824  memset(&th_v, 0, sizeof(th_v));
1825 
1828  de_ctx->flags |= DE_QUIET;
1829  DetectEngineThreadCtx *det_ctx = NULL;
1830 
1832  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1833  FAIL_IF_NULL(s);
1835  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1836  FAIL_IF_NULL(s);
1838  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1839  FAIL_IF_NULL(s);
1840 
1841  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1842  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10();
1843  FAIL_IF_NULL(g_ut_threshold_fp);
1845 
1847  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1848 
1849  p->ts = TimeGet();
1850 
1851  int alerts10 = 0;
1852  int alerts11 = 0;
1853  int alerts12 = 0;
1854 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1872  alerts10 += PacketAlertCheck(p, 10);
1873  alerts11 += PacketAlertCheck(p, 11);
1874  alerts12 += PacketAlertCheck(p, 12);
1875 
1876  TimeSetIncrementTime(100);
1877  p->ts = TimeGet();
1878 
1879  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1880  alerts10 += PacketAlertCheck(p, 10);
1881  alerts11 += PacketAlertCheck(p, 11);
1882 
1884  p->ts = TimeGet();
1885 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1899  alerts10 += PacketAlertCheck(p, 10);
1900  alerts11 += PacketAlertCheck(p, 11);
1901  alerts12 += PacketAlertCheck(p, 12);
1902 
1903  FAIL_IF_NOT(alerts10 == 10);
1904  /* One on the first interval, another on the second */
1905  FAIL_IF_NOT(alerts11 == 1);
1906  FAIL_IF_NOT(alerts12 == 1);
1907 
1908  UTHFreePacket(p);
1909  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1911  ThresholdDestroy();
1912  StatsThreadCleanup(&th_v);
1913  PASS;
1914 }
1915 
1916 /**
1917  * \test Check if the threshold file is loaded and well parsed
1918  *
1919  * \retval 1 on success
1920  * \retval 0 on failure
1921  */
1922 static int SCThresholdConfTest13(void)
1923 {
1926  de_ctx->flags |= DE_QUIET;
1927 
1929  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1930  FAIL_IF_NULL(sig);
1931 
1932  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1933  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1934  FAIL_IF_NULL(g_ut_threshold_fp);
1936 
1939  FAIL_IF_NULL(m);
1940 
1942  FAIL_IF_NULL(de);
1943  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
1944 
1946  PASS;
1947 }
1948 
1949 /**
1950  * \test Check if the suppress rules work
1951  *
1952  * \retval 1 on success
1953  * \retval 0 on failure
1954  */
1955 static int SCThresholdConfTest14(void)
1956 {
1957  ThresholdInit();
1958 
1959  Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
1960  "192.168.0.100", 1234, 24);
1961  FAIL_IF_NULL(p1);
1962  Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
1963  "192.168.0.100", 1234, 24);
1964  FAIL_IF_NULL(p2);
1965 
1966  DetectEngineThreadCtx *det_ctx = NULL;
1969  de_ctx->flags |= DE_QUIET;
1970 
1972  "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)");
1973  FAIL_IF_NULL(sig);
1975  "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)");
1976  FAIL_IF_NULL(sig);
1978  "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)");
1979  FAIL_IF_NULL(sig);
1980 
1981  ThreadVars th_v;
1982  memset(&th_v, 0, sizeof(th_v));
1983 
1984  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1985  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
1986  FAIL_IF_NULL(g_ut_threshold_fp);
1988 
1990  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1991 
1992  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1993  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1994 
1995  FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0);
1996  FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1);
1997  FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1);
1998  FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0);
1999 
2000  UTHFreePacket(p1);
2001  UTHFreePacket(p2);
2002 
2003  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2005 
2006  ThresholdDestroy();
2007  StatsThreadCleanup(&th_v);
2008  PASS;
2009 }
2010 
2011 /**
2012  * \test Check if the suppress rules work
2013  *
2014  * \retval 1 on success
2015  * \retval 0 on failure
2016  */
2017 static int SCThresholdConfTest15(void)
2018 {
2019  ThresholdInit();
2020 
2021  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2022  "192.168.0.100", 1234, 24);
2023  FAIL_IF_NULL(p);
2024 
2025  ThreadVars th_v;
2026  memset(&th_v, 0, sizeof(th_v));
2027 
2028  DetectEngineThreadCtx *det_ctx = NULL;
2031  de_ctx->flags |= DE_QUIET;
2032 
2034  "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)");
2035  FAIL_IF_NULL(sig);
2036 
2037  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2038  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2039  FAIL_IF_NULL(g_ut_threshold_fp);
2041 
2043  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2044 
2045  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2046 
2047  /* 10000 shouldn't match */
2048  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2049  /* however, it should have set the drop flag */
2050  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2051 
2052  UTHFreePacket(p);
2053  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2055  ThresholdDestroy();
2056  StatsThreadCleanup(&th_v);
2057  PASS;
2058 }
2059 
2060 /**
2061  * \test Check if the suppress rules work
2062  *
2063  * \retval 1 on success
2064  * \retval 0 on failure
2065  */
2066 static int SCThresholdConfTest16(void)
2067 {
2068  ThresholdInit();
2069 
2070  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
2071  "192.168.0.100", 1234, 24);
2072  FAIL_IF_NULL(p);
2073 
2074  ThreadVars th_v;
2075  memset(&th_v, 0, sizeof(th_v));
2076 
2077  DetectEngineThreadCtx *det_ctx = NULL;
2080  de_ctx->flags |= DE_QUIET;
2081 
2083  "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)");
2084  FAIL_IF_NULL(sig);
2085 
2086  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2087  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2088  FAIL_IF_NULL(g_ut_threshold_fp);
2090 
2092  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2093 
2094  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2095 
2096  FAIL_IF(PacketAlertCheck(p, 1000) != 0);
2097  /* however, it should have set the drop flag */
2098  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2099 
2100  UTHFreePacket(p);
2101  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2103  ThresholdDestroy();
2104  StatsThreadCleanup(&th_v);
2105  PASS;
2106 }
2107 
2108 /**
2109  * \test Check if the suppress rules work - ip only rule
2110  *
2111  * \retval 1 on success
2112  * \retval 0 on failure
2113  */
2114 static int SCThresholdConfTest17(void)
2115 {
2116  ThresholdInit();
2117 
2118  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2119  "192.168.0.100", 1234, 24);
2120  FAIL_IF_NULL(p);
2121 
2122  ThreadVars th_v;
2123  memset(&th_v, 0, sizeof(th_v));
2124 
2125  DetectEngineThreadCtx *det_ctx = NULL;
2128  de_ctx->flags |= DE_QUIET;
2129 
2131  "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)");
2132  FAIL_IF_NULL(sig);
2133 
2134  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2135  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2136  FAIL_IF_NULL(g_ut_threshold_fp);
2138 
2140  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2141 
2142  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2143 
2144  /* 10000 shouldn't match */
2145  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2146  /* however, it should have set the drop flag */
2147  FAIL_IF(!(PacketTestAction(p, ACTION_DROP)));
2148 
2149  UTHFreePacket(p);
2150  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2152  ThresholdDestroy();
2153  StatsThreadCleanup(&th_v);
2154  PASS;
2155 }
2156 
2157 /**
2158  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2159  *
2160  * \retval fd Pointer to file descriptor.
2161  */
2162 static FILE *SCThresholdConfGenerateInvalidDummyFD12(void)
2163 {
2164  FILE *fd = NULL;
2165  const char *buffer =
2166  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"
2167  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n";
2168 
2169  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2170  if (fd == NULL)
2171  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2172 
2173  return fd;
2174 }
2175 
2176 /**
2177  * \test Check if the suppress rule parsing handles errors correctly
2178  *
2179  * \retval 1 on success
2180  * \retval 0 on failure
2181  */
2182 static int SCThresholdConfTest18(void)
2183 {
2184  ThresholdInit();
2187  de_ctx->flags |= DE_QUIET;
2188 
2190  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2191  FAIL_IF_NULL(s);
2192  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2193  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12();
2194  FAIL_IF_NULL(g_ut_threshold_fp);
2197 
2201  FAIL_IF_NULL(de);
2202  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2203 
2205  ThresholdDestroy();
2206  PASS;
2207 }
2208 
2209 /**
2210  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2211  *
2212  * \retval fd Pointer to file descriptor.
2213  */
2214 static FILE *SCThresholdConfGenerateInvalidDummyFD13(void)
2215 {
2216  FILE *fd = NULL;
2217  const char *buffer =
2218  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"
2219  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n";
2220 
2221  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2222  if (fd == NULL)
2223  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2224 
2225  return fd;
2226 }
2227 
2228 /**
2229  * \test Check if the suppress rule parsing handles errors correctly
2230  *
2231  * \retval 1 on success
2232  * \retval 0 on failure
2233  */
2234 static int SCThresholdConfTest19(void)
2235 {
2236  ThresholdInit();
2239  de_ctx->flags |= DE_QUIET;
2241  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2242  FAIL_IF_NULL(s);
2243  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2244  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13();
2245  FAIL_IF_NULL(g_ut_threshold_fp);
2251  FAIL_IF_NULL(de);
2252  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2254  ThresholdDestroy();
2255  PASS;
2256 }
2257 
2258 /**
2259  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2260  *
2261  * \retval fd Pointer to file descriptor.
2262  */
2263 static FILE *SCThresholdConfGenerateValidDummyFD20(void)
2264 {
2265  FILE *fd = NULL;
2266  const char *buffer =
2267  "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n"
2268  "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n"
2269  "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
2270 
2271  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2272  if (fd == NULL)
2273  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2274 
2275  return fd;
2276 }
2277 
2278 /**
2279  * \test Check if the threshold file is loaded and well parsed
2280  *
2281  * \retval 1 on success
2282  * \retval 0 on failure
2283  */
2284 static int SCThresholdConfTest20(void)
2285 {
2286  ThresholdInit();
2289  de_ctx->flags |= DE_QUIET;
2291  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)");
2292  FAIL_IF_NULL(s);
2293  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2294  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2295  FAIL_IF_NULL(g_ut_threshold_fp);
2299 
2302  FAIL_IF_NULL(de);
2303  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2304  FAIL_IF(smd->is_last);
2305 
2306  smd++;
2307  de = (DetectThresholdData *)smd->ctx;
2308  FAIL_IF_NULL(de);
2309  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2310  FAIL_IF(smd->is_last);
2311 
2312  smd++;
2313  de = (DetectThresholdData *)smd->ctx;
2314  FAIL_IF_NULL(de);
2315  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2316  FAIL_IF_NOT(smd->is_last);
2317 
2319  ThresholdDestroy();
2320  PASS;
2321 }
2322 
2323 /**
2324  * \test Check if the threshold file is loaded and well parsed, and applied
2325  * correctly to a rule with thresholding
2326  *
2327  * \retval 1 on success
2328  * \retval 0 on failure
2329  */
2330 static int SCThresholdConfTest21(void)
2331 {
2332  ThresholdInit();
2335  de_ctx->flags |= DE_QUIET;
2337  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
2338  FAIL_IF_NULL(s);
2339  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2340  FAIL_IF_NULL(g_ut_threshold_fp);
2344 
2347  FAIL_IF_NULL(de);
2348  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2349  FAIL_IF(smd->is_last);
2350 
2351  smd++;
2352  de = (DetectThresholdData *)smd->ctx;
2353  FAIL_IF_NULL(de);
2354  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2355  FAIL_IF(smd->is_last);
2356 
2357  smd++;
2358  de = (DetectThresholdData *)smd->ctx;
2359  FAIL_IF_NULL(de);
2360  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2361  FAIL_IF_NOT(smd->is_last);
2362 
2364  ThresholdDestroy();
2365  PASS;
2366 }
2367 
2368 /**
2369 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2370 *
2371 * \retval fd Pointer to file descriptor.
2372 */
2373 static FILE *SCThresholdConfGenerateValidDummyFD22(void)
2374 {
2375  FILE *fd = NULL;
2376  const char *buffer =
2377  "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, new_action drop, timeout 6\n";
2378 
2379  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2380  if (fd == NULL)
2381  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2382 
2383  return fd;
2384 }
2385 
2386 /**
2387  * \test Check if the rate_filter rules work with track by_both
2388  *
2389  * \retval 1 on success
2390  * \retval 0 on failure
2391  */
2392 static int SCThresholdConfTest22(void)
2393 {
2394  ThreadVars th_v;
2395  memset(&th_v, 0, sizeof(th_v));
2396 
2397  ThresholdInit();
2398 
2399  /* This packet will cause rate_filter */
2400  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2401  FAIL_IF_NULL(p1);
2402 
2403  /* Should not be filtered for different destination */
2404  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2");
2405  FAIL_IF_NULL(p2);
2406 
2407  /* Should not be filtered when both src and dst the same */
2408  Packet *p3 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1");
2409  FAIL_IF_NULL(p3);
2410 
2411  DetectEngineThreadCtx *det_ctx = NULL;
2412 
2415  de_ctx->flags |= DE_QUIET;
2416 
2418  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2419  FAIL_IF_NULL(sig);
2420 
2421  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2422  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22();
2423  FAIL_IF_NULL(g_ut_threshold_fp);
2425 
2427  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2428 
2429  p1->ts = TimeGet();
2430  p2->ts = p3->ts = p1->ts;
2431 
2432  /* All should be alerted, none dropped */
2433  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2434  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2435  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2436 
2437  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2438  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2439  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2440 
2441  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2442  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2443  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2444 
2445  p1->action = p2->action = p3->action = 0;
2446 
2448  p1->ts = TimeGet();
2449  p2->ts = p3->ts = p1->ts;
2450 
2451  /* p1 still shouldn't be dropped after 2nd alert */
2452  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2453  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2454  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2455 
2456  p1->action = 0;
2457 
2459  p1->ts = TimeGet();
2460  p2->ts = p3->ts = p1->ts;
2461 
2462  /* All should be alerted, only p1 must be dropped due to rate_filter*/
2463  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2464  FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP));
2465  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2466 
2467  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2468  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2469  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2470 
2471  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2472  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2473  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2474 
2475  p1->action = p2->action = p3->action = 0;
2476 
2478  p1->ts = TimeGet();
2479  p2->ts = p3->ts = p1->ts;
2480 
2481  /* All should be alerted, none dropped (because timeout expired) */
2482  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2483  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2484  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2485 
2486  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2487  FAIL_IF(PacketTestAction(p2, ACTION_DROP));
2488  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2489 
2490  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2491  FAIL_IF(PacketTestAction(p3, ACTION_DROP));
2492  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2493 
2494  UTHFreePacket(p3);
2495  UTHFreePacket(p2);
2496  UTHFreePacket(p1);
2497 
2498  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2500  ThresholdDestroy();
2501  StatsThreadCleanup(&th_v);
2502  PASS;
2503 }
2504 
2505 /**
2506 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2507 *
2508 * \retval fd Pointer to file descriptor.
2509 */
2510 static FILE *SCThresholdConfGenerateValidDummyFD23(void)
2511 {
2512  FILE *fd = NULL;
2513  const char *buffer =
2514  "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, new_action drop, timeout 6\n";
2515 
2516  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2517  if (fd == NULL)
2518  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2519 
2520  return fd;
2521 }
2522 
2523 /**
2524  * \test Check if the rate_filter by_both work when similar packets
2525  * going in opposite direction
2526  *
2527  * \retval 1 on success
2528  * \retval 0 on failure
2529  */
2530 static int SCThresholdConfTest23(void)
2531 {
2532  ThreadVars th_v;
2533  memset(&th_v, 0, sizeof(th_v));
2534 
2535  ThresholdInit();
2536 
2537  /* Create two packets between same addresses in opposite direction */
2538  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2539  FAIL_IF_NULL(p1);
2540 
2541  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1");
2542  FAIL_IF_NULL(p2);
2543 
2544  DetectEngineThreadCtx *det_ctx = NULL;
2545 
2548  de_ctx->flags |= DE_QUIET;
2549 
2551  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2552  FAIL_IF_NULL(sig);
2553 
2554  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2555  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23();
2556  FAIL_IF_NULL(g_ut_threshold_fp);
2558 
2560  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2561 
2562  p1->ts = TimeGet();
2563  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2564  /* First packet should be alerted, not dropped */
2565  FAIL_IF(PacketTestAction(p1, ACTION_DROP));
2566  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2567 
2569  p2->ts = TimeGet();
2570  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2571 
2572  /* Second packet should be dropped because it considered as "the same pair"
2573  and rate_filter count reached*/
2574  FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP));
2575  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2576 
2577  UTHFreePacket(p2);
2578  UTHFreePacket(p1);
2579 
2580  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2582  ThresholdDestroy();
2583  StatsThreadCleanup(&th_v);
2584  PASS;
2585 }
2586 #endif /* UNITTESTS */
2587 
2588 /**
2589  * \brief This function registers unit tests for Classification Config API.
2590  */
2592 {
2593 #ifdef UNITTESTS
2594  UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01);
2595  UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02);
2596  UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03);
2597  UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04);
2598  UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05);
2599  UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06);
2600  UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07);
2601  UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08);
2602  UtRegisterTest("SCThresholdConfTest09 - rate_filter",
2603  SCThresholdConfTest09);
2604  UtRegisterTest("SCThresholdConfTest10 - rate_filter",
2605  SCThresholdConfTest10);
2606  UtRegisterTest("SCThresholdConfTest11 - event_filter",
2607  SCThresholdConfTest11);
2608  UtRegisterTest("SCThresholdConfTest12 - event_filter",
2609  SCThresholdConfTest12);
2610  UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13);
2611  UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14);
2612  UtRegisterTest("SCThresholdConfTest15 - suppress drop",
2613  SCThresholdConfTest15);
2614  UtRegisterTest("SCThresholdConfTest16 - suppress drop",
2615  SCThresholdConfTest16);
2616  UtRegisterTest("SCThresholdConfTest17 - suppress drop",
2617  SCThresholdConfTest17);
2618 
2619  UtRegisterTest("SCThresholdConfTest18 - suppress parsing",
2620  SCThresholdConfTest18);
2621  UtRegisterTest("SCThresholdConfTest19 - suppress parsing",
2622  SCThresholdConfTest19);
2623  UtRegisterTest("SCThresholdConfTest20 - suppress parsing",
2624  SCThresholdConfTest20);
2625  UtRegisterTest("SCThresholdConfTest21 - suppress parsing",
2626  SCThresholdConfTest21);
2627  UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both",
2628  SCThresholdConfTest22);
2629  UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite",
2630  SCThresholdConfTest23);
2631 
2632 #endif /* UNITTESTS */
2633 }
2634 
2635 /**
2636  * @}
2637  */
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:2633
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:3360
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:316
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:3592
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:2591
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2594
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:938
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: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: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