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