• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23350763619

20 Mar 2026 03:49PM UTC coverage: 76.429% (-2.9%) from 79.315%
23350763619

Pull #15029

github

web-flow
Merge 5fca25ef1 into 6587e363a
Pull Request #15029: Fw updates/v5

379 of 449 new or added lines in 26 files covered. (84.41%)

13267 existing lines in 297 files now uncovered.

244170 of 319471 relevant lines covered (76.43%)

3147764.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.23
/src/detect-parse.c
1
/* Copyright (C) 2007-2025 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
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * signature parser
24
 */
25

26
#include "suricata-common.h"
27

28
#include "detect.h"
29
#include "detect-engine.h"
30
#include "detect-engine-address.h"
31
#include "detect-engine-port.h"
32
#include "detect-engine-mpm.h"
33
#include "detect-engine-state.h"
34
#include "detect-engine-build.h"
35

36
#include "detect-content.h"
37
#include "detect-bsize.h"
38
#include "detect-isdataat.h"
39
#include "detect-pcre.h"
40
#include "detect-uricontent.h"
41
#include "detect-reference.h"
42
#include "detect-ipproto.h"
43
#include "detect-flow.h"
44
#include "detect-app-layer-protocol.h"
45
#include "detect-lua.h"
46
#include "detect-app-layer-event.h"
47
#include "detect-http-method.h"
48

49
#include "pkt-var.h"
50
#include "host.h"
51
#include "util-profiling.h"
52
#include "decode.h"
53

54
#include "flow.h"
55

56
#include "util-rule-vars.h"
57
#include "conf.h"
58
#include "conf-yaml-loader.h"
59

60
#include "app-layer.h"
61
#include "app-layer-protos.h"
62
#include "app-layer-parser.h"
63
#include "app-layer-htp.h"
64

65
#include "util-classification-config.h"
66
#include "util-unittest.h"
67
#include "util-unittest-helper.h"
68
#include "util-debug.h"
69
#include "string.h"
70
#include "detect-parse.h"
71
#include "detect-engine-iponly.h"
72
#include "detect-engine-file.h"
73
#include "app-layer-detect-proto.h"
74

75
#include "action-globals.h"
76
#include "util-validate.h"
77

78
/* Table with all SigMatch registrations */
79
SigTableElmt *sigmatch_table = NULL;
80

81
extern bool sc_set_caps;
82

83
static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
84
        SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
85
        SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail);
86

87
/**
88
 * \brief Registration table for file handlers
89
 */
90
/**
91
 * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table.
92
 */
93
typedef struct SigDuplWrapper_ {
94
    /* the signature we want to wrap */
95
    Signature *s;
96
    /* the signature right before the above signature in the det_ctx->sig_list */
97
    Signature *s_prev;
98
} SigDuplWrapper;
99

100
/** helper structure for sig parsing */
101
typedef struct SignatureParser_ {
102
    char action[DETECT_MAX_RULE_SIZE];
103
    char protocol[DETECT_MAX_RULE_SIZE];
104
    char direction[DETECT_MAX_RULE_SIZE];
105
    char src[DETECT_MAX_RULE_SIZE];
106
    char dst[DETECT_MAX_RULE_SIZE];
107
    char sp[DETECT_MAX_RULE_SIZE];
108
    char dp[DETECT_MAX_RULE_SIZE];
109
    char opts[DETECT_MAX_RULE_SIZE];
110
} SignatureParser;
111

112
const char *DetectListToHumanString(int list)
UNCOV
113
{
×
UNCOV
114
#define CASE_CODE_STRING(E, S)  case E: return S; break
×
UNCOV
115
    switch (list) {
×
UNCOV
116
        CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet");
×
UNCOV
117
        CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload");
×
UNCOV
118
        CASE_CODE_STRING(DETECT_SM_LIST_BASE64_DATA, "base64_data");
×
UNCOV
119
        CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch");
×
120
        CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag");
×
121
        CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress");
×
122
        CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold");
×
UNCOV
123
        CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
×
UNCOV
124
    }
×
125
#undef CASE_CODE_STRING
×
126
    return "unknown";
×
UNCOV
127
}
×
128

129
#define CASE_CODE(E)  case E: return #E
×
130
const char *DetectListToString(int list)
131
{
×
132
    switch (list) {
×
133
        CASE_CODE(DETECT_SM_LIST_MATCH);
×
134
        CASE_CODE(DETECT_SM_LIST_PMATCH);
×
135
        CASE_CODE(DETECT_SM_LIST_BASE64_DATA);
×
136
        CASE_CODE(DETECT_SM_LIST_TMATCH);
×
137
        CASE_CODE(DETECT_SM_LIST_POSTMATCH);
×
138
        CASE_CODE(DETECT_SM_LIST_SUPPRESS);
×
139
        CASE_CODE(DETECT_SM_LIST_THRESHOLD);
×
140
        CASE_CODE(DETECT_SM_LIST_MAX);
×
141
    }
×
142
    return "unknown";
×
143
}
×
144

145
/** \param arg NULL or empty string */
146
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx,
147
        Signature *s, const char *arg, int sm_type, int sm_list,
148
        AppProto alproto)
149
{
59,029✔
150
    SigMatch *sm = NULL;
59,029✔
151
    int ret = -1;
59,029✔
152

153
    if (arg != NULL && strcmp(arg, "") != 0) {
59,029✔
154
        SCLogError("%s shouldn't be supplied "
×
155
                   "with an argument",
×
156
                sigmatch_table[sm_type].name);
×
157
        goto end;
×
158
    }
×
159

160
    if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
59,029✔
161
        SCLogError("\"%s\" keyword seen "
47✔
162
                   "with a sticky buffer still set.  Reset sticky buffer "
47✔
163
                   "with pkt_data before using the modifier.",
47✔
164
                sigmatch_table[sm_type].name);
47✔
165
        goto end;
47✔
166
    }
47✔
167
    if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
58,982✔
168
        SCLogError("rule contains conflicting "
398✔
169
                   "alprotos set");
398✔
170
        goto end;
398✔
171
    }
398✔
172

173
    sm = DetectGetLastSMByListId(s,
58,584✔
174
            DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1);
58,584✔
175
    if (sm == NULL) {
58,584✔
176
        SCLogError("\"%s\" keyword "
473✔
177
                   "found inside the rule without a content context.  "
473✔
178
                   "Please use a \"content\" keyword before using the "
473✔
179
                   "\"%s\" keyword",
473✔
180
                sigmatch_table[sm_type].name, sigmatch_table[sm_type].name);
473✔
181
        goto end;
473✔
182
    }
473✔
183
    DetectContentData *cd = (DetectContentData *)sm->ctx;
58,111✔
184
    if (cd->flags & DETECT_CONTENT_RAWBYTES) {
58,111✔
185
        SCLogError("%s rule can not "
10✔
186
                   "be used with the rawbytes rule keyword",
10✔
187
                sigmatch_table[sm_type].name);
10✔
188
        goto end;
10✔
189
    }
10✔
190
    if (cd->flags & DETECT_CONTENT_REPLACE) {
58,101✔
191
        SCLogError("%s rule can not "
1✔
192
                   "be used with the replace rule keyword",
1✔
193
                sigmatch_table[sm_type].name);
1✔
194
        goto end;
1✔
195
    }
1✔
196
    if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) {
58,100✔
197
        SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev,
2,097✔
198
            DETECT_CONTENT, DETECT_PCRE, -1);
2,097✔
199
        if (pm != NULL) {
2,097✔
200
            if (pm->type == DETECT_CONTENT) {
1,809✔
201
                DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
1,150✔
202
                tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT;
1,150✔
203
            } else {
1,154✔
204
                DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
659✔
205
                tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT;
659✔
206
            }
659✔
207
        }
1,809✔
208

209
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) {
2,097✔
210
            pm = DetectGetLastSMByListPtr(
1,426✔
211
                    s, s->init_data->curbuf->tail, DETECT_CONTENT, DETECT_PCRE, -1);
1,426✔
212
            if (pm != NULL) {
1,426✔
213
                if (pm->type == DETECT_CONTENT) {
1,426✔
214
                    DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
1,363✔
215
                    tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
1,363✔
216
                } else {
1,363✔
217
                    DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
63✔
218
                    tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
63✔
219
                }
63✔
220
            }
1,426✔
221
        }
1,426✔
222
    }
2,097✔
223
    s->alproto = alproto;
58,100✔
224
    s->flags |= SIG_FLAG_APPLAYER;
58,100✔
225

226
    if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
58,100✔
227
        if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
40,743✔
228
            SCLogError("no matches for previous buffer");
40✔
229
            return -1;
40✔
230
        }
40✔
231
        bool reuse_buffer = false;
40,743✔
232
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
40,703✔
233
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
15,560✔
234
                if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
10,758✔
235
                    s->init_data->curbuf = &s->init_data->buffers[x];
2,959✔
236
                    reuse_buffer = true;
2,959✔
237
                    break;
2,959✔
238
                }
2,959✔
239
            }
10,758✔
240
        }
7,761✔
241

242
        if (!reuse_buffer) {
40,703✔
243
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
37,744✔
244
                SCLogError("failed to expand rule buffer array");
1✔
245
                return -1;
1✔
246
            }
1✔
247

248
            /* initialize a new buffer */
249
            s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
37,743✔
250
            s->init_data->curbuf->id = sm_list;
37,743✔
251
            s->init_data->curbuf->head = NULL;
37,743✔
252
            s->init_data->curbuf->tail = NULL;
37,743✔
253
            SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
37,743✔
254
                    s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
37,743✔
255
                    s->init_data->buffer_index);
37,743✔
256
        }
37,743✔
257
    }
40,703✔
258

259
    /* transfer the sm from the pmatch list to sm_list */
260
    SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
58,059✔
261
            &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], &s->init_data->curbuf->head,
58,059✔
262
            &s->init_data->curbuf->tail);
58,059✔
263

264
    if (sm->type == DETECT_CONTENT) {
58,059✔
265
        s->init_data->max_content_list_id =
58,059✔
266
                MAX(s->init_data->max_content_list_id, (uint32_t)sm_list);
58,059✔
267
    }
58,059✔
268

269
    ret = 0;
58,059✔
270
 end:
58,988✔
271
    return ret;
58,988✔
272
}
58,059✔
273

274
SigMatch *SigMatchAlloc(void)
275
{
2,054,896✔
276
    SigMatch *sm = SCCalloc(1, sizeof(SigMatch));
2,054,896✔
277
    if (unlikely(sm == NULL))
2,054,896✔
278
        return NULL;
×
279

280
    sm->prev = NULL;
2,054,896✔
281
    sm->next = NULL;
2,054,896✔
282
    return sm;
2,054,896✔
283
}
2,054,896✔
284

285
/** \brief free a SigMatch
286
 *  \param sm SigMatch to free.
287
 */
288
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
289
{
2,054,891✔
290
    if (sm == NULL)
2,054,891✔
291
        return;
×
292

293
    /** free the ctx, for that we call the Free func */
294
    if (sm->ctx != NULL) {
2,054,891✔
295
        if (sigmatch_table[sm->type].Free != NULL) {
1,694,907✔
296
            sigmatch_table[sm->type].Free(de_ctx, sm->ctx);
1,694,907✔
297
        }
1,694,907✔
298
    }
1,694,907✔
299
    SCFree(sm);
2,054,891✔
300
}
2,054,891✔
301

302
static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e)
303
{
7,821,539✔
304
    const SigTableElmt *table = &sigmatch_table[0];
7,821,539✔
305
    ptrdiff_t offset = e - table;
7,821,539✔
306
    BUG_ON(offset >= DETECT_TBLSIZE);
7,821,539✔
307
    return (enum DetectKeywordId)offset;
7,821,539✔
308
}
7,821,539✔
309

310
/* Get the detection module by name */
311
static SigTableElmt *SigTableGet(char *name)
312
{
8,100,980✔
313
    SigTableElmt *st = NULL;
8,100,980✔
314
    int i = 0;
8,100,980✔
315

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
566,699,192✔
317
        st = &sigmatch_table[i];
566,426,250✔
318

319
        if (st->name != NULL) {
566,426,250✔
320
            if (strcasecmp(name,st->name) == 0)
541,040,079✔
321
                return st;
7,735,419✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
533,304,660✔
323
                return st;
92,619✔
324
        }
533,304,660✔
325
    }
566,426,250✔
326

327
    return NULL;
272,942✔
328
}
8,100,980✔
329

330
bool SCSigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, uint16_t id)
UNCOV
331
{
×
UNCOV
332
    return de_ctx->sm_types_silent_error[id];
×
UNCOV
333
}
×
334

335
bool SigMatchStrictEnabled(const enum DetectKeywordId id)
336
{
32,711✔
337
    if ((int)id < DETECT_TBLSIZE) {
32,711✔
338
        return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
32,711✔
339
    }
32,711✔
340
    return false;
×
341
}
32,711✔
342

343
void SigTableApplyStrictCommandLineOption(const char *str)
344
{
31✔
345
    if (str == NULL) {
31✔
346
        /* nothing to be done */
347
        return;
31✔
348
    }
31✔
349

350
    /* "all" just sets the flag for each keyword */
UNCOV
351
    if (strcmp(str, "all") == 0) {
×
UNCOV
352
        for (int i = 0; i < DETECT_TBLSIZE; i++) {
×
UNCOV
353
            SigTableElmt *st = &sigmatch_table[i];
×
UNCOV
354
            st->flags |= SIGMATCH_STRICT_PARSING;
×
UNCOV
355
        }
×
UNCOV
356
        return;
×
UNCOV
357
    }
×
358

UNCOV
359
    char *copy = SCStrdup(str);
×
UNCOV
360
    if (copy == NULL)
×
361
        FatalError("could not duplicate opt string");
×
362

UNCOV
363
    char *xsaveptr = NULL;
×
UNCOV
364
    char *key = strtok_r(copy, ",", &xsaveptr);
×
UNCOV
365
    while (key != NULL) {
×
UNCOV
366
        SigTableElmt *st = SigTableGet(key);
×
UNCOV
367
        if (st != NULL) {
×
UNCOV
368
            st->flags |= SIGMATCH_STRICT_PARSING;
×
UNCOV
369
        } else {
×
370
            SCLogWarning("'strict' command line "
×
371
                         "argument '%s' not found",
×
372
                    key);
×
373
        }
×
UNCOV
374
        key = strtok_r(NULL, ",", &xsaveptr);
×
UNCOV
375
    }
×
376

UNCOV
377
    SCFree(copy);
×
UNCOV
378
}
×
379

380
/**
381
 * \brief Append a SigMatch to the list type.
382
 *
383
 * \param s    Signature.
384
 * \param new  The sig match to append.
385
 * \param list The list to append to.
386
 */
387
SigMatch *SCSigMatchAppendSMToList(
388
        DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
389
{
2,054,878✔
390
    SigMatch *new = SigMatchAlloc();
2,054,878✔
391
    if (new == NULL)
2,054,878✔
392
        return NULL;
×
393

394
    new->type = type;
2,054,878✔
395
    new->ctx = ctx;
2,054,878✔
396

397
    if (new->type == DETECT_CONTENT) {
2,054,878✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
719,394✔
399
    }
719,394✔
400

401
    SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new,
2,054,878✔
402
            list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set),
2,054,878✔
403
            s->init_data->list);
2,054,878✔
404

405
    if (list < DETECT_SM_LIST_MAX) {
2,054,878✔
406
        if (s->init_data->smlists[list] == NULL) {
1,061,393✔
407
            s->init_data->smlists[list] = new;
723,556✔
408
            s->init_data->smlists_tail[list] = new;
723,556✔
409
            new->next = NULL;
723,556✔
410
            new->prev = NULL;
723,556✔
411
        } else {
723,556✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
337,837✔
413
            cur->next = new;
337,837✔
414
            new->prev = cur;
337,837✔
415
            new->next = NULL;
337,837✔
416
            s->init_data->smlists_tail[list] = new;
337,837✔
417
        }
337,837✔
418
        new->idx = s->init_data->sm_cnt;
1,061,393✔
419
        s->init_data->sm_cnt++;
1,061,393✔
420

421
    } else {
1,108,121✔
422
        /* app-layer-events (and possibly others?) can get here w/o a "list"
423
         * already set up. */
424

425
        /* unset any existing list if it isn't the same as the new */
426
        if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) {
993,485✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
14,185✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
14,185✔
429
        }
14,185✔
430

431
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) {
993,485✔
432
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
53,075✔
433
                if (s->init_data->buffers[x].id == (uint32_t)list &&
30,818✔
434
                        !s->init_data->buffers[x].multi_capable) {
30,818✔
435
                    SCLogDebug("reusing buffer %u as it isn't multi-capable", x);
3,223✔
436
                    s->init_data->curbuf = &s->init_data->buffers[x];
3,223✔
437
                    break;
3,223✔
438
                }
3,223✔
439
            }
30,818✔
440
        }
25,480✔
441

442
        if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
993,485✔
443
                s->init_data->curbuf == NULL) {
993,485✔
444
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
419,959✔
445
                SCLogError("failed to expand rule buffer array");
3✔
446
                new->ctx = NULL;
3✔
447
                SigMatchFree(de_ctx, new);
3✔
448
                return NULL;
3✔
449
            } else {
419,956✔
450
                /* initialize new buffer */
451
                s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
419,956✔
452
                s->init_data->curbuf->id = list;
419,956✔
453
                /* buffer set up by sigmatch is tracked in case we add a stickybuffer for the
454
                 * same list. */
455
                s->init_data->curbuf->sm_init = true;
419,956✔
456
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT) {
419,956✔
457
                    s->init_data->curbuf->only_tc = true;
21✔
458
                }
21✔
459
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOSERVER) {
419,956✔
460
                    s->init_data->curbuf->only_ts = true;
×
461
                }
×
462
                SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
419,956✔
463
            }
419,956✔
464
        }
419,959✔
465
        BUG_ON(s->init_data->curbuf == NULL);
993,482✔
466

467
        new->prev = s->init_data->curbuf->tail;
993,482✔
468
        if (s->init_data->curbuf->tail)
993,482✔
469
            s->init_data->curbuf->tail->next = new;
205,028✔
470
        if (s->init_data->curbuf->head == NULL)
993,482✔
471
            s->init_data->curbuf->head = new;
788,454✔
472
        s->init_data->curbuf->tail = new;
993,482✔
473
        new->idx = s->init_data->sm_cnt;
993,482✔
474
        s->init_data->sm_cnt++;
993,482✔
475
        SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
993,482✔
476
                sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
993,482✔
477

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
4,149,012✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
3,155,530✔
480
                    sigmatch_table[sm->type].name, sm->idx);
3,155,530✔
481
        }
3,155,530✔
482
    }
993,482✔
483
    return new;
2,054,875✔
484
}
2,054,878✔
485

486
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487
{
10,661✔
488
    if (sm == s->init_data->smlists[sm_list]) {
10,661✔
489
        s->init_data->smlists[sm_list] = sm->next;
6,698✔
490
    }
6,698✔
491
    if (sm == s->init_data->smlists_tail[sm_list]) {
10,661✔
492
        s->init_data->smlists_tail[sm_list] = sm->prev;
7,114✔
493
    }
7,114✔
494
    if (sm->prev != NULL)
10,661✔
495
        sm->prev->next = sm->next;
3,963✔
496
    if (sm->next != NULL)
10,661✔
497
        sm->next->prev = sm->prev;
3,547✔
498
}
10,661✔
499

500
/**
501
 * \brief Returns a pointer to the last SigMatch instance of a particular type
502
 *        in a Signature of the payload list.
503
 *
504
 * \param s    Pointer to the tail of the sigmatch list
505
 * \param type SigMatch type which has to be searched for in the Signature.
506
 *
507
 * \retval match Pointer to the last SigMatch instance of type 'type'.
508
 */
509
static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type)
510
{
1,355,518✔
511
    while (sm != NULL) {
3,857,802✔
512
        if (sm->type == type) {
3,319,785✔
513
            return sm;
817,501✔
514
        }
817,501✔
515
        sm = sm->prev;
2,502,284✔
516
    }
2,502,284✔
517

518
    return NULL;
538,017✔
519
}
1,355,518✔
520

521
/** \brief get the last SigMatch from lists that support
522
 *         MPM.
523
 *  \note only supports the lists that are registered through
524
 *        DetectBufferTypeSupportsMpm().
525
 */
526
SigMatch *DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
527
{
47,395✔
528
    SigMatch *sm_last = NULL;
47,395✔
529
    SigMatch *sm_new;
47,395✔
530
    uint32_t sm_type;
47,395✔
531

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
111,155✔
533
        const int id = s->init_data->buffers[i].id;
63,760✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
63,760✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
63,010✔
536
            if (sm_new == NULL)
63,010✔
537
                continue;
3,537✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
59,473✔
539
                sm_last = sm_new;
57,808✔
540
        }
59,473✔
541
    }
63,760✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
379,160✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
331,765✔
545
            continue;
331,765✔
546
        SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
×
547
        sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
×
548
        if (sm_new == NULL)
×
549
            continue;
×
550
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
×
551
            sm_last = sm_new;
×
552
    }
×
553

554
    return sm_last;
47,395✔
555
}
47,395✔
556

557
/**
558
 * \brief Returns the sm with the largest index (added latest) from the lists
559
 *        passed to us.
560
 *
561
 * \retval Pointer to Last sm.
562
 */
563
SigMatch *SCDetectGetLastSMFromLists(const Signature *s, ...)
564
{
543,082✔
565
    SigMatch *sm_last = NULL;
543,082✔
566
    SigMatch *sm_new;
543,082✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
543,082✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
939,344✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
396,262✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
396,262✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
73,221✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
73,221✔
574

575
            continue;
73,221✔
576
        }
73,221✔
577
        int sm_type;
323,041✔
578
        va_list ap;
323,041✔
579
        va_start(ap, s);
323,041✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
714,066✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
391,025✔
583
            if (sm_new == NULL)
391,025✔
584
                continue;
105,882✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
285,143✔
586
                sm_last = sm_new;
275,992✔
587
        }
285,143✔
588
        va_end(ap);
323,041✔
589
    }
323,041✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
4,344,656✔
592
        if (s->init_data->smlists[buf_type] == NULL)
3,801,574✔
593
            continue;
3,322,373✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
479,201✔
595
            buf_type != s->init_data->list)
479,201✔
596
            continue;
145,176✔
597

598
        int sm_type;
334,025✔
599
        va_list ap;
334,025✔
600
        va_start(ap, s);
334,025✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
863,635✔
603
        {
529,610✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
529,610✔
605
            if (sm_new == NULL)
529,610✔
606
                continue;
280,572✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
249,038✔
608
                sm_last = sm_new;
239,491✔
609
        }
249,038✔
610
        va_end(ap);
334,025✔
611
    }
334,025✔
612

613
    return sm_last;
543,082✔
614
}
543,082✔
615

616
/**
617
 * \brief Returns the sm with the largest index (added last) from the list
618
 *        passed to us as a pointer.
619
 *
620
 * \param sm_list pointer to the SigMatch we should look before
621
 * \param va_args list of keyword types terminated by -1
622
 *
623
 * \retval sm_last to last sm.
624
 */
625
SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...)
626
{
197,181✔
627
    SigMatch *sm_last = NULL;
197,181✔
628
    SigMatch *sm_new;
197,181✔
629
    int sm_type;
197,181✔
630

631
    va_list ap;
197,181✔
632
    va_start(ap, sm_list);
197,181✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
528,533✔
635
    {
331,352✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
331,352✔
637
        if (sm_new == NULL)
331,352✔
638
            continue;
134,303✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
197,049✔
640
            sm_last = sm_new;
184,445✔
641
    }
197,049✔
642

643
    va_end(ap);
197,181✔
644

645
    return sm_last;
197,181✔
646
}
197,181✔
647

648
/**
649
 * \brief Returns the sm with the largest index (added last) from the list
650
 *        passed to us as an id.
651
 *
652
 * \param list_id id of the list to be searched
653
 * \param va_args list of keyword types terminated by -1
654
 *
655
 * \retval sm_last to last sm.
656
 */
657
SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
658
{
146,474✔
659
    SigMatch *sm_last = NULL;
146,474✔
660
    SigMatch *sm_new;
146,474✔
661
    int sm_type;
146,474✔
662

663
    if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
146,474✔
664
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
57,702✔
665
            sm_new = s->init_data->buffers[x].tail;
34,340✔
666
            if (sm_new == NULL)
34,340✔
667
                continue;
16,026✔
668

669
            va_list ap;
18,314✔
670
            va_start(ap, list_id);
18,314✔
671

672
            for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
36,628✔
673
                sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
18,314✔
674
                if (sm_new == NULL)
18,314✔
675
                    continue;
7,392✔
676
                if (sm_last == NULL || sm_new->idx > sm_last->idx)
10,922✔
677
                    sm_last = sm_new;
9,603✔
678
            }
10,922✔
679

680
            va_end(ap);
18,314✔
681
        }
18,314✔
682
    } else {
123,112✔
683
        SigMatch *sm_list = s->init_data->smlists_tail[list_id];
123,112✔
684
        if (sm_list == NULL)
123,112✔
685
            return NULL;
37,895✔
686

687
        va_list ap;
85,217✔
688
        va_start(ap, list_id);
85,217✔
689

690
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
170,434✔
691
            sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
85,217✔
692
            if (sm_new == NULL)
85,217✔
693
                continue;
9,868✔
694
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
75,349✔
695
                sm_last = sm_new;
75,349✔
696
        }
75,349✔
697

698
        va_end(ap);
85,217✔
699
    }
85,217✔
700
    return sm_last;
108,579✔
701
}
146,474✔
702

703
/**
704
 * \brief Returns the sm with the largest index (added latest) from this sig
705
 *
706
 * \retval sm_last Pointer to last sm
707
 */
708
SigMatch *DetectGetLastSM(const Signature *s)
709
{
45,925✔
710
    SigMatch *sm_last = NULL;
45,925✔
711
    SigMatch *sm_new;
45,925✔
712

713
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
51,498✔
714
        sm_new = s->init_data->buffers[x].tail;
5,573✔
715
        if (sm_new == NULL)
5,573✔
716
            continue;
268✔
717
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
5,305✔
718
            sm_last = sm_new;
4,808✔
719
    }
5,305✔
720

721
    for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
367,400✔
722
        sm_new = s->init_data->smlists_tail[i];
321,475✔
723
        if (sm_new == NULL)
321,475✔
724
            continue;
269,303✔
725
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
52,172✔
726
            sm_last = sm_new;
44,671✔
727
    }
52,172✔
728

729
    return sm_last;
45,925✔
730
}
45,925✔
731

732
static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
733
        SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
734
        SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail)
735
{
58,059✔
736
    /* we won't do any checks for args */
737

738
    if (sm->prev != NULL)
58,059✔
739
        sm->prev->next = sm->next;
9,007✔
740
    if (sm->next != NULL)
58,059✔
741
        sm->next->prev = sm->prev;
805✔
742

743
    if (sm == *src_sm_list)
58,059✔
744
        *src_sm_list = sm->next;
49,052✔
745
    if (sm == *src_sm_list_tail)
58,059✔
746
        *src_sm_list_tail = sm->prev;
57,254✔
747

748
    if (*dst_sm_list == NULL) {
58,059✔
749
        *dst_sm_list = sm;
38,335✔
750
        *dst_sm_list_tail = sm;
38,335✔
751
        sm->next = NULL;
38,335✔
752
        sm->prev = NULL;
38,335✔
753
    } else {
38,335✔
754
        SigMatch *cur = *dst_sm_list_tail;
19,724✔
755
        cur->next = sm;
19,724✔
756
        sm->prev = cur;
19,724✔
757
        sm->next = NULL;
19,724✔
758
        *dst_sm_list_tail = sm;
19,724✔
759
    }
19,724✔
760
}
58,059✔
761

762
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
763
{
66,941✔
764
    if (key_sm == NULL)
66,941✔
765
        return -1;
×
766

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
83,058✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
56,075✔
769
        while (sm != NULL) {
133,643✔
770
            if (sm == key_sm)
117,526✔
771
                return s->init_data->buffers[x].id;
39,958✔
772
            sm = sm->next;
77,568✔
773
        }
77,568✔
774
    }
56,075✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
53,968✔
777
        const SigMatch *sm = s->init_data->smlists[list];
53,968✔
778
        while (sm != NULL) {
200,128✔
779
            if (sm == key_sm)
173,143✔
780
                return list;
26,983✔
781
            sm = sm->next;
146,160✔
782
        }
146,160✔
783
    }
53,968✔
784

785
    SCLogError("Unable to find the sm in any of the "
×
786
               "sm lists");
×
787
    return -1;
×
788
}
26,983✔
789

790
/**
791
 * \brief Parse and setup a direction
792
 *
793
 * \param s signature
794
 * \param str argument to the keyword
795
 * \param only_dir argument wether the keyword only accepts a direction
796
 *
797
 * \retval 0 on success, -1 on failure
798
 */
799
static int DetectSetupDirection(Signature *s, char **str, bool only_dir)
800
{
1,465✔
801
    char *orig = *str;
1,465✔
802
    if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
1,465✔
803
        *str += strlen("to_client");
617✔
804
        // skip space
805
        while (**str && isblank(**str)) {
691✔
806
            (*str)++;
74✔
807
        }
74✔
808
        // check comma or nothing
809
        if (**str) {
617✔
810
            if (only_dir) {
48✔
811
                SCLogError("unknown option: only accepts to_server or to_client");
11✔
812
                return -1;
11✔
813
            }
11✔
814
            if (**str != ',') {
37✔
815
                // leave to_client_something for next parser if not only_dir
816
                *str = orig;
4✔
817
                return 0;
4✔
818
            } else {
33✔
819
                (*str)++;
33✔
820
            }
33✔
821
            while (**str && isblank(**str)) {
63✔
822
                (*str)++;
30✔
823
            }
30✔
824
        }
33✔
825
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
602✔
826
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
602✔
827
            if (s->flags & SIG_FLAG_TOSERVER) {
354✔
828
                SCLogError("contradictory directions");
2✔
829
                return -1;
2✔
830
            }
2✔
831
            s->flags |= SIG_FLAG_TOCLIENT;
352✔
832
        }
352✔
833
    } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
850✔
834
        *str += strlen("to_server");
291✔
835
        // skip space
836
        while (**str && isblank(**str)) {
327✔
837
            (*str)++;
36✔
838
        }
36✔
839
        // check comma or nothing
840
        if (**str) {
291✔
841
            if (only_dir) {
8✔
842
                SCLogError("unknown option: only accepts to_server or to_client");
7✔
843
                return -1;
7✔
844
            }
7✔
845
            if (**str != ',') {
1✔
846
                // leave to_client_something for next parser if not only_dir
847
                *str = orig;
1✔
848
                return 0;
1✔
849
            } else {
1✔
850
                (*str)++;
×
851
            }
×
852
            while (**str && isblank(**str)) {
×
853
                (*str)++;
×
854
            }
×
855
        }
×
856
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOSERVER;
283✔
857
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
283✔
858
            if (s->flags & SIG_FLAG_TOCLIENT) {
147✔
859
                SCLogError("contradictory directions");
1✔
860
                return -1;
1✔
861
            }
1✔
862
            s->flags |= SIG_FLAG_TOSERVER;
146✔
863
        }
146✔
864
    } else if (only_dir) {
557✔
865
        SCLogError("unknown option: only accepts to_server or to_client");
58✔
866
        return -1;
58✔
867
    }
58✔
868
    return 0;
1,381✔
869
}
1,465✔
870

871
static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output,
872
        size_t output_size, bool requires)
873
{
20,281,035✔
874
    SigTableElmt *st = NULL;
20,281,035✔
875
    char *optname = NULL;
20,281,035✔
876
    char *optvalue = NULL;
20,281,035✔
877

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
20,281,035✔
880
        optstr++;
17,498,129✔
881
    }
17,498,129✔
882

883
    /* Look for the end of this option, handling escaped semicolons. */
884
    char *optend = optstr;
20,281,035✔
885
    for (;;) {
20,293,939✔
886
        optend = strchr(optend, ';');
20,293,939✔
887
        if (optend == NULL) {
20,293,939✔
888
            SCLogError("no terminating \";\" found");
236,610✔
889
            goto error;
236,610✔
890
        }
236,610✔
891
        else if (optend > optstr && *(optend -1 ) == '\\') {
20,057,329✔
892
            optend++;
12,904✔
893
        } else {
20,044,425✔
894
            break;
20,044,425✔
895
        }
20,044,425✔
896
    }
20,293,939✔
897
    *(optend++) = '\0';
20,044,425✔
898

899
    /* Find the start of the option value. */
900
    char *optvalptr = strchr(optstr, ':');
20,044,425✔
901
    if (optvalptr) {
20,044,425✔
902
        *(optvalptr++) = '\0';
16,749,677✔
903

904
        /* Trim trailing space from name. */
905
        for (size_t i = strlen(optvalptr); i > 0; i--) {
17,079,805✔
906
            if (isblank(optvalptr[i - 1])) {
17,039,054✔
907
                optvalptr[i - 1] = '\0';
330,128✔
908
            } else {
16,708,926✔
909
                break;
16,708,926✔
910
            }
16,708,926✔
911
        }
17,039,054✔
912

913
        optvalue = optvalptr;
16,749,677✔
914
    }
16,749,677✔
915

916
    /* Trim trailing space from name. */
917
    for (size_t i = strlen(optstr); i > 0; i--) {
20,094,759✔
918
        if (isblank(optstr[i - 1])) {
20,026,579✔
919
            optstr[i - 1] = '\0';
50,334✔
920
        } else {
19,976,245✔
921
            break;
19,976,245✔
922
        }
19,976,245✔
923
    }
20,026,579✔
924
    optname = optstr;
20,044,425✔
925

926
    /* Check for options that are only to be processed during the
927
     * first "requires" pass. */
928
    bool requires_only = strcasecmp(optname, "requires") == 0 || strcasecmp(optname, "sid") == 0;
20,044,425✔
929
    if ((requires && !requires_only) || (!requires && requires_only)) {
20,044,425✔
930
        goto finish;
11,943,445✔
931
    }
11,943,445✔
932

933
    /* Call option parsing */
934
    st = SigTableGet(optname);
8,100,980✔
935
    if (st == NULL || st->Setup == NULL) {
8,100,980✔
936
        SCLogError("unknown rule keyword '%s'.", optname);
272,943✔
937
        goto error;
272,943✔
938
    }
272,943✔
939

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
7,828,037✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
6,878,986✔
942
            SCLogError(
6,364✔
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
6,364✔
944
            goto error;
6,364✔
945
        }
6,364✔
946
    } else if (st->flags & SIGMATCH_NOOPT) {
6,878,986✔
947
        if (optvalue && strlen(optvalue)) {
763,721✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
134✔
949
            goto error;
134✔
950
        }
134✔
951
    }
763,721✔
952
    s->init_data->negated = false;
7,821,539✔
953

954
    const enum DetectKeywordId idx = SigTableGetIndex(st);
7,821,539✔
955
    s->init_data->has_possible_prefilter |= de_ctx->sm_types_prefilter[idx];
7,821,539✔
956

957
    if (st->flags & SIGMATCH_INFO_DEPRECATED) {
7,821,539✔
958
#define URL "https://suricata.io/our-story/deprecation-policy/"
×
959
        if (st->alternative == 0)
×
960
            SCLogWarning("keyword '%s' is deprecated "
×
961
                         "and will be removed soon. See %s",
×
962
                    st->name, URL);
×
963
        else
×
964
            SCLogWarning("keyword '%s' is deprecated "
×
965
                         "and will be removed soon. Use '%s' instead. "
×
966
                         "See %s",
×
967
                    st->name, sigmatch_table[st->alternative].name, URL);
×
968
#undef URL
×
969
    }
×
970

971
    int setup_ret = 0;
7,821,539✔
972

973
    /* Validate double quoting, trimming trailing white space along the way. */
974
    if (optvalue != NULL && strlen(optvalue) > 0) {
7,821,539✔
975
        size_t ovlen = strlen(optvalue);
6,898,386✔
976
        char *ptr = optvalue;
6,898,386✔
977

978
        /* skip leading whitespace */
979
        while (ovlen > 0) {
7,343,585✔
980
            if (!isblank(*ptr))
7,343,585✔
981
                break;
6,898,386✔
982
            ptr++;
445,199✔
983
            ovlen--;
445,199✔
984
        }
445,199✔
985
        if (ovlen == 0) {
6,898,386✔
986
            SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
×
987
                    optstr);
×
988
            goto error;
×
989
        }
×
990

991
        if (s->init_data->firewall_rule && (st->flags & SIGMATCH_SUPPORT_FIREWALL) == 0) {
6,898,386✔
UNCOV
992
            SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
×
UNCOV
993
        }
×
994

995
        /* see if value is negated */
996
        if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
6,898,386✔
997
            s->init_data->negated = true;
39,717✔
998
            ptr++;
39,717✔
999
            ovlen--;
39,717✔
1000
        }
39,717✔
1001
        /* skip more whitespace */
1002
        while (ovlen > 0) {
6,900,905✔
1003
            if (!isblank(*ptr))
6,900,697✔
1004
                break;
6,898,178✔
1005
            ptr++;
2,519✔
1006
            ovlen--;
2,519✔
1007
        }
2,519✔
1008
        if (ovlen == 0) {
6,898,386✔
1009
            SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
208✔
1010
                    optstr);
208✔
1011
            goto error;
208✔
1012
        }
208✔
1013
        /* if quoting is mandatory, enforce it */
1014
        if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
6,898,178✔
1015
            SCLogError("invalid formatting to %s keyword: "
10,766✔
1016
                       "value must be double quoted \'%s\'",
10,766✔
1017
                    optname, optstr);
10,766✔
1018
            goto error;
10,766✔
1019
        }
10,766✔
1020

1021
        if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
6,887,412✔
1022
                && ovlen && *ptr == '"')
6,887,412✔
1023
        {
1,788,781✔
1024
            for (; ovlen > 0; ovlen--) {
1,788,781✔
1025
                if (isblank(ptr[ovlen - 1])) {
1,788,781✔
1026
                    ptr[ovlen - 1] = '\0';
×
1027
                } else {
1,788,781✔
1028
                    break;
1,788,781✔
1029
                }
1,788,781✔
1030
            }
1,788,781✔
1031
            if (ovlen && ptr[ovlen - 1] != '"') {
1,788,781✔
1032
                SCLogError("bad option value formatting (possible missing semicolon) "
48,828✔
1033
                           "for keyword %s: \'%s\'",
48,828✔
1034
                        optname, optvalue);
48,828✔
1035
                goto error;
48,828✔
1036
            }
48,828✔
1037
            if (ovlen > 1) {
1,739,953✔
1038
                /* strip leading " */
1039
                ptr++;
1,721,507✔
1040
                ovlen--;
1,721,507✔
1041
                ptr[ovlen - 1] = '\0';
1,721,507✔
1042
                ovlen--;
1,721,507✔
1043
            }
1,721,507✔
1044
            if (ovlen == 0) {
1,739,953✔
1045
                SCLogError("bad input "
614✔
1046
                           "for keyword %s: \'%s\'",
614✔
1047
                        optname, optvalue);
614✔
1048
                goto error;
614✔
1049
            }
614✔
1050
        } else {
5,098,631✔
1051
            if (*ptr == '"') {
5,098,631✔
1052
                SCLogError(
1,281✔
1053
                        "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1,281✔
1054
                goto error;
1,281✔
1055
            }
1,281✔
1056
        }
5,098,631✔
1057
        /* setup may or may not add a new SigMatch to the list */
1058
        if (st->flags & SIGMATCH_SUPPORT_DIR) {
6,836,689✔
1059
            if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1,457✔
1060
                SCLogError("%s failed to setup direction", st->name);
76✔
1061
                goto error;
76✔
1062
            }
76✔
1063
        }
1,457✔
1064
        setup_ret = st->Setup(de_ctx, s, ptr);
6,836,613✔
1065
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
6,836,613✔
1066
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
6,836,613✔
1067
    } else {
6,836,613✔
1068
        /* setup may or may not add a new SigMatch to the list */
1069
        setup_ret = st->Setup(de_ctx, s, NULL);
923,153✔
1070
    }
923,153✔
1071
    if (setup_ret < 0) {
7,759,766✔
1072
        SCLogDebug("\"%s\" failed to setup", st->name);
635,218✔
1073

1074
        /* handle 'silent' error case */
1075
        if (setup_ret == -2) {
635,218✔
UNCOV
1076
            if (!de_ctx->sm_types_silent_error[idx]) {
×
UNCOV
1077
                de_ctx->sm_types_silent_error[idx] = true;
×
UNCOV
1078
                return -1;
×
UNCOV
1079
            }
×
UNCOV
1080
            return -2;
×
UNCOV
1081
        }
×
1082
        return setup_ret;
635,218✔
1083
    }
635,218✔
1084
    s->init_data->negated = false;
7,124,548✔
1085

1086
finish:
19,067,993✔
1087
    if (strlen(optend) > 0) {
19,067,993✔
1088
        strlcpy(output, optend, output_size);
15,373,007✔
1089
        return 1;
15,373,007✔
1090
    }
15,373,007✔
1091

1092
    return 0;
3,694,986✔
1093

1094
error:
577,824✔
1095
    return -1;
577,824✔
1096
}
19,067,993✔
1097

1098
/** \brief Parse address string and update signature
1099
 *
1100
 *  \retval 0 ok, -1 error
1101
 */
1102
static int SigParseAddress(DetectEngineCtx *de_ctx,
1103
        Signature *s, const char *addrstr, char flag)
1104
{
4,000,263✔
1105
    SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
4,000,263✔
1106

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
4,000,263✔
1109
        if (strcasecmp(addrstr, "any") == 0)
2,023,423✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
1,677,889✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
2,023,423✔
1113
                &s->init_data->src_contains_negation);
2,023,423✔
1114
        if (s->init_data->src == NULL)
2,023,423✔
1115
            goto error;
46,583✔
1116
    } else {
2,023,423✔
1117
        if (strcasecmp(addrstr, "any") == 0)
1,976,840✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
1,702,364✔
1119

1120
        s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
1,976,840✔
1121
                &s->init_data->dst_contains_negation);
1,976,840✔
1122
        if (s->init_data->dst == NULL)
1,976,840✔
1123
            goto error;
78,684✔
1124
    }
1,976,840✔
1125

1126
    return 0;
3,874,996✔
1127

1128
error:
125,267✔
1129
    return -1;
125,267✔
1130
}
4,000,263✔
1131

1132
static bool IsBuiltIn(const char *n)
1133
{
1,054✔
1134
    if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
1,054✔
1135
        return true;
68✔
1136
    }
68✔
1137
    if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
986✔
1138
        return true;
68✔
1139
    }
68✔
1140
    return false;
918✔
1141
}
986✔
1142

1143
/** \brief register app hooks as generic lists
1144
 *
1145
 *  Register each hook in each app protocol as:
1146
 *  <alproto>:<hook name>:generic
1147
 *  These lists can be used by lua scripts to hook into.
1148
 *
1149
 *  \todo move elsewhere? maybe a detect-engine-hook.c?
1150
 */
1151
void DetectRegisterAppLayerHookLists(void)
1152
{
34✔
1153
    for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1,326✔
1154
        const char *alproto_name = AppProtoToString(a);
1,292✔
1155
        if (strcmp(alproto_name, "http") == 0)
1,292✔
1156
            alproto_name = "http1";
34✔
1157
        SCLogDebug("alproto %u/%s", a, alproto_name);
1,292✔
1158

1159
        const int max_progress_ts =
1,292✔
1160
                AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOSERVER);
1,292✔
1161
        const int max_progress_tc =
1,292✔
1162
                AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOCLIENT);
1,292✔
1163

1164
        char ts_tx_started[64];
1,292✔
1165
        snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic", alproto_name);
1,292✔
1166
        DetectAppLayerInspectEngineRegister(
1,292✔
1167
                ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1,292✔
1168
        SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1,292✔
1169
                (uint32_t)strlen(ts_tx_started));
1,292✔
1170

1171
        char tc_tx_started[64];
1,292✔
1172
        snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic", alproto_name);
1,292✔
1173
        DetectAppLayerInspectEngineRegister(
1,292✔
1174
                tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1,292✔
1175
        SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1,292✔
1176
                (uint32_t)strlen(tc_tx_started));
1,292✔
1177

1178
        char ts_tx_complete[64];
1,292✔
1179
        snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1,292✔
1180
                alproto_name);
1,292✔
1181
        DetectAppLayerInspectEngineRegister(ts_tx_complete, a, SIG_FLAG_TOSERVER, max_progress_ts,
1,292✔
1182
                DetectEngineInspectGenericList, NULL);
1,292✔
1183
        SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1,292✔
1184
                (uint32_t)strlen(ts_tx_complete));
1,292✔
1185

1186
        char tc_tx_complete[64];
1,292✔
1187
        snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1,292✔
1188
                alproto_name);
1,292✔
1189
        DetectAppLayerInspectEngineRegister(tc_tx_complete, a, SIG_FLAG_TOCLIENT, max_progress_tc,
1,292✔
1190
                DetectEngineInspectGenericList, NULL);
1,292✔
1191
        SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1,292✔
1192
                (uint32_t)strlen(tc_tx_complete));
1,292✔
1193

1194
        for (int p = 0; p <= max_progress_ts; p++) {
4,366✔
1195
            const char *name = AppLayerParserGetStateNameById(
3,074✔
1196
                    IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
3,074✔
1197
            if (name != NULL && !IsBuiltIn(name)) {
3,074✔
1198
                char list_name[64];
442✔
1199
                snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
442✔
1200
                SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
442✔
1201
                        (uint32_t)strlen(list_name));
442✔
1202

1203
                DetectAppLayerInspectEngineRegister(
442✔
1204
                        list_name, a, SIG_FLAG_TOSERVER, p, DetectEngineInspectGenericList, NULL);
442✔
1205
            }
442✔
1206
        }
3,074✔
1207
        for (int p = 0; p <= max_progress_tc; p++) {
4,400✔
1208
            const char *name = AppLayerParserGetStateNameById(
3,108✔
1209
                    IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
3,108✔
1210
            if (name != NULL && !IsBuiltIn(name)) {
3,108✔
1211
                char list_name[64];
476✔
1212
                snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
476✔
1213
                SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
476✔
1214
                        (uint32_t)strlen(list_name));
476✔
1215

1216
                DetectAppLayerInspectEngineRegister(
476✔
1217
                        list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
476✔
1218
            }
476✔
1219
        }
3,108✔
1220
    }
1,292✔
1221
}
34✔
1222

1223
#ifdef DEBUG
1224
static const char *SignatureHookTypeToString(enum SignatureHookType t)
1225
{
1226
    switch (t) {
1227
        case SIGNATURE_HOOK_TYPE_NOT_SET:
1228
            return "not_set";
1229
        case SIGNATURE_HOOK_TYPE_APP:
1230
            return "app";
1231
        case SIGNATURE_HOOK_TYPE_PKT:
1232
            return "pkt";
1233
    }
1234
    return "unknown";
1235
}
1236
#endif
1237

1238
static enum SignatureHookPkt HookPktFromString(const char *str)
1239
{
151✔
1240
    if (strcmp(str, "flow_start") == 0) {
151✔
1241
        return SIGNATURE_HOOK_PKT_FLOW_START;
4✔
1242
    } else if (strcmp(str, "pre_flow") == 0) {
147✔
1243
        return SIGNATURE_HOOK_PKT_PRE_FLOW;
2✔
1244
    } else if (strcmp(str, "pre_stream") == 0) {
145✔
1245
        return SIGNATURE_HOOK_PKT_PRE_STREAM;
2✔
1246
    } else if (strcmp(str, "all") == 0) {
143✔
1247
        return SIGNATURE_HOOK_PKT_ALL;
2✔
1248
    }
2✔
1249
    return SIGNATURE_HOOK_PKT_NOT_SET;
141✔
1250
}
151✔
1251

1252
#ifdef DEBUG
1253
static const char *HookPktToString(const enum SignatureHookPkt ph)
1254
{
1255
    switch (ph) {
1256
        case SIGNATURE_HOOK_PKT_NOT_SET:
1257
            return "not set";
1258
        case SIGNATURE_HOOK_PKT_FLOW_START:
1259
            return "flow_start";
1260
        case SIGNATURE_HOOK_PKT_PRE_FLOW:
1261
            return "pre_flow";
1262
        case SIGNATURE_HOOK_PKT_PRE_STREAM:
1263
            return "pre_stream";
1264
        case SIGNATURE_HOOK_PKT_ALL:
1265
            return "all";
1266
    }
1267
    return "error";
1268
}
1269
#endif
1270

1271
static SignatureHook SetPktHook(const char *hook_str)
1272
{
5✔
1273
    SignatureHook h = {
5✔
1274
        .type = SIGNATURE_HOOK_TYPE_PKT,
5✔
1275
        .t.pkt.ph = HookPktFromString(hook_str),
5✔
1276
    };
5✔
1277
    return h;
5✔
1278
}
5✔
1279

1280
/**
1281
 * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1282
 */
1283
static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1284
{
146✔
1285
    enum SignatureHookPkt hook = HookPktFromString(h);
146✔
1286
    if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
146✔
1287
        s->init_data->hook = SetPktHook(h);
5✔
1288
        if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
5✔
1289
            return -1; // TODO unreachable?
×
1290
        }
×
1291
    } else {
141✔
1292
        SCLogError("unknown pkt hook %s", h);
141✔
1293
        return -1;
141✔
1294
    }
141✔
1295

1296
    SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
5✔
1297
            SignatureHookTypeToString(s->init_data->hook.type),
5✔
1298
            HookPktToString(s->init_data->hook.t.pkt.ph));
5✔
1299
    return 0;
5✔
1300
}
146✔
1301

1302
static SignatureHook SetAppHook(const AppProto alproto, int progress)
1303
{
141✔
1304
    SignatureHook h = {
141✔
1305
        .type = SIGNATURE_HOOK_TYPE_APP,
141✔
1306
        .t.app.alproto = alproto,
141✔
1307
        .t.app.app_progress = progress,
141✔
1308
    };
141✔
1309
    return h;
141✔
1310
}
141✔
1311

1312
/**
1313
 * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1314
 */
1315
static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1316
{
261✔
1317
    if (strcmp(h, "request_started") == 0) {
261✔
1318
        s->flags |= SIG_FLAG_TOSERVER;
3✔
1319
        s->init_data->hook =
3✔
1320
                SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
3✔
1321
    } else if (strcmp(h, "response_started") == 0) {
258✔
1322
        s->flags |= SIG_FLAG_TOCLIENT;
1✔
1323
        s->init_data->hook =
1✔
1324
                SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1✔
1325
    } else if (strcmp(h, "request_complete") == 0) {
257✔
1326
        s->flags |= SIG_FLAG_TOSERVER;
15✔
1327
        s->init_data->hook = SetAppHook(s->alproto,
15✔
1328
                AppLayerParserGetStateProgressCompletionStatus(s->alproto, STREAM_TOSERVER));
15✔
1329
    } else if (strcmp(h, "response_complete") == 0) {
250✔
1330
        s->flags |= SIG_FLAG_TOCLIENT;
5✔
1331
        s->init_data->hook = SetAppHook(s->alproto,
5✔
1332
                AppLayerParserGetStateProgressCompletionStatus(s->alproto, STREAM_TOCLIENT));
5✔
1333
    } else {
237✔
1334
        const int progress_ts = AppLayerParserGetStateIdByName(
237✔
1335
                IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
237✔
1336
        if (progress_ts >= 0) {
237✔
1337
            s->flags |= SIG_FLAG_TOSERVER;
51✔
1338
            s->init_data->hook = SetAppHook(s->alproto, progress_ts);
51✔
1339
        } else {
186✔
1340
            const int progress_tc = AppLayerParserGetStateIdByName(
186✔
1341
                    IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
186✔
1342
            if (progress_tc < 0) {
186✔
1343
                return -1;
120✔
1344
            }
120✔
1345
            s->flags |= SIG_FLAG_TOCLIENT;
66✔
1346
            s->init_data->hook = SetAppHook(s->alproto, progress_tc);
66✔
1347
        }
66✔
1348
    }
237✔
1349

1350
    char generic_hook_name[64];
141✔
1351
    snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
141✔
1352
    int list = DetectBufferTypeGetByName(generic_hook_name);
141✔
1353
    if (list < 0) {
141✔
1354
        SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
4✔
1355
        return -1;
4✔
1356
    }
4✔
1357
    s->init_data->hook.sm_list = list;
137✔
1358

1359
    SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
137✔
1360
            SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
137✔
1361
            s->init_data->hook.t.app.app_progress);
137✔
1362

1363
    s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
137✔
1364
    return 0;
137✔
1365
}
141✔
1366

1367
void DetectListSupportedProtocols(void)
1368
{
1✔
1369
    printf("=========Supported Rule Protocols=========\n");
1✔
1370
    DetectEngineProtoList();
1✔
1371
    AppProtoDetectListNames();
1✔
1372
}
1✔
1373

1374
/**
1375
 * \brief Parses the protocol supplied by the Signature.
1376
 *
1377
 *        http://www.iana.org/assignments/protocol-numbers
1378
 *
1379
 * \param s        Pointer to the Signature instance to which the parsed
1380
 *                 protocol has to be added.
1381
 * \param protostr Pointer to the character string containing the protocol name.
1382
 *
1383
 * \retval  0 On successfully parsing the protocol sent as the argument.
1384
 * \retval -1 On failure
1385
 */
1386
static int SigParseProto(Signature *s, const char *protostr)
1387
{
2,178,396✔
1388
    SCEnter();
2,178,396✔
1389
    if (strlen(protostr) > 32)
2,178,396✔
1390
        return -1;
1,813✔
1391

1392
    char proto[33];
2,176,583✔
1393
    strlcpy(proto, protostr, 33);
2,176,583✔
1394
    const char *p = proto;
2,176,583✔
1395
    const char *h = NULL;
2,176,583✔
1396

1397
    bool has_hook = strchr(proto, ':') != NULL;
2,176,583✔
1398
    if (has_hook) {
2,176,583✔
1399
        char *xsaveptr = NULL;
4,881✔
1400
        p = strtok_r(proto, ":", &xsaveptr);
4,881✔
1401
        h = strtok_r(NULL, ":", &xsaveptr);
4,881✔
1402
        SCLogDebug("p: '%s' h: '%s'", p, h);
4,881✔
1403
    }
4,881✔
1404
    if (p == NULL) {
2,176,583✔
1405
        SCLogError("invalid protocol specification '%s'", proto);
5✔
1406
        return -1;
5✔
1407
    }
5✔
1408

1409
    int r = DetectProtoParse(&s->init_data->proto, (char *)p);
2,176,578✔
1410
    if (r < 0) {
2,176,578✔
1411
        s->alproto = AppLayerGetProtoByName(p);
1,077,757✔
1412
        /* indicate that the signature is app-layer */
1413
        if (s->alproto != ALPROTO_UNKNOWN) {
1,077,757✔
1414
            s->flags |= SIG_FLAG_APPLAYER;
1,017,612✔
1415

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->init_data->proto.proto);
1,017,612✔
1417

1418
            if (h) {
1,017,612✔
1419
                if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
261✔
1420
                    SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
124✔
1421
                    SCReturnInt(-1);
124✔
1422
                }
124✔
1423
            }
261✔
1424
        }
1,017,612✔
1425
        else {
60,145✔
1426
            SCLogError("protocol \"%s\" cannot be used "
60,145✔
1427
                       "in a signature.  Either detection for this protocol "
60,145✔
1428
                       "is not yet supported OR detection has been disabled for "
60,145✔
1429
                       "protocol through the yaml option "
60,145✔
1430
                       "app-layer.protocols.%s.detection-enabled",
60,145✔
1431
                    p, p);
60,145✔
1432
            SCReturnInt(-1);
60,145✔
1433
        }
60,145✔
1434
    } else if (h != NULL) {
1,126,946✔
1435
        SCLogDebug("non-app-layer rule with %s:%s", p, h);
146✔
1436

1437
        if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
146✔
1438
            SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
141✔
1439
            SCReturnInt(-1);
141✔
1440
        }
141✔
1441
    }
146✔
1442

1443
    /* if any of these flags are set they are set in a mutually exclusive
1444
     * manner */
1445
    if (s->init_data->proto.flags & DETECT_PROTO_ONLY_PKT) {
2,116,168✔
1446
        s->flags |= SIG_FLAG_REQUIRE_PACKET;
165,404✔
1447
    } else if (s->init_data->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1,950,764✔
1448
        s->flags |= SIG_FLAG_REQUIRE_STREAM;
21,182✔
1449
    }
21,182✔
1450

1451
    SCReturnInt(0);
2,116,168✔
1452
}
2,176,578✔
1453

1454
/**
1455
 * \brief Parses the port(source or destination) field, from a Signature.
1456
 *
1457
 * \param s       Pointer to the signature which has to be updated with the
1458
 *                port information.
1459
 * \param portstr Pointer to the character string containing the port info.
1460
 * \param         Flag which indicates if the portstr received is src or dst
1461
 *                port.  For src port: flag = 0, dst port: flag = 1.
1462
 *
1463
 * \retval  0 On success.
1464
 * \retval -1 On failure.
1465
 */
1466
static int SigParsePort(const DetectEngineCtx *de_ctx,
1467
        Signature *s, const char *portstr, char flag)
1468
{
3,777,075✔
1469
    int r = 0;
3,777,075✔
1470

1471
    /* XXX VJ exclude handling this for none UDP/TCP proto's */
1472

1473
    SCLogDebug("Port group \"%s\" to be parsed", portstr);
3,777,075✔
1474

1475
    if (flag == 0) {
3,777,075✔
1476
        if (strcasecmp(portstr, "any") == 0)
1,898,156✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
1,478,835✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1,898,156✔
1480
    } else if (flag == 1) {
1,898,156✔
1481
        if (strcasecmp(portstr, "any") == 0)
1,878,919✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
1,396,459✔
1483

1484
        r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1,878,919✔
1485
    }
1,878,919✔
1486

1487
    if (r < 0)
3,777,075✔
1488
        return -1;
94,777✔
1489

1490
    return 0;
3,682,298✔
1491
}
3,777,075✔
1492

1493
/** \retval 1 valid
1494
 *  \retval 0 invalid
1495
 */
1496
static int SigParseActionRejectValidate(const char *action)
1497
{
666✔
1498
#ifdef HAVE_LIBNET11
666✔
1499
#if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1500
    if (sc_set_caps) {
1501
        SCLogError("Libnet 1.1 is "
1502
                   "incompatible with POSIX based capabilities with privs dropping. "
1503
                   "For rejects to work, run as root/super user.");
1504
        return 0;
1505
    }
1506
#endif
1507
#else /* no libnet 1.1 */
1508
    SCLogError("Libnet 1.1.x is "
1509
               "required for action \"%s\" but is not compiled into Suricata",
1510
            action);
1511
    return 0;
1512
#endif
1513
    return 1;
666✔
1514
}
666✔
1515

1516
/** \retval 0 on error
1517
 *  \retval flags on success
1518
 */
1519
static uint8_t ActionStringToFlags(const char *action)
1520
{
2,248,228✔
1521
    if (strcasecmp(action, "alert") == 0) {
2,248,228✔
1522
        return ACTION_ALERT;
1,792,992✔
1523
    } else if (strcasecmp(action, "drop") == 0) {
1,792,992✔
1524
        return ACTION_DROP | ACTION_ALERT;
73,627✔
1525
    } else if (strcasecmp(action, "pass") == 0) {
381,612✔
1526
        return ACTION_PASS;
309,094✔
1527
    } else if (strcasecmp(action, "reject") == 0 ||
309,094✔
1528
               strcasecmp(action, "rejectsrc") == 0)
72,515✔
1529
    {
508✔
1530
        if (!(SigParseActionRejectValidate(action)))
508✔
1531
            return 0;
×
1532
        return ACTION_REJECT | ACTION_DROP | ACTION_ALERT;
508✔
1533
    } else if (strcasecmp(action, "rejectdst") == 0) {
72,009✔
1534
        if (!(SigParseActionRejectValidate(action)))
15✔
1535
            return 0;
×
1536
        return ACTION_REJECT_DST | ACTION_DROP | ACTION_ALERT;
15✔
1537
    } else if (strcasecmp(action, "rejectboth") == 0) {
71,992✔
1538
        if (!(SigParseActionRejectValidate(action)))
143✔
1539
            return 0;
×
1540
        return ACTION_REJECT_BOTH | ACTION_DROP | ACTION_ALERT;
143✔
1541
    } else if (strcasecmp(action, "config") == 0) {
71,849✔
1542
        return ACTION_CONFIG;
2,035✔
1543
    } else if (strcasecmp(action, "accept") == 0) {
69,815✔
1544
        return ACTION_ACCEPT;
38✔
1545
    } else {
69,776✔
1546
        SCLogError("An invalid action \"%s\" was given", action);
69,776✔
1547
        return 0;
69,776✔
1548
    }
69,776✔
1549
}
2,248,228✔
1550

1551
/**
1552
 * \brief Parses the action that has been used by the Signature and allots it
1553
 *        to its Signature instance.
1554
 *
1555
 * \param s      Pointer to the Signature instance to which the action belongs.
1556
 * \param action Pointer to the action string used by the Signature.
1557
 *
1558
 * \retval  0 On successfully parsing the action string and adding it to the
1559
 *            Signature.
1560
 * \retval -1 On failure.
1561
 */
1562
static int SigParseAction(Signature *s, const char *action_in)
1563
{
2,248,234✔
1564
    char action[32];
2,248,234✔
1565
    strlcpy(action, action_in, sizeof(action));
2,248,234✔
1566
    const char *a = action;
2,248,234✔
1567
    const char *o = NULL;
2,248,234✔
1568

1569
    bool has_scope = strchr(action, ':') != NULL;
2,248,234✔
1570
    if (has_scope) {
2,248,234✔
1571
        char *xsaveptr = NULL;
7,884✔
1572
        a = strtok_r(action, ":", &xsaveptr);
7,884✔
1573
        o = strtok_r(NULL, ":", &xsaveptr);
7,884✔
1574
        SCLogDebug("a: '%s' o: '%s'", a, o);
7,884✔
1575
    }
7,884✔
1576
    if (a == NULL) {
2,248,234✔
1577
        SCLogError("invalid protocol specification '%s'", action_in);
6✔
1578
        return -1;
6✔
1579
    }
6✔
1580

1581
    uint8_t flags = ActionStringToFlags(a);
2,248,228✔
1582
    if (flags == 0)
2,248,228✔
1583
        return -1;
69,776✔
1584

1585
    /* parse scope, if any */
1586
    if (o) {
2,178,452✔
1587
        uint8_t scope_flags = 0;
64✔
1588
        if (flags & (ACTION_DROP | ACTION_PASS)) {
64✔
1589
            if (strcmp(o, "packet") == 0) {
20✔
1590
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1✔
1591
            } else if (strcmp(o, "flow") == 0) {
19✔
1592
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
9✔
1593
            } else {
10✔
1594
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
10✔
1595
                           "allowed",
10✔
1596
                        o, action_in);
10✔
1597
                return -1;
10✔
1598
            }
10✔
1599
            s->action_scope = scope_flags;
10✔
1600
        } else if (flags & (ACTION_ACCEPT)) {
44✔
1601
            if (strcmp(o, "packet") == 0) {
36✔
UNCOV
1602
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
×
1603
            } else if (strcmp(o, "hook") == 0) {
36✔
1604
                scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
20✔
1605
            } else if (strcmp(o, "tx") == 0) {
20✔
1606
                scope_flags = (uint8_t)ACTION_SCOPE_TX;
3✔
1607
            } else if (strcmp(o, "flow") == 0) {
13✔
1608
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1✔
1609
            } else {
12✔
1610
                SCLogError(
12✔
1611
                        "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
12✔
1612
                        "'hook' allowed",
12✔
1613
                        o, action_in);
12✔
1614
                return -1;
12✔
1615
            }
12✔
1616
            s->action_scope = scope_flags;
24✔
1617
        } else if (flags & (ACTION_CONFIG)) {
24✔
1618
            if (strcmp(o, "packet") == 0) {
3✔
UNCOV
1619
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
×
1620
            } else {
3✔
1621
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
3✔
1622
                        action_in);
3✔
1623
                return -1;
3✔
1624
            }
3✔
UNCOV
1625
            s->action_scope = scope_flags;
×
1626
        } else {
5✔
1627
            SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
5✔
1628
                       "'drop', 'pass' and 'reject'",
5✔
1629
                    o, action_in);
5✔
1630
            return -1;
5✔
1631
        }
5✔
1632
    }
64✔
1633

1634
    /* require explicit action scope for fw rules */
1635
    if (s->init_data->firewall_rule && s->action_scope == 0) {
2,178,422✔
1636
        SCLogError("firewall rules require setting an explicit action scope");
×
1637
        return -1;
×
1638
    }
×
1639

1640
    if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
2,178,422✔
1641
        SCLogError("'accept' action only supported for firewall rules");
26✔
1642
        return -1;
26✔
1643
    }
26✔
1644

1645
    if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
2,178,396✔
1646
        SCLogError("'pass' action not supported for firewall rules");
×
1647
        return -1;
×
1648
    }
×
1649

1650
    s->action = flags;
2,178,396✔
1651
    return 0;
2,178,396✔
1652
}
2,178,396✔
1653

1654
/**
1655
 * \brief Parse the next token in rule.
1656
 *
1657
 * For rule parsing a token is considered to be a string of characters
1658
 * separated by white space.
1659
 *
1660
 * \param input double pointer to input buffer, will be advanced as input is
1661
 *     parsed.
1662
 * \param output buffer to copy token into.
1663
 * \param output_size length of output buffer.
1664
 */
1665
static inline int SigParseToken(char **input, char *output,
1666
    const size_t output_size)
1667
{
12,512,930✔
1668
    size_t len = *input == NULL ? 0 : strlen(*input);
12,512,930✔
1669

1670
    if (!len) {
12,512,930✔
1671
        return 0;
607,705✔
1672
    }
607,705✔
1673

1674
    while (len && isblank(**input)) {
12,013,823✔
1675
        (*input)++;
108,598✔
1676
        len--;
108,598✔
1677
    }
108,598✔
1678

1679
    char *endptr = strpbrk(*input, " \t\n\r");
11,905,225✔
1680
    if (endptr != NULL) {
11,905,225✔
1681
        *(endptr++) = '\0';
11,625,891✔
1682
    }
11,625,891✔
1683
    strlcpy(output, *input, output_size);
11,905,225✔
1684
    *input = endptr;
11,905,225✔
1685

1686
    return 1;
11,905,225✔
1687
}
12,512,930✔
1688

1689
/**
1690
 * \brief Parse the next rule "list" token.
1691
 *
1692
 * Parses rule tokens that may be lists such as addresses and ports
1693
 * handling the case when they may not be lists.
1694
 *
1695
 * \param input double pointer to input buffer, will be advanced as input is
1696
 *     parsed.
1697
 * \param output buffer to copy token into.
1698
 * \param output_size length of output buffer.
1699
 */
1700
static inline int SigParseList(char **input, char *output,
1701
    const size_t output_size)
1702
{
31,282,325✔
1703
    int in_list = 0;
31,282,325✔
1704
    size_t len = *input != NULL ? strlen(*input) : 0;
31,282,325✔
1705

1706
    if (len == 0) {
31,282,325✔
1707
        return 0;
2,557,782✔
1708
    }
2,557,782✔
1709

1710
    while (len && isblank(**input)) {
29,321,748✔
1711
        (*input)++;
597,205✔
1712
        len--;
597,205✔
1713
    }
597,205✔
1714

1715
    size_t i = 0;
28,724,543✔
1716
    for (i = 0; i < len; i++) {
160,890,792✔
1717
        char c = (*input)[i];
160,336,082✔
1718
        if (c == '[') {
160,336,082✔
1719
            in_list++;
473,206✔
1720
        } else if (c == ']') {
159,862,876✔
1721
            in_list--;
525,483✔
1722
        } else if (c == ' ') {
159,337,393✔
1723
            if (!in_list) {
28,652,467✔
1724
                break;
28,169,833✔
1725
            }
28,169,833✔
1726
        }
28,652,467✔
1727
    }
160,336,082✔
1728
    if (i == len) {
28,724,543✔
1729
        *input = NULL;
554,710✔
1730
        return 0;
554,710✔
1731
    }
554,710✔
1732
    (*input)[i] = '\0';
28,169,833✔
1733
    strlcpy(output, *input, output_size);
28,169,833✔
1734
    *input = *input + i + 1;
28,169,833✔
1735

1736
    return 1;
28,169,833✔
1737
}
28,724,543✔
1738

1739
/**
1740
 *  \internal
1741
 *  \brief split a signature string into a few blocks for further parsing
1742
 *
1743
 *  \param scan_only just scan, don't validate
1744
 */
1745
static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1746
        SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1747
{
6,256,465✔
1748
    char *index, dup[DETECT_MAX_RULE_SIZE];
6,256,465✔
1749

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
6,256,465✔
1751
    index = dup;
6,256,465✔
1752

1753
    /* Action. */
1754
    SigParseToken(&index, parser->action, sizeof(parser->action));
6,256,465✔
1755

1756
    /* Protocol. */
1757
    SigParseList(&index, parser->protocol, sizeof(parser->protocol));
6,256,465✔
1758

1759
    /* Source. */
1760
    SigParseList(&index, parser->src, sizeof(parser->src));
6,256,465✔
1761

1762
    /* Source port(s). */
1763
    SigParseList(&index, parser->sp, sizeof(parser->sp));
6,256,465✔
1764

1765
    /* Direction. */
1766
    SigParseToken(&index, parser->direction, sizeof(parser->direction));
6,256,465✔
1767

1768
    /* Destination. */
1769
    SigParseList(&index, parser->dst, sizeof(parser->dst));
6,256,465✔
1770

1771
    /* Destination port(s). */
1772
    SigParseList(&index, parser->dp, sizeof(parser->dp));
6,256,465✔
1773

1774
    /* Options. */
1775
    if (index == NULL) {
6,256,465✔
1776
        SCLogError("no rule options.");
834,044✔
1777
        goto error;
834,044✔
1778
    }
834,044✔
1779
    while (isspace(*index) || *index == '(') {
9,250,011✔
1780
        index++;
3,827,590✔
1781
    }
3,827,590✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
10,711,501✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
10,641,963✔
1784
            index[i - 1] = '\0';
5,289,080✔
1785
        } else {
5,352,900✔
1786
            break;
5,352,883✔
1787
        }
5,352,883✔
1788
    }
10,641,963✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
5,422,421✔
1790

1791
    if (scan_only) {
5,422,421✔
1792
        return 0;
3,174,187✔
1793
    }
3,174,187✔
1794

1795
    /* Parse Action */
1796
    if (SigParseAction(s, parser->action) < 0)
2,248,234✔
1797
        goto error;
69,838✔
1798

1799
    if (SigParseProto(s, parser->protocol) < 0)
2,178,396✔
1800
        goto error;
62,228✔
1801

1802
    if (strcmp(parser->direction, "<>") == 0) {
2,116,168✔
1803
        s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC;
519,723✔
1804
    } else if (strcmp(parser->direction, "=>") == 0) {
1,596,445✔
1805
        if (s->flags & SIG_FLAG_FIREWALL) {
1,171✔
1806
            SCLogError("transactional bidirectional rules not supported for firewall rules");
×
1807
            goto error;
×
1808
        }
×
1809

1810
        s->flags |= SIG_FLAG_TXBOTHDIR;
1,171✔
1811
    } else if (strcmp(parser->direction, "->") != 0) {
1,595,274✔
1812
        SCLogError("\"%s\" is not a valid direction modifier, "
92,745✔
1813
                   "\"->\" and \"<>\" are supported.",
92,745✔
1814
                parser->direction);
92,745✔
1815
        goto error;
92,745✔
1816
    }
92,745✔
1817

1818
    /* Parse Address & Ports */
1819
    if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
2,023,423✔
1820
       goto error;
46,583✔
1821

1822
    if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1,976,840✔
1823
        goto error;
78,684✔
1824

1825
    /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1826
     * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1827
     * changes that we made sees to it that at this point of time we don't
1828
     * set the ip proto for the sig.  We do it a bit later. */
1829
    if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1,898,156✔
1830
        goto error;
19,237✔
1831
    if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1,878,919✔
1832
        goto error;
75,540✔
1833

1834
    return 0;
1,803,379✔
1835

1836
error:
1,278,899✔
1837
    return -1;
1,278,899✔
1838
}
1,878,919✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
6,554,431✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
956,679,966✔
1843
        if (str[i] < 0x20) {
950,423,501✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1,653,181✔
1846
                continue;
1,377,344✔
1847
            }
1,377,344✔
1848
            return false;
275,837✔
1849
        } else if (str[i] == 0x7f) {
948,770,320✔
1850
            return false;
22,129✔
1851
        }
22,129✔
1852
    }
950,423,501✔
1853
    return true;
6,256,465✔
1854
}
6,554,431✔
1855

1856
/**
1857
 *  \brief parse a signature
1858
 *
1859
 *  \param de_ctx detection engine ctx to add it to
1860
 *  \param s memory structure to store the signature in
1861
 *  \param sigstr the raw signature as a null terminated string
1862
 *  \param addrs_direction direction (for bi-directional sigs)
1863
 *  \param require only scan rule for requires
1864
 *
1865
 *  \param -1 parse error
1866
 *  \param 0 ok
1867
 */
1868
static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1869
        uint8_t addrs_direction, SignatureParser *parser, bool requires)
1870
{
7,448,419✔
1871
    SCEnter();
7,448,419✔
1872

1873
    if (!SCCheckUtf8(sigstr)) {
7,448,419✔
1874
        SCLogError("rule is not valid UTF-8");
893,988✔
1875
        SCReturnInt(-1);
893,988✔
1876
    }
893,988✔
1877

1878
    if (!CheckAscii(sigstr)) {
6,554,431✔
1879
        SCLogError("rule contains invalid (control) characters");
297,966✔
1880
        SCReturnInt(-1);
297,966✔
1881
    }
297,966✔
1882

1883
    int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
6,256,465✔
1884
    if (ret < 0) {
6,256,465✔
1885
        SCLogDebug("SigParseBasics failed");
1,278,899✔
1886
        SCReturnInt(-1);
1,278,899✔
1887
    }
1,278,899✔
1888

1889
    /* we can have no options, so make sure we have them */
1890
    if (strlen(parser->opts) > 0) {
4,977,566✔
1891
        size_t buffer_size = strlen(parser->opts) + 1;
4,908,028✔
1892
        DEBUG_VALIDATE_BUG_ON(buffer_size > DETECT_MAX_RULE_SIZE);
4,908,028✔
1893
        char input[buffer_size];
4,908,028✔
1894
        char output[buffer_size];
4,908,028✔
1895
        memset(input, 0x00, buffer_size);
4,908,028✔
1896
        memcpy(input, parser->opts, strlen(parser->opts) + 1);
4,908,028✔
1897

1898
        /* loop the option parsing. Each run processes one option
1899
         * and returns the rest of the option string through the
1900
         * output variable. */
1901
        do {
20,281,035✔
1902
            memset(output, 0x00, buffer_size);
20,281,035✔
1903
            ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
20,281,035✔
1904
            if (ret == 1) {
20,281,035✔
1905
                memcpy(input, output, buffer_size);
15,373,007✔
1906
            }
15,373,007✔
1907

1908
        } while (ret == 1);
20,281,035✔
1909

1910
        if (ret < 0) {
4,908,028✔
1911
            /* Suricata didn't meet the rule requirements, skip. */
1912
            goto end;
1,213,042✔
1913
        }
1,213,042✔
1914
    }
4,908,028✔
1915

1916
end:
4,977,566✔
1917
    DetectIPProtoRemoveAllSMs(de_ctx, s);
4,977,566✔
1918

1919
    SCReturnInt(ret);
4,977,566✔
1920
}
4,977,566✔
1921

1922
/** \brief check if buffers array still has space left, expand if not
1923
 */
1924
int SignatureInitDataBufferCheckExpand(Signature *s)
1925
{
985,380✔
1926
    if (s->init_data->buffers_size >= 64)
985,380✔
1927
        return -1;
6✔
1928

1929
    if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
985,374✔
1930
        void *ptr = SCRealloc(s->init_data->buffers,
2,027✔
1931
                (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
2,027✔
1932
        if (ptr == NULL)
2,027✔
1933
            return -1;
×
1934
        s->init_data->buffers = ptr;
2,027✔
1935
        for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
18,243✔
1936
            SignatureInitDataBuffer *b = &s->init_data->buffers[x];
16,216✔
1937
            memset(b, 0, sizeof(*b));
16,216✔
1938
        }
16,216✔
1939
        s->init_data->buffers_size += 8;
2,027✔
1940
    }
2,027✔
1941
    return 0;
985,374✔
1942
}
985,374✔
1943

1944
Signature *SigAlloc (void)
1945
{
5,200,236✔
1946
    Signature *sig = SCCalloc(1, sizeof(Signature));
5,200,236✔
1947
    if (unlikely(sig == NULL))
5,200,236✔
1948
        return NULL;
×
1949

1950
    sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
5,200,236✔
1951
    if (sig->init_data == NULL) {
5,200,236✔
1952
        SCFree(sig);
×
1953
        return NULL;
×
1954
    }
×
1955
    sig->init_data->mpm_sm_list = -1;
5,200,236✔
1956

1957
    sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
5,200,236✔
1958
    if (sig->init_data->buffers == NULL) {
5,200,236✔
1959
        SCFree(sig->init_data);
×
1960
        SCFree(sig);
×
1961
        return NULL;
×
1962
    }
×
1963
    sig->init_data->buffers_size = 8;
5,200,236✔
1964

1965
    /* assign it to -1, so that we can later check if the value has been
1966
     * overwritten after the Signature has been parsed, and if it hasn't been
1967
     * overwritten, we can then assign the default value of 3 */
1968
    sig->prio = -1;
5,200,236✔
1969

1970
    /* rule interdepency is false, at start */
1971
    sig->init_data->is_rule_state_dependant = false;
5,200,236✔
1972
    /* first index is 0 */
1973
    sig->init_data->rule_state_dependant_sids_idx = 0;
5,200,236✔
1974

1975
    sig->init_data->list = DETECT_SM_LIST_NOTSET;
5,200,236✔
1976
    return sig;
5,200,236✔
1977
}
5,200,236✔
1978

1979
/**
1980
 * \internal
1981
 * \brief Free Metadata list
1982
 *
1983
 * \param s Pointer to the signature
1984
 */
1985
static void SigMetadataFree(Signature *s)
1986
{
5,200,234✔
1987
    SCEnter();
5,200,234✔
1988

1989
    DetectMetadata *mdata = NULL;
5,200,234✔
1990
    DetectMetadata *next_mdata = NULL;
5,200,234✔
1991

1992
    if (s == NULL || s->metadata == NULL) {
5,200,234✔
1993
        SCReturn;
5,182,355✔
1994
    }
5,182,355✔
1995

1996
    SCLogDebug("s %p, s->metadata %p", s, s->metadata);
17,879✔
1997

1998
    for (mdata = s->metadata->list; mdata != NULL;)   {
61,245✔
1999
        next_mdata = mdata->next;
43,366✔
2000
        DetectMetadataFree(mdata);
43,366✔
2001
        mdata = next_mdata;
43,366✔
2002
    }
43,366✔
2003
    SCFree(s->metadata->json_str);
17,879✔
2004
    SCFree(s->metadata);
17,879✔
2005
    s->metadata = NULL;
17,879✔
2006

2007
    SCReturn;
17,879✔
2008
}
5,200,234✔
2009

2010
/**
2011
 * \internal
2012
 * \brief Free Reference list
2013
 *
2014
 * \param s Pointer to the signature
2015
 */
2016
static void SigRefFree (Signature *s)
2017
{
5,200,234✔
2018
    SCEnter();
5,200,234✔
2019

2020
    DetectReference *ref = NULL;
5,200,234✔
2021
    DetectReference *next_ref = NULL;
5,200,234✔
2022

2023
    if (s == NULL) {
5,200,234✔
2024
        SCReturn;
×
2025
    }
×
2026

2027
    SCLogDebug("s %p, s->references %p", s, s->references);
5,200,234✔
2028

2029
    for (ref = s->references; ref != NULL;)   {
5,270,538✔
2030
        next_ref = ref->next;
70,304✔
2031
        DetectReferenceFree(ref);
70,304✔
2032
        ref = next_ref;
70,304✔
2033
    }
70,304✔
2034

2035
    s->references = NULL;
5,200,234✔
2036

2037
    SCReturn;
5,200,234✔
2038
}
5,200,234✔
2039

2040
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041
{
5,200,234✔
2042
    if (s != NULL) {
5,200,234✔
2043
        int type;
5,200,234✔
2044
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
41,601,872✔
2045
            if (s->sm_arrays[type] != NULL) {
36,401,638✔
2046
                if (ctxs) {
108,805✔
2047
                    SigMatchData *smd = s->sm_arrays[type];
108,805✔
2048
                    while(1) {
140,343✔
2049
                        if (sigmatch_table[smd->type].Free != NULL) {
140,343✔
2050
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
140,025✔
2051
                        }
140,025✔
2052
                        if (smd->is_last)
140,343✔
2053
                            break;
108,805✔
2054
                        smd++;
31,538✔
2055
                    }
31,538✔
2056
                }
108,805✔
2057

2058
                SCFree(s->sm_arrays[type]);
108,805✔
2059
            }
108,805✔
2060
        }
36,401,638✔
2061
    }
5,200,234✔
2062
}
5,200,234✔
2063

2064
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
2065
{
5,215,326✔
2066
    if (s == NULL)
5,215,326✔
2067
        return;
15,092✔
2068

2069
    int i;
5,200,234✔
2070

2071
    if (s->init_data && s->init_data->transforms.cnt) {
5,200,234✔
2072
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
57,933✔
2073
            if (s->init_data->transforms.transforms[i].options) {
32,933✔
2074
                int transform = s->init_data->transforms.transforms[i].transform;
12,375✔
2075
                sigmatch_table[transform].Free(
12,375✔
2076
                        de_ctx, s->init_data->transforms.transforms[i].options);
12,375✔
2077
                s->init_data->transforms.transforms[i].options = NULL;
12,375✔
2078
            }
12,375✔
2079
        }
32,933✔
2080
    }
25,000✔
2081
    if (s->init_data) {
5,200,234✔
2082
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
40,353,536✔
2083
            SigMatch *sm = s->init_data->smlists[i];
35,309,344✔
2084
            while (sm != NULL) {
36,156,678✔
2085
                SigMatch *nsm = sm->next;
847,334✔
2086
                SigMatchFree(de_ctx, sm);
847,334✔
2087
                sm = nsm;
847,334✔
2088
            }
847,334✔
2089
        }
35,309,344✔
2090

2091
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
5,910,245✔
2092
            SigMatch *sm = s->init_data->buffers[x].head;
866,053✔
2093
            while (sm != NULL) {
1,748,337✔
2094
                SigMatch *nsm = sm->next;
882,284✔
2095
                SigMatchFree(de_ctx, sm);
882,284✔
2096
                sm = nsm;
882,284✔
2097
            }
882,284✔
2098
        }
866,053✔
2099
        if (s->init_data->cidr_dst != NULL)
5,044,192✔
2100
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
74,717✔
2101

2102
        if (s->init_data->cidr_src != NULL)
5,044,192✔
2103
            IPOnlyCIDRListFree(s->init_data->cidr_src);
76,419✔
2104

2105
        SCFree(s->init_data->buffers);
5,044,192✔
2106
        s->init_data->buffers = NULL;
5,044,192✔
2107
    }
5,044,192✔
2108
    SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
5,200,234✔
2109
    if (s->init_data) {
5,200,234✔
2110
        SCFree(s->init_data);
5,044,192✔
2111
        s->init_data = NULL;
5,044,192✔
2112
    }
5,044,192✔
2113

2114
    if (s->sp != NULL) {
5,200,234✔
2115
        DetectPortCleanupList(NULL, s->sp);
1,878,921✔
2116
    }
1,878,921✔
2117
    if (s->dp != NULL) {
5,200,234✔
2118
        DetectPortCleanupList(NULL, s->dp);
1,805,786✔
2119
    }
1,805,786✔
2120
    if (s->proto) {
5,200,234✔
2121
        SCFree(s->proto);
110,488✔
2122
    }
110,488✔
2123

2124
    if (s->msg != NULL)
5,200,234✔
2125
        SCFree(s->msg);
896,067✔
2126

2127
    if (s->addr_src_match4 != NULL) {
5,200,234✔
2128
        SCFree(s->addr_src_match4);
868,286✔
2129
    }
868,286✔
2130
    if (s->addr_dst_match4 != NULL) {
5,200,234✔
2131
        SCFree(s->addr_dst_match4);
868,406✔
2132
    }
868,406✔
2133
    if (s->addr_src_match6 != NULL) {
5,200,234✔
2134
        SCFree(s->addr_src_match6);
925,266✔
2135
    }
925,266✔
2136
    if (s->addr_dst_match6 != NULL) {
5,200,234✔
2137
        SCFree(s->addr_dst_match6);
932,299✔
2138
    }
932,299✔
2139
    if (s->sig_str != NULL) {
5,200,234✔
2140
        SCFree(s->sig_str);
5,200,183✔
2141
    }
5,200,183✔
2142

2143
    SigRefFree(s);
5,200,234✔
2144
    SigMetadataFree(s);
5,200,234✔
2145

2146
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
5,200,234✔
2147

2148
    SCFree(s);
5,200,234✔
2149
}
5,200,234✔
2150

2151
/**
2152
 * \brief this function is used to set multiple possible app-layer protos
2153
 * \brief into the current signature (for example ja4 for both tls and quic)
2154
 *
2155
 * \param s pointer to the Current Signature
2156
 * \param alprotos an array terminated by ALPROTO_UNKNOWN
2157
 *
2158
 * \retval 0 on Success
2159
 * \retval -1 on Failure
2160
 */
2161
int DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos)
2162
{
9,586✔
2163
    if (s->alproto != ALPROTO_UNKNOWN) {
9,586✔
2164
        // One alproto was set, check if it matches the new ones proposed
2165
        while (*alprotos != ALPROTO_UNKNOWN) {
9,160✔
2166
            if (s->alproto == *alprotos) {
8,658✔
2167
                // alproto already set to only one
2168
                return 0;
5,280✔
2169
            }
5,280✔
2170
            alprotos++;
3,378✔
2171
        }
3,378✔
2172
        // alproto already set and not matching the new set of alprotos
2173
        return -1;
502✔
2174
    }
5,782✔
2175
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
3,804✔
2176
        // check intersection of already used alprotos and new ones
2177
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,646✔
2178
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,646✔
2179
                break;
2,881✔
2180
            }
2,881✔
2181
            // first disable the ones that do not match
2182
            bool found = false;
8,646✔
2183
            const AppProto *args = alprotos;
5,765✔
2184
            while (*args != ALPROTO_UNKNOWN) {
8,658✔
2185
                if (s->init_data->alprotos[i] == *args) {
8,652✔
2186
                    found = true;
5,759✔
2187
                    break;
5,759✔
2188
                }
5,759✔
2189
                args++;
2,893✔
2190
            }
2,893✔
2191
            if (!found) {
5,765✔
2192
                s->init_data->alprotos[i] = ALPROTO_UNKNOWN;
6✔
2193
            }
6✔
2194
        }
5,765✔
2195
        // Then put at the beginning every defined protocol
2196
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,640✔
2197
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,640✔
2198
                for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
5,769✔
2199
                    if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2,888✔
2200
                        s->init_data->alprotos[i] = s->init_data->alprotos[j];
2✔
2201
                        s->init_data->alprotos[j] = ALPROTO_UNKNOWN;
2✔
2202
                        break;
2✔
2203
                    }
2✔
2204
                }
2,888✔
2205
                if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2,883✔
2206
                    if (i == 0) {
2,881✔
2207
                        // there was no intersection
2208
                        return -1;
1✔
2209
                    } else if (i == 1) {
2,880✔
2210
                        // intersection is singleton, set it as usual
2211
                        AppProto alproto = s->init_data->alprotos[0];
1✔
2212
                        s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
2213
                        return SCDetectSignatureSetAppProto(s, alproto);
1✔
2214
                    }
1✔
2215
                    break;
2,879✔
2216
                }
2,881✔
2217
            }
2,883✔
2218
        }
8,640✔
2219
    } else {
2,887✔
2220
        if (alprotos[0] == ALPROTO_UNKNOWN) {
923✔
2221
            // do not allow empty set
2222
            return -1;
×
2223
        }
×
2224
        if (alprotos[1] == ALPROTO_UNKNOWN) {
923✔
2225
            // allow singleton, but call traditional setter
2226
            return SCDetectSignatureSetAppProto(s, alprotos[0]);
×
2227
        }
×
2228
        // first time we enforce alprotos
2229
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2,773✔
2230
            if (alprotos[i] == ALPROTO_UNKNOWN) {
2,773✔
2231
                break;
923✔
2232
            }
923✔
2233
            s->init_data->alprotos[i] = alprotos[i];
1,850✔
2234
        }
1,850✔
2235
    }
923✔
2236
    return 0;
3,802✔
2237
}
3,804✔
2238

2239
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
2240
{
904,394✔
2241
    if (!AppProtoIsValid(alproto)) {
904,394✔
2242
        SCLogError("invalid alproto %u", alproto);
8✔
2243
        return -1;
8✔
2244
    }
8✔
2245

2246
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
904,386✔
2247
        // Multiple alprotos were set, check if we restrict to one
2248
        bool found = false;
50✔
2249
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
152✔
2250
            if (s->init_data->alprotos[i] == alproto) {
128✔
2251
                found = true;
26✔
2252
                break;
26✔
2253
            }
26✔
2254
        }
128✔
2255
        if (!found) {
50✔
2256
            // fail if we set to a alproto which was not in the set
2257
            return -1;
24✔
2258
        }
24✔
2259
        // we will use s->alproto if there is a single alproto and
2260
        // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2261
        s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
26✔
2262
    }
26✔
2263

2264
    if (s->alproto != ALPROTO_UNKNOWN) {
904,362✔
2265
        alproto = AppProtoCommon(s->alproto, alproto);
660,743✔
2266
        if (alproto == ALPROTO_FAILED) {
660,743✔
2267
            SCLogError("can't set rule app proto to %s: already set to %s",
26,431✔
2268
                    AppProtoToString(alproto), AppProtoToString(s->alproto));
26,431✔
2269
            return -1;
26,431✔
2270
        }
26,431✔
2271
    }
660,743✔
2272

2273
    if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
877,931✔
2274
        SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
1✔
2275
        return -1;
1✔
2276
    }
1✔
2277
    s->alproto = alproto;
877,930✔
2278
    s->flags |= SIG_FLAG_APPLAYER;
877,930✔
2279
    return 0;
877,930✔
2280
}
877,931✔
2281

2282
static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2283
        const DetectAddress *head, uint16_t *match4_cnt)
2284
{
1,948,270✔
2285
    uint16_t cnt = 0;
1,948,270✔
2286

2287
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,850,354✔
2288
        cnt++;
1,902,084✔
2289
    }
1,902,084✔
2290
    if (cnt == 0) {
1,948,270✔
2291
        return NULL;
211,574✔
2292
    }
211,574✔
2293
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
1,736,696✔
2294
    if (addr_match4 == NULL) {
1,736,696✔
2295
        return NULL;
×
2296
    }
×
2297

2298
    uint16_t idx = 0;
1,736,696✔
2299
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,638,780✔
2300
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
1,902,084✔
2301
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
1,902,084✔
2302
        idx++;
1,902,084✔
2303
    }
1,902,084✔
2304
    *match4_cnt = cnt;
1,736,696✔
2305
    return addr_match4;
1,736,696✔
2306
}
1,736,696✔
2307

2308
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2309
        const DetectAddress *head, uint16_t *match6_cnt)
2310
{
1,948,270✔
2311
    uint16_t cnt = 0;
1,948,270✔
2312
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
4,078,755✔
2313
        cnt++;
2,130,485✔
2314
    }
2,130,485✔
2315
    if (cnt == 0) {
1,948,270✔
2316
        return NULL;
90,701✔
2317
    }
90,701✔
2318

2319
    DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
1,857,569✔
2320
    if (addr_match6 == NULL) {
1,857,569✔
2321
        return NULL;
×
2322
    }
×
2323

2324
    uint16_t idx = 0;
1,857,569✔
2325
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,988,054✔
2326
        addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2,130,485✔
2327
        addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2,130,485✔
2328
        addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2,130,485✔
2329
        addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2,130,485✔
2330
        addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2,130,485✔
2331
        addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2,130,485✔
2332
        addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2,130,485✔
2333
        addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2,130,485✔
2334
        idx++;
2,130,485✔
2335
    }
2,130,485✔
2336
    *match6_cnt = cnt;
1,857,569✔
2337
    return addr_match6;
1,857,569✔
2338
}
1,857,569✔
2339

2340
/**
2341
 *  \internal
2342
 *  \brief build address match array for cache efficient matching
2343
 *
2344
 *  \param s the signature
2345
 */
2346
static void SigBuildAddressMatchArray(Signature *s)
2347
{
974,135✔
2348
    /* source addresses */
2349
    s->addr_src_match4 =
974,135✔
2350
            SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
974,135✔
2351
    /* destination addresses */
2352
    s->addr_dst_match4 =
974,135✔
2353
            SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
974,135✔
2354

2355
    /* source addresses IPv6 */
2356
    s->addr_src_match6 =
974,135✔
2357
            SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
974,135✔
2358
    /* destination addresses IPv6 */
2359
    s->addr_dst_match6 =
974,135✔
2360
            SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
974,135✔
2361
}
974,135✔
2362

2363
static int SigMatchListLen(SigMatch *sm)
2364
{
1,123,092✔
2365
    int len = 0;
1,123,092✔
2366
    for (; sm != NULL; sm = sm->next)
1,437,688✔
2367
        len++;
314,596✔
2368

2369
    return len;
1,123,092✔
2370
}
1,123,092✔
2371

2372
/** \brief convert SigMatch list to SigMatchData array
2373
 *  \note ownership of sm->ctx is transferred to smd->ctx
2374
 */
2375
SigMatchData* SigMatchList2DataArray(SigMatch *head)
2376
{
1,123,092✔
2377
    int len = SigMatchListLen(head);
1,123,092✔
2378
    if (len == 0)
1,123,092✔
2379
        return NULL;
891,906✔
2380

2381
    SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
231,186✔
2382
    if (smd == NULL) {
231,186✔
2383
        FatalError("initializing the detection engine failed");
×
2384
    }
×
2385
    SigMatchData *out = smd;
231,186✔
2386

2387
    /* Copy sm type and Context into array */
2388
    SigMatch *sm = head;
231,186✔
2389
    for (; sm != NULL; sm = sm->next, smd++) {
545,782✔
2390
        smd->type = sm->type;
314,596✔
2391
        smd->ctx = sm->ctx;
314,596✔
2392
        sm->ctx = NULL; // SigMatch no longer owns the ctx
314,596✔
2393
        smd->is_last = (sm->next == NULL);
314,596✔
2394
    }
314,596✔
2395
    return out;
231,186✔
2396
}
231,186✔
2397

2398
extern int g_skip_prefilter;
2399

2400
static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2401
{
974,135✔
2402
    SCEnter();
974,135✔
2403
    SCLogDebug("s %u: set up prefilter/mpm", s->id);
974,135✔
2404
    DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
974,135✔
2405

2406
    if (s->init_data->prefilter_sm != NULL) {
974,135✔
2407
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
42,749✔
2408
            RetrieveFPForSig(de_ctx, s);
1,364✔
2409
            if (s->init_data->mpm_sm != NULL) {
1,364✔
2410
                s->flags |= SIG_FLAG_PREFILTER;
1,361✔
2411
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
1,361✔
2412
                SCReturn;
1,361✔
2413
            }
1,361✔
2414
            /* fall through, this can happen if the mpm doesn't support the pattern */
2415
        } else {
41,386✔
2416
            s->flags |= SIG_FLAG_PREFILTER;
41,385✔
2417
            SCReturn;
41,385✔
2418
        }
41,385✔
2419
    } else {
931,386✔
2420
        SCLogDebug("%u: RetrieveFPForSig", s->id);
931,386✔
2421
        RetrieveFPForSig(de_ctx, s);
931,386✔
2422
        if (s->init_data->mpm_sm != NULL) {
931,386✔
2423
            s->flags |= SIG_FLAG_PREFILTER;
344,125✔
2424
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
344,125✔
2425
            SCReturn;
344,125✔
2426
        }
344,125✔
2427
    }
931,386✔
2428

2429
    SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
587,264✔
2430
               "s->init_data->has_possible_prefilter %s",
587,264✔
2431
            s->id, de_ctx->prefilter_setting, BOOL2STR(s->init_data->has_possible_prefilter));
587,264✔
2432

2433
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
587,264✔
2434
        SCReturn;
584,162✔
2435

2436
    DEBUG_VALIDATE_BUG_ON(s->flags & SIG_FLAG_PREFILTER);
3,102✔
2437
    if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) {
3,102✔
2438
        int prefilter_list = DETECT_TBLSIZE;
×
2439
        /* get the keyword supporting prefilter with the lowest type */
2440
        for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
×
2441
            for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
×
2442
                if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
×
2443
                    if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
×
2444
                        prefilter_list = MIN(prefilter_list, sm->type);
×
2445
                    }
×
2446
                }
×
2447
            }
×
2448
        }
×
2449

2450
        /* apply that keyword as prefilter */
2451
        if (prefilter_list != DETECT_TBLSIZE) {
×
2452
            for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
×
2453
                for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
×
2454
                    if (sm->type == prefilter_list) {
×
2455
                        s->init_data->prefilter_sm = sm;
×
2456
                        s->flags |= SIG_FLAG_PREFILTER;
×
2457
                        SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
×
2458
                                sigmatch_table[sm->type].name);
×
2459
                        break;
×
2460
                    }
×
2461
                }
×
2462
            }
×
2463
        }
×
2464
    }
×
2465
    SCReturn;
3,102✔
2466
}
587,264✔
2467

2468
/** \internal
2469
 *  \brief check if signature's table requirement is supported by each of the keywords it uses.
2470
 */
2471
static bool DetectRuleValidateTable(const Signature *s)
2472
{
941,191✔
2473
    if (s->detect_table == 0)
941,191✔
2474
        return true;
×
2475

2476
    const uint8_t table_as_flag = BIT_U8(s->detect_table);
941,191✔
2477

2478
    for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
1,242,738✔
2479
        const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
301,547✔
2480
        if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
301,547✔
2481
            SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
×
2482
                    s->id, DetectTableToString(s->detect_table), sigmatch_table[sm->type].name);
×
2483
            return false;
×
2484
        }
×
2485
    }
301,547✔
2486
    return true;
941,191✔
2487
}
941,191✔
2488

2489
static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
UNCOV
2490
{
×
UNCOV
2491
    if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_NOT_SET) {
×
2492
        SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
×
2493
                   "explicit hook",
×
2494
                s->id);
×
2495
        return false;
×
2496
    }
×
UNCOV
2497
    return true;
×
UNCOV
2498
}
×
2499

2500
static void DetectRuleSetTable(Signature *s)
2501
{
944,566✔
2502
    enum DetectTable table;
944,566✔
2503
    if (s->flags & SIG_FLAG_FIREWALL) {
944,566✔
UNCOV
2504
        if (s->type == SIG_TYPE_PKT) {
×
UNCOV
2505
            if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
×
UNCOV
2506
                    s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_STREAM)
×
UNCOV
2507
                table = DETECT_TABLE_PACKET_PRE_STREAM;
×
UNCOV
2508
            else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
×
UNCOV
2509
                     s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_FLOW)
×
UNCOV
2510
                table = DETECT_TABLE_PACKET_PRE_FLOW;
×
UNCOV
2511
            else
×
UNCOV
2512
                table = DETECT_TABLE_PACKET_FILTER;
×
UNCOV
2513
        } else if (s->type == SIG_TYPE_APP_TX) {
×
UNCOV
2514
            table = DETECT_TABLE_APP_FILTER;
×
UNCOV
2515
        } else {
×
2516
            BUG_ON(1);
×
2517
        }
×
2518
    } else {
944,566✔
2519
        // TODO pre_flow/pre_stream
2520
        if (s->type != SIG_TYPE_APP_TX) {
944,566✔
2521
            table = DETECT_TABLE_PACKET_TD;
390,771✔
2522
        } else {
554,078✔
2523
            table = DETECT_TABLE_APP_TD;
553,795✔
2524
        }
553,795✔
2525
    }
944,566✔
2526

2527
    s->detect_table = (uint8_t)table;
944,566✔
2528
}
944,566✔
2529

2530
static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2531
{
974,135✔
2532
    if (s->init_data->firewall_rule) {
974,135✔
UNCOV
2533
        if (!DetectFirewallRuleValidate(de_ctx, s))
×
2534
            SCReturnInt(0);
×
UNCOV
2535
    }
×
2536
    SCReturnInt(1);
974,135✔
2537
}
974,135✔
2538

2539
static int SigValidateCheckBuffers(
2540
        DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2541
{
974,027✔
2542
    bool has_frame = false;
974,027✔
2543
    bool has_app = false;
974,027✔
2544
    bool has_pkt = false;
974,027✔
2545
    bool has_pmatch = false;
974,027✔
2546

2547
    int nlists = 0;
974,027✔
2548
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,633,411✔
2549
        nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
659,384✔
2550
    }
659,384✔
2551
    nlists += (nlists > 0);
974,027✔
2552
    SCLogDebug("nlists %d", nlists);
974,027✔
2553

2554
    if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
974,027✔
2555
        SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2,215✔
2556
                DetectEngineBufferTypeGetNameById(de_ctx, s->init_data->curbuf->id));
2,215✔
2557
        SCReturnInt(0);
2,215✔
2558
    }
2,215✔
2559

2560
    /* run buffer type validation callbacks if any */
2561
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
971,812✔
2562
        if (!DetectContentPMATCHValidateCallback(s))
172,849✔
2563
            SCReturnInt(0);
1,709✔
2564

2565
        has_pmatch = true;
171,140✔
2566
    }
171,140✔
2567

2568
    DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
970,103✔
2569
    struct BufferVsDir {
970,103✔
2570
        int ts;
970,103✔
2571
        int tc;
970,103✔
2572
    } bufdir[nlists + 1];
970,103✔
2573
    memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
970,103✔
2574

2575
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,601,614✔
2576
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
655,611✔
2577
        const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
655,611✔
2578
        if (bt == NULL) {
655,611✔
2579
            DEBUG_VALIDATE_BUG_ON(1); // should be impossible
×
2580
            continue;
×
2581
        }
×
2582
        SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
655,611✔
2583
        for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
1,497,139✔
2584
            SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
841,528✔
2585
        }
841,528✔
2586

2587
        if (b->head == NULL) {
655,611✔
2588
            SCLogError("no matches in sticky buffer %s", bt->name);
45✔
2589
            SCReturnInt(0);
45✔
2590
        }
45✔
2591

2592
        has_frame |= bt->frame;
655,566✔
2593
        has_app |= (!bt->frame && !bt->packet);
655,566✔
2594
        has_pkt |= bt->packet;
655,566✔
2595

2596
        if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
655,566✔
2597
            SCLogError("Signature combines packet "
864✔
2598
                       "specific matches (like dsize, flags, ttl) with stream / "
864✔
2599
                       "state matching by matching on app layer proto (like using "
864✔
2600
                       "http_* keywords).");
864✔
2601
            SCReturnInt(0);
864✔
2602
        }
864✔
2603

2604
        const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
654,702✔
2605
        for (; app != NULL; app = app->next) {
540,417,091✔
2606
            if (app->sm_list == b->id &&
539,762,389✔
2607
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
539,762,389✔
2608
                SCLogDebug("engine %s dir %d alproto %d",
1,632,283✔
2609
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
1,632,283✔
2610
                        app->alproto);
1,632,283✔
2611
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
1,632,283✔
2612

2613
                if (b->only_tc) {
1,632,283✔
2614
                    if (app->dir == 1)
4,286✔
2615
                        (*tc_excl)++;
2,026✔
2616
                } else if (b->only_ts) {
1,627,997✔
2617
                    if (app->dir == 0)
1,755✔
2618
                        (*ts_excl)++;
924✔
2619
                } else {
1,626,242✔
2620
                    bufdir[b->id].ts += (app->dir == 0);
1,626,242✔
2621
                    bufdir[b->id].tc += (app->dir == 1);
1,626,242✔
2622
                }
1,626,242✔
2623

2624
                /* only allow rules to use the hook for engines at that
2625
                 * exact progress for now. */
2626
                if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_APP) {
1,632,283✔
2627
                    if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
10✔
2628
                            app->progress != s->init_data->hook.t.app.app_progress) {
10✔
2629
                        SCLogError("engine progress value %d doesn't match hook %u", app->progress,
×
2630
                                s->init_data->hook.t.app.app_progress);
×
2631
                        SCReturnInt(0);
×
2632
                    }
×
2633
                    if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
10✔
2634
                            app->progress != s->init_data->hook.t.app.app_progress) {
10✔
2635
                        SCLogError("engine progress value doesn't match hook");
×
2636
                        SCReturnInt(0);
×
2637
                    }
×
2638
                }
10✔
2639
            }
1,632,283✔
2640
        }
539,762,389✔
2641

2642
        if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
654,702✔
2643
            SCReturnInt(0);
10,913✔
2644
        }
10,913✔
2645

2646
        if (!DetectBsizeValidateContentCallback(s, b)) {
643,789✔
2647
            SCReturnInt(0);
12,265✔
2648
        }
12,265✔
2649
        if (!DetectAbsentValidateContentCallback(s, b)) {
631,524✔
2650
            SCReturnInt(0);
13✔
2651
        }
13✔
2652
    }
631,524✔
2653

2654
    if (has_pmatch && has_frame) {
946,003✔
2655
        SCLogError("can't mix pure content and frame inspection");
95✔
2656
        SCReturnInt(0);
95✔
2657
    }
95✔
2658
    if (has_app && has_frame) {
945,908✔
2659
        SCLogError("can't mix app-layer buffer and frame inspection");
23✔
2660
        SCReturnInt(0);
23✔
2661
    }
23✔
2662
    if (has_pkt && has_frame) {
945,885✔
2663
        SCLogError("can't mix pkt buffer and frame inspection");
1✔
2664
        SCReturnInt(0);
1✔
2665
    }
1✔
2666

2667
    for (int x = 0; x < nlists; x++) {
157,463,372✔
2668
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
156,517,488✔
2669
            continue;
155,991,178✔
2670
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
526,310✔
2671
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
526,310✔
2672
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
526,310✔
2673

2674
        SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
526,310✔
2675
                bufdir[x].tc);
526,310✔
2676
    }
526,310✔
2677

2678
    SCReturnInt(1);
945,884✔
2679
}
945,885✔
2680

2681
static int SigValidatePacketStream(const Signature *s)
2682
{
974,135✔
2683
    if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) {
974,135✔
2684
        SCLogError("can't mix packet keywords with "
108✔
2685
                   "tcp-stream or flow:only_stream.  Invalidating signature.");
108✔
2686
        SCReturnInt(0);
108✔
2687
    }
108✔
2688
    SCReturnInt(1);
974,135✔
2689
}
974,135✔
2690

2691
static int SigConsolidateDirection(
2692
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2693
{
945,884✔
2694
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
945,884✔
2695
        if (!ts_excl || !tc_excl) {
733✔
2696
            SCLogError("rule %u should use both directions, but does not", s->id);
412✔
2697
            SCReturnInt(0);
412✔
2698
        }
412✔
2699
        if (dir_amb) {
321✔
2700
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
5✔
2701
                       "directions",
5✔
2702
                    s->id);
5✔
2703
            SCReturnInt(0);
5✔
2704
        }
5✔
2705
    } else if (ts_excl && tc_excl) {
945,151✔
2706
        SCLogError(
254✔
2707
                "rule %u mixes keywords with conflicting directions, a transactional rule with => "
254✔
2708
                "should be used",
254✔
2709
                s->id);
254✔
2710
        SCReturnInt(0);
254✔
2711
    } else if (ts_excl) {
944,897✔
2712
        SCLogDebug("%u: implied rule direction is toserver", s->id);
294,904✔
2713
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
294,904✔
2714
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
635✔
2715
            SCReturnInt(0);
635✔
2716
        }
635✔
2717
    } else if (tc_excl) {
667,778✔
2718
        SCLogDebug("%u: implied rule direction is toclient", s->id);
47,201✔
2719
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
47,201✔
2720
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
12✔
2721
            SCReturnInt(0);
12✔
2722
        }
12✔
2723
    } else if (dir_amb) {
602,792✔
2724
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
125,289✔
2725
    }
125,289✔
2726
    SCReturnInt(1);
945,884✔
2727
}
945,884✔
2728

2729
static void SigConsolidateTcpBuffer(Signature *s)
2730
{
944,566✔
2731
    /* TCP: corner cases:
2732
     * - pkt vs stream vs depth/offset
2733
     * - pkt vs stream vs stream_size
2734
     */
2735
    if (DetectProtoContainsProto(&s->init_data->proto, IPPROTO_TCP)) {
944,566✔
2736
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
912,315✔
2737
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
168,447✔
2738
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
115,242✔
2739
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
316,990✔
2740
                        sm = sm->next) {
216,013✔
2741
                    if (sm->type == DETECT_CONTENT &&
216,013✔
2742
                            (((DetectContentData *)(sm->ctx))->flags &
216,013✔
2743
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
94,936✔
2744
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
14,265✔
2745
                        break;
14,265✔
2746
                    }
14,265✔
2747
                }
216,013✔
2748
                /* if stream_size is in use, also inspect packets */
2749
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
152,905✔
2750
                        sm = sm->next) {
115,416✔
2751
                    if (sm->type == DETECT_STREAM_SIZE) {
39,530✔
2752
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
1,867✔
2753
                        break;
1,867✔
2754
                    }
1,867✔
2755
                }
39,530✔
2756
            }
115,242✔
2757
        }
168,447✔
2758
    }
912,315✔
2759
}
944,566✔
2760

2761
static bool SigInspectsFiles(const Signature *s)
2762
{
1,883,725✔
2763
    return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
1,883,725✔
2764
            (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA));
1,883,725✔
2765
}
1,883,725✔
2766

2767
/** \internal
2768
 *  \brief validate file handling
2769
 *  \retval 1 good signature
2770
 *  \retval 0 bad signature
2771
 */
2772
static int SigValidateFileHandling(const Signature *s)
2773
{
942,534✔
2774
    if (!SigInspectsFiles(s)) {
942,534✔
2775
        SCReturnInt(1);
885,566✔
2776
    }
885,566✔
2777

2778
    if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
56,968✔
2779
            !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
56,968✔
2780
        SCLogError("protocol %s doesn't "
989✔
2781
                   "support file matching",
989✔
2782
                AppProtoToString(s->alproto));
989✔
2783
        SCReturnInt(0);
989✔
2784
    }
989✔
2785
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
55,979✔
2786
        bool found = false;
6✔
2787
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
18✔
2788
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
18✔
2789
                break;
6✔
2790
            }
6✔
2791
            if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
12✔
2792
                    AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
12✔
2793
                found = true;
×
2794
                break;
×
2795
            }
×
2796
        }
12✔
2797
        if (!found) {
6✔
2798
            SCLogError("No protocol support file matching");
6✔
2799
            SCReturnInt(0);
6✔
2800
        }
6✔
2801
    }
6✔
2802
    if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) {
55,973✔
2803
        SCLogError("protocol HTTP2 doesn't support file name matching");
348✔
2804
        SCReturnInt(0);
348✔
2805
    }
348✔
2806
    SCReturnInt(1);
55,973✔
2807
}
55,973✔
2808

2809
static bool SigValidateEthernet(const Signature *s)
2810
{
974,027✔
2811
    if (s->init_data->proto.flags & DETECT_PROTO_ETHERNET) {
974,027✔
2812
        if ((s->flags & (SIG_FLAG_SP_ANY | SIG_FLAG_DP_ANY)) !=
1✔
2813
                (SIG_FLAG_SP_ANY | SIG_FLAG_DP_ANY)) {
1✔
NEW
2814
            SCLogError("can't use ports with ethernet rule");
×
NEW
2815
            return false;
×
NEW
2816
        }
×
2817
    } else {
974,026✔
2818
        if (s->init_data->proto.ether_type != 0) {
974,026✔
NEW
2819
            SCLogError("can't set ether_type with non-ethernet rule");
×
NEW
2820
            return false;
×
NEW
2821
        }
×
2822
    }
974,026✔
2823
    return true;
974,027✔
2824
}
974,027✔
2825

2826
/* `pkthdr` is meant to allow matching on "any" packet with a decoder event. */
2827
static bool SigValidateProtoPkthdr(const Signature *s)
2828
{
944,566✔
2829
    if ((s->init_data->proto.flags & DETECT_PROTO_L2_ANY) && s->type != SIG_TYPE_DEONLY) {
944,566✔
2830
        SCLogError("protocol 'pkthdr' is for decoder-events only");
2,032✔
2831
        return false;
2,032✔
2832
    }
2,032✔
2833
    return true;
942,534✔
2834
}
944,566✔
2835

2836
/**
2837
 *  \internal
2838
 *  \brief validate and consolidate parsed signature
2839
 *
2840
 *  \param de_ctx detect engine
2841
 *  \param s signature to validate and consolidate
2842
 *
2843
 *  \retval 0 invalid
2844
 *  \retval 1 valid
2845
 */
2846
static int SigValidateConsolidate(
2847
        DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2848
{
974,135✔
2849
    SCEnter();
974,135✔
2850

2851
    if (SigValidateFirewall(de_ctx, s) == 0)
974,135✔
2852
        SCReturnInt(0);
×
2853

2854
    if (SigValidatePacketStream(s) == 0) {
974,135✔
2855
        SCReturnInt(0);
108✔
2856
    }
108✔
2857

2858
    if (!SigValidateEthernet(s)) {
974,027✔
NEW
2859
        SCReturnInt(0);
×
NEW
2860
    }
×
2861

2862
    int ts_excl = 0;
974,027✔
2863
    int tc_excl = 0;
974,027✔
2864
    int dir_amb = 0;
974,027✔
2865

2866
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
974,027✔
2867
        SCReturnInt(0);
28,143✔
2868
    }
28,143✔
2869

2870
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
945,884✔
2871
        SCReturnInt(0);
1,318✔
2872
    }
1,318✔
2873

2874
    SigConsolidateTcpBuffer(s);
944,566✔
2875

2876
    SignatureSetType(de_ctx, s);
944,566✔
2877
    DetectRuleSetTable(s);
944,566✔
2878

2879
    if (!SigValidateProtoPkthdr(s)) {
944,566✔
2880
        SCReturnInt(0);
2,032✔
2881
    }
2,032✔
2882

2883
    if (DetectProtoFinalizeSignature(s) != 0)
942,534✔
NEW
2884
        SCReturnInt(0);
×
2885

2886
    int r = SigValidateFileHandling(s);
942,534✔
2887
    if (r == 0) {
942,534✔
2888
        SCReturnInt(0);
1,343✔
2889
    }
1,343✔
2890
    if (SigInspectsFiles(s)) {
941,191✔
2891
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
55,625✔
2892
            AppLayerHtpNeedFileInspection();
10,934✔
2893
        }
10,934✔
2894
    }
55,625✔
2895
    if (DetectRuleValidateTable(s) == false) {
941,191✔
2896
        SCReturnInt(0);
×
2897
    }
×
2898

2899
    if (s->type == SIG_TYPE_IPONLY) {
941,191✔
2900
        /* For IPOnly */
2901
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
82,740✔
2902
            SCReturnInt(0);
557✔
2903

2904
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
82,183✔
2905
            SCReturnInt(0);
1,702✔
2906
    }
82,183✔
2907
    SCReturnInt(1);
941,191✔
2908
}
941,191✔
2909

2910
/**
2911
 * \internal
2912
 * \brief Helper function for SigInit().
2913
 */
2914
static Signature *SigInitHelper(
2915
        DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2916
{
5,200,185✔
2917
    SignatureParser parser;
5,200,185✔
2918
    memset(&parser, 0x00, sizeof(parser));
5,200,185✔
2919

2920
    Signature *sig = SigAlloc();
5,200,185✔
2921
    if (sig == NULL)
5,200,185✔
2922
        goto error;
×
2923
    if (firewall_rule) {
5,200,185✔
UNCOV
2924
        sig->init_data->firewall_rule = true;
×
UNCOV
2925
        sig->flags |= SIG_FLAG_FIREWALL;
×
UNCOV
2926
    }
×
2927

2928
    sig->sig_str = SCStrdup(sigstr);
5,200,185✔
2929
    if (unlikely(sig->sig_str == NULL)) {
5,200,185✔
2930
        goto error;
×
2931
    }
×
2932

2933
    /* default gid to 1 */
2934
    sig->gid = 1;
5,200,185✔
2935

2936
    /* We do a first parse of the rule in a requires, or scan-only
2937
     * mode. Syntactic errors will be picked up here, but the only
2938
     * part of the rule that is validated completely is the "requires"
2939
     * keyword. */
2940
    int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
5,200,185✔
2941
    if (ret == -4) {
5,200,185✔
2942
        /* Rule requirements not met. */
2943
        de_ctx->sigerror_silent = true;
10,403✔
2944
        de_ctx->sigerror_ok = true;
10,403✔
2945
        de_ctx->sigerror_requires = true;
10,403✔
2946
        goto error;
10,403✔
2947
    } else if (ret < 0) {
5,189,782✔
2948
        goto error;
2,399,393✔
2949
    }
2,399,393✔
2950

2951
    /* Check for a SID before continuuing. */
2952
    if (sig->id == 0) {
2,790,389✔
2953
        SCLogError("Signature missing required value \"sid\".");
542,155✔
2954
        goto error;
542,155✔
2955
    }
542,155✔
2956

2957
    /* Now completely parse the rule. */
2958
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2,248,234✔
2959
    BUG_ON(ret == -4);
2,248,234✔
2960
    if (ret == -3) {
2,248,234✔
2961
        de_ctx->sigerror_silent = true;
17,685✔
2962
        de_ctx->sigerror_ok = true;
17,685✔
2963
        goto error;
17,685✔
2964
    } else if (ret == -2) {
2,230,549✔
UNCOV
2965
        de_ctx->sigerror_silent = true;
×
UNCOV
2966
        goto error;
×
2967
    } else if (ret < 0) {
2,230,549✔
2968
        goto error;
1,256,414✔
2969
    }
1,256,414✔
2970

2971
    /* signature priority hasn't been overwritten.  Using default priority */
2972
    if (sig->prio == -1)
974,135✔
2973
        sig->prio = DETECT_DEFAULT_PRIO;
811,345✔
2974

2975
    sig->iid = de_ctx->signum;
974,135✔
2976
    de_ctx->signum++;
974,135✔
2977

2978
    if (sig->alproto != ALPROTO_UNKNOWN) {
974,135✔
2979
        int override_needed = 0;
643,907✔
2980
        if (sig->init_data->proto.flags & DETECT_PROTO_ANY) {
643,907✔
2981
            sig->init_data->proto.flags &= ~DETECT_PROTO_ANY;
151,905✔
2982
            memset(sig->init_data->proto.proto, 0x00, sizeof(sig->init_data->proto.proto));
151,905✔
2983
            override_needed = 1;
151,905✔
2984
        } else {
492,002✔
2985
            override_needed = 1;
492,002✔
2986
            size_t s = 0;
492,002✔
2987
            for (s = 0; s < sizeof(sig->init_data->proto.proto); s++) {
553,335✔
2988
                if (sig->init_data->proto.proto[s] != 0x00) {
552,844✔
2989
                    override_needed = 0;
491,511✔
2990
                    break;
491,511✔
2991
                }
491,511✔
2992
            }
552,844✔
2993
        }
492,002✔
2994

2995
        /* at this point if we had alert ip and the ip proto was not
2996
         * overridden, we use the ip proto that has been configured
2997
         * against the app proto in use. */
2998
        if (override_needed)
643,907✔
2999
            AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->init_data->proto.proto);
152,396✔
3000
    }
643,907✔
3001

3002
    /* set the packet and app layer flags, but only if the
3003
     * app layer flag wasn't already set in which case we
3004
     * only consider the app layer */
3005
    if (!(sig->flags & SIG_FLAG_APPLAYER)) {
974,135✔
3006
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
328,215✔
3007
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
108,189✔
3008
            for ( ; sm != NULL; sm = sm->next) {
267,146✔
3009
                if (sigmatch_table[sm->type].Match != NULL)
158,957✔
3010
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
158,957✔
3011
            }
158,957✔
3012
        } else {
223,130✔
3013
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
220,026✔
3014
        }
220,026✔
3015
    }
328,215✔
3016

3017
    if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
974,135✔
3018
        if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
2✔
3019
            if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2✔
UNCOV
3020
                sig->init_data->init_flags |= SIG_FLAG_INIT_FLOW;
×
UNCOV
3021
            }
×
3022
        }
2✔
3023
    }
2✔
3024

3025
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
974,135✔
3026
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
864,488✔
3027
            sig->flags |= SIG_FLAG_TOSERVER;
834,236✔
3028
            sig->flags |= SIG_FLAG_TOCLIENT;
834,236✔
3029
        }
834,236✔
3030
    }
864,488✔
3031

3032
    SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
974,135✔
3033
        sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
974,135✔
3034
        sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
974,135✔
3035

3036
    SigBuildAddressMatchArray(sig);
974,135✔
3037

3038
    /* run buffer type callbacks if any */
3039
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
7,793,080✔
3040
        if (sig->init_data->smlists[x])
6,818,945✔
3041
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
483,683✔
3042
    }
6,818,945✔
3043
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
1,633,521✔
3044
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
659,386✔
3045
    }
659,386✔
3046

3047
    SigSetupPrefilter(de_ctx, sig);
974,135✔
3048

3049
    /* validate signature, SigValidate will report the error reason */
3050
    if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
974,135✔
3051
        goto error;
35,203✔
3052
    }
35,203✔
3053

3054
    return sig;
938,932✔
3055

3056
error:
4,261,253✔
3057
    if (sig != NULL) {
4,261,253✔
3058
        SigFree(de_ctx, sig);
4,261,253✔
3059
    }
4,261,253✔
3060
    return NULL;
4,261,253✔
3061
}
974,135✔
3062

3063
/**
3064
 * \brief Checks if a signature has the same source and destination
3065
 * \param s parsed signature
3066
 *
3067
 *  \retval true if source and destination are the same, false otherwise
3068
 */
3069
static bool SigHasSameSourceAndDestination(const Signature *s)
3070
{
162,141✔
3071
    if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
162,141✔
3072
        if (!DetectPortListsAreEqual(s->sp, s->dp)) {
146,222✔
3073
            return false;
143,383✔
3074
        }
143,383✔
3075
    }
146,222✔
3076

3077
    if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
18,758✔
3078
        DetectAddress *src = s->init_data->src->ipv4_head;
18,424✔
3079
        DetectAddress *dst = s->init_data->dst->ipv4_head;
18,424✔
3080

3081
        if (!DetectAddressListsAreEqual(src, dst)) {
18,424✔
3082
            return false;
7,639✔
3083
        }
7,639✔
3084

3085
        src = s->init_data->src->ipv6_head;
10,785✔
3086
        dst = s->init_data->dst->ipv6_head;
10,785✔
3087

3088
        if (!DetectAddressListsAreEqual(src, dst)) {
10,785✔
3089
            return false;
8,346✔
3090
        }
8,346✔
3091
    }
10,785✔
3092

3093
    return true;
2,773✔
3094
}
18,758✔
3095

3096
static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3097
{
5,040,817✔
3098
    SCEnter();
5,040,817✔
3099

3100
    uint32_t oldsignum = de_ctx->signum;
5,040,817✔
3101
    de_ctx->sigerror_ok = false;
5,040,817✔
3102
    de_ctx->sigerror_silent = false;
5,040,817✔
3103
    de_ctx->sigerror_requires = false;
5,040,817✔
3104

3105
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
5,040,817✔
3106
    if (sig == NULL) {
5,040,817✔
3107
        goto error;
4,261,253✔
3108
    }
4,261,253✔
3109

3110
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
779,564✔
3111
        if (SigHasSameSourceAndDestination(sig)) {
162,141✔
3112
            SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
2,773✔
3113
                "treating the rule as unidirectional", sig->id);
2,773✔
3114

3115
            sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC;
2,773✔
3116
        } else {
159,368✔
3117
            sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
159,368✔
3118
            if (sig->next == NULL) {
159,368✔
3119
                goto error;
×
3120
            }
×
3121
        }
159,368✔
3122
    }
162,141✔
3123

3124
    SCReturnPtr(sig, "Signature");
779,564✔
3125

3126
error:
4,261,253✔
3127
    if (sig != NULL) {
4,261,253✔
3128
        SigFree(de_ctx, sig);
×
3129
    }
×
3130
    /* if something failed, restore the old signum count
3131
     * since we didn't install it */
3132
    de_ctx->signum = oldsignum;
4,261,253✔
3133

3134
    SCReturnPtr(NULL, "Signature");
4,261,253✔
3135
}
779,564✔
3136

3137
/**
3138
 * \brief Parses a signature and adds it to the Detection Engine Context.
3139
 *
3140
 * \param de_ctx Pointer to the Detection Engine Context.
3141
 * \param sigstr Pointer to a character string containing the signature to be
3142
 *               parsed.
3143
 *
3144
 * \retval Pointer to the Signature instance on success; NULL on failure.
3145
 */
3146
Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3147
{
5,040,817✔
3148
    return SigInitDo(de_ctx, sigstr, false);
5,040,817✔
3149
}
5,040,817✔
3150

3151
static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
UNCOV
3152
{
×
UNCOV
3153
    return SigInitDo(de_ctx, sigstr, true);
×
UNCOV
3154
}
×
3155

3156
/**
3157
 * \brief The hash free function to be the used by the hash table -
3158
 *        DetectEngineCtx->dup_sig_hash_table.
3159
 *
3160
 * \param data    Pointer to the data, in our case SigDuplWrapper to be freed.
3161
 */
3162
static void DetectParseDupSigFreeFunc(void *data)
3163
{
143,779✔
3164
    if (data != NULL)
143,779✔
3165
        SCFree(data);
143,779✔
3166
}
143,779✔
3167

3168
/**
3169
 * \brief The hash function to be the used by the hash table -
3170
 *        DetectEngineCtx->dup_sig_hash_table.
3171
 *
3172
 * \param ht      Pointer to the hash table.
3173
 * \param data    Pointer to the data, in our case SigDuplWrapper.
3174
 * \param datalen Not used in our case.
3175
 *
3176
 * \retval sw->s->id The generated hash value.
3177
 */
3178
static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3179
{
1,031,806✔
3180
    SigDuplWrapper *sw = (SigDuplWrapper *)data;
1,031,806✔
3181

3182
    return (sw->s->id % ht->array_size);
1,031,806✔
3183
}
1,031,806✔
3184

3185
/**
3186
 * \brief The Compare function to be used by the hash table -
3187
 *        DetectEngineCtx->dup_sig_hash_table.
3188
 *
3189
 * \param data1 Pointer to the first SigDuplWrapper.
3190
 * \param len1  Not used.
3191
 * \param data2 Pointer to the second SigDuplWrapper.
3192
 * \param len2  Not used.
3193
 *
3194
 * \retval 1 If the 2 SigDuplWrappers sent as args match.
3195
 * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3196
 */
3197
static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3198
                                  uint16_t len2)
3199
{
785,225✔
3200
    SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
785,225✔
3201
    SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
785,225✔
3202

3203
    if (sw1 == NULL || sw2 == NULL ||
785,225✔
3204
        sw1->s == NULL || sw2->s == NULL)
785,225✔
3205
        return 0;
×
3206

3207
    /* sid and gid match required */
3208
    if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
785,225✔
3209

3210
    return 0;
40,977✔
3211
}
785,225✔
3212

3213
/**
3214
 * \brief Initializes the hash table that is used to cull duplicate sigs.
3215
 *
3216
 * \param de_ctx Pointer to the detection engine context.
3217
 *
3218
 * \retval  0 On success.
3219
 * \retval -1 On failure.
3220
 */
3221
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
3222
{
37,026✔
3223
    de_ctx->dup_sig_hash_table = HashListTableInit(15000,
37,026✔
3224
                                                   DetectParseDupSigHashFunc,
37,026✔
3225
                                                   DetectParseDupSigCompareFunc,
37,026✔
3226
                                                   DetectParseDupSigFreeFunc);
37,026✔
3227
    if (de_ctx->dup_sig_hash_table == NULL)
37,026✔
3228
        return -1;
×
3229

3230
    return 0;
37,026✔
3231
}
37,026✔
3232

3233
/**
3234
 * \brief Frees the hash table that is used to cull duplicate sigs.
3235
 *
3236
 * \param de_ctx Pointer to the detection engine context that holds this table.
3237
 */
3238
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
3239
{
72,501✔
3240
    if (de_ctx->dup_sig_hash_table != NULL)
72,501✔
3241
        HashListTableFree(de_ctx->dup_sig_hash_table);
37,025✔
3242

3243
    de_ctx->dup_sig_hash_table = NULL;
72,501✔
3244
}
72,501✔
3245

3246
/**
3247
 * \brief Check if a signature is a duplicate.
3248
 *
3249
 *        There are 3 types of return values for this function.
3250
 *
3251
 *        - 0, which indicates that the Signature is not a duplicate
3252
 *          and has to be added to the detection engine list.
3253
 *        - 1, Signature is duplicate, and the existing signature in
3254
 *          the list shouldn't be replaced with this duplicate.
3255
 *        - 2, Signature is duplicate, and the existing signature in
3256
 *          the list should be replaced with this duplicate.
3257
 *
3258
 * \param de_ctx Pointer to the detection engine context.
3259
 * \param sig    Pointer to the Signature that has to be checked.
3260
 *
3261
 * \retval 2 If Signature is duplicate and the existing signature in
3262
 *           the list should be chucked out and replaced with this.
3263
 * \retval 1 If Signature is duplicate, and should be chucked out.
3264
 * \retval 0 If Signature is not a duplicate.
3265
 */
3266
static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3267
                                                   Signature *sig)
3268
{
763,796✔
3269
    /* we won't do any NULL checks on the args */
3270

3271
    /* return value */
3272
    int ret = 0;
763,796✔
3273

3274
    SigDuplWrapper *sw_dup = NULL;
763,796✔
3275
    SigDuplWrapper *sw = NULL;
763,796✔
3276

3277
    /* used for making a duplicate_sig_hash_table entry */
3278
    sw = SCCalloc(1, sizeof(SigDuplWrapper));
763,796✔
3279
    if (unlikely(sw == NULL)) {
763,796✔
3280
        exit(EXIT_FAILURE);
×
3281
    }
×
3282
    sw->s = sig;
763,796✔
3283

3284
    /* check if we have a duplicate entry for this signature */
3285
    sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
763,796✔
3286
    /* we don't have a duplicate entry for this sig */
3287
    if (sw_dup == NULL) {
763,796✔
3288
        /* add it to the hash table */
3289
        HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
143,779✔
3290

3291
        /* add the s_prev entry for the previously loaded sw in the hash_table */
3292
        if (de_ctx->sig_list != NULL) {
143,779✔
3293
            SigDuplWrapper *sw_old = NULL;
122,168✔
3294
            SigDuplWrapper sw_tmp;
122,168✔
3295
            memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
122,168✔
3296

3297
            /* the topmost sig would be the last loaded sig */
3298
            sw_tmp.s = de_ctx->sig_list;
122,168✔
3299
            sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
122,168✔
3300
                                         (void *)&sw_tmp, 0);
122,168✔
3301
            /* sw_old == NULL case is impossible */
3302
            sw_old->s_prev = sig;
122,168✔
3303
        }
122,168✔
3304

3305
        ret = 0;
143,779✔
3306
        goto end;
143,779✔
3307
    }
143,779✔
3308

3309
    /* if we have reached here we have a duplicate entry for this signature.
3310
     * Check the signature revision.  Store the signature with the latest rev
3311
     * and discard the other one */
3312
    if (sw->s->rev <= sw_dup->s->rev) {
620,017✔
3313
        ret = 1;
618,803✔
3314
        SCFree(sw);
618,803✔
3315
        sw = NULL;
618,803✔
3316
        goto end;
618,803✔
3317
    }
618,803✔
3318

3319
    /* the new sig is of a newer revision than the one that is already in the
3320
     * list.  Remove the old sig from the list */
3321
    if (sw_dup->s_prev == NULL) {
1,214✔
3322
        SigDuplWrapper sw_temp;
192✔
3323
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
192✔
3324
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
192✔
3325
            sw_temp.s = sw_dup->s->next->next;
38✔
3326
            de_ctx->sig_list = sw_dup->s->next->next;
38✔
3327
            SigFree(de_ctx, sw_dup->s->next);
38✔
3328
        } else {
154✔
3329
            sw_temp.s = sw_dup->s->next;
154✔
3330
            de_ctx->sig_list = sw_dup->s->next;
154✔
3331
        }
154✔
3332
        SigDuplWrapper *sw_next = NULL;
192✔
3333
        if (sw_temp.s != NULL) {
192✔
3334
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
135✔
3335
                                          (void *)&sw_temp, 0);
135✔
3336
            sw_next->s_prev = sw_dup->s_prev;
135✔
3337
        }
135✔
3338
        SigFree(de_ctx, sw_dup->s);
192✔
3339
    } else {
1,022✔
3340
        SigDuplWrapper sw_temp;
1,022✔
3341
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
1,022✔
3342
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
1,022✔
3343
            sw_temp.s = sw_dup->s->next->next;
259✔
3344
            /* If previous signature is bidirectional,
3345
             * it has 2 items in the linked list.
3346
             * So we need to change next->next instead of next
3347
             */
3348
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
259✔
3349
                sw_dup->s_prev->next->next = sw_dup->s->next->next;
151✔
3350
            } else {
151✔
3351
                sw_dup->s_prev->next = sw_dup->s->next->next;
108✔
3352
            }
108✔
3353
            SigFree(de_ctx, sw_dup->s->next);
259✔
3354
        } else {
763✔
3355
            sw_temp.s = sw_dup->s->next;
763✔
3356
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
763✔
3357
                sw_dup->s_prev->next->next = sw_dup->s->next;
115✔
3358
            } else {
648✔
3359
                sw_dup->s_prev->next = sw_dup->s->next;
648✔
3360
            }
648✔
3361
        }
763✔
3362
        SigDuplWrapper *sw_next = NULL;
1,022✔
3363
        if (sw_temp.s != NULL) {
1,022✔
3364
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
771✔
3365
                                          (void *)&sw_temp, 0);
771✔
3366
            sw_next->s_prev = sw_dup->s_prev;
771✔
3367
        }
771✔
3368
        SigFree(de_ctx, sw_dup->s);
1,022✔
3369
    }
1,022✔
3370

3371
    /* make changes to the entry to reflect the presence of the new sig */
3372
    sw_dup->s = sig;
1,214✔
3373
    sw_dup->s_prev = NULL;
1,214✔
3374

3375
    if (de_ctx->sig_list != NULL) {
1,214✔
3376
        SigDuplWrapper sw_tmp;
1,157✔
3377
        memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
1,157✔
3378
        sw_tmp.s = de_ctx->sig_list;
1,157✔
3379
        SigDuplWrapper *sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
1,157✔
3380
                                                     (void *)&sw_tmp, 0);
1,157✔
3381
        if (sw_old->s != sw_dup->s) {
1,157✔
3382
            // Link on top of the list if there was another element
3383
            sw_old->s_prev = sig;
1,157✔
3384
        }
1,157✔
3385
    }
1,157✔
3386

3387
    /* this is duplicate, but a duplicate that replaced the existing sig entry */
3388
    ret = 2;
1,214✔
3389

3390
    SCFree(sw);
1,214✔
3391

3392
end:
763,796✔
3393
    return ret;
763,796✔
3394
}
1,214✔
3395

3396
/**
3397
 * \brief Parse and append a Signature into the Detection Engine Context
3398
 *        signature list.
3399
 *
3400
 *        If the signature is bidirectional it should append two signatures
3401
 *        (with the addresses switched) into the list.  Also handle duplicate
3402
 *        signatures.  In case of duplicate sigs, use the ones that have the
3403
 *        latest revision.  We use the sid and the msg to identify duplicate
3404
 *        sigs.  If 2 sigs have the same sid and gid, they are duplicates.
3405
 *
3406
 * \param de_ctx Pointer to the Detection Engine Context.
3407
 * \param sigstr Pointer to a character string containing the signature to be
3408
 *               parsed.
3409
 * \param sig_file Pointer to a character string containing the filename from
3410
 *                 which signature is read
3411
 * \param lineno Line number from where signature is read
3412
 *
3413
 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3414
 *         on success; NULL on failure.
3415
 */
3416
Signature *DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
UNCOV
3417
{
×
UNCOV
3418
    Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
×
UNCOV
3419
    if (sig == NULL) {
×
3420
        return NULL;
×
3421
    }
×
3422

3423
    /* checking for the status of duplicate signature */
UNCOV
3424
    int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
×
3425
    /* a duplicate signature that should be chucked out.  Check the previously
3426
     * called function details to understand the different return values */
UNCOV
3427
    if (dup_sig == 1) {
×
3428
        SCLogError("Duplicate signature \"%s\"", sigstr);
×
3429
        goto error;
×
UNCOV
3430
    } else if (dup_sig == 2) {
×
3431
        SCLogWarning("Signature with newer revision,"
×
3432
                     " so the older sig replaced by this new signature \"%s\"",
×
3433
                sigstr);
×
3434
    }
×
3435

UNCOV
3436
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
×
UNCOV
3437
        if (sig->next != NULL) {
×
UNCOV
3438
            sig->next->next = de_ctx->sig_list;
×
UNCOV
3439
        } else {
×
3440
            goto error;
×
3441
        }
×
UNCOV
3442
    } else {
×
3443
        /* if this sig is the first one, sig_list should be null */
UNCOV
3444
        sig->next = de_ctx->sig_list;
×
UNCOV
3445
    }
×
3446

UNCOV
3447
    de_ctx->sig_list = sig;
×
3448

3449
    /**
3450
     * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3451
     * so if the signature is bidirectional, the returned sig will point through "next" ptr
3452
     * to the cloned signatures with the switched addresses
3453
     */
UNCOV
3454
    return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
×
3455

3456
error:
×
3457
    /* free the 2nd sig bidir may have set up */
3458
    if (sig != NULL && sig->next != NULL) {
×
3459
        SigFree(de_ctx, sig->next);
×
3460
        sig->next = NULL;
×
3461
    }
×
3462
    if (sig != NULL) {
×
3463
        SigFree(de_ctx, sig);
×
3464
    }
×
3465
    return NULL;
×
UNCOV
3466
}
×
3467

3468
/**
3469
 * \brief Parse and append a Signature into the Detection Engine Context
3470
 *        signature list.
3471
 *
3472
 *        If the signature is bidirectional it should append two signatures
3473
 *        (with the addresses switched) into the list.  Also handle duplicate
3474
 *        signatures.  In case of duplicate sigs, use the ones that have the
3475
 *        latest revision.  We use the sid and the msg to identify duplicate
3476
 *        sigs.  If 2 sigs have the same sid and gid, they are duplicates.
3477
 *
3478
 * \param de_ctx Pointer to the Detection Engine Context.
3479
 * \param sigstr Pointer to a character string containing the signature to be
3480
 *               parsed.
3481
 * \param sig_file Pointer to a character string containing the filename from
3482
 *                 which signature is read
3483
 * \param lineno Line number from where signature is read
3484
 *
3485
 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3486
 *         on success; NULL on failure.
3487
 */
3488
Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
3489
{
5,009,899✔
3490
    Signature *sig = SigInit(de_ctx, sigstr);
5,009,899✔
3491
    if (sig == NULL) {
5,009,899✔
3492
        return NULL;
4,246,103✔
3493
    }
4,246,103✔
3494

3495
    /* checking for the status of duplicate signature */
3496
    int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
763,796✔
3497
    /* a duplicate signature that should be chucked out.  Check the previously
3498
     * called function details to understand the different return values */
3499
    if (dup_sig == 1) {
763,796✔
3500
        SCLogError("Duplicate signature \"%s\"", sigstr);
618,803✔
3501
        goto error;
618,803✔
3502
    } else if (dup_sig == 2) {
656,013✔
3503
        SCLogWarning("Signature with newer revision,"
1,214✔
3504
                     " so the older sig replaced by this new signature \"%s\"",
1,214✔
3505
                sigstr);
1,214✔
3506
    }
1,214✔
3507

3508
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
144,993✔
3509
        if (sig->next != NULL) {
13,019✔
3510
            sig->next->next = de_ctx->sig_list;
13,019✔
3511
        } else {
13,019✔
3512
            goto error;
×
3513
        }
×
3514
    } else {
131,974✔
3515
        /* if this sig is the first one, sig_list should be null */
3516
        sig->next = de_ctx->sig_list;
131,974✔
3517
    }
131,974✔
3518

3519
    de_ctx->sig_list = sig;
144,993✔
3520

3521
    /**
3522
     * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3523
     * so if the signature is bidirectional, the returned sig will point through "next" ptr
3524
     * to the cloned signatures with the switched addresses
3525
     */
3526
    return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
144,993✔
3527

3528
error:
618,803✔
3529
    /* free the 2nd sig bidir may have set up */
3530
    if (sig != NULL && sig->next != NULL) {
618,803✔
3531
        SigFree(de_ctx, sig->next);
133,173✔
3532
        sig->next = NULL;
133,173✔
3533
    }
133,173✔
3534
    if (sig != NULL) {
618,803✔
3535
        SigFree(de_ctx, sig);
618,803✔
3536
    }
618,803✔
3537
    return NULL;
618,803✔
3538
}
144,993✔
3539

3540
static DetectParseRegex *g_detect_parse_regex_list = NULL;
3541

3542
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3543
        int start_offset, int options)
3544
{
1,162,635✔
3545
    *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
1,162,635✔
3546
    if (*match)
1,162,635✔
3547
        return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
1,162,635✔
3548
                *match, parse_regex->context);
1,162,635✔
UNCOV
3549
    return -1;
×
3550
}
1,162,635✔
3551

3552
void DetectParseFreeRegex(DetectParseRegex *r)
3553
{
400,860✔
3554
    if (r->regex) {
400,860✔
3555
        pcre2_code_free(r->regex);
350,966✔
3556
    }
350,966✔
3557
    if (r->context) {
400,860✔
3558
        pcre2_match_context_free(r->context);
349,910✔
3559
    }
349,910✔
3560
}
400,860✔
3561

3562
void DetectParseFreeRegexes(void)
3563
{
24✔
3564
    DetectParseRegex *r = g_detect_parse_regex_list;
24✔
3565
    while (r) {
1,080✔
3566
        DetectParseRegex *next = r->next;
1,056✔
3567

3568
        DetectParseFreeRegex(r);
1,056✔
3569

3570
        SCFree(r);
1,056✔
3571
        r = next;
1,056✔
3572
    }
1,056✔
3573
    g_detect_parse_regex_list = NULL;
24✔
3574
}
24✔
3575

3576
/** \brief add regex and/or study to at exit free list
3577
 */
3578
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
3579
{
1,292✔
3580
    DetectParseRegex *r = SCCalloc(1, sizeof(*r));
1,292✔
3581
    if (r == NULL) {
1,292✔
3582
        FatalError("failed to alloc memory for pcre free list");
×
3583
    }
×
3584
    r->regex = detect_parse->regex;
1,292✔
3585
    r->next = g_detect_parse_regex_list;
1,292✔
3586
    g_detect_parse_regex_list = r;
1,292✔
3587
}
1,292✔
3588

3589
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3590
{
1,292✔
3591
    int en;
1,292✔
3592
    PCRE2_SIZE eo;
1,292✔
3593

3594
    detect_parse->regex =
1,292✔
3595
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
1,292✔
3596
    if (detect_parse->regex == NULL) {
1,292✔
3597
        PCRE2_UCHAR errbuffer[256];
×
3598
        pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
×
3599
        SCLogError("pcre compile of \"%s\" failed at "
×
3600
                   "offset %d: %s",
×
3601
                parse_str, en, errbuffer);
×
3602
        return false;
×
3603
    }
×
3604
    detect_parse->context = pcre2_match_context_create(NULL);
1,292✔
3605
    if (detect_parse->context == NULL) {
1,292✔
3606
        SCLogError("pcre2 could not create match context");
×
3607
        pcre2_code_free(detect_parse->regex);
×
3608
        detect_parse->regex = NULL;
×
3609
        return false;
×
3610
    }
×
3611
    pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
1,292✔
3612
    pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
1,292✔
3613
    DetectParseRegexAddToFreeList(detect_parse);
1,292✔
3614

3615
    return true;
1,292✔
3616
}
1,292✔
3617

3618
DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3619
{
200✔
3620
    int en;
200✔
3621
    PCRE2_SIZE eo;
200✔
3622
    DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
200✔
3623
    if (detect_parse == NULL) {
200✔
3624
        return NULL;
×
3625
    }
×
3626

3627
    detect_parse->regex =
200✔
3628
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
200✔
3629
    if (detect_parse->regex == NULL) {
200✔
3630
        PCRE2_UCHAR errbuffer[256];
×
3631
        pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
×
3632
        SCLogError("pcre2 compile of \"%s\" failed at "
×
3633
                   "offset %d: %s",
×
3634
                parse_str, (int)eo, errbuffer);
×
3635
        SCFree(detect_parse);
×
3636
        return NULL;
×
3637
    }
×
3638

3639
    detect_parse->next = g_detect_parse_regex_list;
200✔
3640
    g_detect_parse_regex_list = detect_parse;
200✔
3641
    return detect_parse;
200✔
3642
}
200✔
3643

3644
int SC_Pcre2SubstringCopy(
3645
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3646
{
209,831✔
3647
    int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
209,831✔
3648
    if (r == PCRE2_ERROR_UNSET) {
209,831✔
3649
        buffer[0] = 0;
874✔
3650
        *bufflen = 0;
874✔
3651
        return 0;
874✔
3652
    }
874✔
3653
    return r;
208,957✔
3654
}
209,831✔
3655

3656
int SC_Pcre2SubstringGet(
3657
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3658
{
×
3659
    int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
×
3660
    if (r == PCRE2_ERROR_UNSET) {
×
3661
        *bufferptr = NULL;
×
3662
        *bufflen = 0;
×
3663
        return 0;
×
3664
    }
×
3665
    return r;
×
3666
}
×
3667

3668
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3669
{
1,292✔
3670
    if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
1,292✔
3671
        FatalError("pcre compile and study failed");
×
3672
    }
×
3673
}
1,292✔
3674

3675
/*
3676
 * TESTS
3677
 */
3678

3679
#ifdef UNITTESTS
3680
#include "detect-engine-alert.h"
3681
#include "packet.h"
3682

3683
static int SigParseTest01 (void)
3684
{
1✔
3685
    int result = 1;
1✔
3686
    Signature *sig = NULL;
1✔
3687

3688
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3689
    if (de_ctx == NULL)
1✔
3690
        goto end;
3691

3692
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
3693
    if (sig == NULL)
1✔
3694
        result = 0;
3695

3696
end:
1✔
3697
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
3698
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
3699
    return result;
1✔
3700
}
1✔
3701

3702
static int SigParseTest02 (void)
3703
{
1✔
3704
    int result = 0;
1✔
3705
    Signature *sig = NULL;
1✔
3706
    DetectPort *port = NULL;
1✔
3707

3708
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3709

3710
    if (de_ctx == NULL)
1✔
3711
        goto end;
3712

3713
    SCClassConfDeInitContext(de_ctx);
1✔
3714
    FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01();
1✔
3715
    SCClassConfLoadClassificationConfigFile(de_ctx, fd);
1✔
3716

3717
    sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)");
1✔
3718
    if (sig == NULL) {
1✔
3719
        goto end;
3720
    }
3721

3722
    int r = DetectPortParse(de_ctx, &port, "0:20");
1✔
3723
    if (r < 0)
1✔
3724
        goto end;
3725

3726
    if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
1✔
3727
        result = 1;
1✔
3728
    } else {
1✔
3729
        DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3730
    }
3731

3732
end:
1✔
3733
    if (port != NULL)
1✔
3734
        DetectPortCleanupList(de_ctx, port);
1✔
3735
    if (sig != NULL)
1✔
3736
        SigFree(de_ctx, sig);
1✔
3737
    if (de_ctx != NULL)
1✔
3738
        DetectEngineCtxFree(de_ctx);
1✔
3739
    return result;
1✔
3740
}
1✔
3741

3742
/**
3743
 * \test SigParseTest03 test for invalid direction operator in rule
3744
 */
3745
static int SigParseTest03 (void)
3746
{
1✔
3747
    int result = 1;
1✔
3748
    Signature *sig = NULL;
1✔
3749

3750
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3751
    if (de_ctx == NULL)
1✔
3752
        goto end;
3753

3754
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
1✔
3755
    if (sig != NULL) {
1✔
3756
        result = 0;
3757
        printf("expected NULL got sig ptr %p: ",sig);
3758
    }
3759

3760
end:
1✔
3761
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
3762
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
3763
    return result;
1✔
3764
}
1✔
3765

3766
static int SigParseTest04 (void)
3767
{
1✔
3768
    int result = 1;
1✔
3769
    Signature *sig = NULL;
1✔
3770

3771
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3772
    if (de_ctx == NULL)
1✔
3773
        goto end;
3774

3775
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
1✔
3776
    if (sig == NULL)
1✔
3777
        result = 0;
3778

3779
end:
1✔
3780
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
3781
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
3782
    return result;
1✔
3783
}
1✔
3784

3785
/** \test Port validation */
3786
static int SigParseTest05 (void)
3787
{
1✔
3788
    int result = 0;
1✔
3789
    Signature *sig = NULL;
1✔
3790

3791
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3792
    if (de_ctx == NULL)
1✔
3793
        goto end;
3794

3795
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
1✔
3796
    if (sig == NULL) {
1✔
3797
        result = 1;
1✔
3798
    } else {
1✔
3799
        printf("signature didn't fail to parse as we expected: ");
3800
    }
3801

3802
end:
1✔
3803
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
3804
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
3805
    return result;
1✔
3806
}
1✔
3807

3808
/** \test Parsing bug debugging at 2010-03-18 */
3809
static int SigParseTest06 (void)
3810
{
1✔
3811
    int result = 0;
1✔
3812
    Signature *sig = NULL;
1✔
3813

3814
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3815
    if (de_ctx == NULL)
1✔
3816
        goto end;
3817

3818
    sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)");
1✔
3819
    if (sig != NULL) {
1✔
3820
        result = 1;
1✔
3821
    } else {
1✔
3822
        printf("signature failed to parse: ");
3823
    }
3824

3825
end:
1✔
3826
    if (sig != NULL)
1✔
3827
        SigFree(de_ctx, sig);
1✔
3828
    if (de_ctx != NULL)
1✔
3829
        DetectEngineCtxFree(de_ctx);
1✔
3830
    return result;
1✔
3831
}
1✔
3832

3833
/**
3834
 * \test Parsing duplicate sigs.
3835
 */
3836
static int SigParseTest07(void)
3837
{
1✔
3838
    int result = 0;
1✔
3839

3840
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3841
    if (de_ctx == NULL)
1✔
3842
        goto end;
3843

3844
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
1✔
3845
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
1✔
3846

3847
    result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
1✔
3848

3849
end:
1✔
3850
    if (de_ctx != NULL)
1✔
3851
        DetectEngineCtxFree(de_ctx);
1✔
3852
    return result;
1✔
3853
}
1✔
3854

3855
/**
3856
 * \test Parsing duplicate sigs.
3857
 */
3858
static int SigParseTest08(void)
3859
{
1✔
3860
    int result = 0;
1✔
3861

3862
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3863
    if (de_ctx == NULL)
1✔
3864
        goto end;
3865

3866
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
1✔
3867
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
1✔
3868

3869
    result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
1✔
3870
              de_ctx->sig_list->rev == 2);
1✔
3871

3872
end:
1✔
3873
    if (de_ctx != NULL)
1✔
3874
        DetectEngineCtxFree(de_ctx);
1✔
3875
    return result;
1✔
3876
}
1✔
3877

3878
/**
3879
 * \test Parsing duplicate sigs.
3880
 */
3881
static int SigParseTest09(void)
3882
{
1✔
3883
    int result = 1;
1✔
3884

3885
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3886
    if (de_ctx == NULL)
1✔
3887
        goto end;
3888

3889
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
1✔
3890
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
1✔
3891
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
1✔
3892
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
1✔
3893
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
1✔
3894
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
1✔
3895
               de_ctx->sig_list->rev == 2);
1✔
3896
    if (result == 0)
1✔
3897
        goto end;
3898
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
1✔
3899
               de_ctx->sig_list->next->rev == 6);
1✔
3900
    if (result == 0)
1✔
3901
        goto end;
3902

3903
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
1✔
3904
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
1✔
3905
               de_ctx->sig_list->rev == 2);
1✔
3906
    if (result == 0)
1✔
3907
        goto end;
3908
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
1✔
3909
               de_ctx->sig_list->next->rev == 6);
1✔
3910
    if (result == 0)
1✔
3911
        goto end;
3912

3913
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
1✔
3914
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
1✔
3915
               de_ctx->sig_list->rev == 4);
1✔
3916
    if (result == 0)
1✔
3917
        goto end;
3918
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
1✔
3919
               de_ctx->sig_list->next->rev == 6);
1✔
3920
    if (result == 0)
1✔
3921
        goto end;
3922

3923
end:
1✔
3924
    if (de_ctx != NULL)
1✔
3925
        DetectEngineCtxFree(de_ctx);
1✔
3926
    return result;
1✔
3927
}
1✔
3928

3929
/**
3930
 * \test Parsing duplicate sigs.
3931
 */
3932
static int SigParseTest10(void)
3933
{
1✔
3934
    int result = 1;
1✔
3935

3936
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3937
    if (de_ctx == NULL)
1✔
3938
        goto end;
3939

3940
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
1✔
3941
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
1✔
3942
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
1✔
3943
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
1✔
3944
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
1✔
3945
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
1✔
3946
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
1✔
3947

3948
    result &= ((de_ctx->sig_list->id == 2) &&
1✔
3949
               (de_ctx->sig_list->next->id == 3) &&
1✔
3950
               (de_ctx->sig_list->next->next->id == 5) &&
1✔
3951
               (de_ctx->sig_list->next->next->next->id == 4) &&
1✔
3952
               (de_ctx->sig_list->next->next->next->next->id == 1));
1✔
3953

3954
end:
1✔
3955
    if (de_ctx != NULL)
1✔
3956
        DetectEngineCtxFree(de_ctx);
1✔
3957
    return result;
1✔
3958
}
1✔
3959

3960
/**
3961
 * \test Parsing sig with trailing space(s) as reported by
3962
 *       Morgan Cox on oisf-users.
3963
 */
3964
static int SigParseTest11(void)
3965
{
1✔
3966
    int result = 0;
1✔
3967

3968
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3969
    if (de_ctx == NULL)
1✔
3970
        goto end;
3971

3972
    Signature *s = NULL;
1✔
3973

3974
    s = DetectEngineAppendSig(de_ctx,
1✔
3975
            "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
1✔
3976
    if (s == NULL) {
1✔
3977
        printf("sig 1 didn't parse: ");
3978
        goto end;
3979
    }
3980

3981
    s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
1✔
3982
                                      "the http link\"; sid:2;)            ");
1✔
3983
    if (s == NULL) {
1✔
3984
        printf("sig 2 didn't parse: ");
3985
        goto end;
3986
    }
3987

3988
    result = 1;
1✔
3989
end:
1✔
3990
    if (de_ctx != NULL)
1✔
3991
        DetectEngineCtxFree(de_ctx);
1✔
3992
    return result;
1✔
3993
}
1✔
3994

3995
/**
3996
 * \test file_data with rawbytes
3997
 */
3998
static int SigParseTest12(void)
3999
{
1✔
4000
    int result = 0;
1✔
4001

4002
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4003
    if (de_ctx == NULL)
1✔
4004
        goto end;
4005

4006
    Signature *s = NULL;
1✔
4007

4008
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
1✔
4009
    if (s != NULL) {
1✔
4010
        printf("sig 1 should have given an error: ");
4011
        goto end;
4012
    }
4013

4014
    result = 1;
1✔
4015
end:
1✔
4016
    if (de_ctx != NULL)
1✔
4017
        DetectEngineCtxFree(de_ctx);
1✔
4018
    return result;
1✔
4019
}
1✔
4020

4021
/**
4022
 * \test packet/stream sig
4023
 */
4024
static int SigParseTest13(void)
4025
{
1✔
4026
    int result = 0;
1✔
4027

4028
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4029
    if (de_ctx == NULL)
1✔
4030
        goto end;
4031

4032
    Signature *s = NULL;
1✔
4033

4034
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
1✔
4035
    if (s == NULL) {
1✔
4036
        printf("sig 1 invalidated: failure");
4037
        goto end;
4038
    }
4039

4040
    if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1✔
4041
        printf("sig doesn't have stream flag set\n");
4042
        goto end;
4043
    }
4044

4045
    if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1✔
4046
        printf("sig has packet flag set\n");
4047
        goto end;
4048
    }
4049

4050
    result = 1;
1✔
4051

4052
end:
1✔
4053
    if (de_ctx != NULL)
1✔
4054
        DetectEngineCtxFree(de_ctx);
1✔
4055
    return result;
1✔
4056
}
1✔
4057

4058
/**
4059
 * \test packet/stream sig
4060
 */
4061
static int SigParseTest14(void)
4062
{
1✔
4063
    int result = 0;
1✔
4064

4065
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4066
    if (de_ctx == NULL)
1✔
4067
        goto end;
4068

4069
    Signature *s = NULL;
1✔
4070

4071
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
1✔
4072
    if (s == NULL) {
1✔
4073
        printf("sig 1 invalidated: failure");
4074
        goto end;
4075
    }
4076

4077
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
1✔
4078
        printf("sig doesn't have packet flag set\n");
4079
        goto end;
4080
    }
4081

4082
    if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1✔
4083
        printf("sig has stream flag set\n");
4084
        goto end;
4085
    }
4086

4087
    result = 1;
1✔
4088

4089
end:
1✔
4090
    if (de_ctx != NULL)
1✔
4091
        DetectEngineCtxFree(de_ctx);
1✔
4092
    return result;
1✔
4093
}
1✔
4094

4095
/**
4096
 * \test packet/stream sig
4097
 */
4098
static int SigParseTest15(void)
4099
{
1✔
4100
    int result = 0;
1✔
4101

4102
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4103
    if (de_ctx == NULL)
1✔
4104
        goto end;
4105

4106
    Signature *s = NULL;
1✔
4107

4108
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
1✔
4109
    if (s == NULL) {
1✔
4110
        printf("sig 1 invalidated: failure");
4111
        goto end;
4112
    }
4113

4114
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
1✔
4115
        printf("sig doesn't have packet flag set\n");
4116
        goto end;
4117
    }
4118

4119
    if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1✔
4120
        printf("sig doesn't have stream flag set\n");
4121
        goto end;
4122
    }
4123

4124
    result = 1;
1✔
4125

4126
end:
1✔
4127
    if (de_ctx != NULL)
1✔
4128
        DetectEngineCtxFree(de_ctx);
1✔
4129
    return result;
1✔
4130
}
1✔
4131

4132
/**
4133
 * \test packet/stream sig
4134
 */
4135
static int SigParseTest16(void)
4136
{
1✔
4137
    int result = 0;
1✔
4138

4139
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4140
    if (de_ctx == NULL)
1✔
4141
        goto end;
4142

4143
    Signature *s = NULL;
1✔
4144

4145
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
1✔
4146
    if (s == NULL) {
1✔
4147
        printf("sig 1 invalidated: failure");
4148
        goto end;
4149
    }
4150

4151
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
1✔
4152
        printf("sig doesn't have packet flag set\n");
4153
        goto end;
4154
    }
4155

4156
    if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1✔
4157
        printf("sig doesn't have stream flag set\n");
4158
        goto end;
4159
    }
4160

4161
    result = 1;
1✔
4162

4163
end:
1✔
4164
    if (de_ctx != NULL)
1✔
4165
        DetectEngineCtxFree(de_ctx);
1✔
4166
    return result;
1✔
4167
}
1✔
4168

4169
/**
4170
 * \test packet/stream sig
4171
 */
4172
static int SigParseTest17(void)
4173
{
1✔
4174
    int result = 0;
1✔
4175

4176
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4177
    if (de_ctx == NULL)
1✔
4178
        goto end;
4179

4180
    Signature *s = NULL;
1✔
4181

4182
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
1✔
4183
    if (s == NULL) {
1✔
4184
        printf("sig 1 invalidated: failure");
4185
        goto end;
4186
    }
4187

4188
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
1✔
4189
        printf("sig doesn't have packet flag set\n");
4190
        goto end;
4191
    }
4192

4193
    if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1✔
4194
        printf("sig doesn't have stream flag set\n");
4195
        goto end;
4196
    }
4197

4198
    result = 1;
1✔
4199

4200
end:
1✔
4201
    if (de_ctx != NULL)
1✔
4202
        DetectEngineCtxFree(de_ctx);
1✔
4203
    return result;
1✔
4204
}
1✔
4205

4206
/** \test sid value too large. Bug #779 */
4207
static int SigParseTest18 (void)
4208
{
1✔
4209
    int result = 0;
1✔
4210

4211
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4212
    if (de_ctx == NULL)
1✔
4213
        goto end;
4214

4215
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
1✔
4216
        goto end;
4217

4218
    result = 1;
1✔
4219
end:
1✔
4220
    if (de_ctx != NULL)
1✔
4221
        DetectEngineCtxFree(de_ctx);
1✔
4222
    return result;
1✔
4223
}
1✔
4224

4225
/** \test gid value too large. Related to bug #779 */
4226
static int SigParseTest19 (void)
4227
{
1✔
4228
    int result = 0;
1✔
4229

4230
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4231
    if (de_ctx == NULL)
1✔
4232
        goto end;
4233

4234
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
1✔
4235
        goto end;
4236

4237
    result = 1;
1✔
4238
end:
1✔
4239
    if (de_ctx != NULL)
1✔
4240
        DetectEngineCtxFree(de_ctx);
1✔
4241
    return result;
1✔
4242
}
1✔
4243

4244
/** \test rev value too large. Related to bug #779 */
4245
static int SigParseTest20 (void)
4246
{
1✔
4247
    int result = 0;
1✔
4248

4249
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4250
    if (de_ctx == NULL)
1✔
4251
        goto end;
4252

4253
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
1✔
4254
        goto end;
4255

4256
    result = 1;
1✔
4257
end:
1✔
4258
    if (de_ctx != NULL)
1✔
4259
        DetectEngineCtxFree(de_ctx);
1✔
4260
    return result;
1✔
4261
}
1✔
4262

4263
/** \test address parsing */
4264
static int SigParseTest21 (void)
4265
{
1✔
4266
    int result = 0;
1✔
4267

4268
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4269
    if (de_ctx == NULL)
1✔
4270
        goto end;
4271

4272
    if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
1✔
4273
        goto end;
4274

4275
    result = 1;
1✔
4276
end:
1✔
4277
    if (de_ctx != NULL)
1✔
4278
        DetectEngineCtxFree(de_ctx);
1✔
4279
    return result;
1✔
4280
}
1✔
4281

4282
/** \test address parsing */
4283
static int SigParseTest22 (void)
4284
{
1✔
4285
    int result = 0;
1✔
4286

4287
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4288
    if (de_ctx == NULL)
1✔
4289
        goto end;
4290

4291
    if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> [10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL)
1✔
4292
        goto end;
4293

4294
    result = 1;
1✔
4295
end:
1✔
4296
    if (de_ctx != NULL)
1✔
4297
        DetectEngineCtxFree(de_ctx);
1✔
4298
    return result;
1✔
4299
}
1✔
4300

4301
/**
4302
 * \test rule ending in carriage return
4303
 */
4304
static int SigParseTest23(void)
4305
{
1✔
4306
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4307
    FAIL_IF_NULL(de_ctx);
1✔
4308

4309
    Signature *s = NULL;
1✔
4310

4311
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
1✔
4312
    FAIL_IF_NULL(s);
1✔
4313

4314
    DetectEngineCtxFree(de_ctx);
1✔
4315
    PASS;
1✔
4316
}
1✔
4317

4318
/** \test Direction operator validation (invalid) */
4319
static int SigParseBidirecTest06 (void)
4320
{
1✔
4321
    int result = 1;
1✔
4322
    Signature *sig = NULL;
1✔
4323

4324
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4325
    if (de_ctx == NULL)
1✔
4326
        goto end;
4327

4328
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4329
    if (sig == NULL)
1✔
4330
        result = 1;
1✔
4331

4332
end:
1✔
4333
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4334
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4335
    return result;
1✔
4336
}
1✔
4337

4338
/** \test Direction operator validation (invalid) */
4339
static int SigParseBidirecTest07 (void)
4340
{
1✔
4341
    int result = 1;
1✔
4342
    Signature *sig = NULL;
1✔
4343

4344
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4345
    if (de_ctx == NULL)
1✔
4346
        goto end;
4347

4348
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4349
    if (sig == NULL)
1✔
4350
        result = 1;
1✔
4351

4352
end:
1✔
4353
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4354
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4355
    return result;
1✔
4356
}
1✔
4357

4358
/** \test Direction operator validation (invalid) */
4359
static int SigParseBidirecTest08 (void)
4360
{
1✔
4361
    int result = 1;
1✔
4362
    Signature *sig = NULL;
1✔
4363

4364
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4365
    if (de_ctx == NULL)
1✔
4366
        goto end;
4367

4368
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4369
    if (sig == NULL)
1✔
4370
        result = 1;
1✔
4371

4372
end:
1✔
4373
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4374
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4375
    return result;
1✔
4376
}
1✔
4377

4378
/** \test Direction operator validation (invalid) */
4379
static int SigParseBidirecTest09 (void)
4380
{
1✔
4381
    int result = 1;
1✔
4382
    Signature *sig = NULL;
1✔
4383

4384
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4385
    if (de_ctx == NULL)
1✔
4386
        goto end;
4387

4388
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4389
    if (sig == NULL)
1✔
4390
        result = 1;
1✔
4391

4392
end:
1✔
4393
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4394
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4395
    return result;
1✔
4396
}
1✔
4397

4398
/** \test Direction operator validation (invalid) */
4399
static int SigParseBidirecTest10 (void)
4400
{
1✔
4401
    int result = 1;
1✔
4402
    Signature *sig = NULL;
1✔
4403

4404
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4405
    if (de_ctx == NULL)
1✔
4406
        goto end;
4407

4408
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4409
    if (sig == NULL)
1✔
4410
        result = 1;
1✔
4411

4412
end:
1✔
4413
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4414
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4415
    return result;
1✔
4416
}
1✔
4417

4418
/** \test Direction operator validation (invalid) */
4419
static int SigParseBidirecTest11 (void)
4420
{
1✔
4421
    int result = 1;
1✔
4422
    Signature *sig = NULL;
1✔
4423

4424
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4425
    if (de_ctx == NULL)
1✔
4426
        goto end;
4427

4428
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4429
    if (sig == NULL)
1✔
4430
        result = 1;
1✔
4431

4432
end:
1✔
4433
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4434
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4435
    return result;
1✔
4436
}
1✔
4437

4438
/** \test Direction operator validation (invalid) */
4439
static int SigParseBidirecTest12 (void)
4440
{
1✔
4441
    int result = 1;
1✔
4442
    Signature *sig = NULL;
1✔
4443

4444
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4445
    if (de_ctx == NULL)
1✔
4446
        goto end;
4447

4448
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4449
    if (sig == NULL)
1✔
4450
        result = 1;
1✔
4451

4452
end:
1✔
4453
    if (sig != NULL) SigFree(de_ctx, sig);
1✔
4454
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4455
    return result;
1✔
4456
}
1✔
4457

4458
/** \test Direction operator validation (valid) */
4459
static int SigParseBidirecTest13 (void)
4460
{
1✔
4461
    int result = 1;
1✔
4462
    Signature *sig = NULL;
1✔
4463

4464
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4465
    if (de_ctx == NULL)
1✔
4466
        goto end;
4467

4468
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4469
    if (sig != NULL)
1✔
4470
        result = 1;
1✔
4471

4472
end:
1✔
4473
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4474
    return result;
1✔
4475
}
1✔
4476

4477
/** \test Direction operator validation (valid) */
4478
static int SigParseBidirecTest14 (void)
4479
{
1✔
4480
    int result = 1;
1✔
4481
    Signature *sig = NULL;
1✔
4482

4483
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4484
    if (de_ctx == NULL)
1✔
4485
        goto end;
4486

4487
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
1✔
4488
    if (sig != NULL)
1✔
4489
        result = 1;
1✔
4490

4491
end:
1✔
4492
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
1✔
4493
    return result;
1✔
4494
}
1✔
4495

4496
/** \test Ensure that we don't set bidirectional in a
4497
 *         normal (one direction) Signature
4498
 */
4499
static int SigTestBidirec01 (void)
4500
{
1✔
4501
    Signature *sig = NULL;
1✔
4502
    int result = 0;
1✔
4503

4504
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4505
    if (de_ctx == NULL)
1✔
4506
        goto end;
4507

4508
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
1✔
4509
    if (sig == NULL)
1✔
4510
        goto end;
4511
    if (sig->next != NULL)
1✔
4512
        goto end;
4513
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)
1✔
4514
        goto end;
4515
    if (de_ctx->signum != 1)
1✔
4516
        goto end;
4517

4518
    result = 1;
1✔
4519

4520
end:
1✔
4521
    if (de_ctx != NULL) {
1✔
4522
        SigCleanSignatures(de_ctx);
1✔
4523
        SigGroupCleanup(de_ctx);
1✔
4524
        DetectEngineCtxFree(de_ctx);
1✔
4525
    }
1✔
4526
    return result;
1✔
4527
}
1✔
4528

4529
/** \test Ensure that we set a bidirectional Signature correctly */
4530
static int SigTestBidirec02 (void)
4531
{
1✔
4532
    int result = 0;
1✔
4533
    Signature *sig = NULL;
1✔
4534
    Signature *copy = NULL;
1✔
4535

4536
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4537
    if (de_ctx == NULL)
1✔
4538
        goto end;
4539

4540
    de_ctx->flags |= DE_QUIET;
1✔
4541

4542
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
1✔
4543
    if (sig == NULL)
1✔
4544
        goto end;
4545
    if (de_ctx->sig_list != sig)
1✔
4546
        goto end;
4547
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
1✔
4548
        goto end;
4549
    if (sig->next == NULL)
1✔
4550
        goto end;
4551
    if (de_ctx->signum != 2)
1✔
4552
        goto end;
4553
    copy = sig->next;
1✔
4554
    if (copy->next != NULL)
1✔
4555
        goto end;
4556
    if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
1✔
4557
        goto end;
4558

4559
    result = 1;
1✔
4560

4561
end:
1✔
4562
    if (de_ctx != NULL) {
1✔
4563
        SigCleanSignatures(de_ctx);
1✔
4564
        SigGroupCleanup(de_ctx);
1✔
4565
        DetectEngineCtxFree(de_ctx);
1✔
4566
    }
1✔
4567

4568
    return result;
1✔
4569
}
1✔
4570

4571
/** \test Ensure that we set a bidirectional Signature correctly
4572
*         and we install it with the rest of the signatures, checking
4573
*         also that it match with the correct addr directions
4574
*/
4575
static int SigTestBidirec03 (void)
4576
{
1✔
4577
    int result = 0;
1✔
4578
    Signature *sig = NULL;
1✔
4579
    Packet *p = NULL;
1✔
4580

4581
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4582
    if (de_ctx == NULL)
1✔
4583
        goto end;
4584

4585
    de_ctx->flags |= DE_QUIET;
1✔
4586

4587
    const char *sigs[3];
1✔
4588
    sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
1✔
4589
    sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
1✔
4590
    sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
1✔
4591
    UTHAppendSigs(de_ctx, sigs, 3);
1✔
4592

4593
    /* Checking that bidirectional rules are set correctly */
4594
    sig = de_ctx->sig_list;
1✔
4595
    if (sig == NULL)
1✔
4596
        goto end;
4597
    if (sig->next == NULL)
1✔
4598
        goto end;
4599
    if (sig->next->next == NULL)
1✔
4600
        goto end;
4601
    if (sig->next->next->next == NULL)
1✔
4602
        goto end;
4603
    if (sig->next->next->next->next != NULL)
1✔
4604
        goto end;
4605
    if (de_ctx->signum != 4)
1✔
4606
        goto end;
4607

4608
    uint8_t rawpkt1_ether[] = {
1✔
4609
        0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
1✔
4610
        0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
1✔
4611
        0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
1✔
4612
        0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
1✔
4613
        0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
1✔
4614
        0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
1✔
4615
        0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
1✔
4616
        0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
1✔
4617
        0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
1✔
4618
        0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
1✔
4619
        0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
1✔
4620
        0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
1✔
4621
        0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
1✔
4622
        0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
1✔
4623
        0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
1✔
4624
        0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
1✔
4625
        0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
1✔
4626
        0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
1✔
4627
        0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
1✔
4628
        0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
1✔
4629
        0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
1✔
4630
        0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
1✔
4631
        0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
1✔
4632
        0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
1✔
4633
        0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
1✔
4634
        0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
1✔
4635
        0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
1✔
4636
        0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
1✔
4637
        0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
1✔
4638
        0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
1✔
4639
        0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
1✔
4640
        0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
1✔
4641
        0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
1✔
4642
        0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
1✔
4643
        0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4644
        0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1✔
4645
        0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
1✔
4646
        0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
1✔
4647
        0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
1✔
4648
        0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
1✔
4649
        0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
1✔
4650
        0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
1✔
4651
        0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
1✔
4652
        0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1✔
4653
        0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
1✔
4654
        0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
1✔
4655
        0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
1✔
4656
        0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4657
        0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4658
        0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
1✔
4659
        0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
1✔
4660
        0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
1✔
4661
        0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
1✔
4662
        0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
1✔
4663
        0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
1✔
4664

4665
    FlowInitConfig(FLOW_QUIET);
1✔
4666
    p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
1✔
4667
    if (p == NULL) {
1✔
4668
        SCLogDebug("Error building packet");
4669
        goto end;
4670
    }
4671
    UTHMatchPackets(de_ctx, &p, 1);
1✔
4672

4673
    uint32_t sids[3] = {1, 2, 3};
1✔
4674
    uint32_t results[3] = {1, 1, 1};
1✔
4675
    result = UTHCheckPacketMatchResults(p, sids, results, 1);
1✔
4676

4677
end:
1✔
4678
    if (p != NULL) {
1✔
4679
        PacketFree(p);
1✔
4680
    }
1✔
4681
    DetectEngineCtxFree(de_ctx);
1✔
4682
    FlowShutdown();
1✔
4683
    return result;
1✔
4684
}
1✔
4685

4686
/** \test Ensure that we set a bidirectional Signature correctly
4687
*         and we install it with the rest of the signatures, checking
4688
*         also that it match with the correct addr directions
4689
*/
4690
static int SigTestBidirec04 (void)
4691
{
1✔
4692
    int result = 0;
1✔
4693
    Signature *sig = NULL;
1✔
4694
    Packet *p = NULL;
1✔
4695

4696
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4697
    if (de_ctx == NULL)
1✔
4698
        goto end;
4699

4700
    de_ctx->flags |= DE_QUIET;
1✔
4701

4702
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
1✔
4703
    if (sig == NULL)
1✔
4704
        goto end;
4705
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
1✔
4706
    if (sig == NULL)
1✔
4707
        goto end;
4708
    if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
1✔
4709
        goto end;
4710
    if (sig->next == NULL)
1✔
4711
        goto end;
4712
    if (sig->next->next == NULL)
1✔
4713
        goto end;
4714
    if (sig->next->next->next != NULL)
1✔
4715
        goto end;
4716
    if (de_ctx->signum != 3)
1✔
4717
        goto end;
4718

4719
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
1✔
4720
    if (sig == NULL)
1✔
4721
        goto end;
4722
    if (sig->next == NULL)
1✔
4723
        goto end;
4724
    if (sig->next->next == NULL)
1✔
4725
        goto end;
4726
    if (sig->next->next->next == NULL)
1✔
4727
        goto end;
4728
    if (sig->next->next->next->next != NULL)
1✔
4729
        goto end;
4730
    if (de_ctx->signum != 4)
1✔
4731
        goto end;
4732

4733
    uint8_t rawpkt1_ether[] = {
1✔
4734
        0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
1✔
4735
        0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
1✔
4736
        0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
1✔
4737
        0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
1✔
4738
        0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
1✔
4739
        0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
1✔
4740
        0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
1✔
4741
        0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
1✔
4742
        0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
1✔
4743
        0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
1✔
4744
        0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
1✔
4745
        0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
1✔
4746
        0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
1✔
4747
        0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
1✔
4748
        0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
1✔
4749
        0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
1✔
4750
        0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
1✔
4751
        0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
1✔
4752
        0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
1✔
4753
        0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
1✔
4754
        0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
1✔
4755
        0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
1✔
4756
        0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
1✔
4757
        0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
1✔
4758
        0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
1✔
4759
        0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
1✔
4760
        0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
1✔
4761
        0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
1✔
4762
        0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
1✔
4763
        0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
1✔
4764
        0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
1✔
4765
        0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
1✔
4766
        0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
1✔
4767
        0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
1✔
4768
        0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4769
        0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1✔
4770
        0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
1✔
4771
        0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
1✔
4772
        0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
1✔
4773
        0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
1✔
4774
        0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
1✔
4775
        0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
1✔
4776
        0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
1✔
4777
        0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1✔
4778
        0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
1✔
4779
        0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
1✔
4780
        0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
1✔
4781
        0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4782
        0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1✔
4783
        0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
1✔
4784
        0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
1✔
4785
        0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
1✔
4786
        0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
1✔
4787
        0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
1✔
4788
        0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
1✔
4789

4790
    p = PacketGetFromAlloc();
1✔
4791
    if (unlikely(p == NULL))
1✔
4792
        return 0;
4793
    DecodeThreadVars dtv;
1✔
4794
    ThreadVars th_v;
1✔
4795
    DetectEngineThreadCtx *det_ctx;
1✔
4796

4797
    memset(&th_v, 0, sizeof(th_v));
1✔
4798
    StatsThreadInit(&th_v.stats);
1✔
4799

4800
    FlowInitConfig(FLOW_QUIET);
1✔
4801
    DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
1✔
4802
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
4803

4804
    /* At this point we have a list of 4 signatures. The last one
4805
       is a copy of the second one. If we receive a packet
4806
       with source 192.168.1.1 80, all the sids should match */
4807

4808
    SigGroupBuild(de_ctx);
1✔
4809
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1✔
4810

4811
    /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4812
    if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
1✔
4813
        PacketAlertCheck(p, 2) == 1) {
1✔
4814
        result = 1;
1✔
4815
    }
1✔
4816

4817
    if (p != NULL) {
1✔
4818
        PacketRecycle(p);
1✔
4819
    }
1✔
4820
    FlowShutdown();
1✔
4821
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
4822

4823
end:
1✔
4824
    if (de_ctx != NULL) {
1✔
4825
        DetectEngineCtxFree(de_ctx);
1✔
4826
    }
1✔
4827

4828
    if (p != NULL)
1✔
4829
        PacketFree(p);
1✔
4830
    StatsThreadCleanup(&th_v.stats);
1✔
4831
    return result;
1✔
4832
}
1✔
4833

4834
/**
4835
 * \test check that we don't allow invalid negation options
4836
 */
4837
static int SigParseTestNegation01 (void)
4838
{
1✔
4839
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4840
    FAIL_IF_NULL(de_ctx);
1✔
4841
    de_ctx->flags |= DE_QUIET;
1✔
4842
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
1✔
4843
    FAIL_IF_NOT_NULL(s);
1✔
4844
    DetectEngineCtxFree(de_ctx);
1✔
4845
    PASS;
1✔
4846
}
1✔
4847

4848
/**
4849
 * \test check that we don't allow invalid negation options
4850
 */
4851
static int SigParseTestNegation02 (void)
4852
{
1✔
4853
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4854
    FAIL_IF_NULL(de_ctx);
1✔
4855
    de_ctx->flags |= DE_QUIET;
1✔
4856
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
4857
            "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
1✔
4858
            "classtype:misc-activity; sid:410002; rev:1;)");
1✔
4859
    FAIL_IF_NOT_NULL(s);
1✔
4860
    DetectEngineCtxFree(de_ctx);
1✔
4861
    PASS;
1✔
4862
}
1✔
4863
/**
4864
 * \test check that we don't allow invalid negation options
4865
 */
4866
static int SigParseTestNegation03 (void)
4867
{
1✔
4868
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4869
    FAIL_IF_NULL(de_ctx);
1✔
4870
    de_ctx->flags |= DE_QUIET;
1✔
4871
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
4872
            "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
1✔
4873
            "classtype:misc-activity; sid:410003; rev:1;)");
1✔
4874
    FAIL_IF_NOT_NULL(s);
1✔
4875
    DetectEngineCtxFree(de_ctx);
1✔
4876
    PASS;
1✔
4877
}
1✔
4878
/**
4879
 * \test check that we don't allow invalid negation options
4880
 */
4881
static int SigParseTestNegation04 (void)
4882
{
1✔
4883
    int result = 0;
1✔
4884
    DetectEngineCtx *de_ctx;
1✔
4885
    Signature *s=NULL;
1✔
4886

4887
    de_ctx = DetectEngineCtxInit();
1✔
4888
    if (de_ctx == NULL)
1✔
4889
        goto end;
4890
    de_ctx->flags |= DE_QUIET;
1✔
4891

4892
    s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
1✔
4893
    if (s != NULL) {
1✔
4894
        SigFree(de_ctx, s);
4895
        goto end;
4896
    }
4897

4898
    result = 1;
1✔
4899
end:
1✔
4900
    if (de_ctx != NULL)
1✔
4901
        DetectEngineCtxFree(de_ctx);
1✔
4902
    return result;
1✔
4903
}
1✔
4904
/**
4905
 * \test check that we don't allow invalid negation options
4906
 */
4907
static int SigParseTestNegation05 (void)
4908
{
1✔
4909
    int result = 0;
1✔
4910
    DetectEngineCtx *de_ctx;
1✔
4911
    Signature *s=NULL;
1✔
4912

4913
    de_ctx = DetectEngineCtxInit();
1✔
4914
    if (de_ctx == NULL)
1✔
4915
        goto end;
4916
    de_ctx->flags |= DE_QUIET;
1✔
4917

4918
    s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
1✔
4919
    if (s != NULL) {
1✔
4920
        SigFree(de_ctx, s);
4921
        goto end;
4922
    }
4923

4924
    result = 1;
1✔
4925
end:
1✔
4926
    if (de_ctx != NULL)
1✔
4927
        DetectEngineCtxFree(de_ctx);
1✔
4928
    return result;
1✔
4929
}
1✔
4930
/**
4931
 * \test check that we don't allow invalid negation options
4932
 */
4933
static int SigParseTestNegation06 (void)
4934
{
1✔
4935
    int result = 0;
1✔
4936
    DetectEngineCtx *de_ctx;
1✔
4937
    Signature *s=NULL;
1✔
4938

4939
    de_ctx = DetectEngineCtxInit();
1✔
4940
    if (de_ctx == NULL)
1✔
4941
        goto end;
4942
    de_ctx->flags |= DE_QUIET;
1✔
4943

4944
    s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
1✔
4945
    if (s != NULL) {
1✔
4946
        SigFree(de_ctx, s);
4947
        goto end;
4948
    }
4949

4950
    result = 1;
1✔
4951
end:
1✔
4952
    if (de_ctx != NULL)
1✔
4953
        DetectEngineCtxFree(de_ctx);
1✔
4954
    return result;
1✔
4955
}
1✔
4956

4957
/**
4958
 * \test check that we don't allow invalid negation options
4959
 */
4960
static int SigParseTestNegation07 (void)
4961
{
1✔
4962
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4963
    FAIL_IF_NULL(de_ctx);
1✔
4964
    de_ctx->flags |= DE_QUIET;
1✔
4965
    Signature *s = DetectEngineAppendSig(
1✔
4966
            de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
1✔
4967
    FAIL_IF_NOT_NULL(s);
1✔
4968
    DetectEngineCtxFree(de_ctx);
1✔
4969
    PASS;
1✔
4970
}
1✔
4971

4972
/**
4973
 * \test check valid negation bug 1079
4974
 */
4975
static int SigParseTestNegation08 (void)
4976
{
1✔
4977
    int result = 0;
1✔
4978
    DetectEngineCtx *de_ctx;
1✔
4979
    Signature *s=NULL;
1✔
4980

4981
    de_ctx = DetectEngineCtxInit();
1✔
4982
    if (de_ctx == NULL)
1✔
4983
        goto end;
4984
    de_ctx->flags |= DE_QUIET;
1✔
4985

4986
    s = DetectEngineAppendSig(de_ctx,
1✔
4987
            "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
1✔
4988
    if (s == NULL) {
1✔
4989
        goto end;
4990
    }
4991

4992
    result = 1;
1✔
4993
end:
1✔
4994
    if (de_ctx != NULL)
1✔
4995
        DetectEngineCtxFree(de_ctx);
1✔
4996
    return result;
1✔
4997
}
1✔
4998

4999
/**
5000
 * \test mpm
5001
 */
5002
static int SigParseTestMpm01 (void)
5003
{
1✔
5004
    int result = 0;
1✔
5005
    Signature *sig = NULL;
1✔
5006

5007
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5008
    if (de_ctx == NULL)
1✔
5009
        goto end;
5010

5011
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
1✔
5012
    if (sig == NULL) {
1✔
5013
        printf("sig failed to init: ");
5014
        goto end;
5015
    }
5016

5017
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
1✔
5018
        printf("sig doesn't have content list: ");
5019
        goto end;
5020
    }
5021

5022
    result = 1;
1✔
5023
end:
1✔
5024
    if (sig != NULL)
1✔
5025
        SigFree(de_ctx, sig);
1✔
5026
    DetectEngineCtxFree(de_ctx);
1✔
5027
    return result;
1✔
5028
}
1✔
5029

5030
/**
5031
 * \test mpm
5032
 */
5033
static int SigParseTestMpm02 (void)
5034
{
1✔
5035
    int result = 0;
1✔
5036
    Signature *sig = NULL;
1✔
5037

5038
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5039
    if (de_ctx == NULL)
1✔
5040
        goto end;
5041

5042
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
1✔
5043
    if (sig == NULL) {
1✔
5044
        printf("sig failed to init: ");
5045
        goto end;
5046
    }
5047

5048
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
1✔
5049
        printf("sig doesn't have content list: ");
5050
        goto end;
5051
    }
5052

5053
    result = 1;
1✔
5054
end:
1✔
5055
    if (sig != NULL)
1✔
5056
        SigFree(de_ctx, sig);
1✔
5057
    DetectEngineCtxFree(de_ctx);
1✔
5058
    return result;
1✔
5059
}
1✔
5060

5061
/**
5062
 * \test test tls (app layer) rule
5063
 */
5064
static int SigParseTestAppLayerTLS01(void)
5065
{
1✔
5066
    int result = 0;
1✔
5067
    DetectEngineCtx *de_ctx;
1✔
5068
    Signature *s=NULL;
1✔
5069

5070
    de_ctx = DetectEngineCtxInit();
1✔
5071
    if (de_ctx == NULL)
1✔
5072
        goto end;
5073
    de_ctx->flags |= DE_QUIET;
1✔
5074

5075
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
1✔
5076
    if (s == NULL) {
1✔
5077
        printf("parsing sig failed: ");
5078
        goto end;
5079
    }
5080

5081
    if (s->alproto == 0) {
1✔
5082
        printf("alproto not set: ");
5083
        goto end;
5084
    }
5085

5086
    result = 1;
1✔
5087
end:
1✔
5088
    if (s != NULL)
1✔
5089
        SigFree(de_ctx, s);
1✔
5090
    if (de_ctx != NULL)
1✔
5091
        DetectEngineCtxFree(de_ctx);
1✔
5092

5093
    return result;
1✔
5094
}
1✔
5095

5096
/**
5097
 * \test test tls (app layer) rule
5098
 */
5099
static int SigParseTestAppLayerTLS02(void)
5100
{
1✔
5101
    int result = 0;
1✔
5102
    DetectEngineCtx *de_ctx;
1✔
5103
    Signature *s=NULL;
1✔
5104

5105
    de_ctx = DetectEngineCtxInit();
1✔
5106
    if (de_ctx == NULL)
1✔
5107
        goto end;
5108
    de_ctx->flags |= DE_QUIET;
1✔
5109

5110
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
1✔
5111
    if (s == NULL) {
1✔
5112
        printf("parsing sig failed: ");
5113
        goto end;
5114
    }
5115

5116
    if (s->alproto == 0) {
1✔
5117
        printf("alproto not set: ");
5118
        goto end;
5119
    }
5120

5121
    result = 1;
1✔
5122
end:
1✔
5123
    if (s != NULL)
1✔
5124
        SigFree(de_ctx, s);
1✔
5125
    if (de_ctx != NULL)
1✔
5126
        DetectEngineCtxFree(de_ctx);
1✔
5127
    return result;
1✔
5128
}
1✔
5129

5130
/**
5131
 * \test test tls (app layer) rule
5132
 */
5133
static int SigParseTestAppLayerTLS03(void)
5134
{
1✔
5135
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5136
    FAIL_IF_NULL(de_ctx);
1✔
5137
    de_ctx->flags |= DE_QUIET;
1✔
5138

5139
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5140
            "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
1✔
5141
            "tls.version:2.5; sid:410006; rev:1;)");
1✔
5142
    FAIL_IF_NOT_NULL(s);
1✔
5143
    DetectEngineCtxFree(de_ctx);
1✔
5144
    PASS;
1✔
5145
}
1✔
5146

5147
static int SigParseTestUnbalancedQuotes01(void)
5148
{
1✔
5149
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5150
    FAIL_IF_NULL(de_ctx);
1✔
5151
    de_ctx->flags |= DE_QUIET;
1✔
5152
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5153
            "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
1✔
5154
            "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
1✔
5155
            "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
1✔
5156
    FAIL_IF_NOT_NULL(s);
1✔
5157
    DetectEngineCtxFree(de_ctx);
1✔
5158
    PASS;
1✔
5159
}
1✔
5160

5161
static int SigParseTestContentGtDsize01(void)
5162
{
1✔
5163
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5164
    FAIL_IF_NULL(de_ctx);
1✔
5165
    de_ctx->flags |= DE_QUIET;
1✔
5166
    Signature *s =
1✔
5167
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
1✔
5168
                                          "dsize:21; content:\"0123456789001234567890|00 00|\"; "
1✔
5169
                                          "sid:1; rev:1;)");
1✔
5170
    FAIL_IF_NOT_NULL(s);
1✔
5171
    DetectEngineCtxFree(de_ctx);
1✔
5172
    PASS;
1✔
5173
}
1✔
5174

5175
static int SigParseTestContentGtDsize02(void)
5176
{
1✔
5177
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5178
    FAIL_IF_NULL(de_ctx);
1✔
5179
    de_ctx->flags |= DE_QUIET;
1✔
5180
    Signature *s =
1✔
5181
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
1✔
5182
                                          "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
1✔
5183
                                          "sid:1; rev:1;)");
1✔
5184
    FAIL_IF_NOT_NULL(s);
1✔
5185
    DetectEngineCtxFree(de_ctx);
1✔
5186
    PASS;
1✔
5187
}
1✔
5188

5189
static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5190
{
8✔
5191
    int cnt = 0;
8✔
5192
    for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
42✔
5193
        if (sid == s->id)
34✔
5194
            cnt++;
12✔
5195
    }
34✔
5196
    return cnt;
8✔
5197
}
8✔
5198

5199
static int SigParseBidirWithSameSrcAndDest01(void)
5200
{
1✔
5201
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5202
    FAIL_IF_NULL(de_ctx);
1✔
5203
    de_ctx->flags |= DE_QUIET;
1✔
5204

5205
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
1✔
5206
    FAIL_IF_NULL(s);
1✔
5207
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
1✔
5208
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5209

5210
    s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
1✔
5211
    FAIL_IF_NULL(s);
1✔
5212
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
1✔
5213
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5214

5215
    s = DetectEngineAppendSig(de_ctx,
1✔
5216
            "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
1✔
5217
    FAIL_IF_NULL(s);
1✔
5218
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
1✔
5219
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5220

5221
    DetectEngineCtxFree(de_ctx);
1✔
5222
    PASS;
1✔
5223
}
1✔
5224

5225
static int SigParseBidirWithSameSrcAndDest02(void)
5226
{
1✔
5227
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5228
    FAIL_IF_NULL(de_ctx);
1✔
5229
    de_ctx->flags |= DE_QUIET;
1✔
5230

5231
    // Source is a subset of destination
5232
    Signature *s = DetectEngineAppendSig(
1✔
5233
            de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
1✔
5234
    FAIL_IF_NULL(s);
1✔
5235
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
1✔
5236
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5237

5238
    // Source is a subset of destination
5239
    s = DetectEngineAppendSig(
1✔
5240
            de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
1✔
5241
    FAIL_IF_NULL(s);
1✔
5242
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
1✔
5243
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5244

5245
    // Source intersects with destination
5246
    s = DetectEngineAppendSig(de_ctx,
1✔
5247
            "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
1✔
5248
    FAIL_IF_NULL(s);
1✔
5249
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
1✔
5250
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5251

5252
    // mix in negation, these are the same
5253
    s = DetectEngineAppendSig(
1✔
5254
            de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
1✔
5255
    FAIL_IF_NULL(s);
1✔
5256
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
1✔
5257
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5258

5259
    // mix in negation, these are not the same
5260
    s = DetectEngineAppendSig(
1✔
5261
            de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
1✔
5262
    FAIL_IF_NULL(s);
1✔
5263
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
1✔
5264
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5265

5266
    DetectEngineCtxFree(de_ctx);
1✔
5267
    PASS;
1✔
5268
}
1✔
5269

5270
static int SigParseTestActionReject(void)
5271
{
1✔
5272
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5273
    FAIL_IF_NULL(de_ctx);
1✔
5274

5275
    Signature *sig = DetectEngineAppendSig(
1✔
5276
            de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5277
#ifdef HAVE_LIBNET11
1✔
5278
    FAIL_IF_NULL(sig);
1✔
5279
    FAIL_IF_NOT((sig->action & (ACTION_DROP | ACTION_REJECT)) == (ACTION_DROP | ACTION_REJECT));
1✔
5280
#else
5281
    FAIL_IF_NOT_NULL(sig);
5282
#endif
5283

5284
    DetectEngineCtxFree(de_ctx);
1✔
5285
    PASS;
1✔
5286
}
1✔
5287

5288
static int SigParseTestActionDrop(void)
5289
{
1✔
5290
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5291
    FAIL_IF_NULL(de_ctx);
1✔
5292

5293
    Signature *sig = DetectEngineAppendSig(
1✔
5294
            de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5295
    FAIL_IF_NULL(sig);
1✔
5296
    FAIL_IF_NOT(sig->action & ACTION_DROP);
1✔
5297

5298
    DetectEngineCtxFree(de_ctx);
1✔
5299
    PASS;
1✔
5300
}
1✔
5301

5302
static int SigSetMultiAppProto(void)
5303
{
1✔
5304
    Signature *s = SigAlloc();
1✔
5305
    FAIL_IF_NULL(s);
1✔
5306

5307
    AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
1✔
5308
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5309

5310
    // check intersection gives multiple entries
5311
    alprotos[0] = 3;
1✔
5312
    alprotos[1] = 2;
1✔
5313
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5314
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5315
    FAIL_IF(s->init_data->alprotos[0] != 3);
1✔
5316
    FAIL_IF(s->init_data->alprotos[1] != 2);
1✔
5317
    FAIL_IF(s->init_data->alprotos[2] != ALPROTO_UNKNOWN);
1✔
5318

5319
    // check single after multiple
5320
    FAIL_IF(SCDetectSignatureSetAppProto(s, 3) < 0);
1✔
5321
    FAIL_IF(s->init_data->alprotos[0] != ALPROTO_UNKNOWN);
1✔
5322
    FAIL_IF(s->alproto != 3);
1✔
5323
    alprotos[0] = 4;
1✔
5324
    alprotos[1] = 3;
1✔
5325
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5326
    // check multiple containing singleton
5327
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5328
    FAIL_IF(s->alproto != 3);
1✔
5329

5330
    // reset
5331
    s->alproto = ALPROTO_UNKNOWN;
1✔
5332
    alprotos[0] = 1;
1✔
5333
    alprotos[1] = 2;
1✔
5334
    alprotos[2] = 3;
1✔
5335
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5336
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5337
    // fail if set single not in multiple
5338
    FAIL_IF(SCDetectSignatureSetAppProto(s, 4) >= 0);
1✔
5339

5340
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5341
    s->alproto = ALPROTO_UNKNOWN;
1✔
5342
    alprotos[0] = 1;
1✔
5343
    alprotos[1] = 2;
1✔
5344
    alprotos[2] = 3;
1✔
5345
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5346
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5347
    alprotos[0] = 4;
1✔
5348
    alprotos[1] = 5;
1✔
5349
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5350
    // fail if multiple do not have intersection
5351
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5352

5353
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5354
    s->alproto = ALPROTO_UNKNOWN;
1✔
5355
    alprotos[0] = 1;
1✔
5356
    alprotos[1] = 2;
1✔
5357
    alprotos[2] = 3;
1✔
5358
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5359
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5360
    alprotos[0] = 3;
1✔
5361
    alprotos[1] = 4;
1✔
5362
    alprotos[2] = 5;
1✔
5363
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5364
    // check multiple intersect to singleton
5365
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5366
    FAIL_IF(s->alproto != 3);
1✔
5367
    alprotos[0] = 5;
1✔
5368
    alprotos[1] = 4;
1✔
5369
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5370
    // fail if multiple do not belong to singleton
5371
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5372

5373
    SigFree(NULL, s);
1✔
5374
    PASS;
1✔
5375
}
1✔
5376

5377
static int DetectSetupDirection01(void)
5378
{
1✔
5379
    Signature *s = SigAlloc();
1✔
5380
    FAIL_IF_NULL(s);
1✔
5381
    // Basic case : ok
5382
    char *str = (char *)"to_client";
1✔
5383
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5384
    SigFree(NULL, s);
1✔
5385
    PASS;
1✔
5386
}
1✔
5387

5388
static int DetectSetupDirection02(void)
5389
{
1✔
5390
    Signature *s = SigAlloc();
1✔
5391
    FAIL_IF_NULL(s);
1✔
5392
    char *str = (char *)"to_server";
1✔
5393
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5394
    // ok so far
5395
    str = (char *)"to_client";
1✔
5396
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5397
    // fails because we cannot have both to_client and to_server for same signature
5398
    SigFree(NULL, s);
1✔
5399
    PASS;
1✔
5400
}
1✔
5401

5402
static int DetectSetupDirection03(void)
5403
{
1✔
5404
    Signature *s = SigAlloc();
1✔
5405
    FAIL_IF_NULL(s);
1✔
5406
    char *str = (char *)"to_client , something";
1✔
5407
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5408
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5409
    str = (char *)"to_client,something";
1✔
5410
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5411
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5412
    SigFree(NULL, s);
1✔
5413
    PASS;
1✔
5414
}
1✔
5415

5416
static int DetectSetupDirection04(void)
5417
{
1✔
5418
    Signature *s = SigAlloc();
1✔
5419
    FAIL_IF_NULL(s);
1✔
5420
    // invalid case
5421
    char *str = (char *)"to_client_toto";
1✔
5422
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5423
    // test we do not change the string pointer if only_dir is false
5424
    str = (char *)"to_client_toto";
1✔
5425
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5426
    FAIL_IF(strcmp(str, "to_client_toto") != 0);
1✔
5427
    str = (char *)"to_client,something";
1✔
5428
    // fails because we call with only_dir=true
5429
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5430
    SigFree(NULL, s);
1✔
5431
    PASS;
1✔
5432
}
1✔
5433

5434
#endif /* UNITTESTS */
5435

5436
#ifdef UNITTESTS
5437
void DetectParseRegisterTests (void);
5438
#include "tests/detect-parse.c"
5439
#endif
5440

5441
void SigParseRegisterTests(void)
5442
{
1✔
5443
#ifdef UNITTESTS
1✔
5444
    DetectParseRegisterTests();
1✔
5445

5446
    UtRegisterTest("SigParseTest01", SigParseTest01);
1✔
5447
    UtRegisterTest("SigParseTest02", SigParseTest02);
1✔
5448
    UtRegisterTest("SigParseTest03", SigParseTest03);
1✔
5449
    UtRegisterTest("SigParseTest04", SigParseTest04);
1✔
5450
    UtRegisterTest("SigParseTest05", SigParseTest05);
1✔
5451
    UtRegisterTest("SigParseTest06", SigParseTest06);
1✔
5452
    UtRegisterTest("SigParseTest07", SigParseTest07);
1✔
5453
    UtRegisterTest("SigParseTest08", SigParseTest08);
1✔
5454
    UtRegisterTest("SigParseTest09", SigParseTest09);
1✔
5455
    UtRegisterTest("SigParseTest10", SigParseTest10);
1✔
5456
    UtRegisterTest("SigParseTest11", SigParseTest11);
1✔
5457
    UtRegisterTest("SigParseTest12", SigParseTest12);
1✔
5458
    UtRegisterTest("SigParseTest13", SigParseTest13);
1✔
5459
    UtRegisterTest("SigParseTest14", SigParseTest14);
1✔
5460
    UtRegisterTest("SigParseTest15", SigParseTest15);
1✔
5461
    UtRegisterTest("SigParseTest16", SigParseTest16);
1✔
5462
    UtRegisterTest("SigParseTest17", SigParseTest17);
1✔
5463
    UtRegisterTest("SigParseTest18", SigParseTest18);
1✔
5464
    UtRegisterTest("SigParseTest19", SigParseTest19);
1✔
5465
    UtRegisterTest("SigParseTest20", SigParseTest20);
1✔
5466
    UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
1✔
5467
    UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
1✔
5468
    UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
1✔
5469

5470
    UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
1✔
5471
    UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
1✔
5472
    UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
1✔
5473
    UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
1✔
5474
    UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
1✔
5475
    UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
1✔
5476
    UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
1✔
5477
    UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
1✔
5478
    UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
1✔
5479
    UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
1✔
5480
    UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
1✔
5481
    UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
1✔
5482
    UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
1✔
5483
    UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
1✔
5484
    UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
1✔
5485
    UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
1✔
5486
    UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
1✔
5487
    UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
1✔
5488
    UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
1✔
5489
    UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
1✔
5490
    UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
1✔
5491
    UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
1✔
5492
    UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
1✔
5493
    UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
1✔
5494
    UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
1✔
5495
    UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
1✔
5496
    UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
1✔
5497

5498
    UtRegisterTest("SigParseTestContentGtDsize01",
1✔
5499
            SigParseTestContentGtDsize01);
1✔
5500
    UtRegisterTest("SigParseTestContentGtDsize02",
1✔
5501
            SigParseTestContentGtDsize02);
1✔
5502

5503
    UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
1✔
5504
            SigParseBidirWithSameSrcAndDest01);
1✔
5505
    UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
1✔
5506
            SigParseBidirWithSameSrcAndDest02);
1✔
5507
    UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
1✔
5508
    UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
1✔
5509

5510
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
1✔
5511

5512
    UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
1✔
5513
    UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
1✔
5514
    UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
1✔
5515
    UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
1✔
5516

5517
#endif /* UNITTESTS */
1✔
5518
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc