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