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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

86.02
/src/detect-parse.c
1
/* Copyright (C) 2007-2025 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * signature parser
24
 */
25

26
#include "suricata-common.h"
27

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

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

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

54
#include "flow.h"
55

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

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

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

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

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

81
extern bool sc_set_caps;
82

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

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

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

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

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

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

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

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

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

226
    if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
56,719✔
227
        if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
39,757✔
228
            SCLogError("no matches for previous buffer");
40✔
229
            return -1;
40✔
230
        }
40✔
231
        bool reuse_buffer = false;
39,757✔
232
        if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
39,717✔
233
            for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
15,356✔
234
                if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
10,597✔
235
                    s->init_data->curbuf = &s->init_data->buffers[x];
2,920✔
236
                    reuse_buffer = true;
2,920✔
237
                    break;
2,920✔
238
                }
2,920✔
239
            }
10,597✔
240
        }
7,679✔
241

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

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

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

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

269
    ret = 0;
56,678✔
270
 end:
57,587✔
271
    return ret;
57,587✔
272
}
56,678✔
273

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

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

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

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

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

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

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
539,305,360✔
317
        st = &sigmatch_table[i];
539,032,730✔
318

319
        if (st->name != NULL) {
539,032,730✔
320
            if (strcasecmp(name,st->name) == 0)
513,675,529✔
321
                return st;
7,216,191✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
506,459,338✔
323
                return st;
91,204✔
324
        }
506,459,338✔
325
    }
539,032,730✔
326

327
    return NULL;
272,630✔
328
}
7,580,025✔
329

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

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

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

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

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

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

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

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

394
    new->type = type;
1,916,165✔
395
    new->ctx = ctx;
1,916,165✔
396

397
    if (new->type == DETECT_CONTENT) {
1,916,165✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
624,884✔
399
    }
624,884✔
400

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

405
    if (list < DETECT_SM_LIST_MAX) {
1,916,165✔
406
        if (s->init_data->smlists[list] == NULL) {
1,015,665✔
407
            s->init_data->smlists[list] = new;
686,873✔
408
            s->init_data->smlists_tail[list] = new;
686,873✔
409
            new->next = NULL;
686,873✔
410
            new->prev = NULL;
686,873✔
411
        } else {
686,873✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
328,792✔
413
            cur->next = new;
328,792✔
414
            new->prev = cur;
328,792✔
415
            new->next = NULL;
328,792✔
416
            s->init_data->smlists_tail[list] = new;
328,792✔
417
        }
328,792✔
418
        new->idx = s->init_data->sm_cnt;
1,015,665✔
419
        s->init_data->sm_cnt++;
1,015,665✔
420

421
    } else {
1,015,665✔
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) {
900,500✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
14,187✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
14,187✔
429
        }
14,187✔
430

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

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

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

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
3,762,668✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
2,862,171✔
480
                    sigmatch_table[sm->type].name, sm->idx);
2,862,171✔
481
        }
2,862,171✔
482
    }
900,497✔
483
    return new;
1,916,162✔
484
}
1,916,165✔
485

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

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

518
    return NULL;
475,962✔
519
}
1,131,579✔
520

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

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
66,676✔
533
        const int id = s->init_data->buffers[i].id;
37,719✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
37,719✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
36,908✔
536
            if (sm_new == NULL)
36,908✔
537
                continue;
3,174✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
33,734✔
539
                sm_last = sm_new;
32,379✔
540
        }
33,734✔
541
    }
37,719✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
231,656✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
202,699✔
545
            continue;
202,699✔
546
        SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
×
547
        sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
×
548
        if (sm_new == NULL)
×
549
            continue;
×
550
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
×
551
            sm_last = sm_new;
×
552
    }
×
553

554
    return sm_last;
28,957✔
555
}
28,957✔
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
{
438,155✔
565
    SigMatch *sm_last = NULL;
438,155✔
566
    SigMatch *sm_new;
438,155✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
438,155✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
701,783✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
263,628✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
263,628✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
25,898✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
25,898✔
574

575
            continue;
25,898✔
576
        }
25,898✔
577
        int sm_type;
237,730✔
578
        va_list ap;
237,730✔
579
        va_start(ap, s);
237,730✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
543,171✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
305,441✔
583
            if (sm_new == NULL)
305,441✔
584
                continue;
105,220✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
200,221✔
586
                sm_last = sm_new;
191,081✔
587
        }
200,221✔
588
        va_end(ap);
237,730✔
589
    }
237,730✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
3,505,240✔
592
        if (s->init_data->smlists[buf_type] == NULL)
3,067,085✔
593
            continue;
2,693,315✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
373,770✔
595
            buf_type != s->init_data->list)
373,770✔
596
            continue;
75,007✔
597

598
        int sm_type;
298,763✔
599
        va_list ap;
298,763✔
600
        va_start(ap, s);
298,763✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
769,789✔
603
        {
471,026✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
471,026✔
605
            if (sm_new == NULL)
471,026✔
606
                continue;
242,690✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
228,336✔
608
                sm_last = sm_new;
220,799✔
609
        }
228,336✔
610
        va_end(ap);
298,763✔
611
    }
298,763✔
612

613
    return sm_last;
438,155✔
614
}
438,155✔
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
{
144,482✔
627
    SigMatch *sm_last = NULL;
144,482✔
628
    SigMatch *sm_new;
144,482✔
629
    int sm_type;
144,482✔
630

631
    va_list ap;
144,482✔
632
    va_start(ap, sm_list);
144,482✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
396,538✔
635
    {
252,056✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
252,056✔
637
        if (sm_new == NULL)
252,056✔
638
            continue;
110,526✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
141,530✔
640
            sm_last = sm_new;
131,318✔
641
    }
141,530✔
642

643
    va_end(ap);
144,482✔
644

645
    return sm_last;
144,482✔
646
}
144,482✔
647

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

663
    if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
145,125✔
664
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
58,746✔
665
            sm_new = s->init_data->buffers[x].tail;
35,289✔
666
            if (sm_new == NULL)
35,289✔
667
                continue;
16,057✔
668

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

672
            for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
38,464✔
673
                sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
19,232✔
674
                if (sm_new == NULL)
19,232✔
675
                    continue;
7,712✔
676
                if (sm_last == NULL || sm_new->idx > sm_last->idx)
11,520✔
677
                    sm_last = sm_new;
10,117✔
678
            }
11,520✔
679

680
            va_end(ap);
19,232✔
681
        }
19,232✔
682
    } else {
121,668✔
683
        SigMatch *sm_list = s->init_data->smlists_tail[list_id];
121,668✔
684
        if (sm_list == NULL)
121,668✔
685
            return NULL;
37,844✔
686

687
        va_list ap;
83,824✔
688
        va_start(ap, list_id);
83,824✔
689

690
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
167,648✔
691
            sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
83,824✔
692
            if (sm_new == NULL)
83,824✔
693
                continue;
9,814✔
694
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
74,010✔
695
                sm_last = sm_new;
74,010✔
696
        }
74,010✔
697

698
        va_end(ap);
83,824✔
699
    }
83,824✔
700
    return sm_last;
107,281✔
701
}
145,125✔
702

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

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

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

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

738
    if (sm->prev != NULL)
56,678✔
739
        sm->prev->next = sm->next;
9,016✔
740
    if (sm->next != NULL)
56,678✔
741
        sm->next->prev = sm->prev;
807✔
742

743
    if (sm == *src_sm_list)
56,678✔
744
        *src_sm_list = sm->next;
47,662✔
745
    if (sm == *src_sm_list_tail)
56,678✔
746
        *src_sm_list_tail = sm->prev;
55,871✔
747

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

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

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
53,392✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
30,507✔
769
        while (sm != NULL) {
90,980✔
770
            if (sm == key_sm)
84,411✔
771
                return s->init_data->buffers[x].id;
23,938✔
772
            sm = sm->next;
60,473✔
773
        }
60,473✔
774
    }
30,507✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
45,772✔
777
        const SigMatch *sm = s->init_data->smlists[list];
45,772✔
778
        while (sm != NULL) {
178,544✔
779
            if (sm == key_sm)
155,657✔
780
                return list;
22,885✔
781
            sm = sm->next;
132,772✔
782
        }
132,772✔
783
    }
45,772✔
784

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

790
/**
791
 * \brief Parse and setup a direction
792
 *
793
 * \param s signature
794
 * \param str argument to the keyword
795
 * \param only_dir argument wether the keyword only accepts a direction
796
 *
797
 * \retval 0 on success, -1 on failure
798
 */
799
static int DetectSetupDirection(Signature *s, char **str, bool only_dir)
800
{
1,445✔
801
    char *orig = *str;
1,445✔
802
    if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
1,445✔
803
        *str += strlen("to_client");
606✔
804
        // skip space
805
        while (**str && isblank(**str)) {
679✔
806
            (*str)++;
73✔
807
        }
73✔
808
        // check comma or nothing
809
        if (**str) {
606✔
810
            if (only_dir) {
43✔
811
                SCLogError("unknown option: only accepts to_server or to_client");
9✔
812
                return -1;
9✔
813
            }
9✔
814
            if (**str != ',') {
34✔
815
                // leave to_client_something for next parser if not only_dir
816
                *str = orig;
3✔
817
                return 0;
3✔
818
            } else {
31✔
819
                (*str)++;
31✔
820
            }
31✔
821
            while (**str && isblank(**str)) {
60✔
822
                (*str)++;
29✔
823
            }
29✔
824
        }
31✔
825
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
594✔
826
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
594✔
827
            if (s->flags & SIG_FLAG_TOSERVER) {
346✔
828
                SCLogError("contradictory directions");
1✔
829
                return -1;
1✔
830
            }
1✔
831
            s->flags |= SIG_FLAG_TOCLIENT;
345✔
832
        }
345✔
833
    } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
839✔
834
        *str += strlen("to_server");
282✔
835
        // skip space
836
        while (**str && isblank(**str)) {
318✔
837
            (*str)++;
36✔
838
        }
36✔
839
        // check comma or nothing
840
        if (**str) {
282✔
841
            if (only_dir) {
8✔
842
                SCLogError("unknown option: only accepts to_server or to_client");
7✔
843
                return -1;
7✔
844
            }
7✔
845
            if (**str != ',') {
1✔
846
                // leave to_client_something for next parser if not only_dir
847
                *str = orig;
1✔
848
                return 0;
1✔
849
            } else {
1✔
850
                (*str)++;
×
851
            }
×
852
            while (**str && isblank(**str)) {
×
853
                (*str)++;
×
854
            }
×
855
        }
×
856
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOSERVER;
274✔
857
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
274✔
858
            if (s->flags & SIG_FLAG_TOCLIENT) {
144✔
859
                SCLogError("contradictory directions");
1✔
860
                return -1;
1✔
861
            }
1✔
862
            s->flags |= SIG_FLAG_TOSERVER;
143✔
863
        }
143✔
864
    } else if (only_dir) {
557✔
865
        SCLogError("unknown option: only accepts to_server or to_client");
59✔
866
        return -1;
59✔
867
    }
59✔
868
    return 0;
1,364✔
869
}
1,445✔
870

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

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
19,234,548✔
880
        optstr++;
16,484,688✔
881
    }
16,484,688✔
882

883
    /* Look for the end of this option, handling escaped semicolons. */
884
    char *optend = optstr;
19,234,548✔
885
    for (;;) {
19,247,560✔
886
        optend = strchr(optend, ';');
19,247,560✔
887
        if (optend == NULL) {
19,247,560✔
888
            SCLogError("no terminating \";\" found");
236,169✔
889
            goto error;
236,169✔
890
        }
236,169✔
891
        else if (optend > optstr && *(optend -1 ) == '\\') {
19,011,391✔
892
            optend++;
13,012✔
893
        } else {
18,998,379✔
894
            break;
18,998,379✔
895
        }
18,998,379✔
896
    }
19,247,560✔
897
    *(optend++) = '\0';
18,998,379✔
898

899
    /* Find the start of the option value. */
900
    char *optvalptr = strchr(optstr, ':');
18,998,379✔
901
    if (optvalptr) {
18,998,379✔
902
        *(optvalptr++) = '\0';
15,956,284✔
903

904
        /* Trim trailing space from name. */
905
        for (size_t i = strlen(optvalptr); i > 0; i--) {
16,290,088✔
906
            if (isblank(optvalptr[i - 1])) {
16,249,309✔
907
                optvalptr[i - 1] = '\0';
333,804✔
908
            } else {
15,915,505✔
909
                break;
15,915,505✔
910
            }
15,915,505✔
911
        }
16,249,309✔
912

913
        optvalue = optvalptr;
15,956,284✔
914
    }
15,956,284✔
915

916
    /* Trim trailing space from name. */
917
    for (size_t i = strlen(optstr); i > 0; i--) {
19,049,104✔
918
        if (isblank(optstr[i - 1])) {
18,981,082✔
919
            optstr[i - 1] = '\0';
50,725✔
920
        } else {
18,930,357✔
921
            break;
18,930,357✔
922
        }
18,930,357✔
923
    }
18,981,082✔
924
    optname = optstr;
18,998,379✔
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;
18,998,379✔
929
    if ((requires && !requires_only) || (!requires && requires_only)) {
18,998,379✔
930
        goto finish;
11,418,354✔
931
    }
11,418,354✔
932

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

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
7,307,394✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
6,482,621✔
942
            SCLogError(
6,363✔
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
6,363✔
944
            goto error;
6,363✔
945
        }
6,363✔
946
    } else if (st->flags & SIGMATCH_NOOPT) {
6,482,621✔
947
        if (optvalue && strlen(optvalue)) {
662,334✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
130✔
949
            goto error;
130✔
950
        }
130✔
951
    }
662,334✔
952
    s->init_data->negated = false;
7,300,901✔
953

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

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

971
    int setup_ret = 0;
7,300,901✔
972

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

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

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

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

1021
        if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
6,490,902✔
1022
                && ovlen && *ptr == '"')
6,490,902✔
1023
        {
1,648,827✔
1024
            for (; ovlen > 0; ovlen--) {
1,648,827✔
1025
                if (isblank(ptr[ovlen - 1])) {
1,648,827✔
1026
                    ptr[ovlen - 1] = '\0';
×
1027
                } else {
1,648,827✔
1028
                    break;
1,648,827✔
1029
                }
1,648,827✔
1030
            }
1,648,827✔
1031
            if (ovlen && ptr[ovlen - 1] != '"') {
1,648,827✔
1032
                SCLogError("bad option value formatting (possible missing semicolon) "
48,600✔
1033
                           "for keyword %s: \'%s\'",
48,600✔
1034
                        optname, optvalue);
48,600✔
1035
                goto error;
48,600✔
1036
            }
48,600✔
1037
            if (ovlen > 1) {
1,600,227✔
1038
                /* strip leading " */
1039
                ptr++;
1,581,787✔
1040
                ovlen--;
1,581,787✔
1041
                ptr[ovlen - 1] = '\0';
1,581,787✔
1042
                ovlen--;
1,581,787✔
1043
            }
1,581,787✔
1044
            if (ovlen == 0) {
1,600,227✔
1045
                SCLogError("bad input "
613✔
1046
                           "for keyword %s: \'%s\'",
613✔
1047
                        optname, optvalue);
613✔
1048
                goto error;
613✔
1049
            }
613✔
1050
        } else {
4,842,075✔
1051
            if (*ptr == '"') {
4,842,075✔
1052
                SCLogError(
1,280✔
1053
                        "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1,280✔
1054
                goto error;
1,280✔
1055
            }
1,280✔
1056
        }
4,842,075✔
1057
        /* setup may or may not add a new SigMatch to the list */
1058
        if (st->flags & SIGMATCH_SUPPORT_DIR) {
6,440,409✔
1059
            if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1,445✔
1060
                SCLogError("%s failed to setup direction", st->name);
77✔
1061
                goto error;
77✔
1062
            }
77✔
1063
        }
1,445✔
1064
        setup_ret = st->Setup(de_ctx, s, ptr);
6,440,332✔
1065
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
6,440,332✔
1066
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
6,440,332✔
1067
    } else {
6,440,332✔
1068
        /* setup may or may not add a new SigMatch to the list */
1069
        setup_ret = st->Setup(de_ctx, s, NULL);
799,027✔
1070
    }
799,027✔
1071
    if (setup_ret < 0) {
7,239,359✔
1072
        SCLogDebug("\"%s\" failed to setup", st->name);
634,329✔
1073

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

1086
finish:
18,023,384✔
1087
    if (strlen(optend) > 0) {
18,023,384✔
1088
        strlcpy(output, optend, output_size);
14,407,081✔
1089
        return 1;
14,407,081✔
1090
    }
14,407,081✔
1091

1092
    return 0;
3,616,303✔
1093

1094
error:
576,835✔
1095
    return -1;
576,835✔
1096
}
18,023,384✔
1097

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

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
3,921,411✔
1109
        if (strcasecmp(addrstr, "any") == 0)
1,983,993✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
1,672,300✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1,983,993✔
1113
                &s->init_data->src_contains_negation);
1,983,993✔
1114
        if (s->init_data->src == NULL)
1,983,993✔
1115
            goto error;
46,575✔
1116
    } else {
1,983,993✔
1117
        if (strcasecmp(addrstr, "any") == 0)
1,937,418✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
1,690,038✔
1119

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

1126
    return 0;
3,796,128✔
1127

1128
error:
125,283✔
1129
    return -1;
125,283✔
1130
}
3,921,411✔
1131

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

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

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

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

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

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

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

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

1216
                DetectAppLayerInspectEngineRegister(
42✔
1217
                        list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
42✔
1218
            }
42✔
1219
        }
281✔
1220
    }
114✔
1221
}
3✔
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
{
152✔
1240
    if (strcmp(str, "flow_start") == 0) {
152✔
1241
        return SIGNATURE_HOOK_PKT_FLOW_START;
2✔
1242
    } else if (strcmp(str, "pre_flow") == 0) {
150✔
1243
        return SIGNATURE_HOOK_PKT_PRE_FLOW;
2✔
1244
    } else if (strcmp(str, "pre_stream") == 0) {
148✔
1245
        return SIGNATURE_HOOK_PKT_PRE_STREAM;
2✔
1246
    } else if (strcmp(str, "all") == 0) {
146✔
1247
        return SIGNATURE_HOOK_PKT_ALL;
2✔
1248
    }
2✔
1249
    return SIGNATURE_HOOK_PKT_NOT_SET;
144✔
1250
}
152✔
1251

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

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

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

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

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

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

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

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

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

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

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

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

1409
    int r = DetectProtoParse(&s->proto, p);
2,136,624✔
1410
    if (r < 0) {
2,136,624✔
1411
        s->alproto = AppLayerGetProtoByName(p);
1,044,088✔
1412
        /* indicate that the signature is app-layer */
1413
        if (s->alproto != ALPROTO_UNKNOWN) {
1,044,088✔
1414
            s->flags |= SIG_FLAG_APPLAYER;
984,351✔
1415

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
984,351✔
1417

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

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

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

1451
    SCReturnInt(0);
2,076,616✔
1452
}
2,136,624✔
1453

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

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

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

1475
    if (flag == 0) {
3,698,180✔
1476
        if (strcasecmp(portstr, "any") == 0)
1,858,710✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
1,439,912✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1,858,710✔
1480
    } else if (flag == 1) {
1,858,710✔
1481
        if (strcasecmp(portstr, "any") == 0)
1,839,470✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
1,358,832✔
1483

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

1487
    if (r < 0)
3,698,180✔
1488
        return -1;
94,526✔
1489

1490
    return 0;
3,603,654✔
1491
}
3,698,180✔
1492

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

1516
/** \retval 0 on error
1517
 *  \retval flags on success
1518
 */
1519
static uint8_t ActionStringToFlags(const char *action)
1520
{
2,208,112✔
1521
    if (strcasecmp(action, "alert") == 0) {
2,208,112✔
1522
        return ACTION_ALERT;
1,752,805✔
1523
    } else if (strcasecmp(action, "drop") == 0) {
1,752,805✔
1524
        return ACTION_DROP | ACTION_ALERT;
73,887✔
1525
    } else if (strcasecmp(action, "pass") == 0) {
381,420✔
1526
        return ACTION_PASS;
309,075✔
1527
    } else if (strcasecmp(action, "reject") == 0 ||
309,075✔
1528
               strcasecmp(action, "rejectsrc") == 0)
72,345✔
1529
    {
505✔
1530
        if (!(SigParseActionRejectValidate(action)))
505✔
1531
            return 0;
×
1532
        return ACTION_REJECT | ACTION_DROP | ACTION_ALERT;
505✔
1533
    } else if (strcasecmp(action, "rejectdst") == 0) {
71,840✔
1534
        if (!(SigParseActionRejectValidate(action)))
15✔
1535
            return 0;
×
1536
        return ACTION_REJECT_DST | ACTION_DROP | ACTION_ALERT;
15✔
1537
    } else if (strcasecmp(action, "rejectboth") == 0) {
71,825✔
1538
        if (!(SigParseActionRejectValidate(action)))
143✔
1539
            return 0;
×
1540
        return ACTION_REJECT_BOTH | ACTION_DROP | ACTION_ALERT;
143✔
1541
    } else if (strcasecmp(action, "config") == 0) {
71,682✔
1542
        return ACTION_CONFIG;
2,036✔
1543
    } else if (strcasecmp(action, "accept") == 0) {
69,646✔
1544
        return ACTION_ACCEPT;
41✔
1545
    } else {
69,605✔
1546
        SCLogError("An invalid action \"%s\" was given", action);
69,605✔
1547
        return 0;
69,605✔
1548
    }
69,605✔
1549
}
2,208,112✔
1550

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

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

1581
    uint8_t flags = ActionStringToFlags(a);
2,208,112✔
1582
    if (flags == 0)
2,208,112✔
1583
        return -1;
69,605✔
1584

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

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

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

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

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

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

1670
    if (!len) {
12,346,230✔
1671
        return 0;
606,157✔
1672
    }
606,157✔
1673

1674
    while (len && isblank(**input)) {
11,848,688✔
1675
        (*input)++;
108,615✔
1676
        len--;
108,615✔
1677
    }
108,615✔
1678

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

1686
    return 1;
11,740,073✔
1687
}
12,346,230✔
1688

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

1706
    if (len == 0) {
30,865,575✔
1707
        return 0;
2,550,634✔
1708
    }
2,550,634✔
1709

1710
    while (len && isblank(**input)) {
28,911,263✔
1711
        (*input)++;
596,322✔
1712
        len--;
596,322✔
1713
    }
596,322✔
1714

1715
    size_t i = 0;
28,314,941✔
1716
    for (i = 0; i < len; i++) {
158,162,839✔
1717
        char c = (*input)[i];
157,609,033✔
1718
        if (c == '[') {
157,609,033✔
1719
            in_list++;
471,542✔
1720
        } else if (c == ']') {
157,137,491✔
1721
            in_list--;
525,282✔
1722
        } else if (c == ' ') {
156,612,209✔
1723
            if (!in_list) {
28,245,093✔
1724
                break;
27,761,135✔
1725
            }
27,761,135✔
1726
        }
28,245,093✔
1727
    }
157,609,033✔
1728
    if (i == len) {
28,314,941✔
1729
        *input = NULL;
553,806✔
1730
        return 0;
553,806✔
1731
    }
553,806✔
1732
    (*input)[i] = '\0';
27,761,135✔
1733
    strlcpy(output, *input, output_size);
27,761,135✔
1734
    *input = *input + i + 1;
27,761,135✔
1735

1736
    return 1;
27,761,135✔
1737
}
28,314,941✔
1738

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

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
6,173,115✔
1751
    index = dup;
6,173,115✔
1752

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

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

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

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

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

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

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

1774
    /* Options. */
1775
    if (index == NULL) {
6,173,115✔
1776
        SCLogError("no rule options.");
832,177✔
1777
        goto error;
832,177✔
1778
    }
832,177✔
1779
    while (isspace(*index) || *index == '(') {
9,088,306✔
1780
        index++;
3,747,368✔
1781
    }
3,747,368✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
10,547,662✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
10,478,125✔
1784
            index[i - 1] = '\0';
5,206,724✔
1785
        } else {
5,271,401✔
1786
            break;
5,271,401✔
1787
        }
5,271,401✔
1788
    }
10,478,125✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
5,340,938✔
1790

1791
    if (scan_only) {
5,340,938✔
1792
        return 0;
3,132,820✔
1793
    }
3,132,820✔
1794

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

1799
    if (SigParseProto(s, parser->protocol) < 0)
2,138,442✔
1800
        goto error;
61,826✔
1801

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

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

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

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

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

1834
    return 0;
1,764,184✔
1835

1836
error:
1,276,111✔
1837
    return -1;
1,276,111✔
1838
}
1,839,470✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
6,470,376✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
913,153,722✔
1843
        if (str[i] < 0x20) {
906,980,607✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1,672,909✔
1846
                continue;
1,397,737✔
1847
            }
1,397,737✔
1848
            return false;
275,172✔
1849
        } else if (str[i] == 0x7f) {
905,307,698✔
1850
            return false;
22,089✔
1851
        }
22,089✔
1852
    }
906,980,607✔
1853
    return true;
6,173,115✔
1854
}
6,470,376✔
1855

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

1873
    if (!SCCheckUtf8(sigstr)) {
7,363,146✔
1874
        SCLogError("rule is not valid UTF-8");
892,770✔
1875
        SCReturnInt(-1);
892,770✔
1876
    }
892,770✔
1877

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

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

1889
    /* we can have no options, so make sure we have them */
1890
    if (strlen(parser->opts) > 0) {
4,897,004✔
1891
        size_t buffer_size = strlen(parser->opts) + 1;
4,827,467✔
1892
        DEBUG_VALIDATE_BUG_ON(buffer_size > DETECT_MAX_RULE_SIZE);
4,827,467✔
1893
        char input[buffer_size];
4,827,467✔
1894
        char output[buffer_size];
4,827,467✔
1895
        memset(input, 0x00, buffer_size);
4,827,467✔
1896
        memcpy(input, parser->opts, strlen(parser->opts) + 1);
4,827,467✔
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 {
19,234,548✔
1902
            memset(output, 0x00, buffer_size);
19,234,548✔
1903
            ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
19,234,548✔
1904
            if (ret == 1) {
19,234,548✔
1905
                memcpy(input, output, buffer_size);
14,407,081✔
1906
            }
14,407,081✔
1907

1908
        } while (ret == 1);
19,234,548✔
1909

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

1916
end:
4,897,004✔
1917
    DetectIPProtoRemoveAllSMs(de_ctx, s);
4,897,004✔
1918

1919
    SCReturnInt(ret);
4,897,004✔
1920
}
4,897,004✔
1921

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

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

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

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

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

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

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

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

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

1989
    DetectMetadata *mdata = NULL;
5,155,026✔
1990
    DetectMetadata *next_mdata = NULL;
5,155,026✔
1991

1992
    if (s == NULL || s->metadata == NULL) {
5,155,026✔
1993
        SCReturn;
5,137,150✔
1994
    }
5,137,150✔
1995

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

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

2007
    SCReturn;
17,876✔
2008
}
5,155,026✔
2009

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

2020
    DetectReference *ref = NULL;
5,155,026✔
2021
    DetectReference *next_ref = NULL;
5,155,026✔
2022

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

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

2029
    for (ref = s->references; ref != NULL;)   {
5,186,932✔
2030
        next_ref = ref->next;
31,906✔
2031
        DetectReferenceFree(ref);
31,906✔
2032
        ref = next_ref;
31,906✔
2033
    }
31,906✔
2034

2035
    s->references = NULL;
5,155,026✔
2036

2037
    SCReturn;
5,155,026✔
2038
}
5,155,026✔
2039

2040
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041
{
5,155,026✔
2042
    if (s != NULL) {
5,155,026✔
2043
        int type;
5,155,026✔
2044
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
41,240,208✔
2045
            if (s->sm_arrays[type] != NULL) {
36,085,182✔
2046
                if (ctxs) {
74,303✔
2047
                    SigMatchData *smd = s->sm_arrays[type];
74,303✔
2048
                    while(1) {
94,416✔
2049
                        if (sigmatch_table[smd->type].Free != NULL) {
94,416✔
2050
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
94,115✔
2051
                        }
94,115✔
2052
                        if (smd->is_last)
94,416✔
2053
                            break;
74,303✔
2054
                        smd++;
20,113✔
2055
                    }
20,113✔
2056
                }
74,303✔
2057

2058
                SCFree(s->sm_arrays[type]);
74,303✔
2059
            }
74,303✔
2060
        }
36,085,182✔
2061
    }
5,155,026✔
2062
}
5,155,026✔
2063

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

2069
    int i;
5,155,026✔
2070

2071
    if (s->init_data && s->init_data->transforms.cnt) {
5,155,026✔
2072
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
57,295✔
2073
            if (s->init_data->transforms.transforms[i].options) {
32,534✔
2074
                int transform = s->init_data->transforms.transforms[i].transform;
12,195✔
2075
                sigmatch_table[transform].Free(
12,195✔
2076
                        de_ctx, s->init_data->transforms.transforms[i].options);
12,195✔
2077
                s->init_data->transforms.transforms[i].options = NULL;
12,195✔
2078
            }
12,195✔
2079
        }
32,534✔
2080
    }
24,761✔
2081
    if (s->init_data) {
5,155,026✔
2082
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
40,285,720✔
2083
            SigMatch *sm = s->init_data->smlists[i];
35,250,005✔
2084
            while (sm != NULL) {
36,099,453✔
2085
                SigMatch *nsm = sm->next;
849,448✔
2086
                SigMatchFree(de_ctx, sm);
849,448✔
2087
                sm = nsm;
849,448✔
2088
            }
849,448✔
2089
        }
35,250,005✔
2090

2091
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
5,899,362✔
2092
            SigMatch *sm = s->init_data->buffers[x].head;
863,647✔
2093
            while (sm != NULL) {
1,744,467✔
2094
                SigMatch *nsm = sm->next;
880,820✔
2095
                SigMatchFree(de_ctx, sm);
880,820✔
2096
                sm = nsm;
880,820✔
2097
            }
880,820✔
2098
        }
863,647✔
2099
        if (s->init_data->cidr_dst != NULL)
5,035,715✔
2100
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
74,659✔
2101

2102
        if (s->init_data->cidr_src != NULL)
5,035,715✔
2103
            IPOnlyCIDRListFree(s->init_data->cidr_src);
76,363✔
2104

2105
        SCFree(s->init_data->buffers);
5,035,715✔
2106
        s->init_data->buffers = NULL;
5,035,715✔
2107
    }
5,035,715✔
2108
    SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
5,155,026✔
2109
    if (s->init_data) {
5,155,026✔
2110
        SCFree(s->init_data);
5,035,715✔
2111
        s->init_data = NULL;
5,035,715✔
2112
    }
5,035,715✔
2113

2114
    if (s->sp != NULL) {
5,155,026✔
2115
        DetectPortCleanupList(NULL, s->sp);
1,839,472✔
2116
    }
1,839,472✔
2117
    if (s->dp != NULL) {
5,155,026✔
2118
        DetectPortCleanupList(NULL, s->dp);
1,766,467✔
2119
    }
1,766,467✔
2120

2121
    if (s->msg != NULL)
5,155,026✔
2122
        SCFree(s->msg);
858,926✔
2123

2124
    if (s->addr_src_match4 != NULL) {
5,155,026✔
2125
        SCFree(s->addr_src_match4);
830,102✔
2126
    }
830,102✔
2127
    if (s->addr_dst_match4 != NULL) {
5,155,026✔
2128
        SCFree(s->addr_dst_match4);
830,222✔
2129
    }
830,222✔
2130
    if (s->addr_src_match6 != NULL) {
5,155,026✔
2131
        SCFree(s->addr_src_match6);
921,270✔
2132
    }
921,270✔
2133
    if (s->addr_dst_match6 != NULL) {
5,155,026✔
2134
        SCFree(s->addr_dst_match6);
921,653✔
2135
    }
921,653✔
2136
    if (s->sig_str != NULL) {
5,155,026✔
2137
        SCFree(s->sig_str);
5,155,026✔
2138
    }
5,155,026✔
2139

2140
    SigRefFree(s);
5,155,026✔
2141
    SigMetadataFree(s);
5,155,026✔
2142

2143
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
5,155,026✔
2144

2145
    SCFree(s);
5,155,026✔
2146
}
5,155,026✔
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
{
9,482✔
2160
    if (s->alproto != ALPROTO_UNKNOWN) {
9,482✔
2161
        // One alproto was set, check if it matches the new ones proposed
2162
        while (*alprotos != ALPROTO_UNKNOWN) {
9,037✔
2163
            if (s->alproto == *alprotos) {
8,538✔
2164
                // alproto already set to only one
2165
                return 0;
5,168✔
2166
            }
5,168✔
2167
            alprotos++;
3,370✔
2168
        }
3,370✔
2169
        // alproto already set and not matching the new set of alprotos
2170
        return -1;
499✔
2171
    }
5,667✔
2172
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
3,815✔
2173
        // check intersection of already used alprotos and new ones
2174
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,691✔
2175
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,691✔
2176
                break;
2,897✔
2177
            }
2,897✔
2178
            // first disable the ones that do not match
2179
            bool found = false;
8,691✔
2180
            const AppProto *args = alprotos;
5,794✔
2181
            while (*args != ALPROTO_UNKNOWN) {
8,691✔
2182
                if (s->init_data->alprotos[i] == *args) {
8,691✔
2183
                    found = true;
5,794✔
2184
                    break;
5,794✔
2185
                }
5,794✔
2186
                args++;
2,897✔
2187
            }
2,897✔
2188
            if (!found) {
5,794✔
UNCOV
2189
                s->init_data->alprotos[i] = ALPROTO_UNKNOWN;
×
UNCOV
2190
            }
×
2191
        }
5,794✔
2192
        // Then put at the beginning every defined protocol
2193
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,691✔
2194
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,691✔
2195
                for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
5,794✔
2196
                    if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2,897✔
UNCOV
2197
                        s->init_data->alprotos[i] = s->init_data->alprotos[j];
×
UNCOV
2198
                        s->init_data->alprotos[j] = ALPROTO_UNKNOWN;
×
UNCOV
2199
                        break;
×
UNCOV
2200
                    }
×
2201
                }
2,897✔
2202
                if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2,897✔
2203
                    if (i == 0) {
2,897✔
2204
                        // there was no intersection
UNCOV
2205
                        return -1;
×
2206
                    } else if (i == 1) {
2,897✔
2207
                        // intersection is singleton, set it as usual
UNCOV
2208
                        AppProto alproto = s->init_data->alprotos[0];
×
UNCOV
2209
                        s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
×
UNCOV
2210
                        return SCDetectSignatureSetAppProto(s, alproto);
×
UNCOV
2211
                    }
×
2212
                    break;
2,897✔
2213
                }
2,897✔
2214
            }
2,897✔
2215
        }
8,691✔
2216
    } else {
2,897✔
2217
        if (alprotos[0] == ALPROTO_UNKNOWN) {
918✔
2218
            // do not allow empty set
2219
            return -1;
×
2220
        }
×
2221
        if (alprotos[1] == ALPROTO_UNKNOWN) {
918✔
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++) {
2,754✔
2227
            if (alprotos[i] == ALPROTO_UNKNOWN) {
2,754✔
2228
                break;
918✔
2229
            }
918✔
2230
            s->init_data->alprotos[i] = alprotos[i];
1,836✔
2231
        }
1,836✔
2232
    }
918✔
2233
    return 0;
3,815✔
2234
}
3,815✔
2235

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

2243
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
855,649✔
2244
        // Multiple alprotos were set, check if we restrict to one
2245
        bool found = false;
46✔
2246
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
139✔
2247
            if (s->init_data->alprotos[i] == alproto) {
117✔
2248
                found = true;
24✔
2249
                break;
24✔
2250
            }
24✔
2251
        }
117✔
2252
        if (!found) {
46✔
2253
            // fail if we set to a alproto which was not in the set
2254
            return -1;
22✔
2255
        }
22✔
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;
24✔
2259
    }
24✔
2260

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

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

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

2284
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,548,895✔
2285
        cnt++;
1,676,769✔
2286
    }
1,676,769✔
2287
    if (cnt == 0) {
1,872,126✔
2288
        return NULL;
211,798✔
2289
    }
211,798✔
2290
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
1,660,328✔
2291
    if (addr_match4 == NULL) {
1,660,328✔
2292
        return NULL;
×
2293
    }
×
2294

2295
    uint16_t idx = 0;
1,660,328✔
2296
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,337,097✔
2297
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
1,676,769✔
2298
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
1,676,769✔
2299
        idx++;
1,676,769✔
2300
    }
1,676,769✔
2301
    *match4_cnt = cnt;
1,660,328✔
2302
    return addr_match4;
1,660,328✔
2303
}
1,660,328✔
2304

2305
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2306
        const DetectAddress *head, uint16_t *match6_cnt)
2307
{
1,872,126✔
2308
    uint16_t cnt = 0;
1,872,126✔
2309
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,987,906✔
2310
        cnt++;
2,115,780✔
2311
    }
2,115,780✔
2312
    if (cnt == 0) {
1,872,126✔
2313
        return NULL;
29,199✔
2314
    }
29,199✔
2315

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

2321
    uint16_t idx = 0;
1,842,927✔
2322
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
3,958,707✔
2323
        addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2,115,780✔
2324
        addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2,115,780✔
2325
        addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2,115,780✔
2326
        addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2,115,780✔
2327
        addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2,115,780✔
2328
        addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2,115,780✔
2329
        addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2,115,780✔
2330
        addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2,115,780✔
2331
        idx++;
2,115,780✔
2332
    }
2,115,780✔
2333
    *match6_cnt = cnt;
1,842,927✔
2334
    return addr_match6;
1,842,927✔
2335
}
1,842,927✔
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
{
936,063✔
2345
    /* source addresses */
2346
    s->addr_src_match4 =
936,063✔
2347
            SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
936,063✔
2348
    /* destination addresses */
2349
    s->addr_dst_match4 =
936,063✔
2350
            SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
936,063✔
2351

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

2360
static int SigMatchListLen(SigMatch *sm)
2361
{
847,125✔
2362
    int len = 0;
847,125✔
2363
    for (; sm != NULL; sm = sm->next)
1,022,366✔
2364
        len++;
175,241✔
2365

2366
    return len;
847,125✔
2367
}
847,125✔
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
{
847,125✔
2374
    int len = SigMatchListLen(head);
847,125✔
2375
    if (len == 0)
847,125✔
2376
        return NULL;
700,927✔
2377

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

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

2395
extern int g_skip_prefilter;
2396

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

2403
    if (s->init_data->prefilter_sm != NULL) {
936,063✔
2404
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
42,748✔
2405
            RetrieveFPForSig(de_ctx, s);
1,363✔
2406
            if (s->init_data->mpm_sm != NULL) {
1,363✔
2407
                s->flags |= SIG_FLAG_PREFILTER;
1,360✔
2408
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
1,360✔
2409
                SCReturn;
1,360✔
2410
            }
1,360✔
2411
            /* fall through, this can happen if the mpm doesn't support the pattern */
2412
        } else {
41,385✔
2413
            s->flags |= SIG_FLAG_PREFILTER;
41,385✔
2414
            SCReturn;
41,385✔
2415
        }
41,385✔
2416
    } else {
893,315✔
2417
        SCLogDebug("%u: RetrieveFPForSig", s->id);
893,315✔
2418
        RetrieveFPForSig(de_ctx, s);
893,315✔
2419
        if (s->init_data->mpm_sm != NULL) {
893,315✔
2420
            s->flags |= SIG_FLAG_PREFILTER;
306,510✔
2421
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
306,510✔
2422
            SCReturn;
306,510✔
2423
        }
306,510✔
2424
    }
893,315✔
2425

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

2430
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
586,808✔
2431
        SCReturn;
583,690✔
2432

2433
    DEBUG_VALIDATE_BUG_ON(s->flags & SIG_FLAG_PREFILTER);
3,118✔
2434
    if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) {
3,118✔
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;
3,118✔
2463
}
586,808✔
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
{
905,173✔
2470
    if (s->detect_table == 0)
905,173✔
2471
        return true;
×
2472

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

2475
    for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
1,177,952✔
2476
        const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
272,779✔
2477
        if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
272,779✔
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
    }
272,779✔
2483
    return true;
905,173✔
2484
}
905,173✔
2485

2486
static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
UNCOV
2487
{
×
UNCOV
2488
    if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_NOT_SET) {
×
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
    }
×
UNCOV
2494
    return true;
×
UNCOV
2495
}
×
2496

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

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

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

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

2544
    int nlists = 0;
935,955✔
2545
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,544,451✔
2546
        nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
608,496✔
2547
    }
608,496✔
2548
    nlists += (nlists > 0);
935,955✔
2549
    SCLogDebug("nlists %d", nlists);
935,955✔
2550

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

2557
    /* run buffer type validation callbacks if any */
2558
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
933,745✔
2559
        if (!DetectContentPMATCHValidateCallback(s))
167,250✔
2560
            SCReturnInt(0);
1,706✔
2561

2562
        has_pmatch = true;
165,544✔
2563
    }
165,544✔
2564

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

2572
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,512,678✔
2573
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
604,726✔
2574
        const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
604,726✔
2575
        if (bt == NULL) {
604,726✔
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);
604,726✔
2580
        for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
1,352,923✔
2581
            SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
748,197✔
2582
        }
748,197✔
2583

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

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

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

2601
        const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
603,818✔
2602
        for (; app != NULL; app = app->next) {
502,306,933✔
2603
            if (app->sm_list == b->id &&
501,703,115✔
2604
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
501,703,115✔
2605
                SCLogDebug("engine %s dir %d alproto %d",
1,511,376✔
2606
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
1,511,376✔
2607
                        app->alproto);
1,511,376✔
2608
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
1,511,376✔
2609

2610
                if (b->only_tc) {
1,511,376✔
2611
                    if (app->dir == 1)
4,290✔
2612
                        (*tc_excl)++;
2,028✔
2613
                } else if (b->only_ts) {
1,507,086✔
2614
                    if (app->dir == 0)
1,755✔
2615
                        (*ts_excl)++;
924✔
2616
                } else {
1,505,331✔
2617
                    bufdir[b->id].ts += (app->dir == 0);
1,505,331✔
2618
                    bufdir[b->id].tc += (app->dir == 1);
1,505,331✔
2619
                }
1,505,331✔
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) {
1,511,376✔
2624
                    if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2✔
2625
                            app->progress != s->init_data->hook.t.app.app_progress) {
2✔
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) &&
2✔
2631
                            app->progress != s->init_data->hook.t.app.app_progress) {
2✔
2632
                        SCLogError("engine progress value doesn't match hook");
×
2633
                        SCReturnInt(0);
×
2634
                    }
×
2635
                }
2✔
2636
            }
1,511,376✔
2637
        }
501,703,115✔
2638

2639
        if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
603,818✔
2640
            SCReturnInt(0);
10,912✔
2641
        }
10,912✔
2642

2643
        if (!DetectBsizeValidateContentCallback(s, b)) {
592,906✔
2644
            SCReturnInt(0);
12,254✔
2645
        }
12,254✔
2646
        if (!DetectAbsentValidateContentCallback(s, b)) {
580,652✔
2647
            SCReturnInt(0);
13✔
2648
        }
13✔
2649
    }
580,652✔
2650

2651
    if (has_pmatch && has_frame) {
907,952✔
2652
        SCLogError("can't mix pure content and frame inspection");
94✔
2653
        SCReturnInt(0);
94✔
2654
    }
94✔
2655
    if (has_app && has_frame) {
907,858✔
2656
        SCLogError("can't mix app-layer buffer and frame inspection");
24✔
2657
        SCReturnInt(0);
24✔
2658
    }
24✔
2659
    if (has_pkt && has_frame) {
907,834✔
2660
        SCLogError("can't mix pkt buffer and frame inspection");
1✔
2661
        SCReturnInt(0);
1✔
2662
    }
1✔
2663

2664
    for (int x = 0; x < nlists; x++) {
148,430,869✔
2665
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
147,523,036✔
2666
            continue;
147,047,594✔
2667
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
475,442✔
2668
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
475,442✔
2669
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
475,442✔
2670

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

2675
    SCReturnInt(1);
907,833✔
2676
}
907,834✔
2677

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

2688
static int SigConsolidateDirection(
2689
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2690
{
907,833✔
2691
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
907,833✔
2692
        if (!ts_excl || !tc_excl) {
734✔
2693
            SCLogError("rule %u should use both directions, but does not", s->id);
414✔
2694
            SCReturnInt(0);
414✔
2695
        }
414✔
2696
        if (dir_amb) {
320✔
2697
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
5✔
2698
                       "directions",
5✔
2699
                    s->id);
5✔
2700
            SCReturnInt(0);
5✔
2701
        }
5✔
2702
    } else if (ts_excl && tc_excl) {
907,099✔
2703
        SCLogError(
254✔
2704
                "rule %u mixes keywords with conflicting directions, a transactional rule with => "
254✔
2705
                "should be used",
254✔
2706
                s->id);
254✔
2707
        SCReturnInt(0);
254✔
2708
    } else if (ts_excl) {
906,845✔
2709
        SCLogDebug("%u: implied rule direction is toserver", s->id);
267,678✔
2710
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
267,678✔
2711
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
635✔
2712
            SCReturnInt(0);
635✔
2713
        }
635✔
2714
    } else if (tc_excl) {
639,167✔
2715
        SCLogDebug("%u: implied rule direction is toclient", s->id);
46,118✔
2716
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
46,118✔
2717
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
12✔
2718
            SCReturnInt(0);
12✔
2719
        }
12✔
2720
    } else if (dir_amb) {
593,049✔
2721
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
121,039✔
2722
    }
121,039✔
2723
    SCReturnInt(1);
907,833✔
2724
}
907,833✔
2725

2726
static void SigConsolidateTcpBuffer(Signature *s)
2727
{
906,513✔
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))) {
906,513✔
2733
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
874,824✔
2734
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
163,315✔
2735
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
110,935✔
2736
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
308,568✔
2737
                        sm = sm->next) {
209,838✔
2738
                    if (sm->type == DETECT_CONTENT &&
209,838✔
2739
                            (((DetectContentData *)(sm->ctx))->flags &
209,838✔
2740
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
88,532✔
2741
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
12,205✔
2742
                        break;
12,205✔
2743
                    }
12,205✔
2744
                }
209,838✔
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;
144,782✔
2747
                        sm = sm->next) {
110,935✔
2748
                    if (sm->type == DETECT_STREAM_SIZE) {
35,677✔
2749
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
1,830✔
2750
                        break;
1,830✔
2751
                    }
1,830✔
2752
                }
35,677✔
2753
            }
110,935✔
2754
        }
163,315✔
2755
    }
874,824✔
2756
}
906,513✔
2757

2758
static bool SigInspectsFiles(const Signature *s)
2759
{
1,811,686✔
2760
    return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
1,811,686✔
2761
            (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA));
1,811,686✔
2762
}
1,811,686✔
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
{
906,513✔
2771
    if (!SigInspectsFiles(s)) {
906,513✔
2772
        SCReturnInt(1);
852,577✔
2773
    }
852,577✔
2774

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

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

2824
    if (SigValidatePacketStream(s) == 0) {
936,063✔
2825
        SCReturnInt(0);
108✔
2826
    }
108✔
2827

2828
    int ts_excl = 0;
935,955✔
2829
    int tc_excl = 0;
935,955✔
2830
    int dir_amb = 0;
935,955✔
2831

2832
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
935,955✔
2833
        SCReturnInt(0);
28,122✔
2834
    }
28,122✔
2835

2836
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
907,833✔
2837
        SCReturnInt(0);
1,320✔
2838
    }
1,320✔
2839

2840
    SigConsolidateTcpBuffer(s);
906,513✔
2841

2842
    SignatureSetType(de_ctx, s);
906,513✔
2843
    DetectRuleSetTable(s);
906,513✔
2844

2845
    int r = SigValidateFileHandling(s);
906,513✔
2846
    if (r == 0) {
906,513✔
2847
        SCReturnInt(0);
1,340✔
2848
    }
1,340✔
2849
    if (SigInspectsFiles(s)) {
905,173✔
2850
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
52,596✔
2851
            AppLayerHtpNeedFileInspection();
8,433✔
2852
        }
8,433✔
2853
    }
52,596✔
2854
    if (DetectRuleValidateTable(s) == false) {
905,173✔
2855
        SCReturnInt(0);
×
2856
    }
×
2857

2858
    if (s->type == SIG_TYPE_IPONLY) {
905,173✔
2859
        /* For IPOnly */
2860
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
82,571✔
2861
            SCReturnInt(0);
557✔
2862

2863
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
82,014✔
2864
            SCReturnInt(0);
1,704✔
2865
    }
82,014✔
2866
    SCReturnInt(1);
905,173✔
2867
}
905,173✔
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
{
5,155,028✔
2876
    SignatureParser parser;
5,155,028✔
2877
    memset(&parser, 0x00, sizeof(parser));
5,155,028✔
2878

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

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

2892
    /* default gid to 1 */
2893
    sig->gid = 1;
5,155,028✔
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);
5,155,028✔
2900
    if (ret == -4) {
5,155,028✔
2901
        /* Rule requirements not met. */
2902
        de_ctx->sigerror_silent = true;
10,417✔
2903
        de_ctx->sigerror_ok = true;
10,417✔
2904
        de_ctx->sigerror_requires = true;
10,417✔
2905
        goto error;
10,417✔
2906
    } else if (ret < 0) {
5,144,611✔
2907
        goto error;
2,394,834✔
2908
    }
2,394,834✔
2909

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

2916
    /* Now completely parse the rule. */
2917
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2,208,118✔
2918
    BUG_ON(ret == -4);
2,208,118✔
2919
    if (ret == -3) {
2,208,118✔
2920
        de_ctx->sigerror_silent = true;
17,697✔
2921
        de_ctx->sigerror_ok = true;
17,697✔
2922
        goto error;
17,697✔
2923
    } else if (ret == -2) {
2,190,421✔
UNCOV
2924
        de_ctx->sigerror_silent = true;
×
UNCOV
2925
        goto error;
×
2926
    } else if (ret < 0) {
2,190,421✔
2927
        goto error;
1,254,358✔
2928
    }
1,254,358✔
2929

2930
    /* signature priority hasn't been overwritten.  Using default priority */
2931
    if (sig->prio == -1)
936,063✔
2932
        sig->prio = DETECT_DEFAULT_PRIO;
808,971✔
2933

2934
    sig->iid = de_ctx->signum;
936,063✔
2935
    de_ctx->signum++;
936,063✔
2936

2937
    if (sig->alproto != ALPROTO_UNKNOWN) {
936,063✔
2938
        int override_needed = 0;
611,075✔
2939
        if (sig->proto.flags & DETECT_PROTO_ANY) {
611,075✔
2940
            sig->proto.flags &= ~DETECT_PROTO_ANY;
152,419✔
2941
            memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
152,419✔
2942
            override_needed = 1;
152,419✔
2943
        } else {
458,656✔
2944
            override_needed = 1;
458,656✔
2945
            size_t s = 0;
458,656✔
2946
            for (s = 0; s < sizeof(sig->proto.proto); s++) {
504,357✔
2947
                if (sig->proto.proto[s] != 0x00) {
504,354✔
2948
                    override_needed = 0;
458,653✔
2949
                    break;
458,653✔
2950
                }
458,653✔
2951
            }
504,354✔
2952
        }
458,656✔
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)
611,075✔
2958
            AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->proto.proto);
152,422✔
2959
    }
611,075✔
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)) {
936,063✔
2965
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
322,970✔
2966
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
104,575✔
2967
            for ( ; sm != NULL; sm = sm->next) {
259,092✔
2968
                if (sigmatch_table[sm->type].Match != NULL)
154,517✔
2969
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
154,517✔
2970
            }
154,517✔
2971
        } else {
218,395✔
2972
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
218,395✔
2973
        }
218,395✔
2974
    }
322,970✔
2975

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

2984
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
936,063✔
2985
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
853,623✔
2986
            sig->flags |= SIG_FLAG_TOSERVER;
823,534✔
2987
            sig->flags |= SIG_FLAG_TOCLIENT;
823,534✔
2988
        }
823,534✔
2989
    }
853,623✔
2990

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

2995
    SigBuildAddressMatchArray(sig);
936,063✔
2996

2997
    /* run buffer type callbacks if any */
2998
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
7,488,504✔
2999
        if (sig->init_data->smlists[x])
6,552,441✔
3000
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
448,348✔
3001
    }
6,552,441✔
3002
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
1,544,561✔
3003
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
608,498✔
3004
    }
608,498✔
3005

3006
    SigSetupPrefilter(de_ctx, sig);
936,063✔
3007

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

3013
    return sig;
902,912✔
3014

3015
error:
4,252,116✔
3016
    if (sig != NULL) {
4,252,116✔
3017
        SigFree(de_ctx, sig);
4,252,116✔
3018
    }
4,252,116✔
3019
    return NULL;
4,252,116✔
3020
}
936,063✔
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
{
162,205✔
3030
    if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
162,205✔
3031
        if (!DetectPortListsAreEqual(s->sp, s->dp)) {
146,298✔
3032
            return false;
143,445✔
3033
        }
143,445✔
3034
    }
146,298✔
3035

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

3040
        if (!DetectAddressListsAreEqual(src, dst)) {
18,428✔
3041
            return false;
7,632✔
3042
        }
7,632✔
3043

3044
        src = s->init_data->src->ipv6_head;
10,796✔
3045
        dst = s->init_data->dst->ipv6_head;
10,796✔
3046

3047
        if (!DetectAddressListsAreEqual(src, dst)) {
10,796✔
3048
            return false;
8,344✔
3049
        }
8,344✔
3050
    }
10,796✔
3051

3052
    return true;
2,784✔
3053
}
18,760✔
3054

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

3059
    uint32_t oldsignum = de_ctx->signum;
4,995,607✔
3060
    de_ctx->sigerror_ok = false;
4,995,607✔
3061
    de_ctx->sigerror_silent = false;
4,995,607✔
3062
    de_ctx->sigerror_requires = false;
4,995,607✔
3063

3064
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
4,995,607✔
3065
    if (sig == NULL) {
4,995,607✔
3066
        goto error;
4,252,116✔
3067
    }
4,252,116✔
3068

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

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

3083
    SCReturnPtr(sig, "Signature");
743,491✔
3084

3085
error:
4,252,116✔
3086
    if (sig != NULL) {
4,252,116✔
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;
4,252,116✔
3092

3093
    SCReturnPtr(NULL, "Signature");
4,252,116✔
3094
}
743,491✔
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
{
4,995,607✔
3107
    return SigInitDo(de_ctx, sigstr, false);
4,995,607✔
3108
}
4,995,607✔
3109

3110
static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
UNCOV
3111
{
×
UNCOV
3112
    return SigInitDo(de_ctx, sigstr, true);
×
UNCOV
3113
}
×
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
{
106,607✔
3123
    if (data != NULL)
106,607✔
3124
        SCFree(data);
106,607✔
3125
}
106,607✔
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
{
922,661✔
3139
    SigDuplWrapper *sw = (SigDuplWrapper *)data;
922,661✔
3140

3141
    return (sw->s->id % ht->array_size);
922,661✔
3142
}
922,661✔
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
{
720,389✔
3159
    SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
720,389✔
3160
    SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
720,389✔
3161

3162
    if (sw1 == NULL || sw2 == NULL ||
720,389✔
3163
        sw1->s == NULL || sw2->s == NULL)
720,389✔
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;
720,389✔
3168

3169
    return 0;
10,942✔
3170
}
720,389✔
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
{
35,469✔
3182
    de_ctx->dup_sig_hash_table = HashListTableInit(15000,
35,469✔
3183
                                                   DetectParseDupSigHashFunc,
35,469✔
3184
                                                   DetectParseDupSigCompareFunc,
35,469✔
3185
                                                   DetectParseDupSigFreeFunc);
35,469✔
3186
    if (de_ctx->dup_sig_hash_table == NULL)
35,469✔
3187
        return -1;
×
3188

3189
    return 0;
35,469✔
3190
}
35,469✔
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
{
70,904✔
3199
    if (de_ctx->dup_sig_hash_table != NULL)
70,904✔
3200
        HashListTableFree(de_ctx->dup_sig_hash_table);
35,468✔
3201

3202
    de_ctx->dup_sig_hash_table = NULL;
70,904✔
3203
}
70,904✔
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
{
727,913✔
3228
    /* we won't do any NULL checks on the args */
3229

3230
    /* return value */
3231
    int ret = 0;
727,913✔
3232

3233
    SigDuplWrapper *sw_dup = NULL;
727,913✔
3234
    SigDuplWrapper *sw = NULL;
727,913✔
3235

3236
    /* used for making a duplicate_sig_hash_table entry */
3237
    sw = SCCalloc(1, sizeof(SigDuplWrapper));
727,913✔
3238
    if (unlikely(sw == NULL)) {
727,913✔
3239
        exit(EXIT_FAILURE);
×
3240
    }
×
3241
    sw->s = sig;
727,913✔
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);
727,913✔
3245
    /* we don't have a duplicate entry for this sig */
3246
    if (sw_dup == NULL) {
727,913✔
3247
        /* add it to the hash table */
3248
        HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
106,607✔
3249

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

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

3264
        ret = 0;
106,607✔
3265
        goto end;
106,607✔
3266
    }
106,607✔
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) {
621,306✔
3272
        ret = 1;
620,097✔
3273
        SCFree(sw);
620,097✔
3274
        sw = NULL;
620,097✔
3275
        goto end;
620,097✔
3276
    }
620,097✔
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) {
1,209✔
3281
        SigDuplWrapper sw_temp;
187✔
3282
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
187✔
3283
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
187✔
3284
            sw_temp.s = sw_dup->s->next->next;
38✔
3285
            de_ctx->sig_list = sw_dup->s->next->next;
38✔
3286
            SigFree(de_ctx, sw_dup->s->next);
38✔
3287
        } else {
149✔
3288
            sw_temp.s = sw_dup->s->next;
149✔
3289
            de_ctx->sig_list = sw_dup->s->next;
149✔
3290
        }
149✔
3291
        SigDuplWrapper *sw_next = NULL;
187✔
3292
        if (sw_temp.s != NULL) {
187✔
3293
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
133✔
3294
                                          (void *)&sw_temp, 0);
133✔
3295
            sw_next->s_prev = sw_dup->s_prev;
133✔
3296
        }
133✔
3297
        SigFree(de_ctx, sw_dup->s);
187✔
3298
    } else {
1,022✔
3299
        SigDuplWrapper sw_temp;
1,022✔
3300
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
1,022✔
3301
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
1,022✔
3302
            sw_temp.s = sw_dup->s->next->next;
262✔
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
             */
3307
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
262✔
3308
                sw_dup->s_prev->next->next = sw_dup->s->next->next;
152✔
3309
            } else {
152✔
3310
                sw_dup->s_prev->next = sw_dup->s->next->next;
110✔
3311
            }
110✔
3312
            SigFree(de_ctx, sw_dup->s->next);
262✔
3313
        } else {
760✔
3314
            sw_temp.s = sw_dup->s->next;
760✔
3315
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
760✔
3316
                sw_dup->s_prev->next->next = sw_dup->s->next;
115✔
3317
            } else {
645✔
3318
                sw_dup->s_prev->next = sw_dup->s->next;
645✔
3319
            }
645✔
3320
        }
760✔
3321
        SigDuplWrapper *sw_next = NULL;
1,022✔
3322
        if (sw_temp.s != NULL) {
1,022✔
3323
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
773✔
3324
                                          (void *)&sw_temp, 0);
773✔
3325
            sw_next->s_prev = sw_dup->s_prev;
773✔
3326
        }
773✔
3327
        SigFree(de_ctx, sw_dup->s);
1,022✔
3328
    }
1,022✔
3329

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

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

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

3349
    SCFree(sw);
1,209✔
3350

3351
end:
727,913✔
3352
    return ret;
727,913✔
3353
}
1,209✔
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)
UNCOV
3376
{
×
UNCOV
3377
    Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
×
UNCOV
3378
    if (sig == NULL) {
×
3379
        return NULL;
×
3380
    }
×
3381

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

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

UNCOV
3406
    de_ctx->sig_list = sig;
×
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
     */
UNCOV
3413
    return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
×
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;
×
UNCOV
3425
}
×
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
{
4,964,433✔
3449
    Signature *sig = SigInit(de_ctx, sigstr);
4,964,433✔
3450
    if (sig == NULL) {
4,964,433✔
3451
        return NULL;
4,236,520✔
3452
    }
4,236,520✔
3453

3454
    /* checking for the status of duplicate signature */
3455
    int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
727,913✔
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) {
727,913✔
3459
        SCLogError("Duplicate signature \"%s\"", sigstr);
620,097✔
3460
        goto error;
620,097✔
3461
    } else if (dup_sig == 2) {
620,097✔
3462
        SCLogWarning("Signature with newer revision,"
1,209✔
3463
                     " so the older sig replaced by this new signature \"%s\"",
1,209✔
3464
                sigstr);
1,209✔
3465
    }
1,209✔
3466

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

3478
    de_ctx->sig_list = sig;
107,816✔
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;
107,816✔
3486

3487
error:
620,097✔
3488
    /* free the 2nd sig bidir may have set up */
3489
    if (sig != NULL && sig->next != NULL) {
620,097✔
3490
        SigFree(de_ctx, sig->next);
133,171✔
3491
        sig->next = NULL;
133,171✔
3492
    }
133,171✔
3493
    if (sig != NULL) {
620,097✔
3494
        SigFree(de_ctx, sig);
620,097✔
3495
    }
620,097✔
3496
    return NULL;
620,097✔
3497
}
107,816✔
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
{
1,048,432✔
3504
    *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
1,048,432✔
3505
    if (*match)
1,048,432✔
3506
        return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
1,048,432✔
3507
                *match, parse_regex->context);
1,048,432✔
UNCOV
3508
    return -1;
×
3509
}
1,048,432✔
3510

3511
void DetectParseFreeRegex(DetectParseRegex *r)
3512
{
394,444✔
3513
    if (r->regex) {
394,444✔
3514
        pcre2_code_free(r->regex);
344,559✔
3515
    }
344,559✔
3516
    if (r->context) {
394,444✔
3517
        pcre2_match_context_free(r->context);
344,559✔
3518
    }
344,559✔
3519
}
394,444✔
3520

3521
void DetectParseFreeRegexes(void)
UNCOV
3522
{
×
UNCOV
3523
    DetectParseRegex *r = g_detect_parse_regex_list;
×
UNCOV
3524
    while (r) {
×
UNCOV
3525
        DetectParseRegex *next = r->next;
×
3526

UNCOV
3527
        DetectParseFreeRegex(r);
×
3528

UNCOV
3529
        SCFree(r);
×
UNCOV
3530
        r = next;
×
UNCOV
3531
    }
×
UNCOV
3532
    g_detect_parse_regex_list = NULL;
×
UNCOV
3533
}
×
3534

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

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

3553
    detect_parse->regex =
114✔
3554
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
114✔
3555
    if (detect_parse->regex == NULL) {
114✔
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);
114✔
3564
    if (detect_parse->context == NULL) {
114✔
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);
114✔
3571
    pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
114✔
3572
    DetectParseRegexAddToFreeList(detect_parse);
114✔
3573

3574
    return true;
114✔
3575
}
114✔
3576

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

3586
    detect_parse->regex =
14✔
3587
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
14✔
3588
    if (detect_parse->regex == NULL) {
14✔
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;
14✔
3599
    g_detect_parse_regex_list = detect_parse;
14✔
3600
    return detect_parse;
14✔
3601
}
14✔
3602

3603
int SC_Pcre2SubstringCopy(
3604
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3605
{
182,455✔
3606
    int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
182,455✔
3607
    if (r == PCRE2_ERROR_UNSET) {
182,455✔
3608
        buffer[0] = 0;
881✔
3609
        *bufflen = 0;
881✔
3610
        return 0;
881✔
3611
    }
881✔
3612
    return r;
181,574✔
3613
}
182,455✔
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
{
114✔
3629
    if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
114✔
3630
        FatalError("pcre compile and study failed");
×
3631
    }
×
3632
}
114✔
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
{
3644
    int result = 1;
3645
    Signature *sig = NULL;
3646

3647
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3648
    if (de_ctx == NULL)
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;)");
3652
    if (sig == NULL)
3653
        result = 0;
3654

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

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

3667
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3668

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

3672
    SCClassConfDeInitContext(de_ctx);
3673
    FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01();
3674
    SCClassConfLoadClassificationConfigFile(de_ctx, fd);
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;)");
3677
    if (sig == NULL) {
3678
        goto end;
3679
    }
3680

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

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

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

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

3709
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3710
    if (de_ctx == NULL)
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;)");
3714
    if (sig != NULL) {
3715
        result = 0;
3716
        printf("expected NULL got sig ptr %p: ",sig);
3717
    }
3718

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

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

3730
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3731
    if (de_ctx == NULL)
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;)");
3735
    if (sig == NULL)
3736
        result = 0;
3737

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

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

3750
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3751
    if (de_ctx == NULL)
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;)");
3755
    if (sig == NULL) {
3756
        result = 1;
3757
    } else {
3758
        printf("signature didn't fail to parse as we expected: ");
3759
    }
3760

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

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

3773
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3774
    if (de_ctx == NULL)
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;)");
3778
    if (sig != NULL) {
3779
        result = 1;
3780
    } else {
3781
        printf("signature failed to parse: ");
3782
    }
3783

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3913
end:
3914
    if (de_ctx != NULL)
3915
        DetectEngineCtxFree(de_ctx);
3916
    return result;
3917
}
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
{
3925
    int result = 0;
3926

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

3931
    Signature *s = NULL;
3932

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

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

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

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

3965
    Signature *s = NULL;
3966

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

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

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

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

3991
    Signature *s = NULL;
3992

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

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

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

4009
    result = 1;
4010

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

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

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

4028
    Signature *s = NULL;
4029

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

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

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

4046
    result = 1;
4047

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

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

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

4065
    Signature *s = NULL;
4066

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

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

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

4083
    result = 1;
4084

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

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

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

4102
    Signature *s = NULL;
4103

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

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

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

4120
    result = 1;
4121

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

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

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

4139
    Signature *s = NULL;
4140

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

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

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

4157
    result = 1;
4158

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

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

4170
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4171
    if (de_ctx == NULL)
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)
4175
        goto end;
4176

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

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

4189
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4190
    if (de_ctx == NULL)
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)
4194
        goto end;
4195

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

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

4208
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4209
    if (de_ctx == NULL)
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)
4213
        goto end;
4214

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

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

4227
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4228
    if (de_ctx == NULL)
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)
4232
        goto end;
4233

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

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

4246
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4247
    if (de_ctx == NULL)
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)
4251
        goto end;
4252

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

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

4268
    Signature *s = NULL;
4269

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

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

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

4283
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4284
    if (de_ctx == NULL)
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;)");
4288
    if (sig == NULL)
4289
        result = 1;
4290

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

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

4303
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4304
    if (de_ctx == NULL)
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;)");
4308
    if (sig == NULL)
4309
        result = 1;
4310

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

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

4323
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4324
    if (de_ctx == NULL)
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;)");
4328
    if (sig == NULL)
4329
        result = 1;
4330

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

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

4343
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4344
    if (de_ctx == NULL)
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;)");
4348
    if (sig == NULL)
4349
        result = 1;
4350

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

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

4363
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4364
    if (de_ctx == NULL)
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;)");
4368
    if (sig == NULL)
4369
        result = 1;
4370

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

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

4383
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4384
    if (de_ctx == NULL)
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;)");
4388
    if (sig == NULL)
4389
        result = 1;
4390

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

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

4403
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4404
    if (de_ctx == NULL)
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;)");
4408
    if (sig == NULL)
4409
        result = 1;
4410

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

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

4423
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4424
    if (de_ctx == NULL)
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;)");
4428
    if (sig != NULL)
4429
        result = 1;
4430

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

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

4442
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4443
    if (de_ctx == NULL)
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;)");
4447
    if (sig != NULL)
4448
        result = 1;
4449

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

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

4463
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4464
    if (de_ctx == NULL)
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;)");
4468
    if (sig == NULL)
4469
        goto end;
4470
    if (sig->next != NULL)
4471
        goto end;
4472
    if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)
4473
        goto end;
4474
    if (de_ctx->signum != 1)
4475
        goto end;
4476

4477
    result = 1;
4478

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

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

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

4499
    de_ctx->flags |= DE_QUIET;
4500

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

4518
    result = 1;
4519

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

4527
    return result;
4528
}
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
{
4536
    int result = 0;
4537
    Signature *sig = NULL;
4538
    Packet *p = NULL;
4539

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

4544
    de_ctx->flags |= DE_QUIET;
4545

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

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

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

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

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

4636
end:
4637
    if (p != NULL) {
4638
        PacketFree(p);
4639
    }
4640
    DetectEngineCtxFree(de_ctx);
4641
    FlowShutdown();
4642
    return result;
4643
}
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
{
4651
    int result = 0;
4652
    Signature *sig = NULL;
4653
    Packet *p = NULL;
4654

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

4659
    de_ctx->flags |= DE_QUIET;
4660

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

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

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

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

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

4759
    FlowInitConfig(FLOW_QUIET);
4760
    DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4761
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
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);
4768
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
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 &&
4772
        PacketAlertCheck(p, 2) == 1) {
4773
        result = 1;
4774
    }
4775

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

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

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

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

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

4846
    de_ctx = DetectEngineCtxInit();
4847
    if (de_ctx == NULL)
4848
        goto end;
4849
    de_ctx->flags |= DE_QUIET;
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;)");
4852
    if (s != NULL) {
4853
        SigFree(de_ctx, s);
4854
        goto end;
4855
    }
4856

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

4872
    de_ctx = DetectEngineCtxInit();
4873
    if (de_ctx == NULL)
4874
        goto end;
4875
    de_ctx->flags |= DE_QUIET;
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;)");
4878
    if (s != NULL) {
4879
        SigFree(de_ctx, s);
4880
        goto end;
4881
    }
4882

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

4898
    de_ctx = DetectEngineCtxInit();
4899
    if (de_ctx == NULL)
4900
        goto end;
4901
    de_ctx->flags |= DE_QUIET;
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;)");
4904
    if (s != NULL) {
4905
        SigFree(de_ctx, s);
4906
        goto end;
4907
    }
4908

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5052
    return result;
5053
}
5054

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5174
    s = DetectEngineAppendSig(de_ctx,
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;)");
5176
    FAIL_IF_NULL(s);
5177
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5178
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5179

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

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

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

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

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

5211
    // mix in negation, these are the same
5212
    s = DetectEngineAppendSig(
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;)");
5214
    FAIL_IF_NULL(s);
5215
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5216
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5217

5218
    // mix in negation, these are not the same
5219
    s = DetectEngineAppendSig(
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;)");
5221
    FAIL_IF_NULL(s);
5222
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5223
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
5224

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5375
static int DetectSetupDirection04(void)
5376
{
5377
    Signature *s = SigAlloc();
5378
    FAIL_IF_NULL(s);
5379
    // invalid case
5380
    char *str = (char *)"to_client_toto";
5381
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5382
    // test we do not change the string pointer if only_dir is false
5383
    str = (char *)"to_client_toto";
5384
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5385
    FAIL_IF(strcmp(str, "to_client_toto") != 0);
5386
    str = (char *)"to_client,something";
5387
    // fails because we call with only_dir=true
5388
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5389
    SigFree(NULL, s);
5390
    PASS;
5391
}
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)
UNCOV
5401
{
×
5402
#ifdef UNITTESTS
5403
    DetectParseRegisterTests();
5404

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

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

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

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

5469
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5470

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

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