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

OISF / suricata / 22550237931

01 Mar 2026 06:56PM UTC coverage: 64.812% (-8.9%) from 73.687%
22550237931

Pull #14920

github

web-flow
Merge e05854a6d into 90823fa90
Pull Request #14920: draft: rust based configuration file parser and loader - v4

561 of 789 new or added lines in 4 files covered. (71.1%)

23225 existing lines in 498 files now uncovered.

131605 of 203055 relevant lines covered (64.81%)

2328818.84 hits per line

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

86.42
/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
{
58,076✔
150
    SigMatch *sm = NULL;
58,076✔
151
    int ret = -1;
58,076✔
152

153
    if (arg != NULL && strcmp(arg, "") != 0) {
58,076✔
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) {
58,076✔
161
        SCLogError("\"%s\" keyword seen "
46✔
162
                   "with a sticky buffer still set.  Reset sticky buffer "
46✔
163
                   "with pkt_data before using the modifier.",
46✔
164
                sigmatch_table[sm_type].name);
46✔
165
        goto end;
46✔
166
    }
46✔
167
    if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
58,030✔
168
        SCLogError("rule contains conflicting "
394✔
169
                   "alprotos set");
394✔
170
        goto end;
394✔
171
    }
394✔
172

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

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

226
    if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
57,154✔
227
        if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
40,104✔
228
            SCLogError("no matches for previous buffer");
38✔
229
            return -1;
38✔
230
        }
38✔
231
        bool reuse_buffer = false;
40,104✔
232
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
40,066✔
233
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
15,977✔
234
                if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
11,221✔
235
                    s->init_data->curbuf = &s->init_data->buffers[x];
3,131✔
236
                    reuse_buffer = true;
3,131✔
237
                    break;
3,131✔
238
                }
3,131✔
239
            }
11,221✔
240
        }
7,887✔
241

242
        if (!reuse_buffer) {
40,066✔
243
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
36,935✔
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++];
36,934✔
250
            s->init_data->curbuf->id = sm_list;
36,934✔
251
            s->init_data->curbuf->head = NULL;
36,934✔
252
            s->init_data->curbuf->tail = NULL;
36,934✔
253
            SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
36,934✔
254
                    s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
36,934✔
255
                    s->init_data->buffer_index);
36,934✔
256
        }
36,934✔
257
    }
40,066✔
258

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

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

269
    ret = 0;
57,115✔
270
 end:
58,037✔
271
    return ret;
58,037✔
272
}
57,115✔
273

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

280
    sm->prev = NULL;
1,915,097✔
281
    sm->next = NULL;
1,915,097✔
282
    return sm;
1,915,097✔
283
}
1,915,097✔
284

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

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

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

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

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
530,185,890✔
317
        st = &sigmatch_table[i];
529,912,170✔
318

319
        if (st->name != NULL) {
529,912,170✔
320
            if (strcasecmp(name,st->name) == 0)
504,453,609✔
321
                return st;
7,231,017✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
497,222,592✔
323
                return st;
91,569✔
324
        }
497,222,592✔
325
    }
529,912,170✔
326

327
    return NULL;
2,147,757,367✔
328
}
7,596,305✔
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,760✔
337
    if ((int)id < DETECT_TBLSIZE) {
32,760✔
338
        return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
32,760✔
339
    }
32,760✔
340
    return false;
×
341
}
32,760✔
342

343
void SigTableApplyStrictCommandLineOption(const char *str)
344
{
29✔
345
    if (str == NULL) {
29✔
346
        /* nothing to be done */
347
        return;
29✔
348
    }
29✔
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
{
1,915,097✔
390
    SigMatch *new = SigMatchAlloc();
1,915,097✔
391
    if (new == NULL)
1,915,097✔
392
        return NULL;
×
393

394
    new->type = type;
1,915,097✔
395
    new->ctx = ctx;
1,915,097✔
396

397
    if (new->type == DETECT_CONTENT) {
1,915,097✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
626,639✔
399
    }
626,639✔
400

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

405
    if (list < DETECT_SM_LIST_MAX) {
1,915,097✔
406
        if (s->init_data->smlists[list] == NULL) {
1,013,730✔
407
            s->init_data->smlists[list] = new;
687,743✔
408
            s->init_data->smlists_tail[list] = new;
687,743✔
409
            new->next = NULL;
687,743✔
410
            new->prev = NULL;
687,743✔
411
        } else {
687,743✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
325,987✔
413
            cur->next = new;
325,987✔
414
            new->prev = cur;
325,987✔
415
            new->next = NULL;
325,987✔
416
            s->init_data->smlists_tail[list] = new;
325,987✔
417
        }
325,987✔
418
        new->idx = s->init_data->sm_cnt;
1,013,730✔
419
        s->init_data->sm_cnt++;
1,013,730✔
420

421
    } else {
1,013,730✔
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) {
901,367✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
14,129✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
14,129✔
429
        }
14,129✔
430

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

442
        if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
901,367✔
443
                s->init_data->curbuf == NULL) {
901,367✔
444
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
419,795✔
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,792✔
450
                /* initialize new buffer */
451
                s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
419,792✔
452
                s->init_data->curbuf->id = list;
419,792✔
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,792✔
456
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT) {
419,792✔
457
                    s->init_data->curbuf->only_tc = true;
21✔
458
                }
21✔
459
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOSERVER) {
419,792✔
460
                    s->init_data->curbuf->only_ts = true;
×
461
                }
×
462
                SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
419,792✔
463
            }
419,792✔
464
        }
419,795✔
465
        BUG_ON(s->init_data->curbuf == NULL);
901,364✔
466

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

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
3,827,296✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
2,925,932✔
480
                    sigmatch_table[sm->type].name, sm->idx);
2,925,932✔
481
        }
2,925,932✔
482
    }
901,364✔
483
    return new;
1,915,094✔
484
}
1,915,097✔
485

486
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487
{
10,692✔
488
    if (sm == s->init_data->smlists[sm_list]) {
10,692✔
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,692✔
492
        s->init_data->smlists_tail[sm_list] = sm->prev;
7,115✔
493
    }
7,115✔
494
    if (sm->prev != NULL)
10,692✔
495
        sm->prev->next = sm->next;
3,994✔
496
    if (sm->next != NULL)
10,692✔
497
        sm->next->prev = sm->prev;
3,577✔
498
}
10,692✔
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,134,169✔
511
    while (sm != NULL) {
3,552,121✔
512
        if (sm->type == type) {
3,075,216✔
513
            return sm;
657,264✔
514
        }
657,264✔
515
        sm = sm->prev;
2,417,952✔
516
    }
2,417,952✔
517

518
    return NULL;
476,905✔
519
}
1,134,169✔
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
{
28,834✔
528
    SigMatch *sm_last = NULL;
28,834✔
529
    SigMatch *sm_new;
28,834✔
530
    uint32_t sm_type;
28,834✔
531

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
67,520✔
533
        const int id = s->init_data->buffers[i].id;
38,686✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
38,686✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
38,031✔
536
            if (sm_new == NULL)
38,031✔
537
                continue;
3,797✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
34,234✔
539
                sm_last = sm_new;
32,849✔
540
        }
34,234✔
541
    }
38,686✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
230,672✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
201,838✔
545
            continue;
201,838✔
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;
28,834✔
555
}
28,834✔
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
{
439,306✔
565
    SigMatch *sm_last = NULL;
439,306✔
566
    SigMatch *sm_new;
439,306✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
439,306✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
703,743✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
264,437✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
264,437✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
24,328✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
24,328✔
574

575
            continue;
24,328✔
576
        }
24,328✔
577
        int sm_type;
240,109✔
578
        va_list ap;
240,109✔
579
        va_start(ap, s);
240,109✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
547,468✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
307,359✔
583
            if (sm_new == NULL)
307,359✔
584
                continue;
105,571✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
201,788✔
586
                sm_last = sm_new;
192,504✔
587
        }
201,788✔
588
        va_end(ap);
240,109✔
589
    }
240,109✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
3,514,448✔
592
        if (s->init_data->smlists[buf_type] == NULL)
3,075,142✔
593
            continue;
2,701,570✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
373,572✔
595
            buf_type != s->init_data->list)
373,572✔
596
            continue;
74,528✔
597

598
        int sm_type;
299,044✔
599
        va_list ap;
299,044✔
600
        va_start(ap, s);
299,044✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
770,466✔
603
        {
471,422✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
471,422✔
605
            if (sm_new == NULL)
471,422✔
606
                continue;
242,822✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
228,600✔
608
                sm_last = sm_new;
221,043✔
609
        }
228,600✔
610
        va_end(ap);
299,044✔
611
    }
299,044✔
612

613
    return sm_last;
439,306✔
614
}
439,306✔
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
{
145,503✔
627
    SigMatch *sm_last = NULL;
145,503✔
628
    SigMatch *sm_new;
145,503✔
629
    int sm_type;
145,503✔
630

631
    va_list ap;
145,503✔
632
    va_start(ap, sm_list);
145,503✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
398,478✔
635
    {
252,975✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
252,975✔
637
        if (sm_new == NULL)
252,975✔
638
            continue;
111,481✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
141,494✔
640
            sm_last = sm_new;
131,642✔
641
    }
141,494✔
642

643
    va_end(ap);
145,503✔
644

645
    return sm_last;
145,503✔
646
}
145,503✔
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
{
145,447✔
659
    SigMatch *sm_last = NULL;
145,447✔
660
    SigMatch *sm_new;
145,447✔
661
    int sm_type;
145,447✔
662

663
    if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
145,447✔
664
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
57,645✔
665
            sm_new = s->init_data->buffers[x].tail;
34,275✔
666
            if (sm_new == NULL)
34,275✔
667
                continue;
16,051✔
668

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

672
            for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
36,448✔
673
                sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
18,224✔
674
                if (sm_new == NULL)
18,224✔
675
                    continue;
7,213✔
676
                if (sm_last == NULL || sm_new->idx > sm_last->idx)
11,011✔
677
                    sm_last = sm_new;
9,758✔
678
            }
11,011✔
679

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

687
        va_list ap;
84,189✔
688
        va_start(ap, list_id);
84,189✔
689

690
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
168,378✔
691
            sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
84,189✔
692
            if (sm_new == NULL)
84,189✔
693
                continue;
9,818✔
694
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
74,371✔
695
                sm_last = sm_new;
74,371✔
696
        }
74,371✔
697

698
        va_end(ap);
84,189✔
699
    }
84,189✔
700
    return sm_last;
107,559✔
701
}
145,447✔
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,987✔
710
    SigMatch *sm_last = NULL;
45,987✔
711
    SigMatch *sm_new;
45,987✔
712

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

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

729
    return sm_last;
45,987✔
730
}
45,987✔
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
{
57,115✔
736
    /* we won't do any checks for args */
737

738
    if (sm->prev != NULL)
57,115✔
739
        sm->prev->next = sm->next;
9,047✔
740
    if (sm->next != NULL)
57,115✔
741
        sm->next->prev = sm->prev;
811✔
742

743
    if (sm == *src_sm_list)
57,115✔
744
        *src_sm_list = sm->next;
48,068✔
745
    if (sm == *src_sm_list_tail)
57,115✔
746
        *src_sm_list_tail = sm->prev;
56,304✔
747

748
    if (*dst_sm_list == NULL) {
57,115✔
749
        *dst_sm_list = sm;
37,549✔
750
        *dst_sm_list_tail = sm;
37,549✔
751
        sm->next = NULL;
37,549✔
752
        sm->prev = NULL;
37,549✔
753
    } else {
37,549✔
754
        SigMatch *cur = *dst_sm_list_tail;
19,566✔
755
        cur->next = sm;
19,566✔
756
        sm->prev = cur;
19,566✔
757
        sm->next = NULL;
19,566✔
758
        *dst_sm_list_tail = sm;
19,566✔
759
    }
19,566✔
760
}
57,115✔
761

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

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
53,494✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
30,543✔
769
        while (sm != NULL) {
92,367✔
770
            if (sm == key_sm)
85,755✔
771
                return s->init_data->buffers[x].id;
23,931✔
772
            sm = sm->next;
61,824✔
773
        }
61,824✔
774
    }
30,543✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
45,904✔
777
        const SigMatch *sm = s->init_data->smlists[list];
45,904✔
778
        while (sm != NULL) {
185,288✔
779
            if (sm == key_sm)
162,335✔
780
                return list;
22,951✔
781
            sm = sm->next;
139,384✔
782
        }
139,384✔
783
    }
45,904✔
784

785
    SCLogError("Unable to find the sm in any of the "
×
786
               "sm lists");
×
787
    return -1;
×
788
}
22,951✔
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,443✔
801
    char *orig = *str;
1,443✔
802
    if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
1,443✔
803
        *str += strlen("to_client");
618✔
804
        // skip space
805
        while (**str && isblank(**str)) {
693✔
806
            (*str)++;
75✔
807
        }
75✔
808
        // check comma or nothing
809
        if (**str) {
618✔
810
            if (only_dir) {
43✔
811
                SCLogError("unknown option: only accepts to_server or to_client");
9✔
812
                return -1;
9✔
813
            }
9✔
814
            if (**str != ',') {
34✔
815
                // leave to_client_something for next parser if not only_dir
816
                *str = orig;
3✔
817
                return 0;
3✔
818
            } else {
31✔
819
                (*str)++;
31✔
820
            }
31✔
821
            while (**str && isblank(**str)) {
60✔
822
                (*str)++;
29✔
823
            }
29✔
824
        }
31✔
825
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
606✔
826
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
606✔
827
            if (s->flags & SIG_FLAG_TOSERVER) {
358✔
828
                SCLogError("contradictory directions");
1✔
829
                return -1;
1✔
830
            }
1✔
831
            s->flags |= SIG_FLAG_TOCLIENT;
357✔
832
        }
357✔
833
    } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
825✔
834
        *str += strlen("to_server");
296✔
835
        // skip space
836
        while (**str && isblank(**str)) {
332✔
837
            (*str)++;
36✔
838
        }
36✔
839
        // check comma or nothing
840
        if (**str) {
296✔
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;
288✔
857
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
288✔
858
            if (s->flags & SIG_FLAG_TOCLIENT) {
159✔
859
                SCLogError("contradictory directions");
1✔
860
                return -1;
1✔
861
            }
1✔
862
            s->flags |= SIG_FLAG_TOSERVER;
158✔
863
        }
158✔
864
    } else if (only_dir) {
529✔
865
        SCLogError("unknown option: only accepts to_server or to_client");
30✔
866
        return -1;
30✔
867
    }
30✔
868
    return 0;
1,391✔
869
}
1,443✔
870

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

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
19,283,169✔
880
        optstr++;
16,573,416✔
881
    }
16,573,416✔
882

883
    /* Look for the end of this option, handling escaped semicolons. */
884
    char *optend = optstr;
19,283,169✔
885
    for (;;) {
19,296,173✔
886
        optend = strchr(optend, ';');
19,296,171✔
887
        if (optend == NULL) {
19,296,171✔
888
            SCLogError("no terminating \";\" found");
237,561✔
889
            goto error;
237,561✔
890
        }
237,561✔
891
        else if (optend > optstr && *(optend -1 ) == '\\') {
19,058,612✔
892
            optend++;
13,004✔
893
        } else {
19,045,606✔
894
            break;
19,045,606✔
895
        }
19,045,606✔
896
    }
19,296,171✔
897
    *(optend++) = '\0';
19,045,608✔
898

899
    /* Find the start of the option value. */
900
    char *optvalptr = strchr(optstr, ':');
19,045,608✔
901
    if (optvalptr) {
19,045,608✔
902
        *(optvalptr++) = '\0';
15,989,292✔
903

904
        /* Trim trailing space from name. */
905
        for (size_t i = strlen(optvalptr); i > 0; i--) {
16,325,398✔
906
            if (isblank(optvalptr[i - 1])) {
16,284,485✔
907
                optvalptr[i - 1] = '\0';
336,106✔
908
            } else {
15,948,379✔
909
                break;
15,948,379✔
910
            }
15,948,379✔
911
        }
16,284,485✔
912

913
        optvalue = optvalptr;
15,989,292✔
914
    }
15,989,292✔
915

916
    /* Trim trailing space from name. */
917
    for (size_t i = strlen(optstr); i > 0; i--) {
19,095,941✔
918
        if (isblank(optstr[i - 1])) {
19,027,781✔
919
            optstr[i - 1] = '\0';
50,332✔
920
        } else {
18,977,449✔
921
            break;
18,977,449✔
922
        }
18,977,449✔
923
    }
19,027,781✔
924
    optname = optstr;
19,045,608✔
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;
19,045,609✔
929
    if ((requires && !requires_only) || (!requires && requires_only)) {
19,045,608✔
930
        goto finish;
11,449,302✔
931
    }
11,449,302✔
932

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

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
7,322,585✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
6,494,684✔
942
            SCLogError(
6,384✔
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
6,384✔
944
            goto error;
6,384✔
945
        }
6,384✔
946
    } else if (st->flags & SIGMATCH_NOOPT) {
6,494,684✔
947
        if (optvalue && strlen(optvalue)) {
664,936✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
131✔
949
            goto error;
131✔
950
        }
131✔
951
    }
664,936✔
952
    s->init_data->negated = false;
7,316,070✔
953

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

957
    if (st->flags & SIGMATCH_INFO_DEPRECATED) {
7,316,070✔
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,316,070✔
972

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

978
        /* skip leading whitespace */
979
        while (ovlen > 0) {
6,958,671✔
980
            if (!isblank(*ptr))
6,958,670✔
981
                break;
6,513,590✔
982
            ptr++;
445,080✔
983
            ovlen--;
445,080✔
984
        }
445,080✔
985
        if (ovlen == 0) {
6,513,591✔
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,513,591✔
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,513,591✔
997
            s->init_data->negated = true;
34,217✔
998
            ptr++;
34,217✔
999
            ovlen--;
34,217✔
1000
        }
34,217✔
1001
        /* skip more whitespace */
1002
        while (ovlen > 0) {
6,516,104✔
1003
            if (!isblank(*ptr))
6,515,895✔
1004
                break;
6,513,383✔
1005
            ptr++;
2,147,486,160✔
1006
            ovlen--;
2,147,486,160✔
1007
        }
2,147,486,160✔
1008
        if (ovlen == 0) {
6,513,591✔
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,513,383✔
1015
            SCLogError("invalid formatting to %s keyword: "
10,775✔
1016
                       "value must be double quoted \'%s\'",
10,775✔
1017
                    optname, optstr);
10,775✔
1018
            goto error;
10,775✔
1019
        }
10,775✔
1020

1021
        if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
6,502,608✔
1022
                && ovlen && *ptr == '"')
6,502,608✔
1023
        {
1,654,435✔
1024
            for (; ovlen > 0; ovlen--) {
1,654,435✔
1025
                if (isblank(ptr[ovlen - 1])) {
1,654,435✔
1026
                    ptr[ovlen - 1] = '\0';
×
1027
                } else {
1,654,435✔
1028
                    break;
1,654,435✔
1029
                }
1,654,435✔
1030
            }
1,654,435✔
1031
            if (ovlen && ptr[ovlen - 1] != '"') {
1,654,435✔
1032
                SCLogError("bad option value formatting (possible missing semicolon) "
48,929✔
1033
                           "for keyword %s: \'%s\'",
48,929✔
1034
                        optname, optvalue);
48,929✔
1035
                goto error;
48,929✔
1036
            }
48,929✔
1037
            if (ovlen > 1) {
1,605,506✔
1038
                /* strip leading " */
1039
                ptr++;
1,586,943✔
1040
                ovlen--;
1,586,943✔
1041
                ptr[ovlen - 1] = '\0';
1,586,943✔
1042
                ovlen--;
1,586,943✔
1043
            }
1,586,943✔
1044
            if (ovlen == 0) {
1,605,506✔
1045
                SCLogError("bad input "
613✔
1046
                           "for keyword %s: \'%s\'",
613✔
1047
                        optname, optvalue);
613✔
1048
                goto error;
613✔
1049
            }
613✔
1050
        } else {
4,848,173✔
1051
            if (*ptr == '"') {
4,848,173✔
1052
                SCLogError(
1,282✔
1053
                        "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1,282✔
1054
                goto error;
1,282✔
1055
            }
1,282✔
1056
        }
4,848,173✔
1057
        /* setup may or may not add a new SigMatch to the list */
1058
        if (st->flags & SIGMATCH_SUPPORT_DIR) {
6,451,784✔
1059
            if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1,443✔
1060
                SCLogError("%s failed to setup direction", st->name);
48✔
1061
                goto error;
48✔
1062
            }
48✔
1063
        }
1,443✔
1064
        setup_ret = st->Setup(de_ctx, s, ptr);
6,451,736✔
1065
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
6,451,736✔
1066
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
6,451,736✔
1067
    } else {
6,451,736✔
1068
        /* setup may or may not add a new SigMatch to the list */
1069
        setup_ret = st->Setup(de_ctx, s, NULL);
802,479✔
1070
    }
802,479✔
1071
    if (setup_ret < 0) {
7,254,215✔
1072
        SCLogDebug("\"%s\" failed to setup", st->name);
636,022✔
1073

1074
        /* handle 'silent' error case */
1075
        if (setup_ret == -2) {
636,022✔
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;
636,022✔
1083
    }
636,022✔
1084
    s->init_data->negated = false;
6,618,193✔
1085

1086
finish:
18,067,496✔
1087
    if (strlen(optend) > 0) {
18,067,496✔
1088
        strlcpy(output, optend, output_size);
14,442,066✔
1089
        return 1;
14,442,066✔
1090
    }
14,442,066✔
1091

1092
    return 0;
3,625,430✔
1093

1094
error:
579,652✔
1095
    return -1;
579,652✔
1096
}
18,067,496✔
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
{
3,930,304✔
1105
    SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
3,930,304✔
1106

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
3,930,304✔
1109
        if (strcasecmp(addrstr, "any") == 0)
1,988,516✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
1,677,253✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1,988,516✔
1113
                &s->init_data->src_contains_negation);
1,988,516✔
1114
        if (s->init_data->src == NULL)
1,988,516✔
1115
            goto error;
46,727✔
1116
    } else {
1,988,516✔
1117
        if (strcasecmp(addrstr, "any") == 0)
1,941,788✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
1,694,939✔
1119

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

1126
    return 0;
3,804,718✔
1127

1128
error:
125,586✔
1129
    return -1;
125,586✔
1130
}
3,930,304✔
1131

1132
static bool IsBuiltIn(const char *n)
1133
{
930✔
1134
    if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
930✔
1135
        return true;
60✔
1136
    }
60✔
1137
    if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
870✔
1138
        return true;
60✔
1139
    }
60✔
1140
    return false;
810✔
1141
}
870✔
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
{
30✔
1153
    for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1,170✔
1154
        const char *alproto_name = AppProtoToString(a);
1,140✔
1155
        if (strcmp(alproto_name, "http") == 0)
1,140✔
1156
            alproto_name = "http1";
30✔
1157
        SCLogDebug("alproto %u/%s", a, alproto_name);
1,140✔
1158

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

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

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

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

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

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

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

1216
                DetectAppLayerInspectEngineRegister(
420✔
1217
                        list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
420✔
1218
            }
420✔
1219
        }
2,744✔
1220
    }
1,140✔
1221
}
30✔
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
{
137✔
1240
    if (strcmp(str, "flow_start") == 0) {
137✔
1241
        return SIGNATURE_HOOK_PKT_FLOW_START;
2✔
1242
    } else if (strcmp(str, "pre_flow") == 0) {
135✔
1243
        return SIGNATURE_HOOK_PKT_PRE_FLOW;
2✔
1244
    } else if (strcmp(str, "pre_stream") == 0) {
133✔
1245
        return SIGNATURE_HOOK_PKT_PRE_STREAM;
2✔
1246
    } else if (strcmp(str, "all") == 0) {
131✔
1247
        return SIGNATURE_HOOK_PKT_ALL;
2✔
1248
    }
2✔
1249
    return SIGNATURE_HOOK_PKT_NOT_SET;
129✔
1250
}
137✔
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
{
4✔
1273
    SignatureHook h = {
4✔
1274
        .type = SIGNATURE_HOOK_TYPE_PKT,
4✔
1275
        .t.pkt.ph = HookPktFromString(hook_str),
4✔
1276
    };
4✔
1277
    return h;
4✔
1278
}
4✔
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
{
133✔
1285
    enum SignatureHookPkt hook = HookPktFromString(h);
133✔
1286
    if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
133✔
1287
        s->init_data->hook = SetPktHook(h);
4✔
1288
        if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
4✔
1289
            return -1; // TODO unreachable?
×
1290
        }
×
1291
    } else {
129✔
1292
        SCLogError("unknown pkt hook %s", h);
129✔
1293
        return -1;
129✔
1294
    }
129✔
1295

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

1302
static SignatureHook SetAppHook(const AppProto alproto, int progress)
1303
{
136✔
1304
    SignatureHook h = {
136✔
1305
        .type = SIGNATURE_HOOK_TYPE_APP,
136✔
1306
        .t.app.alproto = alproto,
136✔
1307
        .t.app.app_progress = progress,
136✔
1308
    };
136✔
1309
    return h;
136✔
1310
}
136✔
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
{
273✔
1317
    if (strcmp(h, "request_started") == 0) {
273✔
1318
        s->flags |= SIG_FLAG_TOSERVER;
4✔
1319
        s->init_data->hook =
4✔
1320
                SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
4✔
1321
    } else if (strcmp(h, "response_started") == 0) {
269✔
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) {
268✔
1326
        s->flags |= SIG_FLAG_TOSERVER;
8✔
1327
        s->init_data->hook = SetAppHook(s->alproto,
8✔
1328
                AppLayerParserGetStateProgressCompletionStatus(s->alproto, STREAM_TOSERVER));
8✔
1329
    } else if (strcmp(h, "response_complete") == 0) {
260✔
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 {
255✔
1334
        const int progress_ts = AppLayerParserGetStateIdByName(
255✔
1335
                IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
255✔
1336
        if (progress_ts >= 0) {
255✔
1337
            s->flags |= SIG_FLAG_TOSERVER;
51✔
1338
            s->init_data->hook = SetAppHook(s->alproto, progress_ts);
51✔
1339
        } else {
204✔
1340
            const int progress_tc = AppLayerParserGetStateIdByName(
204✔
1341
                    IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
204✔
1342
            if (progress_tc < 0) {
204✔
1343
                return -1;
137✔
1344
            }
137✔
1345
            s->flags |= SIG_FLAG_TOCLIENT;
67✔
1346
            s->init_data->hook = SetAppHook(s->alproto, progress_tc);
67✔
1347
        }
67✔
1348
    }
255✔
1349

1350
    char generic_hook_name[64];
136✔
1351
    snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
136✔
1352
    int list = DetectBufferTypeGetByName(generic_hook_name);
136✔
1353
    if (list < 0) {
136✔
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;
132✔
1358

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

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

1367
void DetectListSupportedProtocols(void)
UNCOV
1368
{
×
UNCOV
1369
    printf("=========Supported Rule Protocols=========\n");
×
UNCOV
1370
    DetectEngineProtoList();
×
UNCOV
1371
    AppProtoDetectListNames();
×
UNCOV
1372
}
×
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,143,973✔
1388
    SCEnter();
2,143,973✔
1389
    if (strlen(protostr) > 32)
2,143,973✔
1390
        return -1;
1,872✔
1391

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

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

1409
    int r = DetectProtoParse(&s->proto, p);
2,142,096✔
1410
    if (r < 0) {
2,142,096✔
1411
        s->alproto = AppLayerGetProtoByName(p);
1,047,707✔
1412
        /* indicate that the signature is app-layer */
1413
        if (s->alproto != ALPROTO_UNKNOWN) {
1,047,707✔
1414
            s->flags |= SIG_FLAG_APPLAYER;
987,371✔
1415

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
987,371✔
1417

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

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

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

1451
    SCReturnInt(0);
2,081,490✔
1452
}
2,142,096✔
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,706,603✔
1469
    int r = 0;
3,706,603✔
1470

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

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

1475
    if (flag == 0) {
3,706,603✔
1476
        if (strcasecmp(portstr, "any") == 0)
1,862,929✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
1,444,301✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1,862,929✔
1480
    } else if (flag == 1) {
1,862,929✔
1481
        if (strcasecmp(portstr, "any") == 0)
1,843,674✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
1,363,181✔
1483

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

1487
    if (r < 0)
3,706,603✔
1488
        return -1;
94,881✔
1489

1490
    return 0;
3,611,722✔
1491
}
3,706,603✔
1492

1493
/** \retval 1 valid
1494
 *  \retval 0 invalid
1495
 */
1496
static int SigParseActionRejectValidate(const char *action)
1497
{
663✔
1498
#ifdef HAVE_LIBNET11
663✔
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;
663✔
1514
}
663✔
1515

1516
/** \retval 0 on error
1517
 *  \retval flags on success
1518
 */
1519
static uint8_t ActionStringToFlags(const char *action)
1520
{
2,214,113✔
1521
    if (strcasecmp(action, "alert") == 0) {
2,214,113✔
1522
        return ACTION_ALERT;
1,758,594✔
1523
    } else if (strcasecmp(action, "drop") == 0) {
1,758,594✔
1524
        return ACTION_DROP | ACTION_ALERT;
73,598✔
1525
    } else if (strcasecmp(action, "pass") == 0) {
381,921✔
1526
        return ACTION_PASS;
309,104✔
1527
    } else if (strcasecmp(action, "reject") == 0 ||
309,104✔
1528
               strcasecmp(action, "rejectsrc") == 0)
72,817✔
1529
    {
505✔
1530
        if (!(SigParseActionRejectValidate(action)))
505✔
1531
            return 0;
×
1532
        return ACTION_REJECT | ACTION_DROP | ACTION_ALERT;
505✔
1533
    } else if (strcasecmp(action, "rejectdst") == 0) {
72,312✔
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) {
72,297✔
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) {
72,154✔
1542
        return ACTION_CONFIG;
2,039✔
1543
    } else if (strcasecmp(action, "accept") == 0) {
70,115✔
1544
        return ACTION_ACCEPT;
37✔
1545
    } else {
70,078✔
1546
        SCLogError("An invalid action \"%s\" was given", action);
70,078✔
1547
        return 0;
70,078✔
1548
    }
70,078✔
1549
}
2,214,113✔
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,214,119✔
1564
    char action[32];
2,214,119✔
1565
    strlcpy(action, action_in, sizeof(action));
2,214,119✔
1566
    const char *a = action;
2,214,119✔
1567
    const char *o = NULL;
2,214,119✔
1568

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

1581
    uint8_t flags = ActionStringToFlags(a);
2,214,113✔
1582
    if (flags == 0)
2,214,113✔
1583
        return -1;
70,078✔
1584

1585
    /* parse scope, if any */
1586
    if (o) {
2,144,035✔
1587
        uint8_t scope_flags = 0;
64✔
1588
        if (flags & (ACTION_DROP | ACTION_PASS)) {
64✔
1589
            if (strcmp(o, "packet") == 0) {
19✔
1590
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1✔
1591
            } else if (strcmp(o, "flow") == 0) {
18✔
1592
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
4✔
1593
            } else {
14✔
1594
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
14✔
1595
                           "allowed",
14✔
1596
                        o, action_in);
14✔
1597
                return -1;
14✔
1598
            }
14✔
1599
            s->action_scope = scope_flags;
5✔
1600
        } else if (flags & (ACTION_ACCEPT)) {
45✔
1601
            if (strcmp(o, "packet") == 0) {
35✔
UNCOV
1602
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
×
1603
            } else if (strcmp(o, "hook") == 0) {
35✔
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) {
12✔
1608
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1✔
1609
            } else {
11✔
1610
                SCLogError(
11✔
1611
                        "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
11✔
1612
                        "'hook' allowed",
11✔
1613
                        o, action_in);
11✔
1614
                return -1;
11✔
1615
            }
11✔
1616
            s->action_scope = scope_flags;
24✔
1617
        } else if (flags & (ACTION_CONFIG)) {
24✔
1618
            if (strcmp(o, "packet") == 0) {
5✔
UNCOV
1619
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
×
1620
            } else {
5✔
1621
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
5✔
1622
                        action_in);
5✔
1623
                return -1;
5✔
1624
            }
5✔
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,144,000✔
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,144,000✔
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,143,974✔
1646
        SCLogError("'pass' action not supported for firewall rules");
×
1647
        return -1;
×
1648
    }
×
1649

1650
    s->action = flags;
2,143,974✔
1651
    return 0;
2,143,974✔
1652
}
2,143,974✔
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,385,073✔
1668
    size_t len = *input == NULL ? 0 : strlen(*input);
12,385,073✔
1669

1670
    if (!len) {
12,385,073✔
1671
        return 0;
608,702✔
1672
    }
608,702✔
1673

1674
    while (len && isblank(**input)) {
11,885,209✔
1675
        (*input)++;
108,838✔
1676
        len--;
108,838✔
1677
    }
108,838✔
1678

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

1686
    return 1;
11,776,371✔
1687
}
12,385,073✔
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
{
30,962,687✔
1703
    int in_list = 0;
30,962,687✔
1704
    size_t len = *input != NULL ? strlen(*input) : 0;
30,962,687✔
1705

1706
    if (len == 0) {
30,962,687✔
1707
        return 0;
2,561,688✔
1708
    }
2,561,688✔
1709

1710
    while (len && isblank(**input)) {
28,999,961✔
1711
        (*input)++;
598,962✔
1712
        len--;
598,962✔
1713
    }
598,962✔
1714

1715
    size_t i = 0;
28,400,999✔
1716
    for (i = 0; i < len; i++) {
158,674,355✔
1717
        char c = (*input)[i];
158,118,385✔
1718
        if (c == '[') {
158,118,385✔
1719
            in_list++;
473,559✔
1720
        } else if (c == ']') {
157,644,826✔
1721
            in_list--;
532,732✔
1722
        } else if (c == ' ') {
157,112,094✔
1723
            if (!in_list) {
28,329,029✔
1724
                break;
27,845,029✔
1725
            }
27,845,029✔
1726
        }
28,329,029✔
1727
    }
158,118,385✔
1728
    if (i == len) {
28,400,999✔
1729
        *input = NULL;
555,967✔
1730
        return 0;
555,967✔
1731
    }
555,967✔
1732
    (*input)[i] = '\0';
27,845,032✔
1733
    strlcpy(output, *input, output_size);
27,845,032✔
1734
    *input = *input + i + 1;
27,845,032✔
1735

1736
    return 1;
27,845,032✔
1737
}
28,400,999✔
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,192,538✔
1748
    char *index, dup[DETECT_MAX_RULE_SIZE];
6,192,538✔
1749

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
6,192,538✔
1751
    index = dup;
6,192,538✔
1752

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

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

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

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

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

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

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

1774
    /* Options. */
1775
    if (index == NULL) {
6,192,538✔
1776
        SCLogError("no rule options.");
835,808✔
1777
        goto error;
835,808✔
1778
    }
835,808✔
1779
    while (isspace(*index) || *index == '(') {
9,116,065✔
1780
        index++;
3,759,335✔
1781
    }
3,759,335✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
10,579,758✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
10,510,202✔
1784
            index[i - 1] = '\0';
5,223,028✔
1785
        } else {
5,287,174✔
1786
            break;
5,287,174✔
1787
        }
5,287,174✔
1788
    }
10,510,202✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
5,356,730✔
1790

1791
    if (scan_only) {
5,356,730✔
1792
        return 0;
3,142,610✔
1793
    }
3,142,610✔
1794

1795
    /* Parse Action */
1796
    if (SigParseAction(s, parser->action) < 0)
2,214,120✔
1797
        goto error;
70,145✔
1798

1799
    if (SigParseProto(s, parser->protocol) < 0)
2,143,975✔
1800
        goto error;
62,483✔
1801

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

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

1818
    /* Parse Address & Ports */
1819
    if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1,988,517✔
1820
       goto error;
46,727✔
1821

1822
    if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1,941,790✔
1823
        goto error;
78,859✔
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,862,931✔
1830
        goto error;
19,254✔
1831
    if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1,843,677✔
1832
        goto error;
75,627✔
1833

1834
    return 0;
1,768,050✔
1835

1836
error:
1,281,878✔
1837
    return -1;
1,281,878✔
1838
}
1,843,677✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
6,491,484✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
915,719,741✔
1843
        if (str[i] < 0x20) {
909,527,203✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1,689,084✔
1846
                continue;
1,412,271✔
1847
            }
1,412,271✔
1848
            return false;
276,813✔
1849
        } else if (str[i] == 0x7f) {
907,838,119✔
1850
            return false;
22,133✔
1851
        }
22,133✔
1852
    }
909,527,203✔
1853
    return true;
6,192,538✔
1854
}
6,491,484✔
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,388,318✔
1871
    SCEnter();
7,388,318✔
1872

1873
    if (!SCCheckUtf8(sigstr)) {
7,388,318✔
1874
        SCLogError("rule is not valid UTF-8");
896,835✔
1875
        SCReturnInt(-1);
896,835✔
1876
    }
896,835✔
1877

1878
    if (!CheckAscii(sigstr)) {
6,491,483✔
1879
        SCLogError("rule contains invalid (control) characters");
298,946✔
1880
        SCReturnInt(-1);
298,946✔
1881
    }
298,946✔
1882

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

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

1897
        /* loop the option parsing. Each run processes one option
1898
         * and returns the rest of the option string through the
1899
         * output variable. */
1900
        do {
19,283,170✔
1901
            memset(output, 0x00, buffer_size);
19,283,170✔
1902
            ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
19,283,170✔
1903
            if (ret == 1) {
19,283,170✔
1904
                memcpy(input, output, buffer_size);
14,442,066✔
1905
            }
14,442,066✔
1906

1907
        } while (ret == 1);
19,283,170✔
1908

1909
        if (ret < 0) {
4,841,104✔
1910
            /* Suricata didn't meet the rule requirements, skip. */
1911
            goto end;
1,215,674✔
1912
        }
1,215,674✔
1913
    }
4,841,104✔
1914

1915
end:
4,910,659✔
1916
    DetectIPProtoRemoveAllSMs(de_ctx, s);
4,910,658✔
1917

1918
    SCReturnInt(ret);
4,910,658✔
1919
}
4,910,659✔
1920

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

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

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

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

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

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

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

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

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

1988
    DetectMetadata *mdata = NULL;
5,174,198✔
1989
    DetectMetadata *next_mdata = NULL;
5,174,198✔
1990

1991
    if (s == NULL || s->metadata == NULL) {
5,174,198✔
1992
        SCReturn;
5,156,317✔
1993
    }
5,156,317✔
1994

1995
    SCLogDebug("s %p, s->metadata %p", s, s->metadata);
17,881✔
1996

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

2006
    SCReturn;
17,881✔
2007
}
5,174,198✔
2008

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

2019
    DetectReference *ref = NULL;
5,174,198✔
2020
    DetectReference *next_ref = NULL;
5,174,198✔
2021

2022
    if (s == NULL) {
5,174,198✔
2023
        SCReturn;
×
2024
    }
×
2025

2026
    SCLogDebug("s %p, s->references %p", s, s->references);
5,174,198✔
2027

2028
    for (ref = s->references; ref != NULL;)   {
5,206,268✔
2029
        next_ref = ref->next;
32,070✔
2030
        DetectReferenceFree(ref);
32,070✔
2031
        ref = next_ref;
32,070✔
2032
    }
32,070✔
2033

2034
    s->references = NULL;
5,174,198✔
2035

2036
    SCReturn;
5,174,198✔
2037
}
5,174,198✔
2038

2039
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2040
{
5,174,198✔
2041
    if (s != NULL) {
5,174,198✔
2042
        int type;
5,174,198✔
2043
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
41,393,584✔
2044
            if (s->sm_arrays[type] != NULL) {
36,219,386✔
2045
                if (ctxs) {
74,660✔
2046
                    SigMatchData *smd = s->sm_arrays[type];
74,660✔
2047
                    while(1) {
94,809✔
2048
                        if (sigmatch_table[smd->type].Free != NULL) {
94,809✔
2049
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
94,511✔
2050
                        }
94,511✔
2051
                        if (smd->is_last)
94,809✔
2052
                            break;
74,660✔
2053
                        smd++;
20,149✔
2054
                    }
20,149✔
2055
                }
74,660✔
2056

2057
                SCFree(s->sm_arrays[type]);
74,660✔
2058
            }
74,660✔
2059
        }
36,219,386✔
2060
    }
5,174,198✔
2061
}
5,174,198✔
2062

2063
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
2064
{
5,189,208✔
2065
    if (s == NULL)
5,189,208✔
2066
        return;
15,010✔
2067

2068
    int i;
5,174,198✔
2069

2070
    if (s->init_data && s->init_data->transforms.cnt) {
5,174,198✔
2071
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
58,053✔
2072
            if (s->init_data->transforms.transforms[i].options) {
32,994✔
2073
                int transform = s->init_data->transforms.transforms[i].transform;
12,387✔
2074
                sigmatch_table[transform].Free(
12,387✔
2075
                        de_ctx, s->init_data->transforms.transforms[i].options);
12,387✔
2076
                s->init_data->transforms.transforms[i].options = NULL;
12,387✔
2077
            }
12,387✔
2078
        }
32,994✔
2079
    }
25,059✔
2080
    if (s->init_data) {
5,174,198✔
2081
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
40,435,672✔
2082
            SigMatch *sm = s->init_data->smlists[i];
35,381,213✔
2083
            while (sm != NULL) {
36,227,847✔
2084
                SigMatch *nsm = sm->next;
846,634✔
2085
                SigMatchFree(de_ctx, sm);
846,634✔
2086
                sm = nsm;
846,634✔
2087
            }
846,634✔
2088
        }
35,381,213✔
2089

2090
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
5,920,696✔
2091
            SigMatch *sm = s->init_data->buffers[x].head;
866,237✔
2092
            while (sm != NULL) {
1,748,124✔
2093
                SigMatch *nsm = sm->next;
881,887✔
2094
                SigMatchFree(de_ctx, sm);
881,887✔
2095
                sm = nsm;
881,887✔
2096
            }
881,887✔
2097
        }
866,237✔
2098
        if (s->init_data->cidr_dst != NULL)
5,054,459✔
2099
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
74,877✔
2100

2101
        if (s->init_data->cidr_src != NULL)
5,054,459✔
2102
            IPOnlyCIDRListFree(s->init_data->cidr_src);
76,577✔
2103

2104
        SCFree(s->init_data->buffers);
5,054,459✔
2105
        s->init_data->buffers = NULL;
5,054,459✔
2106
    }
5,054,459✔
2107
    SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
5,174,198✔
2108
    if (s->init_data) {
5,174,198✔
2109
        SCFree(s->init_data);
5,054,459✔
2110
        s->init_data = NULL;
5,054,459✔
2111
    }
5,054,459✔
2112

2113
    if (s->sp != NULL) {
5,174,198✔
2114
        DetectPortCleanupList(NULL, s->sp);
1,843,679✔
2115
    }
1,843,679✔
2116
    if (s->dp != NULL) {
5,174,198✔
2117
        DetectPortCleanupList(NULL, s->dp);
1,770,459✔
2118
    }
1,770,459✔
2119

2120
    if (s->msg != NULL)
5,174,198✔
2121
        SCFree(s->msg);
861,383✔
2122

2123
    if (s->addr_src_match4 != NULL) {
5,174,198✔
2124
        SCFree(s->addr_src_match4);
832,033✔
2125
    }
832,033✔
2126
    if (s->addr_dst_match4 != NULL) {
5,174,198✔
2127
        SCFree(s->addr_dst_match4);
832,154✔
2128
    }
832,154✔
2129
    if (s->addr_src_match6 != NULL) {
5,174,198✔
2130
        SCFree(s->addr_src_match6);
922,819✔
2131
    }
922,819✔
2132
    if (s->addr_dst_match6 != NULL) {
5,174,198✔
2133
        SCFree(s->addr_dst_match6);
923,206✔
2134
    }
923,206✔
2135
    if (s->sig_str != NULL) {
5,174,198✔
2136
        SCFree(s->sig_str);
5,174,198✔
2137
    }
5,174,198✔
2138

2139
    SigRefFree(s);
5,174,198✔
2140
    SigMetadataFree(s);
5,174,198✔
2141

2142
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
5,174,198✔
2143

2144
    SCFree(s);
5,174,198✔
2145
}
5,174,198✔
2146

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

2235
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
2236
{
857,975✔
2237
    if (!AppProtoIsValid(alproto)) {
857,975✔
2238
        SCLogError("invalid alproto %u", alproto);
8✔
2239
        return -1;
8✔
2240
    }
8✔
2241

2242
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
857,967✔
2243
        // Multiple alprotos were set, check if we restrict to one
2244
        bool found = false;
44✔
2245
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
137✔
2246
            if (s->init_data->alprotos[i] == alproto) {
115✔
2247
                found = true;
22✔
2248
                break;
22✔
2249
            }
22✔
2250
        }
115✔
2251
        if (!found) {
44✔
2252
            // fail if we set to a alproto which was not in the set
2253
            return -1;
22✔
2254
        }
22✔
2255
        // we will use s->alproto if there is a single alproto and
2256
        // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2257
        s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
22✔
2258
    }
22✔
2259

2260
    if (s->alproto != ALPROTO_UNKNOWN) {
857,945✔
2261
        alproto = AppProtoCommon(s->alproto, alproto);
614,460✔
2262
        if (alproto == ALPROTO_FAILED) {
614,460✔
2263
            SCLogError("can't set rule app proto to %s: already set to %s",
26,563✔
2264
                    AppProtoToString(alproto), AppProtoToString(s->alproto));
26,563✔
2265
            return -1;
26,563✔
2266
        }
26,563✔
2267
    }
614,460✔
2268

2269
    if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
831,382✔
2270
        SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
1✔
2271
        return -1;
1✔
2272
    }
1✔
2273
    s->alproto = alproto;
831,381✔
2274
    s->flags |= SIG_FLAG_APPLAYER;
831,381✔
2275
    return 0;
831,381✔
2276
}
831,382✔
2277

2278
static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2279
        const DetectAddress *head, uint16_t *match4_cnt)
2280
{
1,875,262✔
2281
    uint16_t cnt = 0;
1,875,262✔
2282

2283
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,555,896✔
2284
        cnt++;
1,680,634✔
2285
    }
1,680,634✔
2286
    if (cnt == 0) {
1,875,262✔
2287
        return NULL;
211,071✔
2288
    }
211,071✔
2289
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
1,664,191✔
2290
    if (addr_match4 == NULL) {
1,664,191✔
2291
        return NULL;
×
2292
    }
×
2293

2294
    uint16_t idx = 0;
1,664,191✔
2295
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,344,825✔
2296
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
1,680,634✔
2297
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
1,680,634✔
2298
        idx++;
1,680,634✔
2299
    }
1,680,634✔
2300
    *match4_cnt = cnt;
1,664,191✔
2301
    return addr_match4;
1,664,191✔
2302
}
1,664,191✔
2303

2304
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2305
        const DetectAddress *head, uint16_t *match6_cnt)
2306
{
1,875,262✔
2307
    uint16_t cnt = 0;
1,875,262✔
2308
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,994,529✔
2309
        cnt++;
2,119,267✔
2310
    }
2,119,267✔
2311
    if (cnt == 0) {
1,875,262✔
2312
        return NULL;
29,233✔
2313
    }
29,233✔
2314

2315
    DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
1,846,029✔
2316
    if (addr_match6 == NULL) {
1,846,029✔
2317
        return NULL;
×
2318
    }
×
2319

2320
    uint16_t idx = 0;
1,846,029✔
2321
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,965,296✔
2322
        addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2,119,267✔
2323
        addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2,119,267✔
2324
        addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2,119,267✔
2325
        addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2,119,267✔
2326
        addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2,119,267✔
2327
        addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2,119,267✔
2328
        addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2,119,267✔
2329
        addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2,119,267✔
2330
        idx++;
2,119,267✔
2331
    }
2,119,267✔
2332
    *match6_cnt = cnt;
1,846,029✔
2333
    return addr_match6;
1,846,029✔
2334
}
1,846,029✔
2335

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

2351
    /* source addresses IPv6 */
2352
    s->addr_src_match6 =
937,631✔
2353
            SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
937,631✔
2354
    /* destination addresses IPv6 */
2355
    s->addr_dst_match6 =
937,631✔
2356
            SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
937,631✔
2357
}
937,631✔
2358

2359
static int SigMatchListLen(SigMatch *sm)
2360
{
850,170✔
2361
    int len = 0;
850,170✔
2362
    for (; sm != NULL; sm = sm->next)
1,026,050✔
2363
        len++;
175,880✔
2364

2365
    return len;
850,170✔
2366
}
850,170✔
2367

2368
/** \brief convert SigMatch list to SigMatchData array
2369
 *  \note ownership of sm->ctx is transferred to smd->ctx
2370
 */
2371
SigMatchData* SigMatchList2DataArray(SigMatch *head)
2372
{
850,170✔
2373
    int len = SigMatchListLen(head);
850,170✔
2374
    if (len == 0)
850,170✔
2375
        return NULL;
703,375✔
2376

2377
    SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
146,795✔
2378
    if (smd == NULL) {
146,795✔
2379
        FatalError("initializing the detection engine failed");
×
2380
    }
×
2381
    SigMatchData *out = smd;
146,795✔
2382

2383
    /* Copy sm type and Context into array */
2384
    SigMatch *sm = head;
146,795✔
2385
    for (; sm != NULL; sm = sm->next, smd++) {
322,676✔
2386
        smd->type = sm->type;
175,881✔
2387
        smd->ctx = sm->ctx;
175,881✔
2388
        sm->ctx = NULL; // SigMatch no longer owns the ctx
175,881✔
2389
        smd->is_last = (sm->next == NULL);
175,881✔
2390
    }
175,881✔
2391
    return out;
146,795✔
2392
}
146,795✔
2393

2394
extern int g_skip_prefilter;
2395

2396
static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2397
{
937,630✔
2398
    SCEnter();
937,630✔
2399
    SCLogDebug("s %u: set up prefilter/mpm", s->id);
937,630✔
2400
    DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
937,630✔
2401

2402
    if (s->init_data->prefilter_sm != NULL) {
937,630✔
2403
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
42,777✔
2404
            RetrieveFPForSig(de_ctx, s);
1,368✔
2405
            if (s->init_data->mpm_sm != NULL) {
1,368✔
2406
                s->flags |= SIG_FLAG_PREFILTER;
1,365✔
2407
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
1,365✔
2408
                SCReturn;
1,365✔
2409
            }
1,365✔
2410
            /* fall through, this can happen if the mpm doesn't support the pattern */
2411
        } else {
41,409✔
2412
            s->flags |= SIG_FLAG_PREFILTER;
41,409✔
2413
            SCReturn;
41,409✔
2414
        }
41,409✔
2415
    } else {
894,853✔
2416
        SCLogDebug("%u: RetrieveFPForSig", s->id);
894,853✔
2417
        RetrieveFPForSig(de_ctx, s);
894,853✔
2418
        if (s->init_data->mpm_sm != NULL) {
894,853✔
2419
            s->flags |= SIG_FLAG_PREFILTER;
307,341✔
2420
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
307,341✔
2421
            SCReturn;
307,341✔
2422
        }
307,341✔
2423
    }
894,853✔
2424

2425
    SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
587,515✔
2426
               "s->init_data->has_possible_prefilter %s",
587,515✔
2427
            s->id, de_ctx->prefilter_setting, BOOL2STR(s->init_data->has_possible_prefilter));
587,515✔
2428

2429
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
587,515✔
2430
        SCReturn;
584,416✔
2431

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

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

2464
/** \internal
2465
 *  \brief check if signature's table requirement is supported by each of the keywords it uses.
2466
 */
2467
static bool DetectRuleValidateTable(const Signature *s)
2468
{
906,716✔
2469
    if (s->detect_table == 0)
906,716✔
2470
        return true;
×
2471

2472
    const uint8_t table_as_flag = BIT_U8(s->detect_table);
906,716✔
2473

2474
    for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
1,179,388✔
2475
        const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
272,672✔
2476
        if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
272,672✔
2477
            SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
×
2478
                    s->id, DetectTableToString(s->detect_table), sigmatch_table[sm->type].name);
×
2479
            return false;
×
2480
        }
×
2481
    }
272,672✔
2482
    return true;
906,716✔
2483
}
906,716✔
2484

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

2496
static void DetectRuleSetTable(Signature *s)
2497
{
908,059✔
2498
    enum DetectTable table;
908,059✔
2499
    if (s->flags & SIG_FLAG_FIREWALL) {
908,059✔
UNCOV
2500
        if (s->type == SIG_TYPE_PKT) {
×
UNCOV
2501
            if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
×
UNCOV
2502
                    s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_STREAM)
×
UNCOV
2503
                table = DETECT_TABLE_PACKET_PRE_STREAM;
×
UNCOV
2504
            else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
×
UNCOV
2505
                     s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_FLOW)
×
UNCOV
2506
                table = DETECT_TABLE_PACKET_PRE_FLOW;
×
UNCOV
2507
            else
×
UNCOV
2508
                table = DETECT_TABLE_PACKET_FILTER;
×
UNCOV
2509
        } else if (s->type == SIG_TYPE_APP_TX) {
×
UNCOV
2510
            table = DETECT_TABLE_APP_FILTER;
×
UNCOV
2511
        } else {
×
2512
            BUG_ON(1);
×
2513
        }
×
2514
    } else {
908,059✔
2515
        // TODO pre_flow/pre_stream
2516
        if (s->type != SIG_TYPE_APP_TX) {
908,059✔
2517
            table = DETECT_TABLE_PACKET_TD;
385,803✔
2518
        } else {
522,307✔
2519
            table = DETECT_TABLE_APP_TD;
522,256✔
2520
        }
522,256✔
2521
    }
908,059✔
2522

2523
    s->detect_table = (uint8_t)table;
908,059✔
2524
}
908,059✔
2525

2526
static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2527
{
937,631✔
2528
    if (s->init_data->firewall_rule) {
937,631✔
UNCOV
2529
        if (!DetectFirewallRuleValidate(de_ctx, s))
×
2530
            SCReturnInt(0);
×
UNCOV
2531
    }
×
2532
    SCReturnInt(1);
937,631✔
2533
}
937,631✔
2534

2535
static int SigValidateCheckBuffers(
2536
        DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2537
{
937,523✔
2538
    bool has_frame = false;
937,523✔
2539
    bool has_app = false;
937,523✔
2540
    bool has_pkt = false;
937,523✔
2541
    bool has_pmatch = false;
937,523✔
2542

2543
    int nlists = 0;
937,523✔
2544
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,546,956✔
2545
        nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
609,433✔
2546
    }
609,433✔
2547
    nlists += (nlists > 0);
937,523✔
2548
    SCLogDebug("nlists %d", nlists);
937,523✔
2549

2550
    if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
937,523✔
2551
        SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2,210✔
2552
                DetectEngineBufferTypeGetNameById(de_ctx, s->init_data->curbuf->id));
2,210✔
2553
        SCReturnInt(0);
2,210✔
2554
    }
2,210✔
2555

2556
    /* run buffer type validation callbacks if any */
2557
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
935,313✔
2558
        if (!DetectContentPMATCHValidateCallback(s))
167,241✔
2559
            SCReturnInt(0);
1,707✔
2560

2561
        has_pmatch = true;
165,534✔
2562
    }
165,534✔
2563

2564
    DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
933,606✔
2565
    struct BufferVsDir {
933,606✔
2566
        int ts;
933,606✔
2567
        int tc;
933,606✔
2568
    } bufdir[nlists + 1];
933,606✔
2569
    memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
933,606✔
2570

2571
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,515,141✔
2572
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
605,658✔
2573
        const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
605,658✔
2574
        if (bt == NULL) {
605,658✔
2575
            DEBUG_VALIDATE_BUG_ON(1); // should be impossible
×
2576
            continue;
×
2577
        }
×
2578
        SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
605,658✔
2579
        for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
1,354,236✔
2580
            SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
748,578✔
2581
        }
748,578✔
2582

2583
        if (b->head == NULL) {
605,658✔
2584
            SCLogError("no matches in sticky buffer %s", bt->name);
46✔
2585
            SCReturnInt(0);
46✔
2586
        }
46✔
2587

2588
        has_frame |= bt->frame;
605,612✔
2589
        has_app |= (!bt->frame && !bt->packet);
605,612✔
2590
        has_pkt |= bt->packet;
605,612✔
2591

2592
        if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
605,612✔
2593
            SCLogError("Signature combines packet "
862✔
2594
                       "specific matches (like dsize, flags, ttl) with stream / "
862✔
2595
                       "state matching by matching on app layer proto (like using "
862✔
2596
                       "http_* keywords).");
862✔
2597
            SCReturnInt(0);
862✔
2598
        }
862✔
2599

2600
        const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
604,750✔
2601
        for (; app != NULL; app = app->next) {
505,937,014✔
2602
            if (app->sm_list == b->id &&
505,332,264✔
2603
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
505,332,264✔
2604
                SCLogDebug("engine %s dir %d alproto %d",
1,519,121✔
2605
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
1,519,121✔
2606
                        app->alproto);
1,519,121✔
2607
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
1,519,121✔
2608

2609
                if (b->only_tc) {
1,519,121✔
2610
                    if (app->dir == 1)
4,352✔
2611
                        (*tc_excl)++;
2,057✔
2612
                } else if (b->only_ts) {
1,514,769✔
2613
                    if (app->dir == 0)
1,719✔
2614
                        (*ts_excl)++;
904✔
2615
                } else {
1,513,050✔
2616
                    bufdir[b->id].ts += (app->dir == 0);
1,513,050✔
2617
                    bufdir[b->id].tc += (app->dir == 1);
1,513,050✔
2618
                }
1,513,050✔
2619

2620
                /* only allow rules to use the hook for engines at that
2621
                 * exact progress for now. */
2622
                if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_APP) {
1,519,121✔
2623
                    if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2✔
2624
                            app->progress != s->init_data->hook.t.app.app_progress) {
2✔
2625
                        SCLogError("engine progress value %d doesn't match hook %u", app->progress,
×
2626
                                s->init_data->hook.t.app.app_progress);
×
2627
                        SCReturnInt(0);
×
2628
                    }
×
2629
                    if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2✔
2630
                            app->progress != s->init_data->hook.t.app.app_progress) {
2✔
2631
                        SCLogError("engine progress value doesn't match hook");
×
2632
                        SCReturnInt(0);
×
2633
                    }
×
2634
                }
2✔
2635
            }
1,519,121✔
2636
        }
505,332,264✔
2637

2638
        if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
604,750✔
2639
            SCReturnInt(0);
10,946✔
2640
        }
10,946✔
2641

2642
        if (!DetectBsizeValidateContentCallback(s, b)) {
593,804✔
2643
            SCReturnInt(0);
12,257✔
2644
        }
12,257✔
2645
        if (!DetectAbsentValidateContentCallback(s, b)) {
581,547✔
2646
            SCReturnInt(0);
12✔
2647
        }
12✔
2648
    }
581,547✔
2649

2650
    if (has_pmatch && has_frame) {
909,483✔
2651
        SCLogError("can't mix pure content and frame inspection");
95✔
2652
        SCReturnInt(0);
95✔
2653
    }
95✔
2654
    if (has_app && has_frame) {
909,388✔
2655
        SCLogError("can't mix app-layer buffer and frame inspection");
25✔
2656
        SCReturnInt(0);
25✔
2657
    }
25✔
2658
    if (has_pkt && has_frame) {
909,363✔
2659
        SCLogError("can't mix pkt buffer and frame inspection");
1✔
2660
        SCReturnInt(0);
1✔
2661
    }
1✔
2662

2663
    for (int x = 0; x < nlists; x++) {
148,868,458✔
2664
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
147,959,126✔
2665
            continue;
147,483,131✔
2666
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
475,965✔
2667
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
475,965✔
2668
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
475,965✔
2669

2670
        SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
475,965✔
2671
                bufdir[x].tc);
475,965✔
2672
    }
475,965✔
2673

2674
    SCReturnInt(1);
909,362✔
2675
}
909,363✔
2676

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

2687
static int SigConsolidateDirection(
2688
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2689
{
909,362✔
2690
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
909,362✔
2691
        if (!ts_excl || !tc_excl) {
716✔
2692
            SCLogError("rule %u should use both directions, but does not", s->id);
395✔
2693
            SCReturnInt(0);
395✔
2694
        }
395✔
2695
        if (dir_amb) {
321✔
2696
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
5✔
2697
                       "directions",
5✔
2698
                    s->id);
5✔
2699
            SCReturnInt(0);
5✔
2700
        }
5✔
2701
    } else if (ts_excl && tc_excl) {
908,646✔
2702
        SCLogError(
256✔
2703
                "rule %u mixes keywords with conflicting directions, a transactional rule with => "
256✔
2704
                "should be used",
256✔
2705
                s->id);
256✔
2706
        SCReturnInt(0);
256✔
2707
    } else if (ts_excl) {
908,390✔
2708
        SCLogDebug("%u: implied rule direction is toserver", s->id);
267,905✔
2709
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
267,905✔
2710
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
635✔
2711
            SCReturnInt(0);
635✔
2712
        }
635✔
2713
    } else if (tc_excl) {
640,485✔
2714
        SCLogDebug("%u: implied rule direction is toclient", s->id);
46,093✔
2715
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
46,093✔
2716
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
12✔
2717
            SCReturnInt(0);
12✔
2718
        }
12✔
2719
    } else if (dir_amb) {
594,392✔
2720
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
121,516✔
2721
    }
121,516✔
2722
    SCReturnInt(1);
909,362✔
2723
}
909,362✔
2724

2725
static void SigConsolidateTcpBuffer(Signature *s)
2726
{
908,059✔
2727
    /* TCP: corner cases:
2728
     * - pkt vs stream vs depth/offset
2729
     * - pkt vs stream vs stream_size
2730
     */
2731
    if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
908,059✔
2732
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
876,265✔
2733
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
163,319✔
2734
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
110,892✔
2735
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
307,507✔
2736
                        sm = sm->next) {
208,830✔
2737
                    if (sm->type == DETECT_CONTENT &&
208,830✔
2738
                            (((DetectContentData *)(sm->ctx))->flags &
208,830✔
2739
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
88,288✔
2740
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
12,215✔
2741
                        break;
12,215✔
2742
                    }
12,215✔
2743
                }
208,830✔
2744
                /* if stream_size is in use, also inspect packets */
2745
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
144,733✔
2746
                        sm = sm->next) {
110,892✔
2747
                    if (sm->type == DETECT_STREAM_SIZE) {
35,669✔
2748
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
1,828✔
2749
                        break;
1,828✔
2750
                    }
1,828✔
2751
                }
35,669✔
2752
            }
110,892✔
2753
        }
163,319✔
2754
    }
876,265✔
2755
}
908,059✔
2756

2757
static bool SigInspectsFiles(const Signature *s)
2758
{
1,814,775✔
2759
    return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
1,814,775✔
2760
            (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA));
1,814,775✔
2761
}
1,814,775✔
2762

2763
/** \internal
2764
 *  \brief validate file handling
2765
 *  \retval 1 good signature
2766
 *  \retval 0 bad signature
2767
 */
2768
static int SigValidateFileHandling(const Signature *s)
2769
{
908,059✔
2770
    if (!SigInspectsFiles(s)) {
908,059✔
2771
        SCReturnInt(1);
853,647✔
2772
    }
853,647✔
2773

2774
    if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
54,412✔
2775
            !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
54,412✔
2776
        SCLogError("protocol %s doesn't "
992✔
2777
                   "support file matching",
992✔
2778
                AppProtoToString(s->alproto));
992✔
2779
        SCReturnInt(0);
992✔
2780
    }
992✔
2781
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
53,420✔
2782
        bool found = false;
4✔
2783
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
12✔
2784
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
12✔
2785
                break;
4✔
2786
            }
4✔
2787
            if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
8✔
2788
                    AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
8✔
2789
                found = true;
×
2790
                break;
×
2791
            }
×
2792
        }
8✔
2793
        if (!found) {
4✔
2794
            SCLogError("No protocol support file matching");
4✔
2795
            SCReturnInt(0);
4✔
2796
        }
4✔
2797
    }
4✔
2798
    if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) {
53,416✔
2799
        SCLogError("protocol HTTP2 doesn't support file name matching");
347✔
2800
        SCReturnInt(0);
347✔
2801
    }
347✔
2802
    SCReturnInt(1);
53,416✔
2803
}
53,416✔
2804

2805
/**
2806
 *  \internal
2807
 *  \brief validate and consolidate parsed signature
2808
 *
2809
 *  \param de_ctx detect engine
2810
 *  \param s signature to validate and consolidate
2811
 *
2812
 *  \retval 0 invalid
2813
 *  \retval 1 valid
2814
 */
2815
static int SigValidateConsolidate(
2816
        DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2817
{
937,631✔
2818
    SCEnter();
937,631✔
2819

2820
    if (SigValidateFirewall(de_ctx, s) == 0)
937,631✔
2821
        SCReturnInt(0);
×
2822

2823
    if (SigValidatePacketStream(s) == 0) {
937,631✔
2824
        SCReturnInt(0);
108✔
2825
    }
108✔
2826

2827
    int ts_excl = 0;
937,523✔
2828
    int tc_excl = 0;
937,523✔
2829
    int dir_amb = 0;
937,523✔
2830

2831
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
937,523✔
2832
        SCReturnInt(0);
28,161✔
2833
    }
28,161✔
2834

2835
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
909,362✔
2836
        SCReturnInt(0);
1,303✔
2837
    }
1,303✔
2838

2839
    SigConsolidateTcpBuffer(s);
908,059✔
2840

2841
    SignatureSetType(de_ctx, s);
908,059✔
2842
    DetectRuleSetTable(s);
908,059✔
2843

2844
    int r = SigValidateFileHandling(s);
908,059✔
2845
    if (r == 0) {
908,059✔
2846
        SCReturnInt(0);
1,343✔
2847
    }
1,343✔
2848
    if (SigInspectsFiles(s)) {
906,716✔
2849
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
53,069✔
2850
            AppLayerHtpNeedFileInspection();
8,435✔
2851
        }
8,435✔
2852
    }
53,069✔
2853
    if (DetectRuleValidateTable(s) == false) {
906,716✔
2854
        SCReturnInt(0);
×
2855
    }
×
2856

2857
    if (s->type == SIG_TYPE_IPONLY) {
906,716✔
2858
        /* For IPOnly */
2859
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
82,807✔
2860
            SCReturnInt(0);
556✔
2861

2862
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
82,251✔
2863
            SCReturnInt(0);
1,700✔
2864
    }
82,251✔
2865
    SCReturnInt(1);
906,716✔
2866
}
906,716✔
2867

2868
/**
2869
 * \internal
2870
 * \brief Helper function for SigInit().
2871
 */
2872
static Signature *SigInitHelper(
2873
        DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2874
{
5,174,199✔
2875
    SignatureParser parser;
5,174,199✔
2876
    memset(&parser, 0x00, sizeof(parser));
5,174,199✔
2877

2878
    Signature *sig = SigAlloc();
5,174,199✔
2879
    if (sig == NULL)
5,174,199✔
2880
        goto error;
×
2881
    if (firewall_rule) {
5,174,199✔
UNCOV
2882
        sig->init_data->firewall_rule = true;
×
UNCOV
2883
        sig->flags |= SIG_FLAG_FIREWALL;
×
UNCOV
2884
    }
×
2885

2886
    sig->sig_str = SCStrdup(sigstr);
5,174,199✔
2887
    if (unlikely(sig->sig_str == NULL)) {
5,174,199✔
2888
        goto error;
×
2889
    }
×
2890

2891
    /* default gid to 1 */
2892
    sig->gid = 1;
5,174,199✔
2893

2894
    /* We do a first parse of the rule in a requires, or scan-only
2895
     * mode. Syntactic errors will be picked up here, but the only
2896
     * part of the rule that is validated completely is the "requires"
2897
     * keyword. */
2898
    int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
5,174,199✔
2899
    if (ret == -4) {
5,174,199✔
2900
        /* Rule requirements not met. */
2901
        de_ctx->sigerror_silent = true;
10,552✔
2902
        de_ctx->sigerror_ok = true;
10,552✔
2903
        de_ctx->sigerror_requires = true;
10,552✔
2904
        goto error;
10,552✔
2905
    } else if (ret < 0) {
5,163,647✔
2906
        goto error;
2,406,293✔
2907
    }
2,406,293✔
2908

2909
    /* Check for a SID before continuuing. */
2910
    if (sig->id == 0) {
2,757,354✔
2911
        SCLogError("Signature missing required value \"sid\".");
543,236✔
2912
        goto error;
543,236✔
2913
    }
543,236✔
2914

2915
    /* Now completely parse the rule. */
2916
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2,214,118✔
2917
    BUG_ON(ret == -4);
2,214,118✔
2918
    if (ret == -3) {
2,214,119✔
2919
        de_ctx->sigerror_silent = true;
17,903✔
2920
        de_ctx->sigerror_ok = true;
17,903✔
2921
        goto error;
17,903✔
2922
    } else if (ret == -2) {
2,196,216✔
UNCOV
2923
        de_ctx->sigerror_silent = true;
×
UNCOV
2924
        goto error;
×
2925
    } else if (ret < 0) {
2,196,216✔
2926
        goto error;
1,258,585✔
2927
    }
1,258,585✔
2928

2929
    /* signature priority hasn't been overwritten.  Using default priority */
2930
    if (sig->prio == -1)
937,631✔
2931
        sig->prio = DETECT_DEFAULT_PRIO;
810,062✔
2932

2933
    sig->iid = de_ctx->signum;
937,631✔
2934
    de_ctx->signum++;
937,631✔
2935

2936
    if (sig->alproto != ALPROTO_UNKNOWN) {
937,631✔
2937
        int override_needed = 0;
611,796✔
2938
        if (sig->proto.flags & DETECT_PROTO_ANY) {
611,796✔
2939
            sig->proto.flags &= ~DETECT_PROTO_ANY;
152,342✔
2940
            memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
152,342✔
2941
            override_needed = 1;
152,342✔
2942
        } else {
459,454✔
2943
            override_needed = 1;
459,454✔
2944
            size_t s = 0;
459,454✔
2945
            for (s = 0; s < sizeof(sig->proto.proto); s++) {
505,243✔
2946
                if (sig->proto.proto[s] != 0x00) {
505,240✔
2947
                    override_needed = 0;
459,451✔
2948
                    break;
459,451✔
2949
                }
459,451✔
2950
            }
505,240✔
2951
        }
459,454✔
2952

2953
        /* at this point if we had alert ip and the ip proto was not
2954
         * overridden, we use the ip proto that has been configured
2955
         * against the app proto in use. */
2956
        if (override_needed)
611,796✔
2957
            AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->proto.proto);
152,345✔
2958
    }
611,796✔
2959

2960
    /* set the packet and app layer flags, but only if the
2961
     * app layer flag wasn't already set in which case we
2962
     * only consider the app layer */
2963
    if (!(sig->flags & SIG_FLAG_APPLAYER)) {
937,631✔
2964
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
323,837✔
2965
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
104,776✔
2966
            for ( ; sm != NULL; sm = sm->next) {
258,996✔
2967
                if (sigmatch_table[sm->type].Match != NULL)
154,220✔
2968
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
154,220✔
2969
            }
154,220✔
2970
        } else {
219,112✔
2971
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
219,061✔
2972
        }
219,061✔
2973
    }
323,837✔
2974

2975
    if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
937,631✔
2976
        if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
1✔
2977
            if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
1✔
UNCOV
2978
                sig->init_data->init_flags |= SIG_FLAG_INIT_FLOW;
×
UNCOV
2979
            }
×
2980
        }
1✔
2981
    }
1✔
2982

2983
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
937,631✔
2984
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
855,055✔
2985
            sig->flags |= SIG_FLAG_TOSERVER;
824,918✔
2986
            sig->flags |= SIG_FLAG_TOCLIENT;
824,918✔
2987
        }
824,918✔
2988
    }
855,055✔
2989

2990
    SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
937,631✔
2991
        sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
937,631✔
2992
        sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
937,631✔
2993

2994
    SigBuildAddressMatchArray(sig);
937,631✔
2995

2996
    /* run buffer type callbacks if any */
2997
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
7,501,046✔
2998
        if (sig->init_data->smlists[x])
6,563,415✔
2999
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
448,709✔
3000
    }
6,563,415✔
3001
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
1,547,065✔
3002
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
609,434✔
3003
    }
609,434✔
3004

3005
    SigSetupPrefilter(de_ctx, sig);
937,631✔
3006

3007
    /* validate signature, SigValidate will report the error reason */
3008
    if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
937,631✔
3009
        goto error;
33,171✔
3010
    }
33,171✔
3011

3012
    return sig;
904,460✔
3013

3014
error:
4,269,740✔
3015
    if (sig != NULL) {
4,269,740✔
3016
        SigFree(de_ctx, sig);
4,269,740✔
3017
    }
4,269,740✔
3018
    return NULL;
4,269,740✔
3019
}
937,631✔
3020

3021
/**
3022
 * \brief Checks if a signature has the same source and destination
3023
 * \param s parsed signature
3024
 *
3025
 *  \retval true if source and destination are the same, false otherwise
3026
 */
3027
static bool SigHasSameSourceAndDestination(const Signature *s)
3028
{
162,089✔
3029
    if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
162,089✔
3030
        if (!DetectPortListsAreEqual(s->sp, s->dp)) {
146,158✔
3031
            return false;
143,399✔
3032
        }
143,399✔
3033
    }
146,158✔
3034

3035
    if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
18,690✔
3036
        DetectAddress *src = s->init_data->src->ipv4_head;
18,360✔
3037
        DetectAddress *dst = s->init_data->dst->ipv4_head;
18,360✔
3038

3039
        if (!DetectAddressListsAreEqual(src, dst)) {
18,360✔
3040
            return false;
7,639✔
3041
        }
7,639✔
3042

3043
        src = s->init_data->src->ipv6_head;
10,721✔
3044
        dst = s->init_data->dst->ipv6_head;
10,721✔
3045

3046
        if (!DetectAddressListsAreEqual(src, dst)) {
10,721✔
3047
            return false;
8,350✔
3048
        }
8,350✔
3049
    }
10,721✔
3050

3051
    return true;
2,701✔
3052
}
18,690✔
3053

3054
static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3055
{
5,014,812✔
3056
    SCEnter();
5,014,812✔
3057

3058
    uint32_t oldsignum = de_ctx->signum;
5,014,812✔
3059
    de_ctx->sigerror_ok = false;
5,014,812✔
3060
    de_ctx->sigerror_silent = false;
5,014,812✔
3061
    de_ctx->sigerror_requires = false;
5,014,812✔
3062

3063
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
5,014,812✔
3064
    if (sig == NULL) {
5,014,812✔
3065
        goto error;
4,269,740✔
3066
    }
4,269,740✔
3067

3068
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
745,072✔
3069
        if (SigHasSameSourceAndDestination(sig)) {
162,089✔
3070
            SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
2,701✔
3071
                "treating the rule as unidirectional", sig->id);
2,701✔
3072

3073
            sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC;
2,701✔
3074
        } else {
159,388✔
3075
            sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
159,388✔
3076
            if (sig->next == NULL) {
159,388✔
3077
                goto error;
×
3078
            }
×
3079
        }
159,388✔
3080
    }
162,089✔
3081

3082
    SCReturnPtr(sig, "Signature");
745,072✔
3083

3084
error:
4,269,740✔
3085
    if (sig != NULL) {
4,269,740✔
3086
        SigFree(de_ctx, sig);
×
3087
    }
×
3088
    /* if something failed, restore the old signum count
3089
     * since we didn't install it */
3090
    de_ctx->signum = oldsignum;
4,269,740✔
3091

3092
    SCReturnPtr(NULL, "Signature");
4,269,740✔
3093
}
745,072✔
3094

3095
/**
3096
 * \brief Parses a signature and adds it to the Detection Engine Context.
3097
 *
3098
 * \param de_ctx Pointer to the Detection Engine Context.
3099
 * \param sigstr Pointer to a character string containing the signature to be
3100
 *               parsed.
3101
 *
3102
 * \retval Pointer to the Signature instance on success; NULL on failure.
3103
 */
3104
Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3105
{
5,014,812✔
3106
    return SigInitDo(de_ctx, sigstr, false);
5,014,812✔
3107
}
5,014,812✔
3108

3109
static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
UNCOV
3110
{
×
UNCOV
3111
    return SigInitDo(de_ctx, sigstr, true);
×
UNCOV
3112
}
×
3113

3114
/**
3115
 * \brief The hash free function to be the used by the hash table -
3116
 *        DetectEngineCtx->dup_sig_hash_table.
3117
 *
3118
 * \param data    Pointer to the data, in our case SigDuplWrapper to be freed.
3119
 */
3120
static void DetectParseDupSigFreeFunc(void *data)
3121
{
107,014✔
3122
    if (data != NULL)
107,014✔
3123
        SCFree(data);
107,014✔
3124
}
107,014✔
3125

3126
/**
3127
 * \brief The hash function to be the used by the hash table -
3128
 *        DetectEngineCtx->dup_sig_hash_table.
3129
 *
3130
 * \param ht      Pointer to the hash table.
3131
 * \param data    Pointer to the data, in our case SigDuplWrapper.
3132
 * \param datalen Not used in our case.
3133
 *
3134
 * \retval sw->s->id The generated hash value.
3135
 */
3136
static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3137
{
925,253✔
3138
    SigDuplWrapper *sw = (SigDuplWrapper *)data;
925,253✔
3139

3140
    return (sw->s->id % ht->array_size);
925,253✔
3141
}
925,253✔
3142

3143
/**
3144
 * \brief The Compare function to be used by the hash table -
3145
 *        DetectEngineCtx->dup_sig_hash_table.
3146
 *
3147
 * \param data1 Pointer to the first SigDuplWrapper.
3148
 * \param len1  Not used.
3149
 * \param data2 Pointer to the second SigDuplWrapper.
3150
 * \param len2  Not used.
3151
 *
3152
 * \retval 1 If the 2 SigDuplWrappers sent as args match.
3153
 * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3154
 */
3155
static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3156
                                  uint16_t len2)
3157
{
722,201✔
3158
    SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
722,201✔
3159
    SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
722,201✔
3160

3161
    if (sw1 == NULL || sw2 == NULL ||
722,201✔
3162
        sw1->s == NULL || sw2->s == NULL)
722,201✔
3163
        return 0;
×
3164

3165
    /* sid and gid match required */
3166
    if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
722,201✔
3167

3168
    return 0;
10,976✔
3169
}
722,201✔
3170

3171
/**
3172
 * \brief Initializes the hash table that is used to cull duplicate sigs.
3173
 *
3174
 * \param de_ctx Pointer to the detection engine context.
3175
 *
3176
 * \retval  0 On success.
3177
 * \retval -1 On failure.
3178
 */
3179
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
3180
{
35,612✔
3181
    de_ctx->dup_sig_hash_table = HashListTableInit(15000,
35,612✔
3182
                                                   DetectParseDupSigHashFunc,
35,612✔
3183
                                                   DetectParseDupSigCompareFunc,
35,612✔
3184
                                                   DetectParseDupSigFreeFunc);
35,612✔
3185
    if (de_ctx->dup_sig_hash_table == NULL)
35,612✔
3186
        return -1;
×
3187

3188
    return 0;
35,612✔
3189
}
35,612✔
3190

3191
/**
3192
 * \brief Frees the hash table that is used to cull duplicate sigs.
3193
 *
3194
 * \param de_ctx Pointer to the detection engine context that holds this table.
3195
 */
3196
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
3197
{
71,187✔
3198
    if (de_ctx->dup_sig_hash_table != NULL)
71,187✔
3199
        HashListTableFree(de_ctx->dup_sig_hash_table);
35,611✔
3200

3201
    de_ctx->dup_sig_hash_table = NULL;
71,187✔
3202
}
71,187✔
3203

3204
/**
3205
 * \brief Check if a signature is a duplicate.
3206
 *
3207
 *        There are 3 types of return values for this function.
3208
 *
3209
 *        - 0, which indicates that the Signature is not a duplicate
3210
 *          and has to be added to the detection engine list.
3211
 *        - 1, Signature is duplicate, and the existing signature in
3212
 *          the list shouldn't be replaced with this duplicate.
3213
 *        - 2, Signature is duplicate, and the existing signature in
3214
 *          the list should be replaced with this duplicate.
3215
 *
3216
 * \param de_ctx Pointer to the detection engine context.
3217
 * \param sig    Pointer to the Signature that has to be checked.
3218
 *
3219
 * \retval 2 If Signature is duplicate and the existing signature in
3220
 *           the list should be chucked out and replaced with this.
3221
 * \retval 1 If Signature is duplicate, and should be chucked out.
3222
 * \retval 0 If Signature is not a duplicate.
3223
 */
3224
static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3225
                                                   Signature *sig)
3226
{
729,758✔
3227
    /* we won't do any NULL checks on the args */
3228

3229
    /* return value */
3230
    int ret = 0;
729,758✔
3231

3232
    SigDuplWrapper *sw_dup = NULL;
729,758✔
3233
    SigDuplWrapper *sw = NULL;
729,758✔
3234

3235
    /* used for making a duplicate_sig_hash_table entry */
3236
    sw = SCCalloc(1, sizeof(SigDuplWrapper));
729,758✔
3237
    if (unlikely(sw == NULL)) {
729,758✔
3238
        exit(EXIT_FAILURE);
×
3239
    }
×
3240
    sw->s = sig;
729,758✔
3241

3242
    /* check if we have a duplicate entry for this signature */
3243
    sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
729,758✔
3244
    /* we don't have a duplicate entry for this sig */
3245
    if (sw_dup == NULL) {
729,758✔
3246
        /* add it to the hash table */
3247
        HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
107,014✔
3248

3249
        /* add the s_prev entry for the previously loaded sw in the hash_table */
3250
        if (de_ctx->sig_list != NULL) {
107,014✔
3251
            SigDuplWrapper *sw_old = NULL;
86,420✔
3252
            SigDuplWrapper sw_tmp;
86,420✔
3253
            memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
86,420✔
3254

3255
            /* the topmost sig would be the last loaded sig */
3256
            sw_tmp.s = de_ctx->sig_list;
86,420✔
3257
            sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
86,420✔
3258
                                         (void *)&sw_tmp, 0);
86,420✔
3259
            /* sw_old == NULL case is impossible */
3260
            sw_old->s_prev = sig;
86,420✔
3261
        }
86,420✔
3262

3263
        ret = 0;
107,014✔
3264
        goto end;
107,014✔
3265
    }
107,014✔
3266

3267
    /* if we have reached here we have a duplicate entry for this signature.
3268
     * Check the signature revision.  Store the signature with the latest rev
3269
     * and discard the other one */
3270
    if (sw->s->rev <= sw_dup->s->rev) {
622,744✔
3271
        ret = 1;
621,535✔
3272
        SCFree(sw);
621,535✔
3273
        sw = NULL;
621,535✔
3274
        goto end;
621,535✔
3275
    }
621,535✔
3276

3277
    /* the new sig is of a newer revision than the one that is already in the
3278
     * list.  Remove the old sig from the list */
3279
    if (sw_dup->s_prev == NULL) {
1,209✔
3280
        SigDuplWrapper sw_temp;
187✔
3281
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
187✔
3282
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
187✔
3283
            sw_temp.s = sw_dup->s->next->next;
38✔
3284
            de_ctx->sig_list = sw_dup->s->next->next;
38✔
3285
            SigFree(de_ctx, sw_dup->s->next);
38✔
3286
        } else {
149✔
3287
            sw_temp.s = sw_dup->s->next;
149✔
3288
            de_ctx->sig_list = sw_dup->s->next;
149✔
3289
        }
149✔
3290
        SigDuplWrapper *sw_next = NULL;
187✔
3291
        if (sw_temp.s != NULL) {
187✔
3292
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
133✔
3293
                                          (void *)&sw_temp, 0);
133✔
3294
            sw_next->s_prev = sw_dup->s_prev;
133✔
3295
        }
133✔
3296
        SigFree(de_ctx, sw_dup->s);
187✔
3297
    } else {
1,022✔
3298
        SigDuplWrapper sw_temp;
1,022✔
3299
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
1,022✔
3300
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
1,022✔
3301
            sw_temp.s = sw_dup->s->next->next;
262✔
3302
            /* If previous signature is bidirectional,
3303
             * it has 2 items in the linked list.
3304
             * So we need to change next->next instead of next
3305
             */
3306
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
262✔
3307
                sw_dup->s_prev->next->next = sw_dup->s->next->next;
152✔
3308
            } else {
152✔
3309
                sw_dup->s_prev->next = sw_dup->s->next->next;
110✔
3310
            }
110✔
3311
            SigFree(de_ctx, sw_dup->s->next);
262✔
3312
        } else {
760✔
3313
            sw_temp.s = sw_dup->s->next;
760✔
3314
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
760✔
3315
                sw_dup->s_prev->next->next = sw_dup->s->next;
115✔
3316
            } else {
645✔
3317
                sw_dup->s_prev->next = sw_dup->s->next;
645✔
3318
            }
645✔
3319
        }
760✔
3320
        SigDuplWrapper *sw_next = NULL;
1,022✔
3321
        if (sw_temp.s != NULL) {
1,022✔
3322
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
773✔
3323
                                          (void *)&sw_temp, 0);
773✔
3324
            sw_next->s_prev = sw_dup->s_prev;
773✔
3325
        }
773✔
3326
        SigFree(de_ctx, sw_dup->s);
1,022✔
3327
    }
1,022✔
3328

3329
    /* make changes to the entry to reflect the presence of the new sig */
3330
    sw_dup->s = sig;
1,209✔
3331
    sw_dup->s_prev = NULL;
1,209✔
3332

3333
    if (de_ctx->sig_list != NULL) {
1,209✔
3334
        SigDuplWrapper sw_tmp;
1,155✔
3335
        memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
1,155✔
3336
        sw_tmp.s = de_ctx->sig_list;
1,155✔
3337
        SigDuplWrapper *sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
1,155✔
3338
                                                     (void *)&sw_tmp, 0);
1,155✔
3339
        if (sw_old->s != sw_dup->s) {
1,155✔
3340
            // Link on top of the list if there was another element
3341
            sw_old->s_prev = sig;
1,155✔
3342
        }
1,155✔
3343
    }
1,155✔
3344

3345
    /* this is duplicate, but a duplicate that replaced the existing sig entry */
3346
    ret = 2;
1,209✔
3347

3348
    SCFree(sw);
1,209✔
3349

3350
end:
729,758✔
3351
    return ret;
729,758✔
3352
}
1,209✔
3353

3354
/**
3355
 * \brief Parse and append a Signature into the Detection Engine Context
3356
 *        signature list.
3357
 *
3358
 *        If the signature is bidirectional it should append two signatures
3359
 *        (with the addresses switched) into the list.  Also handle duplicate
3360
 *        signatures.  In case of duplicate sigs, use the ones that have the
3361
 *        latest revision.  We use the sid and the msg to identify duplicate
3362
 *        sigs.  If 2 sigs have the same sid and gid, they are duplicates.
3363
 *
3364
 * \param de_ctx Pointer to the Detection Engine Context.
3365
 * \param sigstr Pointer to a character string containing the signature to be
3366
 *               parsed.
3367
 * \param sig_file Pointer to a character string containing the filename from
3368
 *                 which signature is read
3369
 * \param lineno Line number from where signature is read
3370
 *
3371
 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3372
 *         on success; NULL on failure.
3373
 */
3374
Signature *DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
UNCOV
3375
{
×
UNCOV
3376
    Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
×
UNCOV
3377
    if (sig == NULL) {
×
3378
        return NULL;
×
3379
    }
×
3380

3381
    /* checking for the status of duplicate signature */
UNCOV
3382
    int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
×
3383
    /* a duplicate signature that should be chucked out.  Check the previously
3384
     * called function details to understand the different return values */
UNCOV
3385
    if (dup_sig == 1) {
×
3386
        SCLogError("Duplicate signature \"%s\"", sigstr);
×
3387
        goto error;
×
UNCOV
3388
    } else if (dup_sig == 2) {
×
3389
        SCLogWarning("Signature with newer revision,"
×
3390
                     " so the older sig replaced by this new signature \"%s\"",
×
3391
                sigstr);
×
3392
    }
×
3393

UNCOV
3394
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
×
UNCOV
3395
        if (sig->next != NULL) {
×
UNCOV
3396
            sig->next->next = de_ctx->sig_list;
×
UNCOV
3397
        } else {
×
3398
            goto error;
×
3399
        }
×
UNCOV
3400
    } else {
×
3401
        /* if this sig is the first one, sig_list should be null */
UNCOV
3402
        sig->next = de_ctx->sig_list;
×
UNCOV
3403
    }
×
3404

UNCOV
3405
    de_ctx->sig_list = sig;
×
3406

3407
    /**
3408
     * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3409
     * so if the signature is bidirectional, the returned sig will point through "next" ptr
3410
     * to the cloned signatures with the switched addresses
3411
     */
UNCOV
3412
    return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
×
3413

3414
error:
×
3415
    /* free the 2nd sig bidir may have set up */
3416
    if (sig != NULL && sig->next != NULL) {
×
3417
        SigFree(de_ctx, sig->next);
×
3418
        sig->next = NULL;
×
3419
    }
×
3420
    if (sig != NULL) {
×
3421
        SigFree(de_ctx, sig);
×
3422
    }
×
3423
    return NULL;
×
UNCOV
3424
}
×
3425

3426
/**
3427
 * \brief Parse and append a Signature into the Detection Engine Context
3428
 *        signature list.
3429
 *
3430
 *        If the signature is bidirectional it should append two signatures
3431
 *        (with the addresses switched) into the list.  Also handle duplicate
3432
 *        signatures.  In case of duplicate sigs, use the ones that have the
3433
 *        latest revision.  We use the sid and the msg to identify duplicate
3434
 *        sigs.  If 2 sigs have the same sid and gid, they are duplicates.
3435
 *
3436
 * \param de_ctx Pointer to the Detection Engine Context.
3437
 * \param sigstr Pointer to a character string containing the signature to be
3438
 *               parsed.
3439
 * \param sig_file Pointer to a character string containing the filename from
3440
 *                 which signature is read
3441
 * \param lineno Line number from where signature is read
3442
 *
3443
 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3444
 *         on success; NULL on failure.
3445
 */
3446
Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
3447
{
4,984,488✔
3448
    Signature *sig = SigInit(de_ctx, sigstr);
4,984,488✔
3449
    if (sig == NULL) {
4,984,488✔
3450
        return NULL;
4,254,730✔
3451
    }
4,254,730✔
3452

3453
    /* checking for the status of duplicate signature */
3454
    int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
729,758✔
3455
    /* a duplicate signature that should be chucked out.  Check the previously
3456
     * called function details to understand the different return values */
3457
    if (dup_sig == 1) {
729,758✔
3458
        SCLogError("Duplicate signature \"%s\"", sigstr);
621,535✔
3459
        goto error;
621,535✔
3460
    } else if (dup_sig == 2) {
621,586✔
3461
        SCLogWarning("Signature with newer revision,"
1,209✔
3462
                     " so the older sig replaced by this new signature \"%s\"",
1,209✔
3463
                sigstr);
1,209✔
3464
    }
1,209✔
3465

3466
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
108,223✔
3467
        if (sig->next != NULL) {
13,027✔
3468
            sig->next->next = de_ctx->sig_list;
13,027✔
3469
        } else {
13,027✔
3470
            goto error;
×
3471
        }
×
3472
    } else {
95,196✔
3473
        /* if this sig is the first one, sig_list should be null */
3474
        sig->next = de_ctx->sig_list;
95,196✔
3475
    }
95,196✔
3476

3477
    de_ctx->sig_list = sig;
108,223✔
3478

3479
    /**
3480
     * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3481
     * so if the signature is bidirectional, the returned sig will point through "next" ptr
3482
     * to the cloned signatures with the switched addresses
3483
     */
3484
    return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
108,223✔
3485

3486
error:
621,535✔
3487
    /* free the 2nd sig bidir may have set up */
3488
    if (sig != NULL && sig->next != NULL) {
621,535✔
3489
        SigFree(de_ctx, sig->next);
133,308✔
3490
        sig->next = NULL;
133,308✔
3491
    }
133,308✔
3492
    if (sig != NULL) {
621,535✔
3493
        SigFree(de_ctx, sig);
621,535✔
3494
    }
621,535✔
3495
    return NULL;
621,535✔
3496
}
108,223✔
3497

3498
static DetectParseRegex *g_detect_parse_regex_list = NULL;
3499

3500
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3501
        int start_offset, int options)
3502
{
1,046,678✔
3503
    *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
1,046,678✔
3504
    if (*match)
1,046,678✔
3505
        return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
1,046,678✔
3506
                *match, parse_regex->context);
1,046,678✔
3507
    return -1;
×
3508
}
1,046,678✔
3509

3510
void DetectParseFreeRegex(DetectParseRegex *r)
3511
{
393,934✔
3512
    if (r->regex) {
393,934✔
3513
        pcre2_code_free(r->regex);
344,033✔
3514
    }
344,033✔
3515
    if (r->context) {
393,934✔
3516
        pcre2_match_context_free(r->context);
343,065✔
3517
    }
343,065✔
3518
}
393,934✔
3519

3520
void DetectParseFreeRegexes(void)
3521
{
22✔
3522
    DetectParseRegex *r = g_detect_parse_regex_list;
22✔
3523
    while (r) {
990✔
3524
        DetectParseRegex *next = r->next;
968✔
3525

3526
        DetectParseFreeRegex(r);
968✔
3527

3528
        SCFree(r);
968✔
3529
        r = next;
968✔
3530
    }
968✔
3531
    g_detect_parse_regex_list = NULL;
22✔
3532
}
22✔
3533

3534
/** \brief add regex and/or study to at exit free list
3535
 */
3536
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
3537
{
1,140✔
3538
    DetectParseRegex *r = SCCalloc(1, sizeof(*r));
1,140✔
3539
    if (r == NULL) {
1,140✔
3540
        FatalError("failed to alloc memory for pcre free list");
×
3541
    }
×
3542
    r->regex = detect_parse->regex;
1,140✔
3543
    r->next = g_detect_parse_regex_list;
1,140✔
3544
    g_detect_parse_regex_list = r;
1,140✔
3545
}
1,140✔
3546

3547
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3548
{
1,140✔
3549
    int en;
1,140✔
3550
    PCRE2_SIZE eo;
1,140✔
3551

3552
    detect_parse->regex =
1,140✔
3553
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
1,140✔
3554
    if (detect_parse->regex == NULL) {
1,140✔
3555
        PCRE2_UCHAR errbuffer[256];
×
3556
        pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
×
3557
        SCLogError("pcre compile of \"%s\" failed at "
×
3558
                   "offset %d: %s",
×
3559
                parse_str, en, errbuffer);
×
3560
        return false;
×
3561
    }
×
3562
    detect_parse->context = pcre2_match_context_create(NULL);
1,140✔
3563
    if (detect_parse->context == NULL) {
1,140✔
3564
        SCLogError("pcre2 could not create match context");
×
3565
        pcre2_code_free(detect_parse->regex);
×
3566
        detect_parse->regex = NULL;
×
3567
        return false;
×
3568
    }
×
3569
    pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
1,140✔
3570
    pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
1,140✔
3571
    DetectParseRegexAddToFreeList(detect_parse);
1,140✔
3572

3573
    return true;
1,140✔
3574
}
1,140✔
3575

3576
DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3577
{
176✔
3578
    int en;
176✔
3579
    PCRE2_SIZE eo;
176✔
3580
    DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
176✔
3581
    if (detect_parse == NULL) {
176✔
3582
        return NULL;
×
3583
    }
×
3584

3585
    detect_parse->regex =
176✔
3586
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
176✔
3587
    if (detect_parse->regex == NULL) {
176✔
3588
        PCRE2_UCHAR errbuffer[256];
×
3589
        pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
×
3590
        SCLogError("pcre2 compile of \"%s\" failed at "
×
3591
                   "offset %d: %s",
×
3592
                parse_str, (int)eo, errbuffer);
×
3593
        SCFree(detect_parse);
×
3594
        return NULL;
×
3595
    }
×
3596

3597
    detect_parse->next = g_detect_parse_regex_list;
176✔
3598
    g_detect_parse_regex_list = detect_parse;
176✔
3599
    return detect_parse;
176✔
3600
}
176✔
3601

3602
int SC_Pcre2SubstringCopy(
3603
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3604
{
182,627✔
3605
    int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
182,627✔
3606
    if (r == PCRE2_ERROR_UNSET) {
182,627✔
3607
        buffer[0] = 0;
854✔
3608
        *bufflen = 0;
854✔
3609
        return 0;
854✔
3610
    }
854✔
3611
    return r;
181,773✔
3612
}
182,627✔
3613

3614
int SC_Pcre2SubstringGet(
3615
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3616
{
×
3617
    int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
×
3618
    if (r == PCRE2_ERROR_UNSET) {
×
3619
        *bufferptr = NULL;
×
3620
        *bufflen = 0;
×
3621
        return 0;
×
3622
    }
×
3623
    return r;
×
3624
}
×
3625

3626
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3627
{
1,140✔
3628
    if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
1,140✔
3629
        FatalError("pcre compile and study failed");
×
3630
    }
×
3631
}
1,140✔
3632

3633
/*
3634
 * TESTS
3635
 */
3636

3637
#ifdef UNITTESTS
3638
#include "detect-engine-alert.h"
3639
#include "packet.h"
3640

3641
static int SigParseTest01 (void)
3642
{
3643
    int result = 1;
3644
    Signature *sig = NULL;
3645

3646
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3647
    if (de_ctx == NULL)
3648
        goto end;
3649

3650
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3651
    if (sig == NULL)
3652
        result = 0;
3653

3654
end:
3655
    if (sig != NULL) SigFree(de_ctx, sig);
3656
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3657
    return result;
3658
}
3659

3660
static int SigParseTest02 (void)
3661
{
3662
    int result = 0;
3663
    Signature *sig = NULL;
3664
    DetectPort *port = NULL;
3665

3666
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3667

3668
    if (de_ctx == NULL)
3669
        goto end;
3670

3671
    SCClassConfDeInitContext(de_ctx);
3672
    FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01();
3673
    SCClassConfLoadClassificationConfigFile(de_ctx, fd);
3674

3675
    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;)");
3676
    if (sig == NULL) {
3677
        goto end;
3678
    }
3679

3680
    int r = DetectPortParse(de_ctx, &port, "0:20");
3681
    if (r < 0)
3682
        goto end;
3683

3684
    if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3685
        result = 1;
3686
    } else {
3687
        DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3688
    }
3689

3690
end:
3691
    if (port != NULL)
3692
        DetectPortCleanupList(de_ctx, port);
3693
    if (sig != NULL)
3694
        SigFree(de_ctx, sig);
3695
    if (de_ctx != NULL)
3696
        DetectEngineCtxFree(de_ctx);
3697
    return result;
3698
}
3699

3700
/**
3701
 * \test SigParseTest03 test for invalid direction operator in rule
3702
 */
3703
static int SigParseTest03 (void)
3704
{
3705
    int result = 1;
3706
    Signature *sig = NULL;
3707

3708
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3709
    if (de_ctx == NULL)
3710
        goto end;
3711

3712
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3713
    if (sig != NULL) {
3714
        result = 0;
3715
        printf("expected NULL got sig ptr %p: ",sig);
3716
    }
3717

3718
end:
3719
    if (sig != NULL) SigFree(de_ctx, sig);
3720
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3721
    return result;
3722
}
3723

3724
static int SigParseTest04 (void)
3725
{
3726
    int result = 1;
3727
    Signature *sig = NULL;
3728

3729
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3730
    if (de_ctx == NULL)
3731
        goto end;
3732

3733
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3734
    if (sig == NULL)
3735
        result = 0;
3736

3737
end:
3738
    if (sig != NULL) SigFree(de_ctx, sig);
3739
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3740
    return result;
3741
}
3742

3743
/** \test Port validation */
3744
static int SigParseTest05 (void)
3745
{
3746
    int result = 0;
3747
    Signature *sig = NULL;
3748

3749
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3750
    if (de_ctx == NULL)
3751
        goto end;
3752

3753
    sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3754
    if (sig == NULL) {
3755
        result = 1;
3756
    } else {
3757
        printf("signature didn't fail to parse as we expected: ");
3758
    }
3759

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

3766
/** \test Parsing bug debugging at 2010-03-18 */
3767
static int SigParseTest06 (void)
3768
{
3769
    int result = 0;
3770
    Signature *sig = NULL;
3771

3772
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3773
    if (de_ctx == NULL)
3774
        goto end;
3775

3776
    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;)");
3777
    if (sig != NULL) {
3778
        result = 1;
3779
    } else {
3780
        printf("signature failed to parse: ");
3781
    }
3782

3783
end:
3784
    if (sig != NULL)
3785
        SigFree(de_ctx, sig);
3786
    if (de_ctx != NULL)
3787
        DetectEngineCtxFree(de_ctx);
3788
    return result;
3789
}
3790

3791
/**
3792
 * \test Parsing duplicate sigs.
3793
 */
3794
static int SigParseTest07(void)
3795
{
3796
    int result = 0;
3797

3798
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3799
    if (de_ctx == NULL)
3800
        goto end;
3801

3802
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3803
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3804

3805
    result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3806

3807
end:
3808
    if (de_ctx != NULL)
3809
        DetectEngineCtxFree(de_ctx);
3810
    return result;
3811
}
3812

3813
/**
3814
 * \test Parsing duplicate sigs.
3815
 */
3816
static int SigParseTest08(void)
3817
{
3818
    int result = 0;
3819

3820
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3821
    if (de_ctx == NULL)
3822
        goto end;
3823

3824
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3825
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3826

3827
    result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3828
              de_ctx->sig_list->rev == 2);
3829

3830
end:
3831
    if (de_ctx != NULL)
3832
        DetectEngineCtxFree(de_ctx);
3833
    return result;
3834
}
3835

3836
/**
3837
 * \test Parsing duplicate sigs.
3838
 */
3839
static int SigParseTest09(void)
3840
{
3841
    int result = 1;
3842

3843
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3844
    if (de_ctx == NULL)
3845
        goto end;
3846

3847
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3848
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3849
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3850
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3851
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3852
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3853
               de_ctx->sig_list->rev == 2);
3854
    if (result == 0)
3855
        goto end;
3856
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3857
               de_ctx->sig_list->next->rev == 6);
3858
    if (result == 0)
3859
        goto end;
3860

3861
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3862
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3863
               de_ctx->sig_list->rev == 2);
3864
    if (result == 0)
3865
        goto end;
3866
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3867
               de_ctx->sig_list->next->rev == 6);
3868
    if (result == 0)
3869
        goto end;
3870

3871
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3872
    result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3873
               de_ctx->sig_list->rev == 4);
3874
    if (result == 0)
3875
        goto end;
3876
    result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3877
               de_ctx->sig_list->next->rev == 6);
3878
    if (result == 0)
3879
        goto end;
3880

3881
end:
3882
    if (de_ctx != NULL)
3883
        DetectEngineCtxFree(de_ctx);
3884
    return result;
3885
}
3886

3887
/**
3888
 * \test Parsing duplicate sigs.
3889
 */
3890
static int SigParseTest10(void)
3891
{
3892
    int result = 1;
3893

3894
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3895
    if (de_ctx == NULL)
3896
        goto end;
3897

3898
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3899
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3900
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3901
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3902
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3903
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3904
    DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3905

3906
    result &= ((de_ctx->sig_list->id == 2) &&
3907
               (de_ctx->sig_list->next->id == 3) &&
3908
               (de_ctx->sig_list->next->next->id == 5) &&
3909
               (de_ctx->sig_list->next->next->next->id == 4) &&
3910
               (de_ctx->sig_list->next->next->next->next->id == 1));
3911

3912
end:
3913
    if (de_ctx != NULL)
3914
        DetectEngineCtxFree(de_ctx);
3915
    return result;
3916
}
3917

3918
/**
3919
 * \test Parsing sig with trailing space(s) as reported by
3920
 *       Morgan Cox on oisf-users.
3921
 */
3922
static int SigParseTest11(void)
3923
{
3924
    int result = 0;
3925

3926
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3927
    if (de_ctx == NULL)
3928
        goto end;
3929

3930
    Signature *s = NULL;
3931

3932
    s = DetectEngineAppendSig(de_ctx,
3933
            "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3934
    if (s == NULL) {
3935
        printf("sig 1 didn't parse: ");
3936
        goto end;
3937
    }
3938

3939
    s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3940
                                      "the http link\"; sid:2;)            ");
3941
    if (s == NULL) {
3942
        printf("sig 2 didn't parse: ");
3943
        goto end;
3944
    }
3945

3946
    result = 1;
3947
end:
3948
    if (de_ctx != NULL)
3949
        DetectEngineCtxFree(de_ctx);
3950
    return result;
3951
}
3952

3953
/**
3954
 * \test file_data with rawbytes
3955
 */
3956
static int SigParseTest12(void)
3957
{
3958
    int result = 0;
3959

3960
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3961
    if (de_ctx == NULL)
3962
        goto end;
3963

3964
    Signature *s = NULL;
3965

3966
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3967
    if (s != NULL) {
3968
        printf("sig 1 should have given an error: ");
3969
        goto end;
3970
    }
3971

3972
    result = 1;
3973
end:
3974
    if (de_ctx != NULL)
3975
        DetectEngineCtxFree(de_ctx);
3976
    return result;
3977
}
3978

3979
/**
3980
 * \test packet/stream sig
3981
 */
3982
static int SigParseTest13(void)
3983
{
3984
    int result = 0;
3985

3986
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3987
    if (de_ctx == NULL)
3988
        goto end;
3989

3990
    Signature *s = NULL;
3991

3992
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3993
    if (s == NULL) {
3994
        printf("sig 1 invalidated: failure");
3995
        goto end;
3996
    }
3997

3998
    if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3999
        printf("sig doesn't have stream flag set\n");
4000
        goto end;
4001
    }
4002

4003
    if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4004
        printf("sig has packet flag set\n");
4005
        goto end;
4006
    }
4007

4008
    result = 1;
4009

4010
end:
4011
    if (de_ctx != NULL)
4012
        DetectEngineCtxFree(de_ctx);
4013
    return result;
4014
}
4015

4016
/**
4017
 * \test packet/stream sig
4018
 */
4019
static int SigParseTest14(void)
4020
{
4021
    int result = 0;
4022

4023
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4024
    if (de_ctx == NULL)
4025
        goto end;
4026

4027
    Signature *s = NULL;
4028

4029
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4030
    if (s == NULL) {
4031
        printf("sig 1 invalidated: failure");
4032
        goto end;
4033
    }
4034

4035
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4036
        printf("sig doesn't have packet flag set\n");
4037
        goto end;
4038
    }
4039

4040
    if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4041
        printf("sig has stream flag set\n");
4042
        goto end;
4043
    }
4044

4045
    result = 1;
4046

4047
end:
4048
    if (de_ctx != NULL)
4049
        DetectEngineCtxFree(de_ctx);
4050
    return result;
4051
}
4052

4053
/**
4054
 * \test packet/stream sig
4055
 */
4056
static int SigParseTest15(void)
4057
{
4058
    int result = 0;
4059

4060
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4061
    if (de_ctx == NULL)
4062
        goto end;
4063

4064
    Signature *s = NULL;
4065

4066
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4067
    if (s == NULL) {
4068
        printf("sig 1 invalidated: failure");
4069
        goto end;
4070
    }
4071

4072
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4073
        printf("sig doesn't have packet flag set\n");
4074
        goto end;
4075
    }
4076

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

4082
    result = 1;
4083

4084
end:
4085
    if (de_ctx != NULL)
4086
        DetectEngineCtxFree(de_ctx);
4087
    return result;
4088
}
4089

4090
/**
4091
 * \test packet/stream sig
4092
 */
4093
static int SigParseTest16(void)
4094
{
4095
    int result = 0;
4096

4097
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4098
    if (de_ctx == NULL)
4099
        goto end;
4100

4101
    Signature *s = NULL;
4102

4103
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4104
    if (s == NULL) {
4105
        printf("sig 1 invalidated: failure");
4106
        goto end;
4107
    }
4108

4109
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4110
        printf("sig doesn't have packet flag set\n");
4111
        goto end;
4112
    }
4113

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

4119
    result = 1;
4120

4121
end:
4122
    if (de_ctx != NULL)
4123
        DetectEngineCtxFree(de_ctx);
4124
    return result;
4125
}
4126

4127
/**
4128
 * \test packet/stream sig
4129
 */
4130
static int SigParseTest17(void)
4131
{
4132
    int result = 0;
4133

4134
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4135
    if (de_ctx == NULL)
4136
        goto end;
4137

4138
    Signature *s = NULL;
4139

4140
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4141
    if (s == NULL) {
4142
        printf("sig 1 invalidated: failure");
4143
        goto end;
4144
    }
4145

4146
    if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4147
        printf("sig doesn't have packet flag set\n");
4148
        goto end;
4149
    }
4150

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

4156
    result = 1;
4157

4158
end:
4159
    if (de_ctx != NULL)
4160
        DetectEngineCtxFree(de_ctx);
4161
    return result;
4162
}
4163

4164
/** \test sid value too large. Bug #779 */
4165
static int SigParseTest18 (void)
4166
{
4167
    int result = 0;
4168

4169
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4170
    if (de_ctx == NULL)
4171
        goto end;
4172

4173
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4174
        goto end;
4175

4176
    result = 1;
4177
end:
4178
    if (de_ctx != NULL)
4179
        DetectEngineCtxFree(de_ctx);
4180
    return result;
4181
}
4182

4183
/** \test gid value too large. Related to bug #779 */
4184
static int SigParseTest19 (void)
4185
{
4186
    int result = 0;
4187

4188
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4189
    if (de_ctx == NULL)
4190
        goto end;
4191

4192
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4193
        goto end;
4194

4195
    result = 1;
4196
end:
4197
    if (de_ctx != NULL)
4198
        DetectEngineCtxFree(de_ctx);
4199
    return result;
4200
}
4201

4202
/** \test rev value too large. Related to bug #779 */
4203
static int SigParseTest20 (void)
4204
{
4205
    int result = 0;
4206

4207
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4208
    if (de_ctx == NULL)
4209
        goto end;
4210

4211
    if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4212
        goto end;
4213

4214
    result = 1;
4215
end:
4216
    if (de_ctx != NULL)
4217
        DetectEngineCtxFree(de_ctx);
4218
    return result;
4219
}
4220

4221
/** \test address parsing */
4222
static int SigParseTest21 (void)
4223
{
4224
    int result = 0;
4225

4226
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4227
    if (de_ctx == NULL)
4228
        goto end;
4229

4230
    if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4231
        goto end;
4232

4233
    result = 1;
4234
end:
4235
    if (de_ctx != NULL)
4236
        DetectEngineCtxFree(de_ctx);
4237
    return result;
4238
}
4239

4240
/** \test address parsing */
4241
static int SigParseTest22 (void)
4242
{
4243
    int result = 0;
4244

4245
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4246
    if (de_ctx == NULL)
4247
        goto end;
4248

4249
    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)
4250
        goto end;
4251

4252
    result = 1;
4253
end:
4254
    if (de_ctx != NULL)
4255
        DetectEngineCtxFree(de_ctx);
4256
    return result;
4257
}
4258

4259
/**
4260
 * \test rule ending in carriage return
4261
 */
4262
static int SigParseTest23(void)
4263
{
4264
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4265
    FAIL_IF_NULL(de_ctx);
4266

4267
    Signature *s = NULL;
4268

4269
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4270
    FAIL_IF_NULL(s);
4271

4272
    DetectEngineCtxFree(de_ctx);
4273
    PASS;
4274
}
4275

4276
/** \test Direction operator validation (invalid) */
4277
static int SigParseBidirecTest06 (void)
4278
{
4279
    int result = 1;
4280
    Signature *sig = NULL;
4281

4282
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4283
    if (de_ctx == NULL)
4284
        goto end;
4285

4286
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4287
    if (sig == NULL)
4288
        result = 1;
4289

4290
end:
4291
    if (sig != NULL) SigFree(de_ctx, sig);
4292
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4293
    return result;
4294
}
4295

4296
/** \test Direction operator validation (invalid) */
4297
static int SigParseBidirecTest07 (void)
4298
{
4299
    int result = 1;
4300
    Signature *sig = NULL;
4301

4302
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4303
    if (de_ctx == NULL)
4304
        goto end;
4305

4306
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4307
    if (sig == NULL)
4308
        result = 1;
4309

4310
end:
4311
    if (sig != NULL) SigFree(de_ctx, sig);
4312
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4313
    return result;
4314
}
4315

4316
/** \test Direction operator validation (invalid) */
4317
static int SigParseBidirecTest08 (void)
4318
{
4319
    int result = 1;
4320
    Signature *sig = NULL;
4321

4322
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4323
    if (de_ctx == NULL)
4324
        goto end;
4325

4326
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4327
    if (sig == NULL)
4328
        result = 1;
4329

4330
end:
4331
    if (sig != NULL) SigFree(de_ctx, sig);
4332
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4333
    return result;
4334
}
4335

4336
/** \test Direction operator validation (invalid) */
4337
static int SigParseBidirecTest09 (void)
4338
{
4339
    int result = 1;
4340
    Signature *sig = NULL;
4341

4342
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4343
    if (de_ctx == NULL)
4344
        goto end;
4345

4346
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4347
    if (sig == NULL)
4348
        result = 1;
4349

4350
end:
4351
    if (sig != NULL) SigFree(de_ctx, sig);
4352
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4353
    return result;
4354
}
4355

4356
/** \test Direction operator validation (invalid) */
4357
static int SigParseBidirecTest10 (void)
4358
{
4359
    int result = 1;
4360
    Signature *sig = NULL;
4361

4362
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4363
    if (de_ctx == NULL)
4364
        goto end;
4365

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

4370
end:
4371
    if (sig != NULL) SigFree(de_ctx, sig);
4372
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4373
    return result;
4374
}
4375

4376
/** \test Direction operator validation (invalid) */
4377
static int SigParseBidirecTest11 (void)
4378
{
4379
    int result = 1;
4380
    Signature *sig = NULL;
4381

4382
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4383
    if (de_ctx == NULL)
4384
        goto end;
4385

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

4390
end:
4391
    if (sig != NULL) SigFree(de_ctx, sig);
4392
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4393
    return result;
4394
}
4395

4396
/** \test Direction operator validation (invalid) */
4397
static int SigParseBidirecTest12 (void)
4398
{
4399
    int result = 1;
4400
    Signature *sig = NULL;
4401

4402
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4403
    if (de_ctx == NULL)
4404
        goto end;
4405

4406
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4407
    if (sig == NULL)
4408
        result = 1;
4409

4410
end:
4411
    if (sig != NULL) SigFree(de_ctx, sig);
4412
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4413
    return result;
4414
}
4415

4416
/** \test Direction operator validation (valid) */
4417
static int SigParseBidirecTest13 (void)
4418
{
4419
    int result = 1;
4420
    Signature *sig = NULL;
4421

4422
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4423
    if (de_ctx == NULL)
4424
        goto end;
4425

4426
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4427
    if (sig != NULL)
4428
        result = 1;
4429

4430
end:
4431
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4432
    return result;
4433
}
4434

4435
/** \test Direction operator validation (valid) */
4436
static int SigParseBidirecTest14 (void)
4437
{
4438
    int result = 1;
4439
    Signature *sig = NULL;
4440

4441
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4442
    if (de_ctx == NULL)
4443
        goto end;
4444

4445
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4446
    if (sig != NULL)
4447
        result = 1;
4448

4449
end:
4450
    if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4451
    return result;
4452
}
4453

4454
/** \test Ensure that we don't set bidirectional in a
4455
 *         normal (one direction) Signature
4456
 */
4457
static int SigTestBidirec01 (void)
4458
{
4459
    Signature *sig = NULL;
4460
    int result = 0;
4461

4462
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4463
    if (de_ctx == NULL)
4464
        goto end;
4465

4466
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4467
    if (sig == NULL)
4468
        goto end;
4469
    if (sig->next != NULL)
4470
        goto end;
4471
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)
4472
        goto end;
4473
    if (de_ctx->signum != 1)
4474
        goto end;
4475

4476
    result = 1;
4477

4478
end:
4479
    if (de_ctx != NULL) {
4480
        SigCleanSignatures(de_ctx);
4481
        SigGroupCleanup(de_ctx);
4482
        DetectEngineCtxFree(de_ctx);
4483
    }
4484
    return result;
4485
}
4486

4487
/** \test Ensure that we set a bidirectional Signature correctly */
4488
static int SigTestBidirec02 (void)
4489
{
4490
    int result = 0;
4491
    Signature *sig = NULL;
4492
    Signature *copy = NULL;
4493

4494
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4495
    if (de_ctx == NULL)
4496
        goto end;
4497

4498
    de_ctx->flags |= DE_QUIET;
4499

4500
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4501
    if (sig == NULL)
4502
        goto end;
4503
    if (de_ctx->sig_list != sig)
4504
        goto end;
4505
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4506
        goto end;
4507
    if (sig->next == NULL)
4508
        goto end;
4509
    if (de_ctx->signum != 2)
4510
        goto end;
4511
    copy = sig->next;
4512
    if (copy->next != NULL)
4513
        goto end;
4514
    if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4515
        goto end;
4516

4517
    result = 1;
4518

4519
end:
4520
    if (de_ctx != NULL) {
4521
        SigCleanSignatures(de_ctx);
4522
        SigGroupCleanup(de_ctx);
4523
        DetectEngineCtxFree(de_ctx);
4524
    }
4525

4526
    return result;
4527
}
4528

4529
/** \test Ensure that we set a bidirectional Signature correctly
4530
*         and we install it with the rest of the signatures, checking
4531
*         also that it match with the correct addr directions
4532
*/
4533
static int SigTestBidirec03 (void)
4534
{
4535
    int result = 0;
4536
    Signature *sig = NULL;
4537
    Packet *p = NULL;
4538

4539
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4540
    if (de_ctx == NULL)
4541
        goto end;
4542

4543
    de_ctx->flags |= DE_QUIET;
4544

4545
    const char *sigs[3];
4546
    sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4547
    sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4548
    sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4549
    UTHAppendSigs(de_ctx, sigs, 3);
4550

4551
    /* Checking that bidirectional rules are set correctly */
4552
    sig = de_ctx->sig_list;
4553
    if (sig == NULL)
4554
        goto end;
4555
    if (sig->next == NULL)
4556
        goto end;
4557
    if (sig->next->next == NULL)
4558
        goto end;
4559
    if (sig->next->next->next == NULL)
4560
        goto end;
4561
    if (sig->next->next->next->next != NULL)
4562
        goto end;
4563
    if (de_ctx->signum != 4)
4564
        goto end;
4565

4566
    uint8_t rawpkt1_ether[] = {
4567
        0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4568
        0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4569
        0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4570
        0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4571
        0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4572
        0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4573
        0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4574
        0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4575
        0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4576
        0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4577
        0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4578
        0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4579
        0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4580
        0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4581
        0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4582
        0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4583
        0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4584
        0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4585
        0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4586
        0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4587
        0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4588
        0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4589
        0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4590
        0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4591
        0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4592
        0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4593
        0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4594
        0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4595
        0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4596
        0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4597
        0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4598
        0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4599
        0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4600
        0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4601
        0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4602
        0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4603
        0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4604
        0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4605
        0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4606
        0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4607
        0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4608
        0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4609
        0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4610
        0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4611
        0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4612
        0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4613
        0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4614
        0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4615
        0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4616
        0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4617
        0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4618
        0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4619
        0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4620
        0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4621
        0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4622

4623
    FlowInitConfig(FLOW_QUIET);
4624
    p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4625
    if (p == NULL) {
4626
        SCLogDebug("Error building packet");
4627
        goto end;
4628
    }
4629
    UTHMatchPackets(de_ctx, &p, 1);
4630

4631
    uint32_t sids[3] = {1, 2, 3};
4632
    uint32_t results[3] = {1, 1, 1};
4633
    result = UTHCheckPacketMatchResults(p, sids, results, 1);
4634

4635
end:
4636
    if (p != NULL) {
4637
        PacketFree(p);
4638
    }
4639
    DetectEngineCtxFree(de_ctx);
4640
    FlowShutdown();
4641
    return result;
4642
}
4643

4644
/** \test Ensure that we set a bidirectional Signature correctly
4645
*         and we install it with the rest of the signatures, checking
4646
*         also that it match with the correct addr directions
4647
*/
4648
static int SigTestBidirec04 (void)
4649
{
4650
    int result = 0;
4651
    Signature *sig = NULL;
4652
    Packet *p = NULL;
4653

4654
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4655
    if (de_ctx == NULL)
4656
        goto end;
4657

4658
    de_ctx->flags |= DE_QUIET;
4659

4660
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4661
    if (sig == NULL)
4662
        goto end;
4663
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4664
    if (sig == NULL)
4665
        goto end;
4666
    if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4667
        goto end;
4668
    if (sig->next == NULL)
4669
        goto end;
4670
    if (sig->next->next == NULL)
4671
        goto end;
4672
    if (sig->next->next->next != NULL)
4673
        goto end;
4674
    if (de_ctx->signum != 3)
4675
        goto end;
4676

4677
    sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4678
    if (sig == NULL)
4679
        goto end;
4680
    if (sig->next == NULL)
4681
        goto end;
4682
    if (sig->next->next == NULL)
4683
        goto end;
4684
    if (sig->next->next->next == NULL)
4685
        goto end;
4686
    if (sig->next->next->next->next != NULL)
4687
        goto end;
4688
    if (de_ctx->signum != 4)
4689
        goto end;
4690

4691
    uint8_t rawpkt1_ether[] = {
4692
        0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4693
        0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4694
        0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4695
        0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4696
        0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4697
        0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4698
        0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4699
        0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4700
        0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4701
        0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4702
        0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4703
        0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4704
        0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4705
        0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4706
        0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4707
        0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4708
        0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4709
        0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4710
        0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4711
        0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4712
        0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4713
        0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4714
        0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4715
        0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4716
        0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4717
        0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4718
        0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4719
        0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4720
        0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4721
        0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4722
        0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4723
        0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4724
        0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4725
        0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4726
        0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4727
        0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4728
        0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4729
        0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4730
        0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4731
        0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4732
        0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4733
        0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4734
        0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4735
        0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4736
        0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4737
        0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4738
        0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4739
        0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4740
        0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4741
        0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4742
        0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4743
        0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4744
        0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4745
        0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4746
        0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4747

4748
    p = PacketGetFromAlloc();
4749
    if (unlikely(p == NULL))
4750
        return 0;
4751
    DecodeThreadVars dtv;
4752
    ThreadVars th_v;
4753
    DetectEngineThreadCtx *det_ctx;
4754

4755
    memset(&th_v, 0, sizeof(th_v));
4756
    StatsThreadInit(&th_v.stats);
4757

4758
    FlowInitConfig(FLOW_QUIET);
4759
    DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4760
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4761

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

4766
    SigGroupBuild(de_ctx);
4767
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4768

4769
    /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4770
    if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4771
        PacketAlertCheck(p, 2) == 1) {
4772
        result = 1;
4773
    }
4774

4775
    if (p != NULL) {
4776
        PacketRecycle(p);
4777
    }
4778
    FlowShutdown();
4779
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4780

4781
end:
4782
    if (de_ctx != NULL) {
4783
        DetectEngineCtxFree(de_ctx);
4784
    }
4785

4786
    if (p != NULL)
4787
        PacketFree(p);
4788
    StatsThreadCleanup(&th_v.stats);
4789
    return result;
4790
}
4791

4792
/**
4793
 * \test check that we don't allow invalid negation options
4794
 */
4795
static int SigParseTestNegation01 (void)
4796
{
4797
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4798
    FAIL_IF_NULL(de_ctx);
4799
    de_ctx->flags |= DE_QUIET;
4800
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4801
    FAIL_IF_NOT_NULL(s);
4802
    DetectEngineCtxFree(de_ctx);
4803
    PASS;
4804
}
4805

4806
/**
4807
 * \test check that we don't allow invalid negation options
4808
 */
4809
static int SigParseTestNegation02 (void)
4810
{
4811
    int result = 0;
4812
    DetectEngineCtx *de_ctx;
4813
    Signature *s=NULL;
4814

4815
    de_ctx = DetectEngineCtxInit();
4816
    if (de_ctx == NULL)
4817
        goto end;
4818
    de_ctx->flags |= DE_QUIET;
4819

4820
    s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
4821
    if (s != NULL) {
4822
        SigFree(de_ctx, s);
4823
        goto end;
4824
    }
4825

4826
    result = 1;
4827
end:
4828
    if (de_ctx != NULL)
4829
        DetectEngineCtxFree(de_ctx);
4830
    return result;
4831
}
4832
/**
4833
 * \test check that we don't allow invalid negation options
4834
 */
4835
static int SigParseTestNegation03 (void)
4836
{
4837
    int result = 0;
4838
    DetectEngineCtx *de_ctx;
4839
    Signature *s=NULL;
4840

4841
    de_ctx = DetectEngineCtxInit();
4842
    if (de_ctx == NULL)
4843
        goto end;
4844
    de_ctx->flags |= DE_QUIET;
4845

4846
    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;)");
4847
    if (s != NULL) {
4848
        SigFree(de_ctx, s);
4849
        goto end;
4850
    }
4851

4852
    result = 1;
4853
end:
4854
    if (de_ctx != NULL)
4855
        DetectEngineCtxFree(de_ctx);
4856
    return result;
4857
}
4858
/**
4859
 * \test check that we don't allow invalid negation options
4860
 */
4861
static int SigParseTestNegation04 (void)
4862
{
4863
    int result = 0;
4864
    DetectEngineCtx *de_ctx;
4865
    Signature *s=NULL;
4866

4867
    de_ctx = DetectEngineCtxInit();
4868
    if (de_ctx == NULL)
4869
        goto end;
4870
    de_ctx->flags |= DE_QUIET;
4871

4872
    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;)");
4873
    if (s != NULL) {
4874
        SigFree(de_ctx, s);
4875
        goto end;
4876
    }
4877

4878
    result = 1;
4879
end:
4880
    if (de_ctx != NULL)
4881
        DetectEngineCtxFree(de_ctx);
4882
    return result;
4883
}
4884
/**
4885
 * \test check that we don't allow invalid negation options
4886
 */
4887
static int SigParseTestNegation05 (void)
4888
{
4889
    int result = 0;
4890
    DetectEngineCtx *de_ctx;
4891
    Signature *s=NULL;
4892

4893
    de_ctx = DetectEngineCtxInit();
4894
    if (de_ctx == NULL)
4895
        goto end;
4896
    de_ctx->flags |= DE_QUIET;
4897

4898
    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;)");
4899
    if (s != NULL) {
4900
        SigFree(de_ctx, s);
4901
        goto end;
4902
    }
4903

4904
    result = 1;
4905
end:
4906
    if (de_ctx != NULL)
4907
        DetectEngineCtxFree(de_ctx);
4908
    return result;
4909
}
4910
/**
4911
 * \test check that we don't allow invalid negation options
4912
 */
4913
static int SigParseTestNegation06 (void)
4914
{
4915
    int result = 0;
4916
    DetectEngineCtx *de_ctx;
4917
    Signature *s=NULL;
4918

4919
    de_ctx = DetectEngineCtxInit();
4920
    if (de_ctx == NULL)
4921
        goto end;
4922
    de_ctx->flags |= DE_QUIET;
4923

4924
    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;)");
4925
    if (s != NULL) {
4926
        SigFree(de_ctx, s);
4927
        goto end;
4928
    }
4929

4930
    result = 1;
4931
end:
4932
    if (de_ctx != NULL)
4933
        DetectEngineCtxFree(de_ctx);
4934
    return result;
4935
}
4936

4937
/**
4938
 * \test check that we don't allow invalid negation options
4939
 */
4940
static int SigParseTestNegation07 (void)
4941
{
4942
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4943
    FAIL_IF_NULL(de_ctx);
4944
    de_ctx->flags |= DE_QUIET;
4945
    Signature *s = DetectEngineAppendSig(
4946
            de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4947
    FAIL_IF_NOT_NULL(s);
4948
    DetectEngineCtxFree(de_ctx);
4949
    PASS;
4950
}
4951

4952
/**
4953
 * \test check valid negation bug 1079
4954
 */
4955
static int SigParseTestNegation08 (void)
4956
{
4957
    int result = 0;
4958
    DetectEngineCtx *de_ctx;
4959
    Signature *s=NULL;
4960

4961
    de_ctx = DetectEngineCtxInit();
4962
    if (de_ctx == NULL)
4963
        goto end;
4964
    de_ctx->flags |= DE_QUIET;
4965

4966
    s = DetectEngineAppendSig(de_ctx,
4967
            "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4968
    if (s == NULL) {
4969
        goto end;
4970
    }
4971

4972
    result = 1;
4973
end:
4974
    if (de_ctx != NULL)
4975
        DetectEngineCtxFree(de_ctx);
4976
    return result;
4977
}
4978

4979
/**
4980
 * \test mpm
4981
 */
4982
static int SigParseTestMpm01 (void)
4983
{
4984
    int result = 0;
4985
    Signature *sig = NULL;
4986

4987
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4988
    if (de_ctx == NULL)
4989
        goto end;
4990

4991
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4992
    if (sig == NULL) {
4993
        printf("sig failed to init: ");
4994
        goto end;
4995
    }
4996

4997
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4998
        printf("sig doesn't have content list: ");
4999
        goto end;
5000
    }
5001

5002
    result = 1;
5003
end:
5004
    if (sig != NULL)
5005
        SigFree(de_ctx, sig);
5006
    DetectEngineCtxFree(de_ctx);
5007
    return result;
5008
}
5009

5010
/**
5011
 * \test mpm
5012
 */
5013
static int SigParseTestMpm02 (void)
5014
{
5015
    int result = 0;
5016
    Signature *sig = NULL;
5017

5018
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5019
    if (de_ctx == NULL)
5020
        goto end;
5021

5022
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5023
    if (sig == NULL) {
5024
        printf("sig failed to init: ");
5025
        goto end;
5026
    }
5027

5028
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5029
        printf("sig doesn't have content list: ");
5030
        goto end;
5031
    }
5032

5033
    result = 1;
5034
end:
5035
    if (sig != NULL)
5036
        SigFree(de_ctx, sig);
5037
    DetectEngineCtxFree(de_ctx);
5038
    return result;
5039
}
5040

5041
/**
5042
 * \test test tls (app layer) rule
5043
 */
5044
static int SigParseTestAppLayerTLS01(void)
5045
{
5046
    int result = 0;
5047
    DetectEngineCtx *de_ctx;
5048
    Signature *s=NULL;
5049

5050
    de_ctx = DetectEngineCtxInit();
5051
    if (de_ctx == NULL)
5052
        goto end;
5053
    de_ctx->flags |= DE_QUIET;
5054

5055
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5056
    if (s == NULL) {
5057
        printf("parsing sig failed: ");
5058
        goto end;
5059
    }
5060

5061
    if (s->alproto == 0) {
5062
        printf("alproto not set: ");
5063
        goto end;
5064
    }
5065

5066
    result = 1;
5067
end:
5068
    if (s != NULL)
5069
        SigFree(de_ctx, s);
5070
    if (de_ctx != NULL)
5071
        DetectEngineCtxFree(de_ctx);
5072

5073
    return result;
5074
}
5075

5076
/**
5077
 * \test test tls (app layer) rule
5078
 */
5079
static int SigParseTestAppLayerTLS02(void)
5080
{
5081
    int result = 0;
5082
    DetectEngineCtx *de_ctx;
5083
    Signature *s=NULL;
5084

5085
    de_ctx = DetectEngineCtxInit();
5086
    if (de_ctx == NULL)
5087
        goto end;
5088
    de_ctx->flags |= DE_QUIET;
5089

5090
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5091
    if (s == NULL) {
5092
        printf("parsing sig failed: ");
5093
        goto end;
5094
    }
5095

5096
    if (s->alproto == 0) {
5097
        printf("alproto not set: ");
5098
        goto end;
5099
    }
5100

5101
    result = 1;
5102
end:
5103
    if (s != NULL)
5104
        SigFree(de_ctx, s);
5105
    if (de_ctx != NULL)
5106
        DetectEngineCtxFree(de_ctx);
5107
    return result;
5108
}
5109

5110
/**
5111
 * \test test tls (app layer) rule
5112
 */
5113
static int SigParseTestAppLayerTLS03(void)
5114
{
5115
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5116
    FAIL_IF_NULL(de_ctx);
5117
    de_ctx->flags |= DE_QUIET;
5118

5119
    Signature *s = DetectEngineAppendSig(de_ctx,
5120
            "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
5121
            "tls.version:2.5; sid:410006; rev:1;)");
5122
    FAIL_IF_NOT_NULL(s);
5123
    DetectEngineCtxFree(de_ctx);
5124
    PASS;
5125
}
5126

5127
static int SigParseTestUnbalancedQuotes01(void)
5128
{
5129
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5130
    FAIL_IF_NULL(de_ctx);
5131
    de_ctx->flags |= DE_QUIET;
5132
    Signature *s = DetectEngineAppendSig(de_ctx,
5133
            "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5134
            "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5135
            "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5136
    FAIL_IF_NOT_NULL(s);
5137
    DetectEngineCtxFree(de_ctx);
5138
    PASS;
5139
}
5140

5141
static int SigParseTestContentGtDsize01(void)
5142
{
5143
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5144
    FAIL_IF_NULL(de_ctx);
5145
    de_ctx->flags |= DE_QUIET;
5146
    Signature *s =
5147
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5148
                                          "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5149
                                          "sid:1; rev:1;)");
5150
    FAIL_IF_NOT_NULL(s);
5151
    DetectEngineCtxFree(de_ctx);
5152
    PASS;
5153
}
5154

5155
static int SigParseTestContentGtDsize02(void)
5156
{
5157
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5158
    FAIL_IF_NULL(de_ctx);
5159
    de_ctx->flags |= DE_QUIET;
5160
    Signature *s =
5161
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5162
                                          "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5163
                                          "sid:1; rev:1;)");
5164
    FAIL_IF_NOT_NULL(s);
5165
    DetectEngineCtxFree(de_ctx);
5166
    PASS;
5167
}
5168

5169
static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5170
{
5171
    int cnt = 0;
5172
    for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5173
        if (sid == s->id)
5174
            cnt++;
5175
    }
5176
    return cnt;
5177
}
5178

5179
static int SigParseBidirWithSameSrcAndDest01(void)
5180
{
5181
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5182
    FAIL_IF_NULL(de_ctx);
5183
    de_ctx->flags |= DE_QUIET;
5184

5185
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5186
    FAIL_IF_NULL(s);
5187
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5188
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5189

5190
    s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5191
    FAIL_IF_NULL(s);
5192
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5193
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5194

5195
    s = DetectEngineAppendSig(de_ctx,
5196
            "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5197
    FAIL_IF_NULL(s);
5198
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5199
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5200

5201
    DetectEngineCtxFree(de_ctx);
5202
    PASS;
5203
}
5204

5205
static int SigParseBidirWithSameSrcAndDest02(void)
5206
{
5207
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5208
    FAIL_IF_NULL(de_ctx);
5209
    de_ctx->flags |= DE_QUIET;
5210

5211
    // Source is a subset of destination
5212
    Signature *s = DetectEngineAppendSig(
5213
            de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5214
    FAIL_IF_NULL(s);
5215
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5216
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5217

5218
    // Source is a subset of destination
5219
    s = DetectEngineAppendSig(
5220
            de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5221
    FAIL_IF_NULL(s);
5222
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5223
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5224

5225
    // Source intersects with destination
5226
    s = DetectEngineAppendSig(de_ctx,
5227
            "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5228
    FAIL_IF_NULL(s);
5229
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5230
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5231

5232
    // mix in negation, these are the same
5233
    s = DetectEngineAppendSig(
5234
            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;)");
5235
    FAIL_IF_NULL(s);
5236
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5237
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5238

5239
    // mix in negation, these are not the same
5240
    s = DetectEngineAppendSig(
5241
            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;)");
5242
    FAIL_IF_NULL(s);
5243
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5244
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5245

5246
    DetectEngineCtxFree(de_ctx);
5247
    PASS;
5248
}
5249

5250
static int SigParseTestActionReject(void)
5251
{
5252
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5253
    FAIL_IF_NULL(de_ctx);
5254

5255
    Signature *sig = DetectEngineAppendSig(
5256
            de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5257
#ifdef HAVE_LIBNET11
5258
    FAIL_IF_NULL(sig);
5259
    FAIL_IF_NOT((sig->action & (ACTION_DROP | ACTION_REJECT)) == (ACTION_DROP | ACTION_REJECT));
5260
#else
5261
    FAIL_IF_NOT_NULL(sig);
5262
#endif
5263

5264
    DetectEngineCtxFree(de_ctx);
5265
    PASS;
5266
}
5267

5268
static int SigParseTestActionDrop(void)
5269
{
5270
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5271
    FAIL_IF_NULL(de_ctx);
5272

5273
    Signature *sig = DetectEngineAppendSig(
5274
            de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5275
    FAIL_IF_NULL(sig);
5276
    FAIL_IF_NOT(sig->action & ACTION_DROP);
5277

5278
    DetectEngineCtxFree(de_ctx);
5279
    PASS;
5280
}
5281

5282
static int SigSetMultiAppProto(void)
5283
{
5284
    Signature *s = SigAlloc();
5285
    FAIL_IF_NULL(s);
5286

5287
    AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5288
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5289

5290
    // check intersection gives multiple entries
5291
    alprotos[0] = 3;
5292
    alprotos[1] = 2;
5293
    alprotos[2] = ALPROTO_UNKNOWN;
5294
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5295
    FAIL_IF(s->init_data->alprotos[0] != 3);
5296
    FAIL_IF(s->init_data->alprotos[1] != 2);
5297
    FAIL_IF(s->init_data->alprotos[2] != ALPROTO_UNKNOWN);
5298

5299
    // check single after multiple
5300
    FAIL_IF(SCDetectSignatureSetAppProto(s, 3) < 0);
5301
    FAIL_IF(s->init_data->alprotos[0] != ALPROTO_UNKNOWN);
5302
    FAIL_IF(s->alproto != 3);
5303
    alprotos[0] = 4;
5304
    alprotos[1] = 3;
5305
    alprotos[2] = ALPROTO_UNKNOWN;
5306
    // check multiple containing singleton
5307
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5308
    FAIL_IF(s->alproto != 3);
5309

5310
    // reset
5311
    s->alproto = ALPROTO_UNKNOWN;
5312
    alprotos[0] = 1;
5313
    alprotos[1] = 2;
5314
    alprotos[2] = 3;
5315
    alprotos[3] = ALPROTO_UNKNOWN;
5316
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5317
    // fail if set single not in multiple
5318
    FAIL_IF(SCDetectSignatureSetAppProto(s, 4) >= 0);
5319

5320
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
5321
    s->alproto = ALPROTO_UNKNOWN;
5322
    alprotos[0] = 1;
5323
    alprotos[1] = 2;
5324
    alprotos[2] = 3;
5325
    alprotos[3] = ALPROTO_UNKNOWN;
5326
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5327
    alprotos[0] = 4;
5328
    alprotos[1] = 5;
5329
    alprotos[2] = ALPROTO_UNKNOWN;
5330
    // fail if multiple do not have intersection
5331
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5332

5333
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
5334
    s->alproto = ALPROTO_UNKNOWN;
5335
    alprotos[0] = 1;
5336
    alprotos[1] = 2;
5337
    alprotos[2] = 3;
5338
    alprotos[3] = ALPROTO_UNKNOWN;
5339
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5340
    alprotos[0] = 3;
5341
    alprotos[1] = 4;
5342
    alprotos[2] = 5;
5343
    alprotos[3] = ALPROTO_UNKNOWN;
5344
    // check multiple intersect to singleton
5345
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5346
    FAIL_IF(s->alproto != 3);
5347
    alprotos[0] = 5;
5348
    alprotos[1] = 4;
5349
    alprotos[2] = ALPROTO_UNKNOWN;
5350
    // fail if multiple do not belong to singleton
5351
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5352

5353
    SigFree(NULL, s);
5354
    PASS;
5355
}
5356

5357
static int DetectSetupDirection01(void)
5358
{
5359
    Signature *s = SigAlloc();
5360
    FAIL_IF_NULL(s);
5361
    // Basic case : ok
5362
    char *str = (char *)"to_client";
5363
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5364
    SigFree(NULL, s);
5365
    PASS;
5366
}
5367

5368
static int DetectSetupDirection02(void)
5369
{
5370
    Signature *s = SigAlloc();
5371
    FAIL_IF_NULL(s);
5372
    char *str = (char *)"to_server";
5373
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5374
    // ok so far
5375
    str = (char *)"to_client";
5376
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5377
    // fails because we cannot have both to_client and to_server for same signature
5378
    SigFree(NULL, s);
5379
    PASS;
5380
}
5381

5382
static int DetectSetupDirection03(void)
5383
{
5384
    Signature *s = SigAlloc();
5385
    FAIL_IF_NULL(s);
5386
    char *str = (char *)"to_client , something";
5387
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5388
    FAIL_IF(strcmp(str, "something") != 0);
5389
    str = (char *)"to_client,something";
5390
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5391
    FAIL_IF(strcmp(str, "something") != 0);
5392
    SigFree(NULL, s);
5393
    PASS;
5394
}
5395

5396
static int DetectSetupDirection04(void)
5397
{
5398
    Signature *s = SigAlloc();
5399
    FAIL_IF_NULL(s);
5400
    // invalid case
5401
    char *str = (char *)"to_client_toto";
5402
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5403
    // test we do not change the string pointer if only_dir is false
5404
    str = (char *)"to_client_toto";
5405
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5406
    FAIL_IF(strcmp(str, "to_client_toto") != 0);
5407
    str = (char *)"to_client,something";
5408
    // fails because we call with only_dir=true
5409
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5410
    SigFree(NULL, s);
5411
    PASS;
5412
}
5413

5414
#endif /* UNITTESTS */
5415

5416
#ifdef UNITTESTS
5417
void DetectParseRegisterTests (void);
5418
#include "tests/detect-parse.c"
5419
#endif
5420

5421
void SigParseRegisterTests(void)
UNCOV
5422
{
×
5423
#ifdef UNITTESTS
5424
    DetectParseRegisterTests();
5425

5426
    UtRegisterTest("SigParseTest01", SigParseTest01);
5427
    UtRegisterTest("SigParseTest02", SigParseTest02);
5428
    UtRegisterTest("SigParseTest03", SigParseTest03);
5429
    UtRegisterTest("SigParseTest04", SigParseTest04);
5430
    UtRegisterTest("SigParseTest05", SigParseTest05);
5431
    UtRegisterTest("SigParseTest06", SigParseTest06);
5432
    UtRegisterTest("SigParseTest07", SigParseTest07);
5433
    UtRegisterTest("SigParseTest08", SigParseTest08);
5434
    UtRegisterTest("SigParseTest09", SigParseTest09);
5435
    UtRegisterTest("SigParseTest10", SigParseTest10);
5436
    UtRegisterTest("SigParseTest11", SigParseTest11);
5437
    UtRegisterTest("SigParseTest12", SigParseTest12);
5438
    UtRegisterTest("SigParseTest13", SigParseTest13);
5439
    UtRegisterTest("SigParseTest14", SigParseTest14);
5440
    UtRegisterTest("SigParseTest15", SigParseTest15);
5441
    UtRegisterTest("SigParseTest16", SigParseTest16);
5442
    UtRegisterTest("SigParseTest17", SigParseTest17);
5443
    UtRegisterTest("SigParseTest18", SigParseTest18);
5444
    UtRegisterTest("SigParseTest19", SigParseTest19);
5445
    UtRegisterTest("SigParseTest20", SigParseTest20);
5446
    UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5447
    UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5448
    UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5449

5450
    UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5451
    UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5452
    UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5453
    UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5454
    UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5455
    UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5456
    UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5457
    UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5458
    UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5459
    UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5460
    UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5461
    UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5462
    UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5463
    UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5464
    UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5465
    UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5466
    UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5467
    UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5468
    UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5469
    UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5470
    UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5471
    UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5472
    UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5473
    UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5474
    UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5475
    UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5476
    UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5477

5478
    UtRegisterTest("SigParseTestContentGtDsize01",
5479
            SigParseTestContentGtDsize01);
5480
    UtRegisterTest("SigParseTestContentGtDsize02",
5481
            SigParseTestContentGtDsize02);
5482

5483
    UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5484
            SigParseBidirWithSameSrcAndDest01);
5485
    UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5486
            SigParseBidirWithSameSrcAndDest02);
5487
    UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5488
    UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5489

5490
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5491

5492
    UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5493
    UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5494
    UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5495
    UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5496

5497
#endif /* UNITTESTS */
UNCOV
5498
}
×
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