suricata
util-threshold-config.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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 #ifndef UNITTESTS
242  FILE *fd = NULL;
243 #else
244  FILE *fd = g_ut_threshold_fp;
245  if (fd == NULL) {
246 #endif
247  filename = SCThresholdConfGetConfFilename(de_ctx);
248  if ( (fd = fopen(filename, "r")) == NULL) {
249  SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno));
250  goto error;
251  }
252 #ifdef UNITTESTS
253  }
254 #endif
255 
257  SCThresholdConfDeInitContext(de_ctx, fd);
258 
259 #ifdef UNITTESTS
260  g_ut_threshold_fp = NULL;
261 #endif
262  SCLogDebug("Global thresholding options defined");
263  return 0;
264 
265 error:
266  SCThresholdConfDeInitContext(de_ctx, fd);
267  return -1;
268 }
269 
270 /**
271  * \brief Releases resources used by the Threshold Config API.
272  *
273  * \param de_ctx Pointer to the Detection Engine Context.
274  * \param fd Pointer to file descriptor.
275  */
276 static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd)
277 {
278  if (fd != NULL)
279  fclose(fd);
280  return;
281 }
282 
283 /** \internal
284  * \brief setup suppress rules
285  * \retval 0 ok
286  * \retval -1 error
287  */
288 static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
289  uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count,
290  uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action,
291  const char *th_ip)
292 {
293  Signature *s = NULL;
294  SigMatch *sm = NULL;
295  DetectThresholdData *de = NULL;
296 
297  BUG_ON(parsed_type != TYPE_SUPPRESS);
298 
299  /* Install it */
300  if (id == 0 && gid == 0) {
301  if (parsed_track == TRACK_RULE) {
302  SCLogWarning(SC_ERR_EVENT_ENGINE, "suppressing all rules");
303  }
304 
305  /* update each sig with our suppress info */
306  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
307  /* tag the rule as noalert */
308  if (parsed_track == TRACK_RULE) {
309  s->flags |= SIG_FLAG_NOALERT;
310  continue;
311  }
312 
313  de = SCMalloc(sizeof(DetectThresholdData));
314  if (unlikely(de == NULL))
315  goto error;
316  memset(de,0,sizeof(DetectThresholdData));
317 
318  de->type = TYPE_SUPPRESS;
319  de->track = parsed_track;
320  de->count = parsed_count;
321  de->seconds = parsed_seconds;
322  de->new_action = parsed_new_action;
323  de->timeout = parsed_timeout;
324 
325  if (parsed_track != TRACK_RULE) {
326  if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) < 0) {
327  SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip);
328  goto error;
329  }
330  }
331 
332  sm = SigMatchAlloc();
333  if (sm == NULL) {
334  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
335  goto error;
336  }
337 
338  sm->type = DETECT_THRESHOLD;
339  sm->ctx = (void *)de;
341  }
342  } else if (id == 0 && gid > 0) {
343  if (parsed_track == TRACK_RULE) {
344  SCLogWarning(SC_ERR_EVENT_ENGINE, "suppressing all rules with gid %"PRIu32, gid);
345  }
346  /* set up suppression for each signature with a matching gid */
347  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
348  if (s->gid != gid)
349  continue;
350 
351  /* tag the rule as noalert */
352  if (parsed_track == TRACK_RULE) {
353  s->flags |= SIG_FLAG_NOALERT;
354  continue;
355  }
356 
357  de = SCMalloc(sizeof(DetectThresholdData));
358  if (unlikely(de == NULL))
359  goto error;
360 
361  memset(de,0,sizeof(DetectThresholdData));
362 
363  de->type = TYPE_SUPPRESS;
364  de->track = parsed_track;
365  de->count = parsed_count;
366  de->seconds = parsed_seconds;
367  de->new_action = parsed_new_action;
368  de->timeout = parsed_timeout;
369 
370  if (parsed_track != TRACK_RULE) {
371  if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) < 0) {
372  SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip);
373  goto error;
374  }
375  }
376 
377  sm = SigMatchAlloc();
378  if (sm == NULL) {
379  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
380  goto error;
381  }
382 
383  sm->type = DETECT_THRESHOLD;
384  sm->ctx = (void *)de;
385 
387  }
388  } else if (id > 0 && gid == 0) {
389  SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has "
390  "sid > 0 and gid == 0. Please fix this "
391  "in your threshold.conf file");
392  goto error;
393  } else {
394  s = SigFindSignatureBySidGid(de_ctx, id, gid);
395  if (s == NULL) {
396  SCLogWarning(SC_ERR_EVENT_ENGINE, "can't suppress sid "
397  "%"PRIu32", gid %"PRIu32": unknown rule", id, gid);
398  } else {
399  if (parsed_track == TRACK_RULE) {
400  s->flags |= SIG_FLAG_NOALERT;
401  goto end;
402  }
403 
404  de = SCMalloc(sizeof(DetectThresholdData));
405  if (unlikely(de == NULL))
406  goto error;
407  memset(de,0,sizeof(DetectThresholdData));
408 
409  de->type = TYPE_SUPPRESS;
410  de->track = parsed_track;
411  de->count = parsed_count;
412  de->seconds = parsed_seconds;
413  de->new_action = parsed_new_action;
414  de->timeout = parsed_timeout;
415 
416  if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) < 0) {
417  SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip);
418  goto error;
419  }
420 
421  sm = SigMatchAlloc();
422  if (sm == NULL) {
423  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
424  goto error;
425  }
426 
427  sm->type = DETECT_THRESHOLD;
428  sm->ctx = (void *)de;
429 
431  }
432  }
433 
434 end:
435  return 0;
436 error:
437  if (de != NULL) {
438  DetectAddressHeadCleanup(&de->addrs);
439  SCFree(de);
440  }
441  return -1;
442 }
443 
444 /** \internal
445  * \brief setup suppress rules
446  * \retval 0 ok
447  * \retval -1 error
448  */
449 static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid,
450  uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count,
451  uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action,
452  const char *th_ip)
453 {
454  Signature *s = NULL;
455  SigMatch *sm = NULL;
456  DetectThresholdData *de = NULL;
457 
458  BUG_ON(parsed_type == TYPE_SUPPRESS);
459 
460  /* Install it */
461  if (id == 0 && gid == 0) {
462  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
465  if (sm != NULL) {
466  SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has "
467  "an event var set. The signature event var is "
468  "given precedence over the threshold.conf one. "
469  "We'll change this in the future though.", s->id);
470  continue;
471  }
472 
475  if (sm != NULL) {
476  SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has "
477  "an event var set. The signature event var is "
478  "given precedence over the threshold.conf one. "
479  "We'll change this in the future though.", s->id);
480  continue;
481  }
482 
483  de = SCMalloc(sizeof(DetectThresholdData));
484  if (unlikely(de == NULL))
485  goto error;
486  memset(de,0,sizeof(DetectThresholdData));
487 
488  de->type = parsed_type;
489  de->track = parsed_track;
490  de->count = parsed_count;
491  de->seconds = parsed_seconds;
492  de->new_action = parsed_new_action;
493  de->timeout = parsed_timeout;
494 
495  sm = SigMatchAlloc();
496  if (sm == NULL) {
497  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
498  goto error;
499  }
500 
501  if (parsed_type == TYPE_RATE)
503  else
504  sm->type = DETECT_THRESHOLD;
505  sm->ctx = (void *)de;
506 
507  if (parsed_track == TRACK_RULE) {
509  }
511  }
512 
513  } else if (id == 0 && gid > 0) {
514  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
515  if (s->gid == gid) {
518  if (sm != NULL) {
519  SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has "
520  "an event var set. The signature event var is "
521  "given precedence over the threshold.conf one. "
522  "We'll change this in the future though.", id);
523  continue;
524  }
525 
526  de = SCMalloc(sizeof(DetectThresholdData));
527  if (unlikely(de == NULL))
528  goto error;
529  memset(de,0,sizeof(DetectThresholdData));
530 
531  de->type = parsed_type;
532  de->track = parsed_track;
533  de->count = parsed_count;
534  de->seconds = parsed_seconds;
535  de->new_action = parsed_new_action;
536  de->timeout = parsed_timeout;
537 
538  sm = SigMatchAlloc();
539  if (sm == NULL) {
540  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
541  goto error;
542  }
543 
544  if (parsed_type == TYPE_RATE)
546  else
547  sm->type = DETECT_THRESHOLD;
548  sm->ctx = (void *)de;
549 
550  if (parsed_track == TRACK_RULE) {
552  }
554  }
555  }
556  } else if (id > 0 && gid == 0) {
557  SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has "
558  "sid > 0 and gid == 0. Please fix this "
559  "in your threshold.conf file");
560  } else {
561  s = SigFindSignatureBySidGid(de_ctx, id, gid);
562  if (s == NULL) {
563  SCLogWarning(SC_ERR_EVENT_ENGINE, "can't suppress sid "
564  "%"PRIu32", gid %"PRIu32": unknown rule", id, gid);
565  } else {
566  if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD &&
567  parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT)
568  {
571  if (sm != NULL) {
572  SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has "
573  "a threshold set. The signature event var is "
574  "given precedence over the threshold.conf one. "
575  "Bug #425.", s->id);
576  goto end;
577  }
578 
581  if (sm != NULL) {
582  SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has "
583  "a detection_filter set. The signature event var is "
584  "given precedence over the threshold.conf one. "
585  "Bug #425.", s->id);
586  goto end;
587  }
588 
589  /* replace threshold on sig if we have a global override for it */
590  } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) {
593  if (sm != NULL) {
595  SigMatchFree(de_ctx, sm);
596  sm = NULL;
597  }
598  }
599 
600  de = SCMalloc(sizeof(DetectThresholdData));
601  if (unlikely(de == NULL))
602  goto error;
603  memset(de,0,sizeof(DetectThresholdData));
604 
605  de->type = parsed_type;
606  de->track = parsed_track;
607  de->count = parsed_count;
608  de->seconds = parsed_seconds;
609  de->new_action = parsed_new_action;
610  de->timeout = parsed_timeout;
611 
612  sm = SigMatchAlloc();
613  if (sm == NULL) {
614  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch");
615  goto error;
616  }
617 
618  if (parsed_type == TYPE_RATE)
620  else
621  sm->type = DETECT_THRESHOLD;
622  sm->ctx = (void *)de;
623 
624  if (parsed_track == TRACK_RULE) {
626  }
627 
629  }
630  }
631 end:
632  return 0;
633 error:
634  if (de != NULL) {
635  DetectAddressHeadCleanup(&de->addrs);
636  SCFree(de);
637  }
638  return -1;
639 }
640 
641 static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr,
642  uint32_t *ret_id, uint32_t *ret_gid,
643  uint8_t *ret_parsed_type, uint8_t *ret_parsed_track,
644  uint32_t *ret_parsed_count, uint32_t *ret_parsed_seconds, uint32_t *ret_parsed_timeout,
645  uint8_t *ret_parsed_new_action,
646  char **ret_th_ip)
647 {
648  char th_rule_type[32];
649  char th_gid[16];
650  char th_sid[16];
651  char rule_extend[1024];
652  char th_type[16] = "";
653  char th_track[16] = "";
654  char th_count[16] = "";
655  char th_seconds[16] = "";
656  char th_new_action[16] = "";
657  char th_timeout[16] = "";
658  char th_ip[64] = "";
659 
660  uint8_t parsed_type = 0;
661  uint8_t parsed_track = 0;
662  uint8_t parsed_new_action = 0;
663  uint32_t parsed_count = 0;
664  uint32_t parsed_seconds = 0;
665  uint32_t parsed_timeout = 0;
666 
667  int ret = 0;
668  int ov[MAX_SUBSTRINGS];
669  uint32_t id = 0, gid = 0;
670  ThresholdRuleType rule_type;
671 
672  if (de_ctx == NULL)
673  return -1;
674 
675  ret = pcre_exec(regex_base, regex_base_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
676  if (ret < 4) {
677  SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
678  goto error;
679  }
680 
681  /* retrieve the classtype name */
682  ret = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, th_rule_type, sizeof(th_rule_type));
683  if (ret < 0) {
684  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
685  goto error;
686  }
687 
688  /* retrieve the classtype name */
689  ret = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, th_gid, sizeof(th_gid));
690  if (ret < 0) {
691  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
692  goto error;
693  }
694 
695  ret = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, th_sid, sizeof(th_sid));
696  if (ret < 0) {
697  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
698  goto error;
699  }
700 
701  ret = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, rule_extend, sizeof(rule_extend));
702  if (ret < 0) {
703  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
704  goto error;
705  }
706 
707  /* get type of rule */
708  if (strcasecmp(th_rule_type,"event_filter") == 0) {
709  rule_type = THRESHOLD_TYPE_EVENT_FILTER;
710  } else if (strcasecmp(th_rule_type,"threshold") == 0) {
711  rule_type = THRESHOLD_TYPE_THRESHOLD;
712  } else if (strcasecmp(th_rule_type,"rate_filter") == 0) {
713  rule_type = THRESHOLD_TYPE_RATE;
714  } else if (strcasecmp(th_rule_type,"suppress") == 0) {
715  rule_type = THRESHOLD_TYPE_SUPPRESS;
716  } else {
717  SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type);
718  goto error;
719  }
720 
721  /* get end of rule */
722  switch(rule_type) {
725  if (strlen(rule_extend) > 0) {
726  ret = pcre_exec(regex_threshold, regex_threshold_study,
727  rule_extend, strlen(rule_extend),
728  0, 0, ov, MAX_SUBSTRINGS);
729  if (ret < 4) {
731  "pcre_exec parse error, ret %" PRId32 ", string %s",
732  ret, rule_extend);
733  goto error;
734  }
735 
736  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, th_type, sizeof(th_type));
737  if (ret < 0) {
738  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
739  goto error;
740  }
741 
742  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, th_track, sizeof(th_track));
743  if (ret < 0) {
744  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
745  goto error;
746  }
747 
748  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 3, th_count, sizeof(th_count));
749  if (ret < 0) {
750  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
751  goto error;
752  }
753 
754  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 4, th_seconds, sizeof(th_seconds));
755  if (ret < 0) {
756  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
757  goto error;
758  }
759 
760  if (strcasecmp(th_type,"limit") == 0)
761  parsed_type = TYPE_LIMIT;
762  else if (strcasecmp(th_type,"both") == 0)
763  parsed_type = TYPE_BOTH;
764  else if (strcasecmp(th_type,"threshold") == 0)
765  parsed_type = TYPE_THRESHOLD;
766  else {
767  SCLogError(SC_ERR_INVALID_ARGUMENTS, "limit type not supported: %s", th_type);
768  goto error;
769  }
770  } else {
771  SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr);
772  goto error;
773  }
774  break;
776  if (strlen(rule_extend) > 0) {
777  ret = pcre_exec(regex_suppress, regex_suppress_study,
778  rule_extend, strlen(rule_extend),
779  0, 0, ov, MAX_SUBSTRINGS);
780  if (ret < 2) {
782  "pcre_exec parse error, ret %" PRId32 ", string %s",
783  ret, rule_extend);
784  goto error;
785  }
786  /* retrieve the track mode */
787  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, th_track, sizeof(th_track));
788  if (ret < 0) {
789  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
790  goto error;
791  }
792  /* retrieve the IP */
793  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, th_ip, sizeof(th_ip));
794  if (ret < 0) {
795  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
796  goto error;
797  }
798  } else {
799  parsed_track = TRACK_RULE;
800  }
801  parsed_type = TYPE_SUPPRESS;
802  break;
803  case THRESHOLD_TYPE_RATE:
804  if (strlen(rule_extend) > 0) {
805  ret = pcre_exec(regex_rate, regex_rate_study,
806  rule_extend, strlen(rule_extend),
807  0, 0, ov, MAX_SUBSTRINGS);
808  if (ret < 5) {
810  "pcre_exec parse error, ret %" PRId32 ", string %s",
811  ret, rule_extend);
812  goto error;
813  }
814 
815  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, th_track, sizeof(th_track));
816  if (ret < 0) {
817  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
818  goto error;
819  }
820 
821  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, th_count, sizeof(th_count));
822  if (ret < 0) {
823  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
824  goto error;
825  }
826 
827  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 3, th_seconds, sizeof(th_seconds));
828  if (ret < 0) {
829  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
830  goto error;
831  }
832 
833  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 4, th_new_action, sizeof(th_new_action));
834  if (ret < 0) {
835  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
836  goto error;
837  }
838 
839  ret = pcre_copy_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 5, th_timeout, sizeof(th_timeout));
840  if (ret < 0) {
841  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
842  goto error;
843  }
844 
845  /* TODO: implement option "apply_to" */
846 
847  if (StringParseUint32(&parsed_timeout, 10, strlen(th_timeout), th_timeout) <= 0) {
848  goto error;
849  }
850 
851  /* Get the new action to take */
852  if (strcasecmp(th_new_action, "alert") == 0)
853  parsed_new_action = TH_ACTION_ALERT;
854  if (strcasecmp(th_new_action, "drop") == 0)
855  parsed_new_action = TH_ACTION_DROP;
856  if (strcasecmp(th_new_action, "pass") == 0)
857  parsed_new_action = TH_ACTION_PASS;
858  if (strcasecmp(th_new_action, "reject") == 0)
859  parsed_new_action = TH_ACTION_REJECT;
860  if (strcasecmp(th_new_action, "log") == 0) {
861  SCLogInfo("log action for rate_filter not supported yet");
862  parsed_new_action = TH_ACTION_LOG;
863  }
864  if (strcasecmp(th_new_action, "sdrop") == 0) {
865  SCLogInfo("sdrop action for rate_filter not supported yet");
866  parsed_new_action = TH_ACTION_SDROP;
867  }
868  parsed_type = TYPE_RATE;
869  } else {
870  SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr);
871  goto error;
872  }
873  break;
874  }
875 
876  switch (rule_type) {
877  /* This part is common to threshold/event_filter/rate_filter */
880  case THRESHOLD_TYPE_RATE:
881  if (strcasecmp(th_track,"by_dst") == 0)
882  parsed_track = TRACK_DST;
883  else if (strcasecmp(th_track,"by_src") == 0)
884  parsed_track = TRACK_SRC;
885  else if (strcasecmp(th_track, "by_both") == 0) {
886  parsed_track = TRACK_BOTH;
887  }
888  else if (strcasecmp(th_track,"by_rule") == 0)
889  parsed_track = TRACK_RULE;
890  else {
891  SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rawstr);
892  goto error;
893  }
894 
895  if (StringParseUint32(&parsed_count, 10, strlen(th_count), th_count) <= 0) {
896  goto error;
897  }
898  if (parsed_count == 0) {
899  SCLogError(SC_ERR_INVALID_VALUE, "rate filter count should be > 0");
900  goto error;
901  }
902 
903  if (StringParseUint32(&parsed_seconds, 10, strlen(th_seconds), th_seconds) <= 0) {
904  goto error;
905  }
906 
907  break;
909  /* need to get IP if extension is provided */
910  if (strcmp("", th_track) != 0) {
911  if (strcasecmp(th_track,"by_dst") == 0)
912  parsed_track = TRACK_DST;
913  else if (strcasecmp(th_track,"by_src") == 0)
914  parsed_track = TRACK_SRC;
915  else if (strcasecmp(th_track,"by_either") == 0) {
916  parsed_track = TRACK_EITHER;
917  }
918  else {
919  SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend);
920  goto error;
921  }
922  }
923  break;
924  }
925 
926  if (StringParseUint32(&id, 10, strlen(th_sid), th_sid) <= 0) {
927  goto error;
928  }
929 
930  if (StringParseUint32(&gid, 10, strlen(th_gid), th_gid) <= 0) {
931  goto error;
932  }
933 
934  *ret_id = id;
935  *ret_gid = gid;
936  *ret_parsed_type = parsed_type;
937  *ret_parsed_track = parsed_track;
938  *ret_parsed_new_action = parsed_new_action;
939  *ret_parsed_count = parsed_count;
940  *ret_parsed_seconds = parsed_seconds;
941  *ret_parsed_timeout = parsed_timeout;
942  *ret_th_ip = NULL;
943  if (strcmp("", th_ip) != 0) {
944  *ret_th_ip = SCStrdup(th_ip);
945  if (*ret_th_ip == NULL)
946  goto error;
947  }
948  return 0;
949 error:
950  return -1;
951 }
952 
953 /**
954  * \brief Parses a line from the threshold file and applies it to the
955  * detection engine
956  *
957  * \param rawstr Pointer to the string to be parsed.
958  * \param de_ctx Pointer to the Detection Engine Context.
959  *
960  * \retval 0 On success.
961  * \retval -1 On failure.
962  */
963 static int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx)
964 {
965  uint8_t parsed_type = 0;
966  uint8_t parsed_track = 0;
967  uint8_t parsed_new_action = 0;
968  uint32_t parsed_count = 0;
969  uint32_t parsed_seconds = 0;
970  uint32_t parsed_timeout = 0;
971  char *th_ip = NULL;
972  uint32_t id = 0, gid = 0;
973 
974  int r = 0;
975  r = ParseThresholdRule(de_ctx, rawstr, &id, &gid, &parsed_type, &parsed_track,
976  &parsed_count, &parsed_seconds, &parsed_timeout, &parsed_new_action,
977  &th_ip);
978  if (r < 0)
979  goto error;
980 
981  if (parsed_type == TYPE_SUPPRESS) {
982  r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track,
983  parsed_count, parsed_seconds, parsed_timeout, parsed_new_action,
984  th_ip);
985  } else {
986  r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track,
987  parsed_count, parsed_seconds, parsed_timeout, parsed_new_action,
988  th_ip);
989  }
990  if (r < 0) {
991  goto error;
992  }
993 
994  SCFree(th_ip);
995  return 0;
996 error:
997  if (th_ip != NULL)
998  SCFree(th_ip);
999  return -1;
1000 }
1001 
1002 /**
1003  * \brief Checks if a string is a comment or a blank line.
1004  *
1005  * Comments lines are lines of the following format -
1006  * "# This is a comment string" or
1007  * " # This is a comment string".
1008  *
1009  * \param line String that has to be checked
1010  *
1011  * \retval 1 On the argument string being a comment or blank line
1012  * \retval 0 Otherwise
1013  */
1014 static int SCThresholdConfIsLineBlankOrComment(char *line)
1015 {
1016  while (*line != '\0') {
1017  /* we have a comment */
1018  if (*line == '#')
1019  return 1;
1020 
1021  /* this line is neither a comment line, nor a blank line */
1022  if (!isspace((unsigned char)*line))
1023  return 0;
1024 
1025  line++;
1026  }
1027 
1028  /* we have a blank line */
1029  return 1;
1030 }
1031 
1032 /**
1033  * \brief Checks if the rule is multiline, by searching an ending slash
1034  *
1035  * \param line String that has to be checked
1036  *
1037  * \retval the position of the slash making it multiline
1038  * \retval 0 Otherwise
1039  */
1040 static int SCThresholdConfLineIsMultiline(char *line)
1041 {
1042  int flag = 0;
1043  char *rline = line;
1044  int len = strlen(line);
1045 
1046  while (line < rline + len && *line != '\n') {
1047  /* we have a comment */
1048  if (*line == '\\')
1049  flag = line - rline;
1050  else
1051  if (!isspace((unsigned char)*line))
1052  flag = 0;
1053 
1054  line++;
1055  }
1056 
1057  /* we have a blank line */
1058  return flag;
1059 }
1060 
1061 /**
1062  * \brief Parses the Threshold Config file
1063  *
1064  * \param de_ctx Pointer to the Detection Engine Context.
1065  * \param fd Pointer to file descriptor.
1066  */
1068 {
1069  char line[8192] = "";
1070  int rule_num = 0;
1071 
1072  /* position of "\", on multiline rules */
1073  int esc_pos = 0;
1074 
1075  if (fp == NULL)
1076  return;
1077 
1078  while (fgets(line + esc_pos, (int)sizeof(line) - esc_pos, fp) != NULL) {
1079  if (SCThresholdConfIsLineBlankOrComment(line)) {
1080  continue;
1081  }
1082 
1083  esc_pos = SCThresholdConfLineIsMultiline(line);
1084  if (esc_pos == 0) {
1085  rule_num++;
1086  SCLogDebug("Adding threshold.config rule num %"PRIu32"( %s )", rule_num, line);
1087  SCThresholdConfAddThresholdtype(line, de_ctx);
1088  }
1089  }
1090 
1091  SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num);
1092 
1093  return;
1094 }
1095 
1096 #ifdef UNITTESTS
1097 
1098 /**
1099  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1100  *
1101  * \retval fd Pointer to file descriptor.
1102  */
1103 static FILE *SCThresholdConfGenerateValidDummyFD01(void)
1104 {
1105  FILE *fd = NULL;
1106  const char *buffer =
1107  "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n"
1108  "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n"
1109  "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds 60\n";
1110 
1111  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1112  if (fd == NULL)
1113  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1114 
1115  return fd;
1116 }
1117 
1118 /**
1119  * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options.
1120  * For testing purposes.
1121  *
1122  * \retval fd Pointer to file descriptor.
1123  */
1124 static FILE *SCThresholdConfGenerateInValidDummyFD02(void)
1125 {
1126  FILE *fd;
1127  const char *buffer =
1128  "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count 100, seconds 60\n";
1129 
1130  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1131  if (fd == NULL)
1132  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1133 
1134  return fd;
1135 }
1136 
1137 /**
1138  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1139  *
1140  * \retval fd Pointer to file descriptor.
1141  */
1142 static FILE *SCThresholdConfGenerateValidDummyFD03(void)
1143 {
1144  FILE *fd;
1145  const char *buffer =
1146  "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count 100, seconds 60\n";
1147 
1148  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1149  if (fd == NULL)
1150  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1151 
1152  return fd;
1153 }
1154 
1155 /**
1156  * \brief Creates a dummy threshold file, with all valid options, but
1157  * with splitted rules (multiline), for testing purposes.
1158  *
1159  * \retval fd Pointer to file descriptor.
1160  */
1161 static FILE *SCThresholdConfGenerateValidDummyFD04(void)
1162 {
1163  FILE *fd = NULL;
1164  const char *buffer =
1165  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n"
1166  "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n"
1167  "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\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, for testing purposes.
1178  *
1179  * \retval fd Pointer to file descriptor.
1180  */
1181 static FILE *SCThresholdConfGenerateValidDummyFD05(void)
1182 {
1183  FILE *fd = NULL;
1184  const char *buffer =
1185  "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n"
1186  "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n"
1187  "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1188  "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, seconds 60, new_action reject, timeout 21\n";
1189 
1190  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1191  if (fd == NULL)
1192  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1193 
1194  return fd;
1195 }
1196 
1197 /**
1198  * \brief Creates a dummy threshold file, with all valid options, but
1199  * with splitted rules (multiline), for testing purposes.
1200  *
1201  * \retval fd Pointer to file descriptor.
1202  */
1203 static FILE *SCThresholdConfGenerateValidDummyFD06(void)
1204 {
1205  FILE *fd = NULL;
1206  const char *buffer =
1207  "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n"
1208  "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n"
1209  "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n"
1210  "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, \\\nseconds 60, new_action reject, timeout 21\n";
1211 
1212  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1213  if (fd == NULL)
1214  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1215 
1216  return fd;
1217 }
1218 
1219 /**
1220  * \brief Creates a dummy threshold file, with all valid options, but
1221  * with splitted rules (multiline), for testing purposes.
1222  *
1223  * \retval fd Pointer to file descriptor.
1224  */
1225 static FILE *SCThresholdConfGenerateValidDummyFD07(void)
1226 {
1227  FILE *fd = NULL;
1228  const char *buffer =
1229  "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n"
1230  "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n";
1231 
1232  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1233  if (fd == NULL)
1234  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1235 
1236  return fd;
1237 }
1238 
1239 /**
1240  * \brief Creates a dummy threshold file, for testing rate_filter, track by_rule
1241  *
1242  * \retval fd Pointer to file descriptor.
1243  */
1244 static FILE *SCThresholdConfGenerateValidDummyFD08(void)
1245 {
1246  FILE *fd = NULL;
1247  const char *buffer =
1248  "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n";
1249 
1250  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1251  if (fd == NULL)
1252  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1253 
1254  return fd;
1255 }
1256 
1257 /**
1258  * \brief Creates a dummy threshold file, with all valid options, but
1259  * with splitted rules (multiline), for testing purposes.
1260  *
1261  * \retval fd Pointer to file descriptor.
1262  */
1263 static FILE *SCThresholdConfGenerateValidDummyFD09(void)
1264 {
1265  FILE *fd = NULL;
1266  const char *buffer =
1267  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n"
1268  "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n"
1269  "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n";
1270 
1271  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1272  if (fd == NULL)
1273  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1274 
1275  return fd;
1276 }
1277 
1278 /**
1279  * \brief Creates a dummy threshold file, with all valid options, but
1280  * with splitted rules (multiline), for testing purposes.
1281  *
1282  * \retval fd Pointer to file descriptor.
1283  */
1284 static FILE *SCThresholdConfGenerateValidDummyFD10(void)
1285 {
1286  FILE *fd = NULL;
1287  const char *buffer =
1288  "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n"
1289  "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n"
1290  "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n";
1291 
1292  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1293  if (fd == NULL)
1294  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1295 
1296  return fd;
1297 }
1298 
1299 /**
1300  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
1301  *
1302  * \retval fd Pointer to file descriptor.
1303  */
1304 static FILE *SCThresholdConfGenerateValidDummyFD11(void)
1305 {
1306  FILE *fd = NULL;
1307  const char *buffer =
1308  "suppress gen_id 1, sig_id 10000\n"
1309  "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
1310 
1311  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
1312  if (fd == NULL)
1313  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
1314 
1315  return fd;
1316 }
1317 
1318 /**
1319  * \test Check if the threshold file is loaded and well parsed
1320  *
1321  * \retval 1 on succces
1322  * \retval 0 on failure
1323  */
1324 static int SCThresholdConfTest01(void)
1325 {
1328  de_ctx->flags |= DE_QUIET;
1329 
1331  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1332  FAIL_IF_NULL(sig);
1333 
1334  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1335  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1336  FAIL_IF_NULL(g_ut_threshold_fp);
1338 
1340  DETECT_THRESHOLD, -1);
1341  FAIL_IF_NULL(m);
1342 
1344  FAIL_IF_NULL(de);
1345 
1346  FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1348  PASS;
1349 }
1350 
1351 /**
1352  * \test Check if the threshold file is loaded and well parsed
1353  *
1354  * \retval 1 on succces
1355  * \retval 0 on failure
1356  */
1357 static int SCThresholdConfTest02(void)
1358 {
1361  de_ctx->flags |= DE_QUIET;
1362 
1364  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)");
1365  FAIL_IF_NULL(sig);
1366 
1367  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1368  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1369  FAIL_IF_NULL(g_ut_threshold_fp);
1371 
1373  DETECT_THRESHOLD, -1);
1374  FAIL_IF_NULL(m);
1375 
1377  FAIL_IF_NULL(de);
1378 
1379  FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60);
1381  PASS;
1382 }
1383 
1384 /**
1385  * \test Check if the threshold file is loaded and well parsed
1386  *
1387  * \retval 1 on succces
1388  * \retval 0 on failure
1389  */
1390 static int SCThresholdConfTest03(void)
1391 {
1394  de_ctx->flags |= DE_QUIET;
1395 
1397  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1398  FAIL_IF_NULL(sig);
1399 
1400  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1401  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01();
1402  FAIL_IF_NULL(g_ut_threshold_fp);
1404 
1406  DETECT_THRESHOLD, -1);
1407  FAIL_IF_NULL(m);
1408 
1410  FAIL_IF_NULL(de);
1411 
1412  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1414  PASS;
1415 }
1416 
1417 /**
1418  * \test Check if the threshold file is loaded and well parsed
1419  *
1420  * \retval 1 on succces
1421  * \retval 0 on failure
1422  */
1423 static int SCThresholdConfTest04(void)
1424 {
1427  de_ctx->flags |= DE_QUIET;
1428 
1430  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
1431  FAIL_IF_NULL(sig);
1432 
1433  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1434  g_ut_threshold_fp = SCThresholdConfGenerateInValidDummyFD02();
1435  FAIL_IF_NULL(g_ut_threshold_fp);
1437 
1439  DETECT_THRESHOLD, -1);
1441 
1443  PASS;
1444 }
1445 
1446 /**
1447  * \test Check if the threshold file is loaded and well parsed
1448  *
1449  * \retval 1 on succces
1450  * \retval 0 on failure
1451  */
1452 static int SCThresholdConfTest05(void)
1453 {
1456  de_ctx->flags |= DE_QUIET;
1457 
1459  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)");
1460  FAIL_IF_NULL(sig);
1462  "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)");
1463  FAIL_IF_NULL(sig);
1464 
1466  "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)");
1467  FAIL_IF_NULL(sig);
1468 
1469  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1470  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03();
1471  FAIL_IF_NULL(g_ut_threshold_fp);
1473 
1474  Signature *s = de_ctx->sig_list;
1476  DETECT_THRESHOLD, -1);
1477  FAIL_IF_NULL(m);
1478  FAIL_IF_NULL(m->ctx);
1480  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1481 
1482  s = de_ctx->sig_list->next;
1484  DETECT_THRESHOLD, -1);
1485  FAIL_IF_NULL(m);
1486  FAIL_IF_NULL(m->ctx);
1487  de = (DetectThresholdData *)m->ctx;
1488  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1489 
1490  s = de_ctx->sig_list->next->next;
1492  DETECT_THRESHOLD, -1);
1493  FAIL_IF_NULL(m);
1494  FAIL_IF_NULL(m->ctx);
1495  de = (DetectThresholdData *)m->ctx;
1496  FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60);
1497 
1498  PASS;
1499 }
1500 
1501 /**
1502  * \test Check if the threshold file is loaded and well parsed
1503  *
1504  * \retval 1 on succces
1505  * \retval 0 on failure
1506  */
1507 static int SCThresholdConfTest06(void)
1508 {
1511  de_ctx->flags |= DE_QUIET;
1512 
1514  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1515  FAIL_IF_NULL(sig);
1516 
1517  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1518  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04();
1519  FAIL_IF_NULL(g_ut_threshold_fp);
1521 
1523  DETECT_THRESHOLD, -1);
1524  FAIL_IF_NULL(m);
1525 
1527  FAIL_IF_NULL(de);
1528  FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1529 
1531  PASS;
1532 }
1533 
1534 /**
1535  * \test Check if the rate_filter rules are loaded and well parsed
1536  *
1537  * \retval 1 on succces
1538  * \retval 0 on failure
1539  */
1540 static int SCThresholdConfTest07(void)
1541 {
1544  de_ctx->flags |= DE_QUIET;
1545 
1547  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1548  FAIL_IF_NULL(sig);
1549 
1550  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1551  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05();
1552  FAIL_IF_NULL(g_ut_threshold_fp);
1554 
1557  FAIL_IF_NULL(m);
1558 
1560  FAIL_IF_NULL(de);
1561  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1562 
1564  PASS;
1565 }
1566 
1567 /**
1568  * \test Check if the rate_filter rules are loaded and well parsed
1569  * with multilines
1570  *
1571  * \retval 1 on succces
1572  * \retval 0 on failure
1573  */
1574 static int SCThresholdConfTest08(void)
1575 {
1578  de_ctx->flags |= DE_QUIET;
1579 
1581  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)");
1582  FAIL_IF_NULL(sig);
1583 
1584  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1585  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06();
1586  FAIL_IF_NULL(g_ut_threshold_fp);
1588 
1591  FAIL_IF_NULL(m);
1592 
1594  FAIL_IF_NULL(de);
1595  FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60);
1596 
1598  PASS;
1599 }
1600 
1601 /**
1602  * \test Check if the rate_filter rules work
1603  *
1604  * \retval 1 on succces
1605  * \retval 0 on failure
1606  */
1607 static int SCThresholdConfTest09(void)
1608 {
1609  ThreadVars th_v;
1610  memset(&th_v, 0, sizeof(th_v));
1611 
1613 
1614  struct timeval ts;
1615  memset (&ts, 0, sizeof(struct timeval));
1616  TimeGet(&ts);
1617 
1618  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1619  FAIL_IF_NULL(p);
1620 
1621  DetectEngineThreadCtx *det_ctx = NULL;
1622 
1625  de_ctx->flags |= DE_QUIET;
1626 
1628  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1629  FAIL_IF_NULL(s);
1630 
1631  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1632  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07();
1633  FAIL_IF_NULL(g_ut_threshold_fp);
1635 
1637  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1638 
1639  TimeGet(&p->ts);
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  p->alerts.cnt = 0;
1649  p->action = 0;
1650  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1652 
1654  TimeGet(&p->ts);
1655 
1656  p->alerts.cnt = 0;
1657  p->action = 0;
1658  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1659  FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP)));
1660 
1662  TimeGet(&p->ts);
1663 
1664  p->alerts.cnt = 0;
1665  p->action = 0;
1666  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1667  FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP)));
1668 
1670  TimeGet(&p->ts);
1671 
1672  p->alerts.cnt = 0;
1673  p->action = 0;
1674  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1676 
1677  p->alerts.cnt = 0;
1678  p->action = 0;
1679  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1681 
1682  UTHFreePacket(p);
1683  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1685  HostShutdown();
1686  PASS;
1687 }
1688 
1689 /**
1690  * \test Check if the rate_filter rules work with track by_rule
1691  *
1692  * \retval 1 on succces
1693  * \retval 0 on failure
1694  */
1695 static int SCThresholdConfTest10(void)
1696 {
1698 
1699  struct timeval ts;
1700  memset (&ts, 0, sizeof(struct timeval));
1701  TimeGet(&ts);
1702 
1703  /* Create two different packets falling to the same rule, and
1704  * because count:3, we should drop on match #4.
1705  */
1706  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1707  "172.26.0.2", "172.26.0.11");
1708  FAIL_IF_NULL(p1);
1709  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP,
1710  "172.26.0.1", "172.26.0.10");
1711  FAIL_IF_NULL(p2);
1712 
1713  ThreadVars th_v;
1714  memset(&th_v, 0, sizeof(th_v));
1715 
1718  de_ctx->flags |= DE_QUIET;
1719  DetectEngineThreadCtx *det_ctx = NULL;
1720 
1722  "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)");
1723  FAIL_IF_NULL(s);
1724 
1725  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1726  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08();
1727  FAIL_IF_NULL(g_ut_threshold_fp);
1729 
1731  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1732  TimeGet(&p1->ts);
1733  p2->ts = p1->ts;
1734 
1735  /* All should be alerted, none dropped */
1736  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1738  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1739  p1->action = 0;
1740  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1742  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1743  p2->action = 0;
1744  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1746  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1747  p1->action = 0;
1748 
1749  /* Match #4 should be dropped*/
1750  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1752  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
1753  p2->action = 0;
1754 
1756  TimeGet(&p1->ts);
1757 
1758  /* Still dropped because timeout not expired */
1759  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1761  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1762  p1->action = 0;
1763 
1765  TimeGet(&p1->ts);
1766 
1767  /* Not dropped because timeout expired */
1768  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
1770  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
1771 
1772  /* Ensure that a Threshold entry was installed at the sig */
1774 
1775  UTHFreePacket(p1);
1776  UTHFreePacket(p2);
1777  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1779  HostShutdown();
1780  PASS;
1781 }
1782 
1783 /**
1784  * \test Check if the rate_filter rules work
1785  *
1786  * \retval 1 on succces
1787  * \retval 0 on failure
1788  */
1789 static int SCThresholdConfTest11(void)
1790 {
1792 
1793  struct timeval ts;
1794  memset (&ts, 0, sizeof(struct timeval));
1795  TimeGet(&ts);
1796 
1797  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1798  FAIL_IF_NULL(p);
1799 
1800  ThreadVars th_v;
1801  memset(&th_v, 0, sizeof(th_v));
1802 
1805  de_ctx->flags |= DE_QUIET;
1806  DetectEngineThreadCtx *det_ctx = NULL;
1807 
1809  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1810  FAIL_IF_NULL(s);
1812  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1813  FAIL_IF_NULL(s);
1815  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1816  FAIL_IF_NULL(s);
1817 
1818  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1819  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09();
1820  FAIL_IF_NULL(g_ut_threshold_fp);
1822 
1824  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1825 
1826  TimeGet(&p->ts);
1827 
1828  int alerts10 = 0;
1829  int alerts11 = 0;
1830  int alerts12 = 0;
1831 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1849  alerts10 += PacketAlertCheck(p, 10);
1850  alerts11 += PacketAlertCheck(p, 11);
1851  alerts12 += PacketAlertCheck(p, 12);
1852 
1853  TimeSetIncrementTime(100);
1854  TimeGet(&p->ts);
1855 
1856  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1857  alerts10 += PacketAlertCheck(p, 10);
1858  alerts11 += PacketAlertCheck(p, 11);
1859 
1861  TimeGet(&p->ts);
1862 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1876  alerts10 += PacketAlertCheck(p, 10);
1877  alerts11 += PacketAlertCheck(p, 11);
1878  alerts12 += PacketAlertCheck(p, 12);
1879 
1880  FAIL_IF_NOT(alerts10 == 4);
1881  /* One on the first interval, another on the second */
1882  FAIL_IF_NOT(alerts11 == 2);
1883  FAIL_IF_NOT(alerts12 == 2);
1884 
1885  UTHFreePacket(p);
1886  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1888  HostShutdown();
1889  PASS;
1890 }
1891 
1892 /**
1893  * \test Check if the rate_filter rules work
1894  *
1895  * \retval 1 on succces
1896  * \retval 0 on failure
1897  */
1898 static int SCThresholdConfTest12(void)
1899 {
1901 
1902  struct timeval ts;
1903  memset (&ts, 0, sizeof(struct timeval));
1904  TimeGet(&ts);
1905 
1906  Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
1907  FAIL_IF_NULL(p);
1908 
1909  ThreadVars th_v;
1910  memset(&th_v, 0, sizeof(th_v));
1911 
1914  de_ctx->flags |= DE_QUIET;
1915  DetectEngineThreadCtx *det_ctx = NULL;
1916 
1918  "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)");
1919  FAIL_IF_NULL(s);
1921  "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)");
1922  FAIL_IF_NULL(s);
1924  "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)");
1925  FAIL_IF_NULL(s);
1926 
1927  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
1928  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10();
1929  FAIL_IF_NULL(g_ut_threshold_fp);
1931 
1933  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1934 
1935  TimeGet(&p->ts);
1936 
1937  int alerts10 = 0;
1938  int alerts11 = 0;
1939  int alerts12 = 0;
1940 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1958  alerts10 += PacketAlertCheck(p, 10);
1959  alerts11 += PacketAlertCheck(p, 11);
1960  alerts12 += PacketAlertCheck(p, 12);
1961 
1962  TimeSetIncrementTime(100);
1963  TimeGet(&p->ts);
1964 
1965  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1966  alerts10 += PacketAlertCheck(p, 10);
1967  alerts11 += PacketAlertCheck(p, 11);
1968 
1970  TimeGet(&p->ts);
1971 
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  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1985  alerts10 += PacketAlertCheck(p, 10);
1986  alerts11 += PacketAlertCheck(p, 11);
1987  alerts12 += PacketAlertCheck(p, 12);
1988 
1989  FAIL_IF_NOT(alerts10 == 10);
1990  /* One on the first interval, another on the second */
1991  FAIL_IF_NOT(alerts11 == 1);
1992  FAIL_IF_NOT(alerts12 == 1);
1993 
1994  UTHFreePacket(p);
1995  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1997  HostShutdown();
1998  PASS;
1999 }
2000 
2001 /**
2002  * \test Check if the threshold file is loaded and well parsed
2003  *
2004  * \retval 1 on succces
2005  * \retval 0 on failure
2006  */
2007 static int SCThresholdConfTest13(void)
2008 {
2011  de_ctx->flags |= DE_QUIET;
2012 
2014  "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)");
2015  FAIL_IF_NULL(sig);
2016 
2017  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2018  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2019  FAIL_IF_NULL(g_ut_threshold_fp);
2021 
2024  FAIL_IF_NULL(m);
2025 
2027  FAIL_IF_NULL(de);
2028  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2029 
2031  PASS;
2032 }
2033 
2034 /**
2035  * \test Check if the suppress rules work
2036  *
2037  * \retval 1 on succces
2038  * \retval 0 on failure
2039  */
2040 static int SCThresholdConfTest14(void)
2041 {
2043 
2044  Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2045  "192.168.0.100", 1234, 24);
2046  FAIL_IF_NULL(p1);
2047  Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
2048  "192.168.0.100", 1234, 24);
2049  FAIL_IF_NULL(p2);
2050 
2051  DetectEngineThreadCtx *det_ctx = NULL;
2054  de_ctx->flags |= DE_QUIET;
2055 
2057  "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)");
2058  FAIL_IF_NULL(sig);
2060  "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)");
2061  FAIL_IF_NULL(sig);
2063  "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)");
2064  FAIL_IF_NULL(sig);
2065 
2066  ThreadVars th_v;
2067  memset(&th_v, 0, sizeof(th_v));
2068 
2069  struct timeval ts;
2070  memset (&ts, 0, sizeof(struct timeval));
2071  TimeGet(&ts);
2072 
2073  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2074  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2075  FAIL_IF_NULL(g_ut_threshold_fp);
2077 
2079  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2080 
2081  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2082  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2083 
2084  FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0);
2085  FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1);
2086  FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1);
2087  FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0);
2088 
2089  UTHFreePacket(p1);
2090  UTHFreePacket(p2);
2091 
2092  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2094 
2095  HostShutdown();
2096  PASS;
2097 }
2098 
2099 /**
2100  * \test Check if the suppress rules work
2101  *
2102  * \retval 1 on succces
2103  * \retval 0 on failure
2104  */
2105 static int SCThresholdConfTest15(void)
2106 {
2108 
2109  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2110  "192.168.0.100", 1234, 24);
2111  FAIL_IF_NULL(p);
2112 
2113  ThreadVars th_v;
2114  memset(&th_v, 0, sizeof(th_v));
2115 
2116  DetectEngineThreadCtx *det_ctx = NULL;
2119  de_ctx->flags |= DE_QUIET;
2120 
2121  struct timeval ts;
2122  memset (&ts, 0, sizeof(struct timeval));
2123  TimeGet(&ts);
2124 
2126  "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)");
2127  FAIL_IF_NULL(sig);
2128 
2129  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2130  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2131  FAIL_IF_NULL(g_ut_threshold_fp);
2133 
2135  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2136 
2137  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2138 
2139  /* 10000 shouldn't match */
2140  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2141  /* however, it should have set the drop flag */
2143 
2144  UTHFreePacket(p);
2145  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2147  HostShutdown();
2148  PASS;
2149 }
2150 
2151 /**
2152  * \test Check if the suppress rules work
2153  *
2154  * \retval 1 on succces
2155  * \retval 0 on failure
2156  */
2157 static int SCThresholdConfTest16(void)
2158 {
2160 
2161  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1",
2162  "192.168.0.100", 1234, 24);
2163  FAIL_IF_NULL(p);
2164 
2165  ThreadVars th_v;
2166  memset(&th_v, 0, sizeof(th_v));
2167 
2168  DetectEngineThreadCtx *det_ctx = NULL;
2171  de_ctx->flags |= DE_QUIET;
2172 
2173  struct timeval ts;
2174  memset (&ts, 0, sizeof(struct timeval));
2175  TimeGet(&ts);
2176 
2178  "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)");
2179  FAIL_IF_NULL(sig);
2180 
2181  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2182  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2183  FAIL_IF_NULL(g_ut_threshold_fp);
2185 
2187  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2188 
2189  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2190 
2191  FAIL_IF(PacketAlertCheck(p, 1000) != 0);
2192  /* however, it should have set the drop flag */
2194 
2195  UTHFreePacket(p);
2196  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2198  HostShutdown();
2199  PASS;
2200 }
2201 
2202 /**
2203  * \test Check if the suppress rules work - ip only rule
2204  *
2205  * \retval 1 on succces
2206  * \retval 0 on failure
2207  */
2208 static int SCThresholdConfTest17(void)
2209 {
2211 
2212  Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10",
2213  "192.168.0.100", 1234, 24);
2214  FAIL_IF_NULL(p);
2215 
2216  ThreadVars th_v;
2217  memset(&th_v, 0, sizeof(th_v));
2218 
2219  DetectEngineThreadCtx *det_ctx = NULL;
2222  de_ctx->flags |= DE_QUIET;
2223 
2224  struct timeval ts;
2225  memset (&ts, 0, sizeof(struct timeval));
2226  TimeGet(&ts);
2227 
2229  "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)");
2230  FAIL_IF_NULL(sig);
2231 
2232  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2233  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11();
2234  FAIL_IF_NULL(g_ut_threshold_fp);
2236 
2238  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2239 
2240  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2241 
2242  /* 10000 shouldn't match */
2243  FAIL_IF(PacketAlertCheck(p, 10000) != 0);
2244  /* however, it should have set the drop flag */
2246 
2247  UTHFreePacket(p);
2248  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2250  HostShutdown();
2251  PASS;
2252 }
2253 
2254 /**
2255  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2256  *
2257  * \retval fd Pointer to file descriptor.
2258  */
2259 static FILE *SCThresholdConfGenerateInvalidDummyFD12(void)
2260 {
2261  FILE *fd = NULL;
2262  const char *buffer =
2263  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"
2264  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n";
2265 
2266  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2267  if (fd == NULL)
2268  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2269 
2270  return fd;
2271 }
2272 
2273 /**
2274  * \test Check if the suppress rule parsing handles errors correctly
2275  *
2276  * \retval 1 on succces
2277  * \retval 0 on failure
2278  */
2279 static int SCThresholdConfTest18(void)
2280 {
2284  de_ctx->flags |= DE_QUIET;
2285 
2287  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2288  FAIL_IF_NULL(s);
2289  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2290  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12();
2291  FAIL_IF_NULL(g_ut_threshold_fp);
2294 
2298  FAIL_IF_NULL(de);
2299  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2300 
2302  HostShutdown();
2303  PASS;
2304 }
2305 
2306 /**
2307  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2308  *
2309  * \retval fd Pointer to file descriptor.
2310  */
2311 static FILE *SCThresholdConfGenerateInvalidDummyFD13(void)
2312 {
2313  FILE *fd = NULL;
2314  const char *buffer =
2315  "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"
2316  "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n";
2317 
2318  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2319  if (fd == NULL)
2320  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2321 
2322  return fd;
2323 }
2324 
2325 /**
2326  * \test Check if the suppress rule parsing handles errors correctly
2327  *
2328  * \retval 1 on succces
2329  * \retval 0 on failure
2330  */
2331 static int SCThresholdConfTest19(void)
2332 {
2336  de_ctx->flags |= DE_QUIET;
2338  "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)");
2339  FAIL_IF_NULL(s);
2340  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2341  g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13();
2342  FAIL_IF_NULL(g_ut_threshold_fp);
2348  FAIL_IF_NULL(de);
2349  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST);
2351  HostShutdown();
2352  PASS;
2353 }
2354 
2355 /**
2356  * \brief Creates a dummy threshold file, with all valid options, for testing purposes.
2357  *
2358  * \retval fd Pointer to file descriptor.
2359  */
2360 static FILE *SCThresholdConfGenerateValidDummyFD20(void)
2361 {
2362  FILE *fd = NULL;
2363  const char *buffer =
2364  "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n"
2365  "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n"
2366  "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n";
2367 
2368  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2369  if (fd == NULL)
2370  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2371 
2372  return fd;
2373 }
2374 
2375 /**
2376  * \test Check if the threshold file is loaded and well parsed
2377  *
2378  * \retval 1 on succces
2379  * \retval 0 on failure
2380  */
2381 static int SCThresholdConfTest20(void)
2382 {
2386  de_ctx->flags |= DE_QUIET;
2388  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)");
2389  FAIL_IF_NULL(s);
2390  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2391  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2392  FAIL_IF_NULL(g_ut_threshold_fp);
2396 
2399  FAIL_IF_NULL(de);
2400  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2401  FAIL_IF(smd->is_last);
2402 
2403  smd++;
2404  de = (DetectThresholdData *)smd->ctx;
2405  FAIL_IF_NULL(de);
2406  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2407  FAIL_IF(smd->is_last);
2408 
2409  smd++;
2410  de = (DetectThresholdData *)smd->ctx;
2411  FAIL_IF_NULL(de);
2412  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2413  FAIL_IF_NOT(smd->is_last);
2414 
2416  HostShutdown();
2417  PASS;
2418 }
2419 
2420 /**
2421  * \test Check if the threshold file is loaded and well parsed, and applied
2422  * correctly to a rule with thresholding
2423  *
2424  * \retval 1 on succces
2425  * \retval 0 on failure
2426  */
2427 static int SCThresholdConfTest21(void)
2428 {
2432  de_ctx->flags |= DE_QUIET;
2434  "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)");
2435  FAIL_IF_NULL(s);
2436  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20();
2437  FAIL_IF_NULL(g_ut_threshold_fp);
2441 
2444  FAIL_IF_NULL(de);
2445  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2446  FAIL_IF(smd->is_last);
2447 
2448  smd++;
2449  de = (DetectThresholdData *)smd->ctx;
2450  FAIL_IF_NULL(de);
2451  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2452  FAIL_IF(smd->is_last);
2453 
2454  smd++;
2455  de = (DetectThresholdData *)smd->ctx;
2456  FAIL_IF_NULL(de);
2457  FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC);
2458  FAIL_IF_NOT(smd->is_last);
2459 
2461  HostShutdown();
2462  PASS;
2463 }
2464 
2465 /**
2466 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2467 *
2468 * \retval fd Pointer to file descriptor.
2469 */
2470 static FILE *SCThresholdConfGenerateValidDummyFD22(void)
2471 {
2472  FILE *fd = NULL;
2473  const char *buffer =
2474  "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, new_action drop, timeout 6\n";
2475 
2476  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2477  if (fd == NULL)
2478  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2479 
2480  return fd;
2481 }
2482 
2483 /**
2484 * \test Check if the rate_filter rules work with track by_both
2485 *
2486 * \retval 1 on succces
2487 * \retval 0 on failure
2488 */
2489 static int SCThresholdConfTest22(void)
2490 {
2491  ThreadVars th_v;
2492  memset(&th_v, 0, sizeof(th_v));
2493 
2495 
2496  struct timeval ts;
2497  memset(&ts, 0, sizeof(struct timeval));
2498  TimeGet(&ts);
2499 
2500  /* This packet will cause rate_filter */
2501  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2502  FAIL_IF_NULL(p1);
2503 
2504  /* Should not be filtered for different destination */
2505  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2");
2506  FAIL_IF_NULL(p2);
2507 
2508  /* Should not be filtered when both src and dst the same */
2509  Packet *p3 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1");
2510  FAIL_IF_NULL(p3);
2511 
2512  DetectEngineThreadCtx *det_ctx = NULL;
2513 
2516  de_ctx->flags |= DE_QUIET;
2517 
2519  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2520  FAIL_IF_NULL(sig);
2521 
2522  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2523  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22();
2524  FAIL_IF_NULL(g_ut_threshold_fp);
2526 
2528  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2529 
2530  TimeGet(&p1->ts);
2531  p2->ts = p3->ts = p1->ts;
2532 
2533  /* All should be alerted, none dropped */
2534  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2536  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2537 
2538  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2540  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2541 
2542  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2544  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2545 
2546  p1->action = p2->action = p3->action = 0;
2547 
2549  TimeGet(&p1->ts);
2550  p2->ts = p3->ts = p1->ts;
2551 
2552  /* p1 still shouldn't be dropped after 2nd alert */
2553  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2555  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2556 
2557  p1->action = 0;
2558 
2560  TimeGet(&p1->ts);
2561  p2->ts = p3->ts = p1->ts;
2562 
2563  /* All should be alerted, only p1 must be dropped due to rate_filter*/
2564  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2566  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2567 
2568  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2570  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2571 
2572  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2574  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2575 
2576  p1->action = p2->action = p3->action = 0;
2577 
2579  TimeGet(&p1->ts);
2580  p2->ts = p3->ts = p1->ts;
2581 
2582  /* All should be alerted, none dropped (because timeout expired) */
2583  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2585  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2586 
2587  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2589  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2590 
2591  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
2593  FAIL_IF(PacketAlertCheck(p3, 10) != 1);
2594 
2595  UTHFreePacket(p3);
2596  UTHFreePacket(p2);
2597  UTHFreePacket(p1);
2598 
2599  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2601  IPPairShutdown();
2602  PASS;
2603 }
2604 
2605 /**
2606 * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination
2607 *
2608 * \retval fd Pointer to file descriptor.
2609 */
2610 static FILE *SCThresholdConfGenerateValidDummyFD23(void)
2611 {
2612  FILE *fd = NULL;
2613  const char *buffer =
2614  "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, new_action drop, timeout 6\n";
2615 
2616  fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
2617  if (fd == NULL)
2618  SCLogDebug("Error with SCFmemopen() called by Threshold Config test code");
2619 
2620  return fd;
2621 }
2622 
2623 /**
2624 * \test Check if the rate_filter by_both work when similar packets
2625 * going in opposite direction
2626 *
2627 * \retval 1 on succces
2628 * \retval 0 on failure
2629 */
2630 static int SCThresholdConfTest23(void)
2631 {
2632  ThreadVars th_v;
2633  memset(&th_v, 0, sizeof(th_v));
2634 
2636 
2637  struct timeval ts;
2638  memset(&ts, 0, sizeof(struct timeval));
2639  TimeGet(&ts);
2640 
2641  /* Create two packets between same addresses in opposite direction */
2642  Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
2643  FAIL_IF_NULL(p1);
2644 
2645  Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1");
2646  FAIL_IF_NULL(p2);
2647 
2648  DetectEngineThreadCtx *det_ctx = NULL;
2649 
2652  de_ctx->flags |= DE_QUIET;
2653 
2655  "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)");
2656  FAIL_IF_NULL(sig);
2657 
2658  FAIL_IF_NOT_NULL(g_ut_threshold_fp);
2659  g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23();
2660  FAIL_IF_NULL(g_ut_threshold_fp);
2662 
2664  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2665 
2666  TimeGet(&p1->ts);
2667  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
2668  /* First packet should be alerted, not dropped */
2670  FAIL_IF(PacketAlertCheck(p1, 10) != 1);
2671 
2673  TimeGet(&p2->ts);
2674  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
2675 
2676  /* Second packet should be dropped because it considered as "the same pair"
2677  and rate_filter count reached*/
2679  FAIL_IF(PacketAlertCheck(p2, 10) != 1);
2680 
2681  UTHFreePacket(p2);
2682  UTHFreePacket(p1);
2683 
2684  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2686  IPPairShutdown();
2687  PASS;
2688 }
2689 #endif /* UNITTESTS */
2690 
2691 /**
2692  * \brief This function registers unit tests for Classification Config API.
2693  */
2695 {
2696 #ifdef UNITTESTS
2697  UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01);
2698  UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02);
2699  UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03);
2700  UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04);
2701  UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05);
2702  UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06);
2703  UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07);
2704  UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08);
2705  UtRegisterTest("SCThresholdConfTest09 - rate_filter",
2706  SCThresholdConfTest09);
2707  UtRegisterTest("SCThresholdConfTest10 - rate_filter",
2708  SCThresholdConfTest10);
2709  UtRegisterTest("SCThresholdConfTest11 - event_filter",
2710  SCThresholdConfTest11);
2711  UtRegisterTest("SCThresholdConfTest12 - event_filter",
2712  SCThresholdConfTest12);
2713  UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13);
2714  UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14);
2715  UtRegisterTest("SCThresholdConfTest15 - suppress drop",
2716  SCThresholdConfTest15);
2717  UtRegisterTest("SCThresholdConfTest16 - suppress drop",
2718  SCThresholdConfTest16);
2719  UtRegisterTest("SCThresholdConfTest17 - suppress drop",
2720  SCThresholdConfTest17);
2721 
2722  UtRegisterTest("SCThresholdConfTest18 - suppress parsing",
2723  SCThresholdConfTest18);
2724  UtRegisterTest("SCThresholdConfTest19 - suppress parsing",
2725  SCThresholdConfTest19);
2726  UtRegisterTest("SCThresholdConfTest20 - suppress parsing",
2727  SCThresholdConfTest20);
2728  UtRegisterTest("SCThresholdConfTest21 - suppress parsing",
2729  SCThresholdConfTest21);
2730  UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both",
2731  SCThresholdConfTest22);
2732  UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite",
2733  SCThresholdConfTest23);
2734 
2735 #endif /* UNITTESTS */
2736 }
2737 
2738 /**
2739  * @}
2740  */
TRACK_BOTH
#define TRACK_BOTH
Definition: detect-threshold.h:42
util-byte.h
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:1406
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:525
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:1485
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:300
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
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:332
Packet_::action
uint8_t action
Definition: decode.h:556
DETECT_SM_LIST_THRESHOLD
@ DETECT_SM_LIST_THRESHOLD
Definition: detect.h:104
HostInitConfig
void HostInitConfig(char quiet)
initialize the configuration
Definition: host.c:173
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:755
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:2040
TRACK_DST
#define TRACK_DST
Definition: detect-detection-filter.c:43
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:568
m
SCMutex m
Definition: flow-hash.h:6
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:567
util-unittest.h
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
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:549
IPPairShutdown
void IPPairShutdown(void)
shutdown the flow engine
Definition: ippair.c:300
Signature_::next
struct Signature_ * next
Definition: detect.h:587
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
DetectEngineThreadCtx_
Definition: detect.h:999
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:63
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:802
IPPairInitConfig
void IPPairInitConfig(char quiet)
initialize the configuration
Definition: ippair.c:168
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:1688
Signature_::flags
uint32_t flags
Definition: detect.h:516
ThresholdCtx_::th_entry
DetectThresholdEntry ** th_entry
Definition: detect.h:704
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:415
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:1888
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:886
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:2375
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Definition: detect-engine.c:2744
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:458
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
Definition: detect-engine.c:2952
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
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:761
SIG_FLAG_NOALERT
#define SIG_FLAG_NOALERT
Definition: detect.h:216
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
SCThresholdConfParseFile
void SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fp)
Parses the Threshold Config file.
Definition: util-threshold-config.c:1067
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:548
detect-parse.h
Signature_
Signature container.
Definition: detect.h:515
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:2694
TimeGet
void TimeGet(struct timeval *tv)
Definition: util-time.c:153
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:1995
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
TRACK_SRC
#define TRACK_SRC
Definition: detect-detection-filter.c:44
ThresholdHashRealloc
void ThresholdHashRealloc(DetectEngineCtx *de_ctx)
Realloc threshold context hash tables.
Definition: detect-engine-threshold.c:665
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:756
THRESHOLD_TYPE_THRESHOLD
@ THRESHOLD_TYPE_THRESHOLD
Definition: util-threshold-config.c:57
THRESHOLD_TYPE_SUPPRESS
@ THRESHOLD_TYPE_SUPPRESS
Definition: util-threshold-config.c:59
DETECT_THRESHOLD_REGEX
#define DETECT_THRESHOLD_REGEX
Definition: util-threshold-config.c:70
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:885
DETECT_RATE_REGEX
#define DETECT_RATE_REGEX
Definition: util-threshold-config.c:73