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