Coverage Report

Created: 2026-01-16 07:00

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