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

OISF / suricata / 23350122333

20 Mar 2026 03:33PM UTC coverage: 76.492% (-2.8%) from 79.315%
23350122333

Pull #15053

github

web-flow
Merge f5bf69f97 into 6587e363a
Pull Request #15053: Flow queue/v3

113 of 129 new or added lines in 9 files covered. (87.6%)

9534 existing lines in 453 files now uncovered.

256601 of 335461 relevant lines covered (76.49%)

4680806.66 hits per line

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

88.89
/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)
113
{
482✔
114
#define CASE_CODE_STRING(E, S)  case E: return S; break
482✔
115
    switch (list) {
482✔
116
        CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet");
156✔
117
        CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload");
275✔
118
        CASE_CODE_STRING(DETECT_SM_LIST_BASE64_DATA, "base64_data");
4✔
119
        CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch");
47✔
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");
×
123
        CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
482✔
124
    }
482✔
125
#undef CASE_CODE_STRING
×
126
    return "unknown";
×
127
}
482✔
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
{
1,444✔
150
    SigMatch *sm = NULL;
1,444✔
151
    int ret = -1;
1,444✔
152

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

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

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

226
    if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
1,422✔
227
        if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
1,028✔
UNCOV
228
            SCLogError("no matches for previous buffer");
×
UNCOV
229
            return -1;
×
UNCOV
230
        }
×
231
        bool reuse_buffer = false;
1,028✔
232
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
1,028✔
233
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
205✔
234
                if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
125✔
UNCOV
235
                    s->init_data->curbuf = &s->init_data->buffers[x];
×
UNCOV
236
                    reuse_buffer = true;
×
UNCOV
237
                    break;
×
UNCOV
238
                }
×
239
            }
125✔
240
        }
80✔
241

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

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

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

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

269
    ret = 0;
1,422✔
270
 end:
1,444✔
271
    return ret;
1,444✔
272
}
1,422✔
273

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

280
    sm->prev = NULL;
291,700✔
281
    sm->next = NULL;
291,700✔
282
    return sm;
291,700✔
283
}
291,700✔
284

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

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

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

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

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
57,372,334✔
317
        st = &sigmatch_table[i];
57,372,332✔
318

319
        if (st->name != NULL) {
57,372,332✔
320
            if (strcasecmp(name,st->name) == 0)
57,372,144✔
321
                return st;
1,193,113✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
56,179,031✔
323
                return st;
4,176✔
324
        }
56,179,031✔
325
    }
57,372,332✔
326

327
    return NULL;
2✔
328
}
1,197,291✔
329

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

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

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

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

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

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

377
    SCFree(copy);
1✔
378
}
1✔
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
{
291,682✔
390
    SigMatch *new = SigMatchAlloc();
291,682✔
391
    if (new == NULL)
291,682✔
392
        return NULL;
×
393

394
    new->type = type;
291,682✔
395
    new->ctx = ctx;
291,682✔
396

397
    if (new->type == DETECT_CONTENT) {
291,682✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
186,723✔
399
    }
186,723✔
400

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

405
    if (list < DETECT_SM_LIST_MAX) {
291,682✔
406
        if (s->init_data->smlists[list] == NULL) {
101,390✔
407
            s->init_data->smlists[list] = new;
77,822✔
408
            s->init_data->smlists_tail[list] = new;
77,822✔
409
            new->next = NULL;
77,822✔
410
            new->prev = NULL;
77,822✔
411
        } else {
77,822✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
23,568✔
413
            cur->next = new;
23,568✔
414
            new->prev = cur;
23,568✔
415
            new->next = NULL;
23,568✔
416
            s->init_data->smlists_tail[list] = new;
23,568✔
417
        }
23,568✔
418
        new->idx = s->init_data->sm_cnt;
101,390✔
419
        s->init_data->sm_cnt++;
101,390✔
420

421
    } else {
192,836✔
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) {
190,292✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
42✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
42✔
429
        }
42✔
430

431
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) {
190,292✔
432
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
207✔
433
                if (s->init_data->buffers[x].id == (uint32_t)list &&
119✔
434
                        !s->init_data->buffers[x].multi_capable) {
119✔
435
                    SCLogDebug("reusing buffer %u as it isn't multi-capable", x);
1✔
436
                    s->init_data->curbuf = &s->init_data->buffers[x];
1✔
437
                    break;
1✔
438
                }
1✔
439
            }
119✔
440
        }
89✔
441

442
        if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
190,292✔
443
                s->init_data->curbuf == NULL) {
190,292✔
444
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
3,979✔
UNCOV
445
                SCLogError("failed to expand rule buffer array");
×
UNCOV
446
                new->ctx = NULL;
×
UNCOV
447
                SigMatchFree(de_ctx, new);
×
UNCOV
448
                return NULL;
×
449
            } else {
3,979✔
450
                /* initialize new buffer */
451
                s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
3,979✔
452
                s->init_data->curbuf->id = list;
3,979✔
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;
3,979✔
456
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT) {
3,979✔
457
                    s->init_data->curbuf->only_tc = true;
2✔
458
                }
2✔
459
                if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOSERVER) {
3,979✔
460
                    s->init_data->curbuf->only_ts = true;
×
461
                }
×
462
                SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
3,979✔
463
            }
3,979✔
464
        }
3,979✔
465
        BUG_ON(s->init_data->curbuf == NULL);
190,292✔
466

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

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
562,665✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
372,373✔
480
                    sigmatch_table[sm->type].name, sm->idx);
372,373✔
481
        }
372,373✔
482
    }
190,292✔
483
    return new;
291,682✔
484
}
291,682✔
485

486
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487
{
25✔
488
    if (sm == s->init_data->smlists[sm_list]) {
25✔
489
        s->init_data->smlists[sm_list] = sm->next;
25✔
490
    }
25✔
491
    if (sm == s->init_data->smlists_tail[sm_list]) {
25✔
492
        s->init_data->smlists_tail[sm_list] = sm->prev;
25✔
493
    }
25✔
494
    if (sm->prev != NULL)
25✔
UNCOV
495
        sm->prev->next = sm->next;
×
496
    if (sm->next != NULL)
25✔
UNCOV
497
        sm->next->prev = sm->prev;
×
498
}
25✔
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
{
447,821✔
511
    while (sm != NULL) {
762,716✔
512
        if (sm->type == type) {
636,429✔
513
            return sm;
321,534✔
514
        }
321,534✔
515
        sm = sm->prev;
314,895✔
516
    }
314,895✔
517

518
    return NULL;
126,287✔
519
}
447,821✔
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
{
36,804✔
528
    SigMatch *sm_last = NULL;
36,804✔
529
    SigMatch *sm_new;
36,804✔
530
    uint32_t sm_type;
36,804✔
531

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
88,895✔
533
        const int id = s->init_data->buffers[i].id;
52,091✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
52,091✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
52,068✔
536
            if (sm_new == NULL)
52,068✔
537
                continue;
735✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
51,333✔
539
                sm_last = sm_new;
50,711✔
540
        }
51,333✔
541
    }
52,091✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
294,432✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
257,628✔
545
            continue;
257,628✔
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;
36,804✔
555
}
36,804✔
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
{
208,098✔
565
    SigMatch *sm_last = NULL;
208,098✔
566
    SigMatch *sm_new;
208,098✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
208,098✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
475,194✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
267,096✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
267,096✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
97,079✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
97,079✔
574

575
            continue;
97,079✔
576
        }
97,079✔
577
        int sm_type;
170,017✔
578
        va_list ap;
170,017✔
579
        va_start(ap, s);
170,017✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
342,210✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
172,193✔
583
            if (sm_new == NULL)
172,193✔
584
                continue;
3,080✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
169,113✔
586
                sm_last = sm_new;
169,091✔
587
        }
169,113✔
588
        va_end(ap);
170,017✔
589
    }
170,017✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
1,664,784✔
592
        if (s->init_data->smlists[buf_type] == NULL)
1,456,686✔
593
            continue;
1,244,692✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
211,994✔
595
            buf_type != s->init_data->list)
211,994✔
596
            continue;
142,196✔
597

598
        int sm_type;
69,798✔
599
        va_list ap;
69,798✔
600
        va_start(ap, s);
69,798✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
186,635✔
603
        {
116,837✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
116,837✔
605
            if (sm_new == NULL)
116,837✔
606
                continue;
76,388✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
40,449✔
608
                sm_last = sm_new;
36,346✔
609
        }
40,449✔
610
        va_end(ap);
69,798✔
611
    }
69,798✔
612

613
    return sm_last;
208,098✔
614
}
208,098✔
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
{
104,597✔
627
    SigMatch *sm_last = NULL;
104,597✔
628
    SigMatch *sm_new;
104,597✔
629
    int sm_type;
104,597✔
630

631
    va_list ap;
104,597✔
632
    va_start(ap, sm_list);
104,597✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
261,723✔
635
    {
157,126✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
157,126✔
637
        if (sm_new == NULL)
157,126✔
638
            continue;
46,670✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
110,456✔
640
            sm_last = sm_new;
105,597✔
641
    }
110,456✔
642

643
    va_end(ap);
104,597✔
644

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

663
    if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
1,760✔
664
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
164✔
665
            sm_new = s->init_data->buffers[x].tail;
98✔
666
            if (sm_new == NULL)
98✔
667
                continue;
14✔
668

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

672
            for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
168✔
673
                sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
84✔
674
                if (sm_new == NULL)
84✔
675
                    continue;
67✔
676
                if (sm_last == NULL || sm_new->idx > sm_last->idx)
17✔
677
                    sm_last = sm_new;
17✔
678
            }
17✔
679

680
            va_end(ap);
84✔
681
        }
84✔
682
    } else {
1,694✔
683
        SigMatch *sm_list = s->init_data->smlists_tail[list_id];
1,694✔
684
        if (sm_list == NULL)
1,694✔
685
            return NULL;
113✔
686

687
        va_list ap;
1,581✔
688
        va_start(ap, list_id);
1,581✔
689

690
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
3,162✔
691
            sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
1,581✔
692
            if (sm_new == NULL)
1,581✔
693
                continue;
82✔
694
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
1,499✔
695
                sm_last = sm_new;
1,499✔
696
        }
1,499✔
697

698
        va_end(ap);
1,581✔
699
    }
1,581✔
700
    return sm_last;
1,647✔
701
}
1,760✔
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
{
60✔
710
    SigMatch *sm_last = NULL;
60✔
711
    SigMatch *sm_new;
60✔
712

713
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
70✔
714
        sm_new = s->init_data->buffers[x].tail;
10✔
715
        if (sm_new == NULL)
10✔
UNCOV
716
            continue;
×
717
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
10✔
718
            sm_last = sm_new;
10✔
719
    }
10✔
720

721
    for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
480✔
722
        sm_new = s->init_data->smlists_tail[i];
420✔
723
        if (sm_new == NULL)
420✔
724
            continue;
357✔
725
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
63✔
726
            sm_last = sm_new;
54✔
727
    }
63✔
728

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

738
    if (sm->prev != NULL)
1,422✔
739
        sm->prev->next = sm->next;
21✔
740
    if (sm->next != NULL)
1,422✔
UNCOV
741
        sm->next->prev = sm->prev;
×
742

743
    if (sm == *src_sm_list)
1,422✔
744
        *src_sm_list = sm->next;
1,401✔
745
    if (sm == *src_sm_list_tail)
1,422✔
746
        *src_sm_list_tail = sm->prev;
1,422✔
747

748
    if (*dst_sm_list == NULL) {
1,422✔
749
        *dst_sm_list = sm;
1,028✔
750
        *dst_sm_list_tail = sm;
1,028✔
751
        sm->next = NULL;
1,028✔
752
        sm->prev = NULL;
1,028✔
753
    } else {
1,028✔
754
        SigMatch *cur = *dst_sm_list_tail;
394✔
755
        cur->next = sm;
394✔
756
        sm->prev = cur;
394✔
757
        sm->next = NULL;
394✔
758
        *dst_sm_list_tail = sm;
394✔
759
    }
394✔
760
}
1,422✔
761

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

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
59,535✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
51,303✔
769
        while (sm != NULL) {
85,891✔
770
            if (sm == key_sm)
66,669✔
771
                return s->init_data->buffers[x].id;
32,081✔
772
            sm = sm->next;
34,588✔
773
        }
34,588✔
774
    }
51,303✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
16,464✔
777
        const SigMatch *sm = s->init_data->smlists[list];
16,464✔
778
        while (sm != NULL) {
43,346✔
779
            if (sm == key_sm)
35,114✔
780
                return list;
8,232✔
781
            sm = sm->next;
26,882✔
782
        }
26,882✔
783
    }
16,464✔
784

785
    SCLogError("Unable to find the sm in any of the "
×
786
               "sm lists");
×
787
    return -1;
×
788
}
8,232✔
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
{
20✔
801
    char *orig = *str;
20✔
802
    if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
20✔
803
        *str += strlen("to_client");
14✔
804
        // skip space
805
        while (**str && isblank(**str)) {
15✔
806
            (*str)++;
1✔
807
        }
1✔
808
        // check comma or nothing
809
        if (**str) {
14✔
810
            if (only_dir) {
7✔
811
                SCLogError("unknown option: only accepts to_server or to_client");
2✔
812
                return -1;
2✔
813
            }
2✔
814
            if (**str != ',') {
5✔
815
                // leave to_client_something for next parser if not only_dir
816
                *str = orig;
1✔
817
                return 0;
1✔
818
            } else {
4✔
819
                (*str)++;
4✔
820
            }
4✔
821
            while (**str && isblank(**str)) {
7✔
822
                (*str)++;
3✔
823
            }
3✔
824
        }
4✔
825
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
11✔
826
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
11✔
827
            if (s->flags & SIG_FLAG_TOSERVER) {
4✔
828
                SCLogError("contradictory directions");
1✔
829
                return -1;
1✔
830
            }
1✔
831
            s->flags |= SIG_FLAG_TOCLIENT;
3✔
832
        }
3✔
833
    } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
11✔
834
        *str += strlen("to_server");
3✔
835
        // skip space
836
        while (**str && isblank(**str)) {
3✔
UNCOV
837
            (*str)++;
×
UNCOV
838
        }
×
839
        // check comma or nothing
840
        if (**str) {
3✔
UNCOV
841
            if (only_dir) {
×
UNCOV
842
                SCLogError("unknown option: only accepts to_server or to_client");
×
UNCOV
843
                return -1;
×
UNCOV
844
            }
×
UNCOV
845
            if (**str != ',') {
×
846
                // leave to_client_something for next parser if not only_dir
UNCOV
847
                *str = orig;
×
UNCOV
848
                return 0;
×
UNCOV
849
            } else {
×
850
                (*str)++;
×
851
            }
×
852
            while (**str && isblank(**str)) {
×
853
                (*str)++;
×
854
            }
×
855
        }
×
856
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOSERVER;
3✔
857
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
3✔
858
            if (s->flags & SIG_FLAG_TOCLIENT) {
1✔
UNCOV
859
                SCLogError("contradictory directions");
×
UNCOV
860
                return -1;
×
UNCOV
861
            }
×
862
            s->flags |= SIG_FLAG_TOSERVER;
1✔
863
        }
1✔
864
    } else if (only_dir) {
3✔
UNCOV
865
        SCLogError("unknown option: only accepts to_server or to_client");
×
UNCOV
866
        return -1;
×
UNCOV
867
    }
×
868
    return 0;
16✔
869
}
20✔
870

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

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
2,394,245✔
880
        optstr++;
2,102,258✔
881
    }
2,102,258✔
882

883
    /* Look for the end of this option, handling escaped semicolons. */
884
    char *optend = optstr;
2,394,245✔
885
    for (;;) {
2,394,361✔
886
        optend = strchr(optend, ';');
2,394,361✔
887
        if (optend == NULL) {
2,394,361✔
UNCOV
888
            SCLogError("no terminating \";\" found");
×
UNCOV
889
            goto error;
×
UNCOV
890
        }
×
891
        else if (optend > optstr && *(optend -1 ) == '\\') {
2,394,361✔
892
            optend++;
116✔
893
        } else {
2,394,245✔
894
            break;
2,394,245✔
895
        }
2,394,245✔
896
    }
2,394,361✔
897
    *(optend++) = '\0';
2,394,245✔
898

899
    /* Find the start of the option value. */
900
    char *optvalptr = strchr(optstr, ':');
2,394,245✔
901
    if (optvalptr) {
2,394,245✔
902
        *(optvalptr++) = '\0';
1,903,822✔
903

904
        /* Trim trailing space from name. */
905
        for (size_t i = strlen(optvalptr); i > 0; i--) {
1,903,922✔
906
            if (isblank(optvalptr[i - 1])) {
1,903,918✔
907
                optvalptr[i - 1] = '\0';
100✔
908
            } else {
1,903,818✔
909
                break;
1,903,818✔
910
            }
1,903,818✔
911
        }
1,903,918✔
912

913
        optvalue = optvalptr;
1,903,822✔
914
    }
1,903,822✔
915

916
    /* Trim trailing space from name. */
917
    for (size_t i = strlen(optstr); i > 0; i--) {
2,394,245✔
918
        if (isblank(optstr[i - 1])) {
2,394,243✔
UNCOV
919
            optstr[i - 1] = '\0';
×
920
        } else {
2,394,243✔
921
            break;
2,394,243✔
922
        }
2,394,243✔
923
    }
2,394,243✔
924
    optname = optstr;
2,394,245✔
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;
2,394,245✔
929
    if ((requires && !requires_only) || (!requires && requires_only)) {
2,394,245✔
930
        goto finish;
1,196,955✔
931
    }
1,196,955✔
932

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

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
1,197,288✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
951,505✔
942
            SCLogError(
3✔
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
3✔
944
            goto error;
3✔
945
        }
3✔
946
    } else if (st->flags & SIGMATCH_NOOPT) {
951,505✔
947
        if (optvalue && strlen(optvalue)) {
199,879✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
3✔
949
            goto error;
3✔
950
        }
3✔
951
    }
199,879✔
952
    s->init_data->negated = false;
1,197,282✔
953

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

957
    if (st->flags & SIGMATCH_INFO_DEPRECATED) {
1,197,282✔
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;
1,197,282✔
972

973
    /* Validate double quoting, trimming trailing white space along the way. */
974
    if (optvalue != NULL && strlen(optvalue) > 0) {
1,197,282✔
975
        size_t ovlen = strlen(optvalue);
952,078✔
976
        char *ptr = optvalue;
952,078✔
977

978
        /* skip leading whitespace */
979
        while (ovlen > 0) {
1,085,757✔
980
            if (!isblank(*ptr))
1,085,757✔
981
                break;
952,078✔
982
            ptr++;
133,679✔
983
            ovlen--;
133,679✔
984
        }
133,679✔
985
        if (ovlen == 0) {
952,078✔
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) {
952,078✔
992
            SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
2✔
993
        }
2✔
994

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

1021
        if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
952,075✔
1022
                && ovlen && *ptr == '"')
952,075✔
1023
        {
345,829✔
1024
            for (; ovlen > 0; ovlen--) {
345,829✔
1025
                if (isblank(ptr[ovlen - 1])) {
345,829✔
1026
                    ptr[ovlen - 1] = '\0';
×
1027
                } else {
345,829✔
1028
                    break;
345,829✔
1029
                }
345,829✔
1030
            }
345,829✔
1031
            if (ovlen && ptr[ovlen - 1] != '"') {
345,829✔
1032
                SCLogError("bad option value formatting (possible missing semicolon) "
4✔
1033
                           "for keyword %s: \'%s\'",
4✔
1034
                        optname, optvalue);
4✔
1035
                goto error;
4✔
1036
            }
4✔
1037
            if (ovlen > 1) {
345,825✔
1038
                /* strip leading " */
1039
                ptr++;
345,823✔
1040
                ovlen--;
345,823✔
1041
                ptr[ovlen - 1] = '\0';
345,823✔
1042
                ovlen--;
345,823✔
1043
            }
345,823✔
1044
            if (ovlen == 0) {
345,825✔
1045
                SCLogError("bad input "
1✔
1046
                           "for keyword %s: \'%s\'",
1✔
1047
                        optname, optvalue);
1✔
1048
                goto error;
1✔
1049
            }
1✔
1050
        } else {
606,246✔
1051
            if (*ptr == '"') {
606,246✔
1052
                SCLogError(
1✔
1053
                        "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1✔
1054
                goto error;
1✔
1055
            }
1✔
1056
        }
606,246✔
1057
        /* setup may or may not add a new SigMatch to the list */
1058
        if (st->flags & SIGMATCH_SUPPORT_DIR) {
952,069✔
1059
            if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
12✔
UNCOV
1060
                SCLogError("%s failed to setup direction", st->name);
×
UNCOV
1061
                goto error;
×
UNCOV
1062
            }
×
1063
        }
12✔
1064
        setup_ret = st->Setup(de_ctx, s, ptr);
952,069✔
1065
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
952,069✔
1066
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
952,069✔
1067
    } else {
952,069✔
1068
        /* setup may or may not add a new SigMatch to the list */
1069
        setup_ret = st->Setup(de_ctx, s, NULL);
245,204✔
1070
    }
245,204✔
1071
    if (setup_ret < 0) {
1,197,273✔
1072
        SCLogDebug("\"%s\" failed to setup", st->name);
636✔
1073

1074
        /* handle 'silent' error case */
1075
        if (setup_ret == -2) {
636✔
1076
            if (!de_ctx->sm_types_silent_error[idx]) {
6✔
1077
                de_ctx->sm_types_silent_error[idx] = true;
5✔
1078
                return -1;
5✔
1079
            }
5✔
1080
            return -2;
1✔
1081
        }
6✔
1082
        return setup_ret;
630✔
1083
    }
636✔
1084
    s->init_data->negated = false;
1,196,637✔
1085

1086
finish:
2,393,584✔
1087
    if (strlen(optend) > 0) {
2,393,584✔
1088
        strlcpy(output, optend, output_size);
2,098,427✔
1089
        return 1;
2,098,427✔
1090
    }
2,098,427✔
1091

1092
    return 0;
295,157✔
1093

1094
error:
17✔
1095
    return -1;
17✔
1096
}
2,393,584✔
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
{
295,787✔
1105
    SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
295,787✔
1106

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
295,787✔
1109
        if (strcasecmp(addrstr, "any") == 0)
147,896✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
79,521✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
147,896✔
1113
                &s->init_data->src_contains_negation);
147,896✔
1114
        if (s->init_data->src == NULL)
147,896✔
1115
            goto error;
5✔
1116
    } else {
147,896✔
1117
        if (strcasecmp(addrstr, "any") == 0)
147,891✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
27,268✔
1119

1120
        s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
147,891✔
1121
                &s->init_data->dst_contains_negation);
147,891✔
1122
        if (s->init_data->dst == NULL)
147,891✔
1123
            goto error;
2✔
1124
    }
147,891✔
1125

1126
    return 0;
295,780✔
1127

1128
error:
7✔
1129
    return -1;
7✔
1130
}
295,787✔
1131

1132
static bool IsBuiltIn(const char *n)
1133
{
68,882✔
1134
    if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
68,882✔
1135
        return true;
4,444✔
1136
    }
4,444✔
1137
    if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
64,438✔
1138
        return true;
4,444✔
1139
    }
4,444✔
1140
    return false;
59,994✔
1141
}
64,438✔
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
{
2,222✔
1153
    for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
86,657✔
1154
        const char *alproto_name = AppProtoToString(a);
84,435✔
1155
        if (strcmp(alproto_name, "http") == 0)
84,435✔
1156
            alproto_name = "http1";
2,222✔
1157
        SCLogDebug("alproto %u/%s", a, alproto_name);
84,435✔
1158

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

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

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

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

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

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

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

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

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

1302
static SignatureHook SetAppHook(const AppProto alproto, int progress)
1303
{
202✔
1304
    SignatureHook h = {
202✔
1305
        .type = SIGNATURE_HOOK_TYPE_APP,
202✔
1306
        .t.app.alproto = alproto,
202✔
1307
        .t.app.app_progress = progress,
202✔
1308
    };
202✔
1309
    return h;
202✔
1310
}
202✔
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
{
202✔
1317
    if (strcmp(h, "request_started") == 0) {
202✔
1318
        s->flags |= SIG_FLAG_TOSERVER;
17✔
1319
        s->init_data->hook =
17✔
1320
                SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
17✔
1321
    } else if (strcmp(h, "response_started") == 0) {
185✔
1322
        s->flags |= SIG_FLAG_TOCLIENT;
12✔
1323
        s->init_data->hook =
12✔
1324
                SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
12✔
1325
    } else if (strcmp(h, "request_complete") == 0) {
173✔
1326
        s->flags |= SIG_FLAG_TOSERVER;
21✔
1327
        s->init_data->hook = SetAppHook(s->alproto,
21✔
1328
                AppLayerParserGetStateProgressCompletionStatus(s->alproto, STREAM_TOSERVER));
21✔
1329
    } else if (strcmp(h, "response_complete") == 0) {
160✔
1330
        s->flags |= SIG_FLAG_TOCLIENT;
12✔
1331
        s->init_data->hook = SetAppHook(s->alproto,
12✔
1332
                AppLayerParserGetStateProgressCompletionStatus(s->alproto, STREAM_TOCLIENT));
12✔
1333
    } else {
140✔
1334
        const int progress_ts = AppLayerParserGetStateIdByName(
140✔
1335
                IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
140✔
1336
        if (progress_ts >= 0) {
140✔
1337
            s->flags |= SIG_FLAG_TOSERVER;
82✔
1338
            s->init_data->hook = SetAppHook(s->alproto, progress_ts);
82✔
1339
        } else {
82✔
1340
            const int progress_tc = AppLayerParserGetStateIdByName(
58✔
1341
                    IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
58✔
1342
            if (progress_tc < 0) {
58✔
UNCOV
1343
                return -1;
×
UNCOV
1344
            }
×
1345
            s->flags |= SIG_FLAG_TOCLIENT;
58✔
1346
            s->init_data->hook = SetAppHook(s->alproto, progress_tc);
58✔
1347
        }
58✔
1348
    }
140✔
1349

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

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

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

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

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

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

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

1409
    int r = DetectProtoParse(&s->proto, p);
147,905✔
1410
    if (r < 0) {
147,905✔
1411
        s->alproto = AppLayerGetProtoByName(p);
69,424✔
1412
        /* indicate that the signature is app-layer */
1413
        if (s->alproto != ALPROTO_UNKNOWN) {
69,424✔
1414
            s->flags |= SIG_FLAG_APPLAYER;
69,423✔
1415

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
69,423✔
1417

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

1437
        if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
144✔
UNCOV
1438
            SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
×
UNCOV
1439
            SCReturnInt(-1);
×
UNCOV
1440
        }
×
1441
    }
144✔
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) {
147,904✔
1446
        s->flags |= SIG_FLAG_REQUIRE_PACKET;
501✔
1447
    } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
147,403✔
1448
        s->flags |= SIG_FLAG_REQUIRE_STREAM;
45✔
1449
    }
45✔
1450

1451
    SCReturnInt(0);
147,904✔
1452
}
147,905✔
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
{
295,776✔
1469
    int r = 0;
295,776✔
1470

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

1473
    SCLogDebug("Port group \"%s\" to be parsed", portstr);
295,776✔
1474

1475
    if (flag == 0) {
295,776✔
1476
        if (strcasecmp(portstr, "any") == 0)
147,889✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
146,729✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
147,889✔
1480
    } else if (flag == 1) {
147,889✔
1481
        if (strcasecmp(portstr, "any") == 0)
147,887✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
143,796✔
1483

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

1487
    if (r < 0)
295,776✔
1488
        return -1;
6✔
1489

1490
    return 0;
295,770✔
1491
}
295,776✔
1492

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

1516
/** \retval 0 on error
1517
 *  \retval flags on success
1518
 */
1519
static uint8_t ActionStringToFlags(const char *action)
1520
{
147,905✔
1521
    if (strcasecmp(action, "alert") == 0) {
147,905✔
1522
        return ACTION_ALERT;
147,241✔
1523
    } else if (strcasecmp(action, "drop") == 0) {
147,247✔
1524
        return ACTION_DROP | ACTION_ALERT;
270✔
1525
    } else if (strcasecmp(action, "pass") == 0) {
403✔
1526
        return ACTION_PASS;
101✔
1527
    } else if (strcasecmp(action, "reject") == 0 ||
308✔
1528
               strcasecmp(action, "rejectsrc") == 0)
293✔
1529
    {
7✔
1530
        if (!(SigParseActionRejectValidate(action)))
7✔
1531
            return 0;
×
1532
        return ACTION_REJECT | ACTION_DROP | ACTION_ALERT;
7✔
1533
    } else if (strcasecmp(action, "rejectdst") == 0) {
288✔
1534
        if (!(SigParseActionRejectValidate(action)))
1✔
1535
            return 0;
×
1536
        return ACTION_REJECT_DST | ACTION_DROP | ACTION_ALERT;
1✔
1537
    } else if (strcasecmp(action, "rejectboth") == 0) {
285✔
1538
        if (!(SigParseActionRejectValidate(action)))
1✔
1539
            return 0;
×
1540
        return ACTION_REJECT_BOTH | ACTION_DROP | ACTION_ALERT;
1✔
1541
    } else if (strcasecmp(action, "config") == 0) {
284✔
1542
        return ACTION_CONFIG;
5✔
1543
    } else if (strcasecmp(action, "accept") == 0) {
280✔
1544
        return ACTION_ACCEPT;
279✔
1545
    } else {
279✔
UNCOV
1546
        SCLogError("An invalid action \"%s\" was given", action);
×
UNCOV
1547
        return 0;
×
UNCOV
1548
    }
×
1549
}
147,905✔
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
{
147,905✔
1564
    char action[32];
147,905✔
1565
    strlcpy(action, action_in, sizeof(action));
147,905✔
1566
    const char *a = action;
147,905✔
1567
    const char *o = NULL;
147,905✔
1568

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

1581
    uint8_t flags = ActionStringToFlags(a);
147,905✔
1582
    if (flags == 0)
147,905✔
UNCOV
1583
        return -1;
×
1584

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

1634
    /* require explicit action scope for fw rules */
1635
    if (s->init_data->firewall_rule && s->action_scope == 0) {
147,905✔
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)) {
147,905✔
UNCOV
1641
        SCLogError("'accept' action only supported for firewall rules");
×
UNCOV
1642
        return -1;
×
UNCOV
1643
    }
×
1644

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

1650
    s->action = flags;
147,905✔
1651
    return 0;
147,905✔
1652
}
147,905✔
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
{
591,680✔
1668
    size_t len = *input == NULL ? 0 : strlen(*input);
591,680✔
1669

1670
    if (!len) {
591,680✔
UNCOV
1671
        return 0;
×
UNCOV
1672
    }
×
1673

1674
    while (len && isblank(**input)) {
591,684✔
1675
        (*input)++;
4✔
1676
        len--;
4✔
1677
    }
4✔
1678

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

1686
    return 1;
591,680✔
1687
}
591,680✔
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
{
1,479,200✔
1703
    int in_list = 0;
1,479,200✔
1704
    size_t len = *input != NULL ? strlen(*input) : 0;
1,479,200✔
1705

1706
    if (len == 0) {
1,479,200✔
UNCOV
1707
        return 0;
×
UNCOV
1708
    }
×
1709

1710
    while (len && isblank(**input)) {
1,479,206✔
1711
        (*input)++;
6✔
1712
        len--;
6✔
1713
    }
6✔
1714

1715
    size_t i = 0;
1,479,200✔
1716
    for (i = 0; i < len; i++) {
9,180,511✔
1717
        char c = (*input)[i];
9,180,511✔
1718
        if (c == '[') {
9,180,511✔
1719
            in_list++;
4,762✔
1720
        } else if (c == ']') {
9,175,749✔
1721
            in_list--;
4,762✔
1722
        } else if (c == ' ') {
9,170,987✔
1723
            if (!in_list) {
1,479,356✔
1724
                break;
1,479,200✔
1725
            }
1,479,200✔
1726
        }
1,479,356✔
1727
    }
9,180,511✔
1728
    if (i == len) {
1,479,200✔
UNCOV
1729
        *input = NULL;
×
UNCOV
1730
        return 0;
×
UNCOV
1731
    }
×
1732
    (*input)[i] = '\0';
1,479,200✔
1733
    strlcpy(output, *input, output_size);
1,479,200✔
1734
    *input = *input + i + 1;
1,479,200✔
1735

1736
    return 1;
1,479,200✔
1737
}
1,479,200✔
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
{
295,840✔
1748
    char *index, dup[DETECT_MAX_RULE_SIZE];
295,840✔
1749

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
295,840✔
1751
    index = dup;
295,840✔
1752

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

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

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

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

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

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

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

1774
    /* Options. */
1775
    if (index == NULL) {
295,840✔
UNCOV
1776
        SCLogError("no rule options.");
×
UNCOV
1777
        goto error;
×
UNCOV
1778
    }
×
1779
    while (isspace(*index) || *index == '(') {
591,971✔
1780
        index++;
296,131✔
1781
    }
296,131✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
591,847✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
591,847✔
1784
            index[i - 1] = '\0';
296,007✔
1785
        } else {
296,007✔
1786
            break;
295,840✔
1787
        }
295,840✔
1788
    }
591,847✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
295,840✔
1790

1791
    if (scan_only) {
295,840✔
1792
        return 0;
147,935✔
1793
    }
147,935✔
1794

1795
    /* Parse Action */
1796
    if (SigParseAction(s, parser->action) < 0)
147,905✔
UNCOV
1797
        goto error;
×
1798

1799
    if (SigParseProto(s, parser->protocol) < 0)
147,905✔
1800
        goto error;
1✔
1801

1802
    if (strcmp(parser->direction, "<>") == 0) {
147,904✔
1803
        s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC;
159✔
1804
    } else if (strcmp(parser->direction, "=>") == 0) {
147,745✔
1805
        if (s->flags & SIG_FLAG_FIREWALL) {
23✔
1806
            SCLogError("transactional bidirectional rules not supported for firewall rules");
×
1807
            goto error;
×
1808
        }
×
1809

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

1818
    /* Parse Address & Ports */
1819
    if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
147,896✔
1820
       goto error;
5✔
1821

1822
    if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
147,891✔
1823
        goto error;
2✔
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)
147,889✔
1830
        goto error;
2✔
1831
    if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
147,887✔
1832
        goto error;
4✔
1833

1834
    return 0;
147,883✔
1835

1836
error:
22✔
1837
    return -1;
22✔
1838
}
147,887✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
295,840✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
98,842,531✔
1843
        if (str[i] < 0x20) {
98,546,691✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
44✔
1846
                continue;
44✔
1847
            }
44✔
UNCOV
1848
            return false;
×
1849
        } else if (str[i] == 0x7f) {
98,546,647✔
UNCOV
1850
            return false;
×
UNCOV
1851
        }
×
1852
    }
98,546,691✔
1853
    return true;
295,840✔
1854
}
295,840✔
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
{
295,840✔
1871
    SCEnter();
295,840✔
1872

1873
    if (!SCCheckUtf8(sigstr)) {
295,840✔
UNCOV
1874
        SCLogError("rule is not valid UTF-8");
×
UNCOV
1875
        SCReturnInt(-1);
×
UNCOV
1876
    }
×
1877

1878
    if (!CheckAscii(sigstr)) {
295,840✔
UNCOV
1879
        SCLogError("rule contains invalid (control) characters");
×
UNCOV
1880
        SCReturnInt(-1);
×
UNCOV
1881
    }
×
1882

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

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

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

1908
        } while (ret == 1);
2,394,245✔
1909

1910
        if (ret < 0) {
295,818✔
1911
            /* Suricata didn't meet the rule requirements, skip. */
1912
            goto end;
653✔
1913
        }
653✔
1914
    }
295,818✔
1915

1916
end:
295,810✔
1917
    DetectIPProtoRemoveAllSMs(de_ctx, s);
295,810✔
1918

1919
    SCReturnInt(ret);
295,810✔
1920
}
295,818✔
1921

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

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

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

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

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

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

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

1975
    sig->init_data->list = DETECT_SM_LIST_NOTSET;
147,986✔
1976
    return sig;
147,986✔
1977
}
147,986✔
1978

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

1989
    DetectMetadata *mdata = NULL;
147,952✔
1990
    DetectMetadata *next_mdata = NULL;
147,952✔
1991

1992
    if (s == NULL || s->metadata == NULL) {
147,952✔
1993
        SCReturn;
112,321✔
1994
    }
112,321✔
1995

1996
    SCLogDebug("s %p, s->metadata %p", s, s->metadata);
35,631✔
1997

1998
    for (mdata = s->metadata->list; mdata != NULL;)   {
303,971✔
1999
        next_mdata = mdata->next;
268,340✔
2000
        DetectMetadataFree(mdata);
268,340✔
2001
        mdata = next_mdata;
268,340✔
2002
    }
268,340✔
2003
    SCFree(s->metadata->json_str);
35,631✔
2004
    SCFree(s->metadata);
35,631✔
2005
    s->metadata = NULL;
35,631✔
2006

2007
    SCReturn;
35,631✔
2008
}
147,952✔
2009

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

2020
    DetectReference *ref = NULL;
147,952✔
2021
    DetectReference *next_ref = NULL;
147,952✔
2022

2023
    if (s == NULL) {
147,952✔
2024
        SCReturn;
×
2025
    }
×
2026

2027
    SCLogDebug("s %p, s->references %p", s, s->references);
147,952✔
2028

2029
    for (ref = s->references; ref != NULL;)   {
224,683✔
2030
        next_ref = ref->next;
76,731✔
2031
        DetectReferenceFree(ref);
76,731✔
2032
        ref = next_ref;
76,731✔
2033
    }
76,731✔
2034

2035
    s->references = NULL;
147,952✔
2036

2037
    SCReturn;
147,952✔
2038
}
147,952✔
2039

2040
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041
{
147,952✔
2042
    if (s != NULL) {
147,952✔
2043
        int type;
147,952✔
2044
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
1,183,616✔
2045
            if (s->sm_arrays[type] != NULL) {
1,035,664✔
2046
                if (ctxs) {
74,845✔
2047
                    SigMatchData *smd = s->sm_arrays[type];
74,845✔
2048
                    while(1) {
97,839✔
2049
                        if (sigmatch_table[smd->type].Free != NULL) {
97,839✔
2050
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
97,815✔
2051
                        }
97,815✔
2052
                        if (smd->is_last)
97,839✔
2053
                            break;
74,845✔
2054
                        smd++;
22,994✔
2055
                    }
22,994✔
2056
                }
74,845✔
2057

2058
                SCFree(s->sm_arrays[type]);
74,845✔
2059
            }
74,845✔
2060
        }
1,035,664✔
2061
    }
147,952✔
2062
}
147,952✔
2063

2064
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
2065
{
147,952✔
2066
    if (s == NULL)
147,952✔
UNCOV
2067
        return;
×
2068

2069
    int i;
147,952✔
2070

2071
    if (s->init_data && s->init_data->transforms.cnt) {
147,952✔
2072
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
2✔
2073
            if (s->init_data->transforms.transforms[i].options) {
1✔
UNCOV
2074
                int transform = s->init_data->transforms.transforms[i].transform;
×
UNCOV
2075
                sigmatch_table[transform].Free(
×
UNCOV
2076
                        de_ctx, s->init_data->transforms.transforms[i].options);
×
UNCOV
2077
                s->init_data->transforms.transforms[i].options = NULL;
×
UNCOV
2078
            }
×
2079
        }
1✔
2080
    }
1✔
2081
    if (s->init_data) {
147,952✔
2082
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
12,184✔
2083
            SigMatch *sm = s->init_data->smlists[i];
10,661✔
2084
            while (sm != NULL) {
11,601✔
2085
                SigMatch *nsm = sm->next;
940✔
2086
                SigMatchFree(de_ctx, sm);
940✔
2087
                sm = nsm;
940✔
2088
            }
940✔
2089
        }
10,661✔
2090

2091
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2,330✔
2092
            SigMatch *sm = s->init_data->buffers[x].head;
807✔
2093
            while (sm != NULL) {
1,923✔
2094
                SigMatch *nsm = sm->next;
1,116✔
2095
                SigMatchFree(de_ctx, sm);
1,116✔
2096
                sm = nsm;
1,116✔
2097
            }
1,116✔
2098
        }
807✔
2099
        if (s->init_data->cidr_dst != NULL)
1,523✔
2100
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
76✔
2101

2102
        if (s->init_data->cidr_src != NULL)
1,523✔
2103
            IPOnlyCIDRListFree(s->init_data->cidr_src);
76✔
2104

2105
        SCFree(s->init_data->buffers);
1,523✔
2106
        s->init_data->buffers = NULL;
1,523✔
2107
    }
1,523✔
2108
    SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
147,952✔
2109
    if (s->init_data) {
147,952✔
2110
        SCFree(s->init_data);
1,523✔
2111
        s->init_data = NULL;
1,523✔
2112
    }
1,523✔
2113

2114
    if (s->sp != NULL) {
147,952✔
2115
        DetectPortCleanupList(NULL, s->sp);
147,853✔
2116
    }
147,853✔
2117
    if (s->dp != NULL) {
147,952✔
2118
        DetectPortCleanupList(NULL, s->dp);
147,849✔
2119
    }
147,849✔
2120

2121
    if (s->msg != NULL)
147,952✔
2122
        SCFree(s->msg);
145,136✔
2123

2124
    if (s->addr_src_match4 != NULL) {
147,952✔
2125
        SCFree(s->addr_src_match4);
147,210✔
2126
    }
147,210✔
2127
    if (s->addr_dst_match4 != NULL) {
147,952✔
2128
        SCFree(s->addr_dst_match4);
147,209✔
2129
    }
147,209✔
2130
    if (s->addr_src_match6 != NULL) {
147,952✔
2131
        SCFree(s->addr_src_match6);
78,912✔
2132
    }
78,912✔
2133
    if (s->addr_dst_match6 != NULL) {
147,952✔
2134
        SCFree(s->addr_dst_match6);
26,660✔
2135
    }
26,660✔
2136
    if (s->sig_str != NULL) {
147,952✔
2137
        SCFree(s->sig_str);
147,901✔
2138
    }
147,901✔
2139

2140
    SigRefFree(s);
147,952✔
2141
    SigMetadataFree(s);
147,952✔
2142

2143
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
147,952✔
2144

2145
    SCFree(s);
147,952✔
2146
}
147,952✔
2147

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

2236
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
2237
{
98,754✔
2238
    if (!AppProtoIsValid(alproto)) {
98,754✔
UNCOV
2239
        SCLogError("invalid alproto %u", alproto);
×
UNCOV
2240
        return -1;
×
UNCOV
2241
    }
×
2242

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

2261
    if (s->alproto != ALPROTO_UNKNOWN) {
98,752✔
2262
        alproto = AppProtoCommon(s->alproto, alproto);
98,403✔
2263
        if (alproto == ALPROTO_FAILED) {
98,403✔
2264
            SCLogError("can't set rule app proto to %s: already set to %s",
5✔
2265
                    AppProtoToString(alproto), AppProtoToString(s->alproto));
5✔
2266
            return -1;
5✔
2267
        }
5✔
2268
    }
98,403✔
2269

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

2279
static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2280
        const DetectAddress *head, uint16_t *match4_cnt)
2281
{
294,494✔
2282
    uint16_t cnt = 0;
294,494✔
2283

2284
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
953,226✔
2285
        cnt++;
658,732✔
2286
    }
658,732✔
2287
    if (cnt == 0) {
294,494✔
2288
        return NULL;
23✔
2289
    }
23✔
2290
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
294,471✔
2291
    if (addr_match4 == NULL) {
294,471✔
2292
        return NULL;
×
2293
    }
×
2294

2295
    uint16_t idx = 0;
294,471✔
2296
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
953,202✔
2297
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
658,731✔
2298
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
658,731✔
2299
        idx++;
658,731✔
2300
    }
658,731✔
2301
    *match4_cnt = cnt;
294,471✔
2302
    return addr_match4;
294,471✔
2303
}
294,471✔
2304

2305
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2306
        const DetectAddress *head, uint16_t *match6_cnt)
2307
{
294,493✔
2308
    uint16_t cnt = 0;
294,493✔
2309
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
400,106✔
2310
        cnt++;
105,613✔
2311
    }
105,613✔
2312
    if (cnt == 0) {
294,493✔
2313
        return NULL;
188,892✔
2314
    }
188,892✔
2315

2316
    DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
105,601✔
2317
    if (addr_match6 == NULL) {
105,601✔
2318
        return NULL;
×
2319
    }
×
2320

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

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

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

2360
static int SigMatchListLen(SigMatch *sm)
2361
{
1,062,920✔
2362
    int len = 0;
1,062,920✔
2363
    for (; sm != NULL; sm = sm->next)
1,352,446✔
2364
        len++;
289,526✔
2365

2366
    return len;
1,062,920✔
2367
}
1,062,920✔
2368

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

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

2384
    /* Copy sm type and Context into array */
2385
    SigMatch *sm = head;
180,459✔
2386
    for (; sm != NULL; sm = sm->next, smd++) {
469,985✔
2387
        smd->type = sm->type;
289,526✔
2388
        smd->ctx = sm->ctx;
289,526✔
2389
        sm->ctx = NULL; // SigMatch no longer owns the ctx
289,526✔
2390
        smd->is_last = (sm->next == NULL);
289,526✔
2391
    }
289,526✔
2392
    return out;
180,459✔
2393
}
180,459✔
2394

2395
extern int g_skip_prefilter;
2396

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

2403
    if (s->init_data->prefilter_sm != NULL) {
147,247✔
2404
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
60✔
2405
            RetrieveFPForSig(de_ctx, s);
9✔
2406
            if (s->init_data->mpm_sm != NULL) {
9✔
2407
                s->flags |= SIG_FLAG_PREFILTER;
9✔
2408
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
9✔
2409
                SCReturn;
9✔
2410
            }
9✔
2411
            /* fall through, this can happen if the mpm doesn't support the pattern */
2412
        } else {
52✔
2413
            s->flags |= SIG_FLAG_PREFILTER;
51✔
2414
            SCReturn;
51✔
2415
        }
51✔
2416
    } else {
147,187✔
2417
        SCLogDebug("%u: RetrieveFPForSig", s->id);
147,187✔
2418
        RetrieveFPForSig(de_ctx, s);
147,187✔
2419
        if (s->init_data->mpm_sm != NULL) {
147,187✔
2420
            s->flags |= SIG_FLAG_PREFILTER;
75,252✔
2421
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
75,252✔
2422
            SCReturn;
75,252✔
2423
        }
75,252✔
2424
    }
147,187✔
2425

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

2430
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
71,935✔
2431
        SCReturn;
71,927✔
2432

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

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

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

2473
    const uint8_t table_as_flag = BIT_U8(s->detect_table);
147,193✔
2474

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

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

2497
static void DetectRuleSetTable(Signature *s)
2498
{
147,195✔
2499
    enum DetectTable table;
147,195✔
2500
    if (s->flags & SIG_FLAG_FIREWALL) {
147,195✔
2501
        if (s->type == SIG_TYPE_PKT) {
308✔
2502
            if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
139✔
2503
                    s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_STREAM)
139✔
2504
                table = DETECT_TABLE_PACKET_PRE_STREAM;
2✔
2505
            else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
137✔
2506
                     s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_FLOW)
137✔
2507
                table = DETECT_TABLE_PACKET_PRE_FLOW;
4✔
2508
            else
133✔
2509
                table = DETECT_TABLE_PACKET_FILTER;
133✔
2510
        } else if (s->type == SIG_TYPE_APP_TX) {
169✔
2511
            table = DETECT_TABLE_APP_FILTER;
169✔
2512
        } else {
169✔
2513
            BUG_ON(1);
×
2514
        }
×
2515
    } else {
146,887✔
2516
        // TODO pre_flow/pre_stream
2517
        if (s->type != SIG_TYPE_APP_TX) {
146,887✔
2518
            table = DETECT_TABLE_PACKET_TD;
78,959✔
2519
        } else {
105,620✔
2520
            table = DETECT_TABLE_APP_TD;
67,928✔
2521
        }
67,928✔
2522
    }
146,887✔
2523

2524
    s->detect_table = (uint8_t)table;
147,195✔
2525
}
147,195✔
2526

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

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

2544
    int nlists = 0;
147,247✔
2545
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
252,385✔
2546
        nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
105,138✔
2547
    }
105,138✔
2548
    nlists += (nlists > 0);
147,247✔
2549
    SCLogDebug("nlists %d", nlists);
147,247✔
2550

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

2557
    /* run buffer type validation callbacks if any */
2558
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
147,242✔
2559
        if (!DetectContentPMATCHValidateCallback(s))
10,931✔
2560
            SCReturnInt(0);
10✔
2561

2562
        has_pmatch = true;
10,921✔
2563
    }
10,921✔
2564

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

2572
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
252,340✔
2573
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
105,133✔
2574
        const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
105,133✔
2575
        if (bt == NULL) {
105,133✔
2576
            DEBUG_VALIDATE_BUG_ON(1); // should be impossible
×
2577
            continue;
×
2578
        }
×
2579
        SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
105,133✔
2580
        for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
296,330✔
2581
            SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
191,197✔
2582
        }
191,197✔
2583

2584
        if (b->head == NULL) {
105,133✔
UNCOV
2585
            SCLogError("no matches in sticky buffer %s", bt->name);
×
UNCOV
2586
            SCReturnInt(0);
×
UNCOV
2587
        }
×
2588

2589
        has_frame |= bt->frame;
105,133✔
2590
        has_app |= (!bt->frame && !bt->packet);
105,133✔
2591
        has_pkt |= bt->packet;
105,133✔
2592

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

2601
        const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
105,131✔
2602
        for (; app != NULL; app = app->next) {
72,552,640✔
2603
            if (app->sm_list == b->id &&
72,447,509✔
2604
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
72,447,509✔
2605
                SCLogDebug("engine %s dir %d alproto %d",
233,307✔
2606
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
233,307✔
2607
                        app->alproto);
233,307✔
2608
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
233,307✔
2609

2610
                if (b->only_tc) {
233,307✔
2611
                    if (app->dir == 1)
28✔
2612
                        (*tc_excl)++;
14✔
2613
                } else if (b->only_ts) {
233,279✔
2614
                    if (app->dir == 0)
8✔
2615
                        (*ts_excl)++;
4✔
2616
                } else {
233,271✔
2617
                    bufdir[b->id].ts += (app->dir == 0);
233,271✔
2618
                    bufdir[b->id].tc += (app->dir == 1);
233,271✔
2619
                }
233,271✔
2620

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

2639
        if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
105,131✔
2640
            SCReturnInt(0);
4✔
2641
        }
4✔
2642

2643
        if (!DetectBsizeValidateContentCallback(s, b)) {
105,127✔
2644
            SCReturnInt(0);
18✔
2645
        }
18✔
2646
        if (!DetectAbsentValidateContentCallback(s, b)) {
105,109✔
2647
            SCReturnInt(0);
1✔
2648
        }
1✔
2649
    }
105,109✔
2650

2651
    if (has_pmatch && has_frame) {
147,207✔
2652
        SCLogError("can't mix pure content and frame inspection");
1✔
2653
        SCReturnInt(0);
1✔
2654
    }
1✔
2655
    if (has_app && has_frame) {
147,206✔
2656
        SCLogError("can't mix app-layer buffer and frame inspection");
1✔
2657
        SCReturnInt(0);
1✔
2658
    }
1✔
2659
    if (has_pkt && has_frame) {
147,205✔
UNCOV
2660
        SCLogError("can't mix pkt buffer and frame inspection");
×
UNCOV
2661
        SCReturnInt(0);
×
UNCOV
2662
    }
×
2663

2664
    for (int x = 0; x < nlists; x++) {
17,718,497✔
2665
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
17,571,292✔
2666
            continue;
17,468,705✔
2667
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
102,587✔
2668
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
102,587✔
2669
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
102,587✔
2670

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

2675
    SCReturnInt(1);
147,205✔
2676
}
147,205✔
2677

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

2688
static int SigConsolidateDirection(
2689
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2690
{
147,204✔
2691
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
147,204✔
2692
        if (!ts_excl || !tc_excl) {
22✔
2693
            SCLogError("rule %u should use both directions, but does not", s->id);
3✔
2694
            SCReturnInt(0);
3✔
2695
        }
3✔
2696
        if (dir_amb) {
19✔
2697
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
1✔
2698
                       "directions",
1✔
2699
                    s->id);
1✔
2700
            SCReturnInt(0);
1✔
2701
        }
1✔
2702
    } else if (ts_excl && tc_excl) {
147,182✔
UNCOV
2703
        SCLogError(
×
UNCOV
2704
                "rule %u mixes keywords with conflicting directions, a transactional rule with => "
×
UNCOV
2705
                "should be used",
×
UNCOV
2706
                s->id);
×
UNCOV
2707
        SCReturnInt(0);
×
2708
    } else if (ts_excl) {
147,182✔
2709
        SCLogDebug("%u: implied rule direction is toserver", s->id);
54,485✔
2710
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
54,485✔
2711
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
6✔
2712
            SCReturnInt(0);
6✔
2713
        }
6✔
2714
    } else if (tc_excl) {
110,482✔
2715
        SCLogDebug("%u: implied rule direction is toclient", s->id);
2,288✔
2716
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
2,288✔
UNCOV
2717
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
×
UNCOV
2718
            SCReturnInt(0);
×
UNCOV
2719
        }
×
2720
    } else if (dir_amb) {
90,409✔
2721
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
8,788✔
2722
    }
8,788✔
2723
    SCReturnInt(1);
147,204✔
2724
}
147,204✔
2725

2726
static void SigConsolidateTcpBuffer(Signature *s)
2727
{
147,194✔
2728
    /* TCP: corner cases:
2729
     * - pkt vs stream vs depth/offset
2730
     * - pkt vs stream vs stream_size
2731
     */
2732
    if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
147,194✔
2733
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
145,781✔
2734
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
10,017✔
2735
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
8,300✔
2736
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
18,110✔
2737
                        sm = sm->next) {
13,768✔
2738
                    if (sm->type == DETECT_CONTENT &&
13,768✔
2739
                            (((DetectContentData *)(sm->ctx))->flags &
13,768✔
2740
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
12,244✔
2741
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
3,958✔
2742
                        break;
3,958✔
2743
                    }
3,958✔
2744
                }
13,768✔
2745
                /* if stream_size is in use, also inspect packets */
2746
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
16,066✔
2747
                        sm = sm->next) {
8,474✔
2748
                    if (sm->type == DETECT_STREAM_SIZE) {
7,844✔
2749
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
78✔
2750
                        break;
78✔
2751
                    }
78✔
2752
                }
7,844✔
2753
            }
8,300✔
2754
        }
10,017✔
2755
    }
145,781✔
2756
}
147,194✔
2757

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

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

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

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

2821
    if (SigValidateFirewall(de_ctx, s) == 0)
147,247✔
2822
        SCReturnInt(0);
×
2823

2824
    if (SigValidatePacketStream(s) == 0) {
147,247✔
UNCOV
2825
        SCReturnInt(0);
×
UNCOV
2826
    }
×
2827

2828
    int ts_excl = 0;
147,247✔
2829
    int tc_excl = 0;
147,247✔
2830
    int dir_amb = 0;
147,247✔
2831

2832
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
147,247✔
2833
        SCReturnInt(0);
42✔
2834
    }
42✔
2835

2836
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
147,205✔
2837
        SCReturnInt(0);
10✔
2838
    }
10✔
2839

2840
    SigConsolidateTcpBuffer(s);
147,195✔
2841

2842
    SignatureSetType(de_ctx, s);
147,195✔
2843
    DetectRuleSetTable(s);
147,195✔
2844

2845
    int r = SigValidateFileHandling(s);
147,195✔
2846
    if (r == 0) {
147,195✔
2847
        SCReturnInt(0);
2✔
2848
    }
2✔
2849
    if (SigInspectsFiles(s)) {
147,193✔
2850
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
6,239✔
2851
            AppLayerHtpNeedFileInspection();
6,070✔
2852
        }
6,070✔
2853
    }
6,239✔
2854
    if (DetectRuleValidateTable(s) == false) {
147,193✔
2855
        SCReturnInt(0);
×
2856
    }
×
2857

2858
    if (s->type == SIG_TYPE_IPONLY) {
147,193✔
2859
        /* For IPOnly */
2860
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
371✔
UNCOV
2861
            SCReturnInt(0);
×
2862

2863
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
371✔
UNCOV
2864
            SCReturnInt(0);
×
2865
    }
371✔
2866
    SCReturnInt(1);
147,193✔
2867
}
147,193✔
2868

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

2879
    Signature *sig = SigAlloc();
147,935✔
2880
    if (sig == NULL)
147,935✔
2881
        goto error;
×
2882
    if (firewall_rule) {
147,935✔
2883
        sig->init_data->firewall_rule = true;
308✔
2884
        sig->flags |= SIG_FLAG_FIREWALL;
308✔
2885
    }
308✔
2886

2887
    sig->sig_str = SCStrdup(sigstr);
147,935✔
2888
    if (unlikely(sig->sig_str == NULL)) {
147,935✔
2889
        goto error;
×
2890
    }
×
2891

2892
    /* default gid to 1 */
2893
    sig->gid = 1;
147,935✔
2894

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

2910
    /* Check for a SID before continuuing. */
2911
    if (sig->id == 0) {
147,910✔
2912
        SCLogError("Signature missing required value \"sid\".");
5✔
2913
        goto error;
5✔
2914
    }
5✔
2915

2916
    /* Now completely parse the rule. */
2917
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
147,905✔
2918
    BUG_ON(ret == -4);
147,905✔
2919
    if (ret == -3) {
147,897✔
2920
        de_ctx->sigerror_silent = true;
68✔
2921
        de_ctx->sigerror_ok = true;
68✔
2922
        goto error;
68✔
2923
    } else if (ret == -2) {
147,829✔
2924
        de_ctx->sigerror_silent = true;
1✔
2925
        goto error;
1✔
2926
    } else if (ret < 0) {
147,828✔
2927
        goto error;
581✔
2928
    }
581✔
2929

2930
    /* signature priority hasn't been overwritten.  Using default priority */
2931
    if (sig->prio == -1)
147,247✔
2932
        sig->prio = DETECT_DEFAULT_PRIO;
71,319✔
2933

2934
    sig->iid = de_ctx->signum;
147,247✔
2935
    de_ctx->signum++;
147,247✔
2936

2937
    if (sig->alproto != ALPROTO_UNKNOWN) {
147,247✔
2938
        int override_needed = 0;
69,780✔
2939
        if (sig->proto.flags & DETECT_PROTO_ANY) {
69,780✔
2940
            sig->proto.flags &= ~DETECT_PROTO_ANY;
7✔
2941
            memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
7✔
2942
            override_needed = 1;
7✔
2943
        } else {
69,773✔
2944
            override_needed = 1;
69,773✔
2945
            size_t s = 0;
69,773✔
2946
            for (s = 0; s < sizeof(sig->proto.proto); s++) {
70,311✔
2947
                if (sig->proto.proto[s] != 0x00) {
70,311✔
2948
                    override_needed = 0;
69,773✔
2949
                    break;
69,773✔
2950
                }
69,773✔
2951
            }
70,311✔
2952
        }
69,773✔
2953

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

2961
    /* set the packet and app layer flags, but only if the
2962
     * app layer flag wasn't already set in which case we
2963
     * only consider the app layer */
2964
    if (!(sig->flags & SIG_FLAG_APPLAYER)) {
147,247✔
2965
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
77,433✔
2966
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
9,795✔
2967
            for ( ; sm != NULL; sm = sm->next) {
22,344✔
2968
                if (sigmatch_table[sm->type].Match != NULL)
12,549✔
2969
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
12,549✔
2970
            }
12,549✔
2971
        } else {
70,748✔
2972
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
67,638✔
2973
        }
67,638✔
2974
    }
77,433✔
2975

2976
    if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
147,247✔
2977
        if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
144✔
2978
            if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
21✔
2979
                sig->init_data->init_flags |= SIG_FLAG_INIT_FLOW;
4✔
2980
            }
4✔
2981
        }
21✔
2982
    }
144✔
2983

2984
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
147,247✔
2985
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
90,968✔
2986
            sig->flags |= SIG_FLAG_TOSERVER;
89,712✔
2987
            sig->flags |= SIG_FLAG_TOCLIENT;
89,712✔
2988
        }
89,712✔
2989
    }
90,968✔
2990

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

2995
    SigBuildAddressMatchArray(sig);
147,247✔
2996

2997
    /* run buffer type callbacks if any */
2998
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
1,177,969✔
2999
        if (sig->init_data->smlists[x])
1,030,722✔
3000
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
76,136✔
3001
    }
1,030,722✔
3002
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
252,385✔
3003
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
105,138✔
3004
    }
105,138✔
3005

3006
    SigSetupPrefilter(de_ctx, sig);
147,247✔
3007

3008
    /* validate signature, SigValidate will report the error reason */
3009
    if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
147,247✔
3010
        goto error;
54✔
3011
    }
54✔
3012

3013
    return sig;
147,193✔
3014

3015
error:
734✔
3016
    if (sig != NULL) {
734✔
3017
        SigFree(de_ctx, sig);
734✔
3018
    }
734✔
3019
    return NULL;
734✔
3020
}
147,247✔
3021

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

3036
    if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
20✔
3037
        DetectAddress *src = s->init_data->src->ipv4_head;
17✔
3038
        DetectAddress *dst = s->init_data->dst->ipv4_head;
17✔
3039

3040
        if (!DetectAddressListsAreEqual(src, dst)) {
17✔
3041
            return false;
15✔
3042
        }
15✔
3043

3044
        src = s->init_data->src->ipv6_head;
2✔
3045
        dst = s->init_data->dst->ipv6_head;
2✔
3046

3047
        if (!DetectAddressListsAreEqual(src, dst)) {
2✔
UNCOV
3048
            return false;
×
UNCOV
3049
        }
×
3050
    }
2✔
3051

3052
    return true;
5✔
3053
}
20✔
3054

3055
static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3056
{
147,860✔
3057
    SCEnter();
147,860✔
3058

3059
    uint32_t oldsignum = de_ctx->signum;
147,860✔
3060
    de_ctx->sigerror_ok = false;
147,860✔
3061
    de_ctx->sigerror_silent = false;
147,860✔
3062
    de_ctx->sigerror_requires = false;
147,860✔
3063

3064
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
147,860✔
3065
    if (sig == NULL) {
147,860✔
3066
        goto error;
734✔
3067
    }
734✔
3068

3069
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
147,126✔
3070
        if (SigHasSameSourceAndDestination(sig)) {
80✔
3071
            SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
5✔
3072
                "treating the rule as unidirectional", sig->id);
5✔
3073

3074
            sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC;
5✔
3075
        } else {
75✔
3076
            sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
75✔
3077
            if (sig->next == NULL) {
75✔
3078
                goto error;
×
3079
            }
×
3080
        }
75✔
3081
    }
80✔
3082

3083
    SCReturnPtr(sig, "Signature");
147,126✔
3084

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

3093
    SCReturnPtr(NULL, "Signature");
734✔
3094
}
147,126✔
3095

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

3110
static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3111
{
259✔
3112
    return SigInitDo(de_ctx, sigstr, true);
259✔
3113
}
259✔
3114

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

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

3141
    return (sw->s->id % ht->array_size);
437,736✔
3142
}
437,736✔
3143

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

3162
    if (sw1 == NULL || sw2 == NULL ||
317,563✔
3163
        sw1->s == NULL || sw2->s == NULL)
317,563✔
3164
        return 0;
×
3165

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

3169
    return 0;
173,498✔
3170
}
317,563✔
3171

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

3189
    return 0;
3,355✔
3190
}
3,355✔
3191

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

3202
    de_ctx->dup_sig_hash_table = NULL;
5,131✔
3203
}
5,131✔
3204

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

3230
    /* return value */
3231
    int ret = 0;
146,849✔
3232

3233
    SigDuplWrapper *sw_dup = NULL;
146,849✔
3234
    SigDuplWrapper *sw = NULL;
146,849✔
3235

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

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

3250
        /* add the s_prev entry for the previously loaded sw in the hash_table */
3251
        if (de_ctx->sig_list != NULL) {
146,836✔
3252
            SigDuplWrapper *sw_old = NULL;
144,044✔
3253
            SigDuplWrapper sw_tmp;
144,044✔
3254
            memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
144,044✔
3255

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

3264
        ret = 0;
146,836✔
3265
        goto end;
146,836✔
3266
    }
146,836✔
3267

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

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

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

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

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

3349
    SCFree(sw);
10✔
3350

3351
end:
146,849✔
3352
    return ret;
146,849✔
3353
}
10✔
3354

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

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

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

3406
    de_ctx->sig_list = sig;
259✔
3407

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

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

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

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

3467
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
146,595✔
3468
        if (sig->next != NULL) {
26✔
3469
            sig->next->next = de_ctx->sig_list;
26✔
3470
        } else {
26✔
3471
            goto error;
×
3472
        }
×
3473
    } else {
146,569✔
3474
        /* if this sig is the first one, sig_list should be null */
3475
        sig->next = de_ctx->sig_list;
146,569✔
3476
    }
146,569✔
3477

3478
    de_ctx->sig_list = sig;
146,595✔
3479

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

3487
error:
3✔
3488
    /* free the 2nd sig bidir may have set up */
3489
    if (sig != NULL && sig->next != NULL) {
3✔
UNCOV
3490
        SigFree(de_ctx, sig->next);
×
UNCOV
3491
        sig->next = NULL;
×
UNCOV
3492
    }
×
3493
    if (sig != NULL) {
3✔
3494
        SigFree(de_ctx, sig);
3✔
3495
    }
3✔
3496
    return NULL;
3✔
3497
}
146,595✔
3498

3499
static DetectParseRegex *g_detect_parse_regex_list = NULL;
3500

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

3511
void DetectParseFreeRegex(DetectParseRegex *r)
3512
{
108,126✔
3513
    if (r->regex) {
108,126✔
3514
        pcre2_code_free(r->regex);
108,118✔
3515
    }
108,118✔
3516
    if (r->context) {
108,126✔
3517
        pcre2_match_context_free(r->context);
13,958✔
3518
    }
13,958✔
3519
}
108,126✔
3520

3521
void DetectParseFreeRegexes(void)
3522
{
2,140✔
3523
    DetectParseRegex *r = g_detect_parse_regex_list;
2,140✔
3524
    while (r) {
96,300✔
3525
        DetectParseRegex *next = r->next;
94,160✔
3526

3527
        DetectParseFreeRegex(r);
94,160✔
3528

3529
        SCFree(r);
94,160✔
3530
        r = next;
94,160✔
3531
    }
94,160✔
3532
    g_detect_parse_regex_list = NULL;
2,140✔
3533
}
2,140✔
3534

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

3548
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3549
{
84,436✔
3550
    int en;
84,436✔
3551
    PCRE2_SIZE eo;
84,436✔
3552

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

3574
    return true;
84,436✔
3575
}
84,436✔
3576

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

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

3598
    detect_parse->next = g_detect_parse_regex_list;
13,348✔
3599
    g_detect_parse_regex_list = detect_parse;
13,348✔
3600
    return detect_parse;
13,348✔
3601
}
13,348✔
3602

3603
int SC_Pcre2SubstringCopy(
3604
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3605
{
57,508✔
3606
    int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
57,508✔
3607
    if (r == PCRE2_ERROR_UNSET) {
57,508✔
3608
        buffer[0] = 0;
13✔
3609
        *bufflen = 0;
13✔
3610
        return 0;
13✔
3611
    }
13✔
3612
    return r;
57,495✔
3613
}
57,508✔
3614

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

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

3634
/*
3635
 * TESTS
3636
 */
3637

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

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

3647
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3648
    if (de_ctx == NULL)
1✔
3649
        goto end;
3650

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

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

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

3667
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3668

3669
    if (de_ctx == NULL)
1✔
3670
        goto end;
3671

3672
    SCClassConfDeInitContext(de_ctx);
1✔
3673
    FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01();
1✔
3674
    SCClassConfLoadClassificationConfigFile(de_ctx, fd);
1✔
3675

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

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

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

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

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

3709
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3710
    if (de_ctx == NULL)
1✔
3711
        goto end;
3712

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

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

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

3730
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3731
    if (de_ctx == NULL)
1✔
3732
        goto end;
3733

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

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

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

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

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

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

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

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

3777
    sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)");
1✔
3778
    if (sig != NULL) {
1✔
3779
        result = 1;
1✔
3780
    } else {
1✔
3781
        printf("signature failed to parse: ");
3782
    }
3783

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

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

3799
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3800
    if (de_ctx == NULL)
1✔
3801
        goto end;
3802

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

3806
    result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
1✔
3807

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

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

3821
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3822
    if (de_ctx == NULL)
1✔
3823
        goto end;
3824

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

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

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

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

3844
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3845
    if (de_ctx == NULL)
1✔
3846
        goto end;
3847

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

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

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

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

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

3895
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3896
    if (de_ctx == NULL)
1✔
3897
        goto end;
3898

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

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

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

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

3927
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3928
    if (de_ctx == NULL)
1✔
3929
        goto end;
3930

3931
    Signature *s = NULL;
1✔
3932

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

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

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

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

3961
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3962
    if (de_ctx == NULL)
1✔
3963
        goto end;
3964

3965
    Signature *s = NULL;
1✔
3966

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

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

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

3987
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
3988
    if (de_ctx == NULL)
1✔
3989
        goto end;
3990

3991
    Signature *s = NULL;
1✔
3992

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

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

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

4009
    result = 1;
1✔
4010

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

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

4024
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4025
    if (de_ctx == NULL)
1✔
4026
        goto end;
4027

4028
    Signature *s = NULL;
1✔
4029

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

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

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

4046
    result = 1;
1✔
4047

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

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

4061
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4062
    if (de_ctx == NULL)
1✔
4063
        goto end;
4064

4065
    Signature *s = NULL;
1✔
4066

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

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

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

4083
    result = 1;
1✔
4084

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

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

4098
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4099
    if (de_ctx == NULL)
1✔
4100
        goto end;
4101

4102
    Signature *s = NULL;
1✔
4103

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

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

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

4120
    result = 1;
1✔
4121

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

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

4135
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4136
    if (de_ctx == NULL)
1✔
4137
        goto end;
4138

4139
    Signature *s = NULL;
1✔
4140

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

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

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

4157
    result = 1;
1✔
4158

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

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

4170
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4171
    if (de_ctx == NULL)
1✔
4172
        goto end;
4173

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

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

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

4189
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4190
    if (de_ctx == NULL)
1✔
4191
        goto end;
4192

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

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

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

4208
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4209
    if (de_ctx == NULL)
1✔
4210
        goto end;
4211

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

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

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

4227
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4228
    if (de_ctx == NULL)
1✔
4229
        goto end;
4230

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

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

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

4246
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4247
    if (de_ctx == NULL)
1✔
4248
        goto end;
4249

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

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

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

4268
    Signature *s = NULL;
1✔
4269

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

4273
    DetectEngineCtxFree(de_ctx);
1✔
4274
    PASS;
1✔
4275
}
1✔
4276

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

4283
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4284
    if (de_ctx == NULL)
1✔
4285
        goto end;
4286

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

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

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

4303
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4304
    if (de_ctx == NULL)
1✔
4305
        goto end;
4306

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4477
    result = 1;
1✔
4478

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

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

4495
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4496
    if (de_ctx == NULL)
1✔
4497
        goto end;
4498

4499
    de_ctx->flags |= DE_QUIET;
1✔
4500

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

4518
    result = 1;
1✔
4519

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

4527
    return result;
1✔
4528
}
1✔
4529

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

4540
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4541
    if (de_ctx == NULL)
1✔
4542
        goto end;
4543

4544
    de_ctx->flags |= DE_QUIET;
1✔
4545

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

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

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

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

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

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

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

4655
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4656
    if (de_ctx == NULL)
1✔
4657
        goto end;
4658

4659
    de_ctx->flags |= DE_QUIET;
1✔
4660

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

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

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

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

4756
    memset(&th_v, 0, sizeof(th_v));
1✔
4757
    StatsThreadInit(&th_v.stats);
1✔
4758

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

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

4767
    SigGroupBuild(de_ctx);
1✔
4768
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1✔
4769

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

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

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

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

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

4807
/**
4808
 * \test check that we don't allow invalid negation options
4809
 */
4810
static int SigParseTestNegation02 (void)
4811
{
1✔
4812
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4813
    FAIL_IF_NULL(de_ctx);
1✔
4814
    de_ctx->flags |= DE_QUIET;
1✔
4815
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
4816
            "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
1✔
4817
            "classtype:misc-activity; sid:410002; rev:1;)");
1✔
4818
    FAIL_IF_NOT_NULL(s);
1✔
4819
    DetectEngineCtxFree(de_ctx);
1✔
4820
    PASS;
1✔
4821
}
1✔
4822
/**
4823
 * \test check that we don't allow invalid negation options
4824
 */
4825
static int SigParseTestNegation03 (void)
4826
{
1✔
4827
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4828
    FAIL_IF_NULL(de_ctx);
1✔
4829
    de_ctx->flags |= DE_QUIET;
1✔
4830
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
4831
            "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
1✔
4832
            "classtype:misc-activity; sid:410003; rev:1;)");
1✔
4833
    FAIL_IF_NOT_NULL(s);
1✔
4834
    DetectEngineCtxFree(de_ctx);
1✔
4835
    PASS;
1✔
4836
}
1✔
4837
/**
4838
 * \test check that we don't allow invalid negation options
4839
 */
4840
static int SigParseTestNegation04 (void)
4841
{
1✔
4842
    int result = 0;
1✔
4843
    DetectEngineCtx *de_ctx;
1✔
4844
    Signature *s=NULL;
1✔
4845

4846
    de_ctx = DetectEngineCtxInit();
1✔
4847
    if (de_ctx == NULL)
1✔
4848
        goto end;
4849
    de_ctx->flags |= DE_QUIET;
1✔
4850

4851
    s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
1✔
4852
    if (s != NULL) {
1✔
4853
        SigFree(de_ctx, s);
4854
        goto end;
4855
    }
4856

4857
    result = 1;
1✔
4858
end:
1✔
4859
    if (de_ctx != NULL)
1✔
4860
        DetectEngineCtxFree(de_ctx);
1✔
4861
    return result;
1✔
4862
}
1✔
4863
/**
4864
 * \test check that we don't allow invalid negation options
4865
 */
4866
static int SigParseTestNegation05 (void)
4867
{
1✔
4868
    int result = 0;
1✔
4869
    DetectEngineCtx *de_ctx;
1✔
4870
    Signature *s=NULL;
1✔
4871

4872
    de_ctx = DetectEngineCtxInit();
1✔
4873
    if (de_ctx == NULL)
1✔
4874
        goto end;
4875
    de_ctx->flags |= DE_QUIET;
1✔
4876

4877
    s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
1✔
4878
    if (s != NULL) {
1✔
4879
        SigFree(de_ctx, s);
4880
        goto end;
4881
    }
4882

4883
    result = 1;
1✔
4884
end:
1✔
4885
    if (de_ctx != NULL)
1✔
4886
        DetectEngineCtxFree(de_ctx);
1✔
4887
    return result;
1✔
4888
}
1✔
4889
/**
4890
 * \test check that we don't allow invalid negation options
4891
 */
4892
static int SigParseTestNegation06 (void)
4893
{
1✔
4894
    int result = 0;
1✔
4895
    DetectEngineCtx *de_ctx;
1✔
4896
    Signature *s=NULL;
1✔
4897

4898
    de_ctx = DetectEngineCtxInit();
1✔
4899
    if (de_ctx == NULL)
1✔
4900
        goto end;
4901
    de_ctx->flags |= DE_QUIET;
1✔
4902

4903
    s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
1✔
4904
    if (s != NULL) {
1✔
4905
        SigFree(de_ctx, s);
4906
        goto end;
4907
    }
4908

4909
    result = 1;
1✔
4910
end:
1✔
4911
    if (de_ctx != NULL)
1✔
4912
        DetectEngineCtxFree(de_ctx);
1✔
4913
    return result;
1✔
4914
}
1✔
4915

4916
/**
4917
 * \test check that we don't allow invalid negation options
4918
 */
4919
static int SigParseTestNegation07 (void)
4920
{
1✔
4921
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4922
    FAIL_IF_NULL(de_ctx);
1✔
4923
    de_ctx->flags |= DE_QUIET;
1✔
4924
    Signature *s = DetectEngineAppendSig(
1✔
4925
            de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
1✔
4926
    FAIL_IF_NOT_NULL(s);
1✔
4927
    DetectEngineCtxFree(de_ctx);
1✔
4928
    PASS;
1✔
4929
}
1✔
4930

4931
/**
4932
 * \test check valid negation bug 1079
4933
 */
4934
static int SigParseTestNegation08 (void)
4935
{
1✔
4936
    int result = 0;
1✔
4937
    DetectEngineCtx *de_ctx;
1✔
4938
    Signature *s=NULL;
1✔
4939

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

4945
    s = DetectEngineAppendSig(de_ctx,
1✔
4946
            "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
1✔
4947
    if (s == NULL) {
1✔
4948
        goto end;
4949
    }
4950

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

4958
/**
4959
 * \test mpm
4960
 */
4961
static int SigParseTestMpm01 (void)
4962
{
1✔
4963
    int result = 0;
1✔
4964
    Signature *sig = NULL;
1✔
4965

4966
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4967
    if (de_ctx == NULL)
1✔
4968
        goto end;
4969

4970
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
1✔
4971
    if (sig == NULL) {
1✔
4972
        printf("sig failed to init: ");
4973
        goto end;
4974
    }
4975

4976
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
1✔
4977
        printf("sig doesn't have content list: ");
4978
        goto end;
4979
    }
4980

4981
    result = 1;
1✔
4982
end:
1✔
4983
    if (sig != NULL)
1✔
4984
        SigFree(de_ctx, sig);
1✔
4985
    DetectEngineCtxFree(de_ctx);
1✔
4986
    return result;
1✔
4987
}
1✔
4988

4989
/**
4990
 * \test mpm
4991
 */
4992
static int SigParseTestMpm02 (void)
4993
{
1✔
4994
    int result = 0;
1✔
4995
    Signature *sig = NULL;
1✔
4996

4997
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4998
    if (de_ctx == NULL)
1✔
4999
        goto end;
5000

5001
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
1✔
5002
    if (sig == NULL) {
1✔
5003
        printf("sig failed to init: ");
5004
        goto end;
5005
    }
5006

5007
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
1✔
5008
        printf("sig doesn't have content list: ");
5009
        goto end;
5010
    }
5011

5012
    result = 1;
1✔
5013
end:
1✔
5014
    if (sig != NULL)
1✔
5015
        SigFree(de_ctx, sig);
1✔
5016
    DetectEngineCtxFree(de_ctx);
1✔
5017
    return result;
1✔
5018
}
1✔
5019

5020
/**
5021
 * \test test tls (app layer) rule
5022
 */
5023
static int SigParseTestAppLayerTLS01(void)
5024
{
1✔
5025
    int result = 0;
1✔
5026
    DetectEngineCtx *de_ctx;
1✔
5027
    Signature *s=NULL;
1✔
5028

5029
    de_ctx = DetectEngineCtxInit();
1✔
5030
    if (de_ctx == NULL)
1✔
5031
        goto end;
5032
    de_ctx->flags |= DE_QUIET;
1✔
5033

5034
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
1✔
5035
    if (s == NULL) {
1✔
5036
        printf("parsing sig failed: ");
5037
        goto end;
5038
    }
5039

5040
    if (s->alproto == 0) {
1✔
5041
        printf("alproto not set: ");
5042
        goto end;
5043
    }
5044

5045
    result = 1;
1✔
5046
end:
1✔
5047
    if (s != NULL)
1✔
5048
        SigFree(de_ctx, s);
1✔
5049
    if (de_ctx != NULL)
1✔
5050
        DetectEngineCtxFree(de_ctx);
1✔
5051

5052
    return result;
1✔
5053
}
1✔
5054

5055
/**
5056
 * \test test tls (app layer) rule
5057
 */
5058
static int SigParseTestAppLayerTLS02(void)
5059
{
1✔
5060
    int result = 0;
1✔
5061
    DetectEngineCtx *de_ctx;
1✔
5062
    Signature *s=NULL;
1✔
5063

5064
    de_ctx = DetectEngineCtxInit();
1✔
5065
    if (de_ctx == NULL)
1✔
5066
        goto end;
5067
    de_ctx->flags |= DE_QUIET;
1✔
5068

5069
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
1✔
5070
    if (s == NULL) {
1✔
5071
        printf("parsing sig failed: ");
5072
        goto end;
5073
    }
5074

5075
    if (s->alproto == 0) {
1✔
5076
        printf("alproto not set: ");
5077
        goto end;
5078
    }
5079

5080
    result = 1;
1✔
5081
end:
1✔
5082
    if (s != NULL)
1✔
5083
        SigFree(de_ctx, s);
1✔
5084
    if (de_ctx != NULL)
1✔
5085
        DetectEngineCtxFree(de_ctx);
1✔
5086
    return result;
1✔
5087
}
1✔
5088

5089
/**
5090
 * \test test tls (app layer) rule
5091
 */
5092
static int SigParseTestAppLayerTLS03(void)
5093
{
1✔
5094
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5095
    FAIL_IF_NULL(de_ctx);
1✔
5096
    de_ctx->flags |= DE_QUIET;
1✔
5097

5098
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5099
            "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
1✔
5100
            "tls.version:2.5; sid:410006; rev:1;)");
1✔
5101
    FAIL_IF_NOT_NULL(s);
1✔
5102
    DetectEngineCtxFree(de_ctx);
1✔
5103
    PASS;
1✔
5104
}
1✔
5105

5106
static int SigParseTestUnbalancedQuotes01(void)
5107
{
1✔
5108
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5109
    FAIL_IF_NULL(de_ctx);
1✔
5110
    de_ctx->flags |= DE_QUIET;
1✔
5111
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5112
            "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
1✔
5113
            "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
1✔
5114
            "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
1✔
5115
    FAIL_IF_NOT_NULL(s);
1✔
5116
    DetectEngineCtxFree(de_ctx);
1✔
5117
    PASS;
1✔
5118
}
1✔
5119

5120
static int SigParseTestContentGtDsize01(void)
5121
{
1✔
5122
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5123
    FAIL_IF_NULL(de_ctx);
1✔
5124
    de_ctx->flags |= DE_QUIET;
1✔
5125
    Signature *s =
1✔
5126
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
1✔
5127
                                          "dsize:21; content:\"0123456789001234567890|00 00|\"; "
1✔
5128
                                          "sid:1; rev:1;)");
1✔
5129
    FAIL_IF_NOT_NULL(s);
1✔
5130
    DetectEngineCtxFree(de_ctx);
1✔
5131
    PASS;
1✔
5132
}
1✔
5133

5134
static int SigParseTestContentGtDsize02(void)
5135
{
1✔
5136
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5137
    FAIL_IF_NULL(de_ctx);
1✔
5138
    de_ctx->flags |= DE_QUIET;
1✔
5139
    Signature *s =
1✔
5140
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
1✔
5141
                                          "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
1✔
5142
                                          "sid:1; rev:1;)");
1✔
5143
    FAIL_IF_NOT_NULL(s);
1✔
5144
    DetectEngineCtxFree(de_ctx);
1✔
5145
    PASS;
1✔
5146
}
1✔
5147

5148
static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5149
{
8✔
5150
    int cnt = 0;
8✔
5151
    for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
42✔
5152
        if (sid == s->id)
34✔
5153
            cnt++;
12✔
5154
    }
34✔
5155
    return cnt;
8✔
5156
}
8✔
5157

5158
static int SigParseBidirWithSameSrcAndDest01(void)
5159
{
1✔
5160
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5161
    FAIL_IF_NULL(de_ctx);
1✔
5162
    de_ctx->flags |= DE_QUIET;
1✔
5163

5164
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
1✔
5165
    FAIL_IF_NULL(s);
1✔
5166
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
1✔
5167
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5168

5169
    s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
1✔
5170
    FAIL_IF_NULL(s);
1✔
5171
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
1✔
5172
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5173

5174
    s = DetectEngineAppendSig(de_ctx,
1✔
5175
            "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
1✔
5176
    FAIL_IF_NULL(s);
1✔
5177
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
1✔
5178
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5179

5180
    DetectEngineCtxFree(de_ctx);
1✔
5181
    PASS;
1✔
5182
}
1✔
5183

5184
static int SigParseBidirWithSameSrcAndDest02(void)
5185
{
1✔
5186
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5187
    FAIL_IF_NULL(de_ctx);
1✔
5188
    de_ctx->flags |= DE_QUIET;
1✔
5189

5190
    // Source is a subset of destination
5191
    Signature *s = DetectEngineAppendSig(
1✔
5192
            de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
1✔
5193
    FAIL_IF_NULL(s);
1✔
5194
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
1✔
5195
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5196

5197
    // Source is a subset of destination
5198
    s = DetectEngineAppendSig(
1✔
5199
            de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
1✔
5200
    FAIL_IF_NULL(s);
1✔
5201
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
1✔
5202
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5203

5204
    // Source intersects with destination
5205
    s = DetectEngineAppendSig(de_ctx,
1✔
5206
            "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
1✔
5207
    FAIL_IF_NULL(s);
1✔
5208
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
1✔
5209
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5210

5211
    // mix in negation, these are the same
5212
    s = DetectEngineAppendSig(
1✔
5213
            de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
1✔
5214
    FAIL_IF_NULL(s);
1✔
5215
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
1✔
5216
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5217

5218
    // mix in negation, these are not the same
5219
    s = DetectEngineAppendSig(
1✔
5220
            de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
1✔
5221
    FAIL_IF_NULL(s);
1✔
5222
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
1✔
5223
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5224

5225
    DetectEngineCtxFree(de_ctx);
1✔
5226
    PASS;
1✔
5227
}
1✔
5228

5229
static int SigParseTestActionReject(void)
5230
{
1✔
5231
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5232
    FAIL_IF_NULL(de_ctx);
1✔
5233

5234
    Signature *sig = DetectEngineAppendSig(
1✔
5235
            de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5236
#ifdef HAVE_LIBNET11
1✔
5237
    FAIL_IF_NULL(sig);
1✔
5238
    FAIL_IF_NOT((sig->action & (ACTION_DROP | ACTION_REJECT)) == (ACTION_DROP | ACTION_REJECT));
1✔
5239
#else
5240
    FAIL_IF_NOT_NULL(sig);
5241
#endif
5242

5243
    DetectEngineCtxFree(de_ctx);
1✔
5244
    PASS;
1✔
5245
}
1✔
5246

5247
static int SigParseTestActionDrop(void)
5248
{
1✔
5249
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5250
    FAIL_IF_NULL(de_ctx);
1✔
5251

5252
    Signature *sig = DetectEngineAppendSig(
1✔
5253
            de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5254
    FAIL_IF_NULL(sig);
1✔
5255
    FAIL_IF_NOT(sig->action & ACTION_DROP);
1✔
5256

5257
    DetectEngineCtxFree(de_ctx);
1✔
5258
    PASS;
1✔
5259
}
1✔
5260

5261
static int SigSetMultiAppProto(void)
5262
{
1✔
5263
    Signature *s = SigAlloc();
1✔
5264
    FAIL_IF_NULL(s);
1✔
5265

5266
    AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
1✔
5267
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5268

5269
    // check intersection gives multiple entries
5270
    alprotos[0] = 3;
1✔
5271
    alprotos[1] = 2;
1✔
5272
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5273
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5274
    FAIL_IF(s->init_data->alprotos[0] != 3);
1✔
5275
    FAIL_IF(s->init_data->alprotos[1] != 2);
1✔
5276
    FAIL_IF(s->init_data->alprotos[2] != ALPROTO_UNKNOWN);
1✔
5277

5278
    // check single after multiple
5279
    FAIL_IF(SCDetectSignatureSetAppProto(s, 3) < 0);
1✔
5280
    FAIL_IF(s->init_data->alprotos[0] != ALPROTO_UNKNOWN);
1✔
5281
    FAIL_IF(s->alproto != 3);
1✔
5282
    alprotos[0] = 4;
1✔
5283
    alprotos[1] = 3;
1✔
5284
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5285
    // check multiple containing singleton
5286
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5287
    FAIL_IF(s->alproto != 3);
1✔
5288

5289
    // reset
5290
    s->alproto = ALPROTO_UNKNOWN;
1✔
5291
    alprotos[0] = 1;
1✔
5292
    alprotos[1] = 2;
1✔
5293
    alprotos[2] = 3;
1✔
5294
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5295
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5296
    // fail if set single not in multiple
5297
    FAIL_IF(SCDetectSignatureSetAppProto(s, 4) >= 0);
1✔
5298

5299
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5300
    s->alproto = ALPROTO_UNKNOWN;
1✔
5301
    alprotos[0] = 1;
1✔
5302
    alprotos[1] = 2;
1✔
5303
    alprotos[2] = 3;
1✔
5304
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5305
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5306
    alprotos[0] = 4;
1✔
5307
    alprotos[1] = 5;
1✔
5308
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5309
    // fail if multiple do not have intersection
5310
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5311

5312
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5313
    s->alproto = ALPROTO_UNKNOWN;
1✔
5314
    alprotos[0] = 1;
1✔
5315
    alprotos[1] = 2;
1✔
5316
    alprotos[2] = 3;
1✔
5317
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5318
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5319
    alprotos[0] = 3;
1✔
5320
    alprotos[1] = 4;
1✔
5321
    alprotos[2] = 5;
1✔
5322
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5323
    // check multiple intersect to singleton
5324
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5325
    FAIL_IF(s->alproto != 3);
1✔
5326
    alprotos[0] = 5;
1✔
5327
    alprotos[1] = 4;
1✔
5328
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5329
    // fail if multiple do not belong to singleton
5330
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5331

5332
    SigFree(NULL, s);
1✔
5333
    PASS;
1✔
5334
}
1✔
5335

5336
static int DetectSetupDirection01(void)
5337
{
1✔
5338
    Signature *s = SigAlloc();
1✔
5339
    FAIL_IF_NULL(s);
1✔
5340
    // Basic case : ok
5341
    char *str = (char *)"to_client";
1✔
5342
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5343
    SigFree(NULL, s);
1✔
5344
    PASS;
1✔
5345
}
1✔
5346

5347
static int DetectSetupDirection02(void)
5348
{
1✔
5349
    Signature *s = SigAlloc();
1✔
5350
    FAIL_IF_NULL(s);
1✔
5351
    char *str = (char *)"to_server";
1✔
5352
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5353
    // ok so far
5354
    str = (char *)"to_client";
1✔
5355
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5356
    // fails because we cannot have both to_client and to_server for same signature
5357
    SigFree(NULL, s);
1✔
5358
    PASS;
1✔
5359
}
1✔
5360

5361
static int DetectSetupDirection03(void)
5362
{
1✔
5363
    Signature *s = SigAlloc();
1✔
5364
    FAIL_IF_NULL(s);
1✔
5365
    char *str = (char *)"to_client , something";
1✔
5366
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5367
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5368
    str = (char *)"to_client,something";
1✔
5369
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5370
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5371
    SigFree(NULL, s);
1✔
5372
    PASS;
1✔
5373
}
1✔
5374

5375
static int DetectSetupDirection04(void)
5376
{
1✔
5377
    Signature *s = SigAlloc();
1✔
5378
    FAIL_IF_NULL(s);
1✔
5379
    // invalid case
5380
    char *str = (char *)"to_client_toto";
1✔
5381
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5382
    // test we do not change the string pointer if only_dir is false
5383
    str = (char *)"to_client_toto";
1✔
5384
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5385
    FAIL_IF(strcmp(str, "to_client_toto") != 0);
1✔
5386
    str = (char *)"to_client,something";
1✔
5387
    // fails because we call with only_dir=true
5388
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5389
    SigFree(NULL, s);
1✔
5390
    PASS;
1✔
5391
}
1✔
5392

5393
#endif /* UNITTESTS */
5394

5395
#ifdef UNITTESTS
5396
void DetectParseRegisterTests (void);
5397
#include "tests/detect-parse.c"
5398
#endif
5399

5400
void SigParseRegisterTests(void)
5401
{
1✔
5402
#ifdef UNITTESTS
1✔
5403
    DetectParseRegisterTests();
1✔
5404

5405
    UtRegisterTest("SigParseTest01", SigParseTest01);
1✔
5406
    UtRegisterTest("SigParseTest02", SigParseTest02);
1✔
5407
    UtRegisterTest("SigParseTest03", SigParseTest03);
1✔
5408
    UtRegisterTest("SigParseTest04", SigParseTest04);
1✔
5409
    UtRegisterTest("SigParseTest05", SigParseTest05);
1✔
5410
    UtRegisterTest("SigParseTest06", SigParseTest06);
1✔
5411
    UtRegisterTest("SigParseTest07", SigParseTest07);
1✔
5412
    UtRegisterTest("SigParseTest08", SigParseTest08);
1✔
5413
    UtRegisterTest("SigParseTest09", SigParseTest09);
1✔
5414
    UtRegisterTest("SigParseTest10", SigParseTest10);
1✔
5415
    UtRegisterTest("SigParseTest11", SigParseTest11);
1✔
5416
    UtRegisterTest("SigParseTest12", SigParseTest12);
1✔
5417
    UtRegisterTest("SigParseTest13", SigParseTest13);
1✔
5418
    UtRegisterTest("SigParseTest14", SigParseTest14);
1✔
5419
    UtRegisterTest("SigParseTest15", SigParseTest15);
1✔
5420
    UtRegisterTest("SigParseTest16", SigParseTest16);
1✔
5421
    UtRegisterTest("SigParseTest17", SigParseTest17);
1✔
5422
    UtRegisterTest("SigParseTest18", SigParseTest18);
1✔
5423
    UtRegisterTest("SigParseTest19", SigParseTest19);
1✔
5424
    UtRegisterTest("SigParseTest20", SigParseTest20);
1✔
5425
    UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
1✔
5426
    UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
1✔
5427
    UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
1✔
5428

5429
    UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
1✔
5430
    UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
1✔
5431
    UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
1✔
5432
    UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
1✔
5433
    UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
1✔
5434
    UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
1✔
5435
    UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
1✔
5436
    UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
1✔
5437
    UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
1✔
5438
    UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
1✔
5439
    UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
1✔
5440
    UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
1✔
5441
    UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
1✔
5442
    UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
1✔
5443
    UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
1✔
5444
    UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
1✔
5445
    UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
1✔
5446
    UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
1✔
5447
    UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
1✔
5448
    UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
1✔
5449
    UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
1✔
5450
    UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
1✔
5451
    UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
1✔
5452
    UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
1✔
5453
    UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
1✔
5454
    UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
1✔
5455
    UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
1✔
5456

5457
    UtRegisterTest("SigParseTestContentGtDsize01",
1✔
5458
            SigParseTestContentGtDsize01);
1✔
5459
    UtRegisterTest("SigParseTestContentGtDsize02",
1✔
5460
            SigParseTestContentGtDsize02);
1✔
5461

5462
    UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
1✔
5463
            SigParseBidirWithSameSrcAndDest01);
1✔
5464
    UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
1✔
5465
            SigParseBidirWithSameSrcAndDest02);
1✔
5466
    UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
1✔
5467
    UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
1✔
5468

5469
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
1✔
5470

5471
    UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
1✔
5472
    UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
1✔
5473
    UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
1✔
5474
    UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
1✔
5475

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

© 2026 Coveralls, Inc