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

jasonish / suricata / 22723505468

04 Mar 2026 07:29PM UTC coverage: 79.272% (+5.6%) from 73.671%
22723505468

push

github

victorjulien
detect: replace stack alloc by member of DetectEngineThreadCtx

To avoid running a big (when many signatures) stack allocation
on each detection loop with postmatches

Ticket: 8001

7 of 9 new or added lines in 2 files covered. (77.78%)

614 existing lines in 26 files now uncovered.

265777 of 335273 relevant lines covered (79.27%)

4984741.53 hits per line

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

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

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

26
#include "suricata-common.h"
27

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

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

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

54
#include "flow.h"
55

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

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

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

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

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

81
extern bool sc_set_caps;
82

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

269
    ret = 0;
58,123✔
270
 end:
59,066✔
271
    return ret;
59,066✔
272
}
58,123✔
273

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

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

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

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

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

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

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
596,915,036✔
317
        st = &sigmatch_table[i];
596,641,871✔
318

319
        if (st->name != NULL) {
596,641,871✔
320
            if (strcasecmp(name,st->name) == 0)
571,234,993✔
321
                return st;
8,411,432✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
562,823,561✔
323
                return st;
95,574✔
324
        }
562,823,561✔
325
    }
596,641,871✔
326

327
    return NULL;
273,165✔
328
}
8,780,171✔
329

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

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

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

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

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

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

377
    SCFree(copy);
1✔
378
}
1✔
379

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

394
    new->type = type;
2,204,240✔
395
    new->ctx = ctx;
2,204,240✔
396

397
    if (new->type == DETECT_CONTENT) {
2,204,240✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
811,564✔
399
    }
811,564✔
400

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

405
    if (list < DETECT_SM_LIST_MAX) {
2,204,240✔
406
        if (s->init_data->smlists[list] == NULL) {
1,114,151✔
407
            s->init_data->smlists[list] = new;
764,789✔
408
            s->init_data->smlists_tail[list] = new;
764,789✔
409
            new->next = NULL;
764,789✔
410
            new->prev = NULL;
764,789✔
411
        } else {
764,789✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
349,362✔
413
            cur->next = new;
349,362✔
414
            new->prev = cur;
349,362✔
415
            new->next = NULL;
349,362✔
416
            s->init_data->smlists_tail[list] = new;
349,362✔
417
        }
349,362✔
418
        new->idx = s->init_data->sm_cnt;
1,114,151✔
419
        s->init_data->sm_cnt++;
1,114,151✔
420

421
    } else {
1,205,576✔
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) {
1,090,089✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
14,177✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
14,177✔
429
        }
14,177✔
430

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

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

467
        new->prev = s->init_data->curbuf->tail;
1,090,086✔
468
        if (s->init_data->curbuf->tail)
1,090,086✔
469
            s->init_data->curbuf->tail->next = new;
247,777✔
470
        if (s->init_data->curbuf->head == NULL)
1,090,086✔
471
            s->init_data->curbuf->head = new;
842,309✔
472
        s->init_data->curbuf->tail = new;
1,090,086✔
473
        new->idx = s->init_data->sm_cnt;
1,090,086✔
474
        s->init_data->sm_cnt++;
1,090,086✔
475
        SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
1,090,086✔
476
                sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
1,090,086✔
477

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
4,374,210✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
3,284,124✔
480
                    sigmatch_table[sm->type].name, sm->idx);
3,284,124✔
481
        }
3,284,124✔
482
    }
1,090,086✔
483
    return new;
2,204,237✔
484
}
2,204,240✔
485

486
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487
{
10,720✔
488
    if (sm == s->init_data->smlists[sm_list]) {
10,720✔
489
        s->init_data->smlists[sm_list] = sm->next;
6,723✔
490
    }
6,723✔
491
    if (sm == s->init_data->smlists_tail[sm_list]) {
10,720✔
492
        s->init_data->smlists_tail[sm_list] = sm->prev;
7,141✔
493
    }
7,141✔
494
    if (sm->prev != NULL)
10,720✔
495
        sm->prev->next = sm->next;
3,997✔
496
    if (sm->next != NULL)
10,720✔
497
        sm->next->prev = sm->prev;
3,579✔
498
}
10,720✔
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,579,046✔
511
    while (sm != NULL) {
4,252,043✔
512
        if (sm->type == type) {
3,648,980✔
513
            return sm;
975,983✔
514
        }
975,983✔
515
        sm = sm->prev;
2,672,997✔
516
    }
2,672,997✔
517

518
    return NULL;
603,063✔
519
}
1,579,046✔
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
{
65,501✔
528
    SigMatch *sm_last = NULL;
65,501✔
529
    SigMatch *sm_new;
65,501✔
530
    uint32_t sm_type;
65,501✔
531

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
155,515✔
533
        const int id = s->init_data->buffers[i].id;
90,014✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
90,014✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
89,335✔
536
            if (sm_new == NULL)
89,335✔
537
                continue;
4,335✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
85,000✔
539
                sm_last = sm_new;
83,002✔
540
        }
85,000✔
541
    }
90,014✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
524,008✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
458,507✔
545
            continue;
458,507✔
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;
65,501✔
555
}
65,501✔
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
{
646,175✔
565
    SigMatch *sm_last = NULL;
646,175✔
566
    SigMatch *sm_new;
646,175✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
646,175✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,175,624✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
529,449✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
529,449✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
121,348✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
121,348✔
574

575
            continue;
121,348✔
576
        }
121,348✔
577
        int sm_type;
408,101✔
578
        va_list ap;
408,101✔
579
        va_start(ap, s);
408,101✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
886,219✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
478,118✔
583
            if (sm_new == NULL)
478,118✔
584
                continue;
108,662✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
369,456✔
586
                sm_last = sm_new;
360,125✔
587
        }
369,456✔
588
        va_end(ap);
408,101✔
589
    }
408,101✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
5,169,400✔
592
        if (s->init_data->smlists[buf_type] == NULL)
4,523,225✔
593
            continue;
3,938,467✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
584,758✔
595
            buf_type != s->init_data->list)
584,758✔
596
            continue;
216,440✔
597

598
        int sm_type;
368,318✔
599
        va_list ap;
368,318✔
600
        va_start(ap, s);
368,318✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
956,429✔
603
        {
588,111✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
588,111✔
605
            if (sm_new == NULL)
588,111✔
606
                continue;
319,316✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
268,795✔
608
                sm_last = sm_new;
257,062✔
609
        }
268,795✔
610
        va_end(ap);
368,318✔
611
    }
368,318✔
612

613
    return sm_last;
646,175✔
614
}
646,175✔
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
{
249,364✔
627
    SigMatch *sm_last = NULL;
249,364✔
628
    SigMatch *sm_new;
249,364✔
629
    int sm_type;
249,364✔
630

631
    va_list ap;
249,364✔
632
    va_start(ap, sm_list);
249,364✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
658,757✔
635
    {
409,393✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
409,393✔
637
        if (sm_new == NULL)
409,393✔
638
            continue;
157,917✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
251,476✔
640
            sm_last = sm_new;
236,716✔
641
    }
251,476✔
642

643
    va_end(ap);
249,364✔
644

645
    return sm_last;
249,364✔
646
}
249,364✔
647

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

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

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

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

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

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

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

698
        va_end(ap);
85,343✔
699
    }
85,343✔
700
    return sm_last;
108,730✔
701
}
146,721✔
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,950✔
710
    SigMatch *sm_last = NULL;
45,950✔
711
    SigMatch *sm_new;
45,950✔
712

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

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

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

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

738
    if (sm->prev != NULL)
58,123✔
739
        sm->prev->next = sm->next;
9,072✔
740
    if (sm->next != NULL)
58,123✔
741
        sm->next->prev = sm->prev;
813✔
742

743
    if (sm == *src_sm_list)
58,123✔
744
        *src_sm_list = sm->next;
49,051✔
745
    if (sm == *src_sm_list_tail)
58,123✔
746
        *src_sm_list_tail = sm->prev;
57,310✔
747

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

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

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
113,086✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
81,900✔
769
        while (sm != NULL) {
177,701✔
770
            if (sm == key_sm)
151,835✔
771
                return s->init_data->buffers[x].id;
56,034✔
772
            sm = sm->next;
95,801✔
773
        }
95,801✔
774
    }
81,900✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
62,374✔
777
        const SigMatch *sm = s->init_data->smlists[list];
62,374✔
778
        while (sm != NULL) {
223,454✔
779
            if (sm == key_sm)
192,266✔
780
                return list;
31,186✔
781
            sm = sm->next;
161,080✔
782
        }
161,080✔
783
    }
62,374✔
784

785
    SCLogError("Unable to find the sm in any of the "
×
786
               "sm lists");
×
787
    return -1;
×
788
}
31,186✔
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,451✔
801
    char *orig = *str;
1,451✔
802
    if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
1,451✔
803
        *str += strlen("to_client");
633✔
804
        // skip space
805
        while (**str && isblank(**str)) {
709✔
806
            (*str)++;
76✔
807
        }
76✔
808
        // check comma or nothing
809
        if (**str) {
633✔
810
            if (only_dir) {
50✔
811
                SCLogError("unknown option: only accepts to_server or to_client");
11✔
812
                return -1;
11✔
813
            }
11✔
814
            if (**str != ',') {
39✔
815
                // leave to_client_something for next parser if not only_dir
816
                *str = orig;
4✔
817
                return 0;
4✔
818
            } else {
35✔
819
                (*str)++;
35✔
820
            }
35✔
821
            while (**str && isblank(**str)) {
67✔
822
                (*str)++;
32✔
823
            }
32✔
824
        }
35✔
825
        s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
618✔
826
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
618✔
827
            if (s->flags & SIG_FLAG_TOSERVER) {
357✔
828
                SCLogError("contradictory directions");
2✔
829
                return -1;
2✔
830
            }
2✔
831
            s->flags |= SIG_FLAG_TOCLIENT;
355✔
832
        }
355✔
833
    } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
823✔
834
        *str += strlen("to_server");
284✔
835
        // skip space
836
        while (**str && isblank(**str)) {
320✔
837
            (*str)++;
36✔
838
        }
36✔
839
        // check comma or nothing
840
        if (**str) {
284✔
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;
276✔
857
        if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
276✔
858
            if (s->flags & SIG_FLAG_TOCLIENT) {
140✔
859
                SCLogError("contradictory directions");
1✔
860
                return -1;
1✔
861
            }
1✔
862
            s->flags |= SIG_FLAG_TOSERVER;
139✔
863
        }
139✔
864
    } else if (only_dir) {
534✔
865
        SCLogError("unknown option: only accepts to_server or to_client");
32✔
866
        return -1;
32✔
867
    }
32✔
868
    return 0;
1,393✔
869
}
1,451✔
870

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

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
21,640,586✔
880
        optstr++;
18,606,968✔
881
    }
18,606,968✔
882

883
    /* Look for the end of this option, handling escaped semicolons. */
884
    char *optend = optstr;
21,640,586✔
885
    for (;;) {
21,653,661✔
886
        optend = strchr(optend, ';');
21,653,661✔
887
        if (optend == NULL) {
21,653,661✔
888
            SCLogError("no terminating \";\" found");
236,573✔
889
            goto error;
236,573✔
890
        }
236,573✔
891
        else if (optend > optstr && *(optend -1 ) == '\\') {
21,417,088✔
892
            optend++;
13,075✔
893
        } else {
21,404,013✔
894
            break;
21,404,013✔
895
        }
21,404,013✔
896
    }
21,653,661✔
897
    *(optend++) = '\0';
21,404,013✔
898

899
    /* Find the start of the option value. */
900
    char *optvalptr = strchr(optstr, ':');
21,404,013✔
901
    if (optvalptr) {
21,404,013✔
902
        *(optvalptr++) = '\0';
17,869,205✔
903

904
        /* Trim trailing space from name. */
905
        for (size_t i = strlen(optvalptr); i > 0; i--) {
18,205,349✔
906
            if (isblank(optvalptr[i - 1])) {
18,164,507✔
907
                optvalptr[i - 1] = '\0';
336,144✔
908
            } else {
17,828,363✔
909
                break;
17,828,363✔
910
            }
17,828,363✔
911
        }
18,164,507✔
912

913
        optvalue = optvalptr;
17,869,205✔
914
    }
17,869,205✔
915

916
    /* Trim trailing space from name. */
917
    for (size_t i = strlen(optstr); i > 0; i--) {
21,454,202✔
918
        if (isblank(optstr[i - 1])) {
21,386,284✔
919
            optstr[i - 1] = '\0';
50,189✔
920
        } else {
21,336,095✔
921
            break;
21,336,095✔
922
        }
21,336,095✔
923
    }
21,386,284✔
924
    optname = optstr;
21,404,013✔
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;
21,404,013✔
929
    if ((requires && !requires_only) || (!requires && requires_only)) {
21,404,013✔
930
        goto finish;
12,623,843✔
931
    }
12,623,843✔
932

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

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
8,507,004✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
7,436,720✔
942
            SCLogError(
6,389✔
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
6,389✔
944
            goto error;
6,389✔
945
        }
6,389✔
946
    } else if (st->flags & SIGMATCH_NOOPT) {
7,436,720✔
947
        if (optvalue && strlen(optvalue)) {
862,484✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
135✔
949
            goto error;
135✔
950
        }
135✔
951
    }
862,484✔
952
    s->init_data->negated = false;
8,500,480✔
953

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

957
    if (st->flags & SIGMATCH_INFO_DEPRECATED) {
8,500,480✔
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;
8,500,480✔
972

973
    /* Validate double quoting, trimming trailing white space along the way. */
974
    if (optvalue != NULL && strlen(optvalue) > 0) {
8,500,480✔
975
        size_t ovlen = strlen(optvalue);
7,455,956✔
976
        char *ptr = optvalue;
7,455,956✔
977

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

995
        /* see if value is negated */
996
        if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
7,455,956✔
997
            s->init_data->negated = true;
45,053✔
998
            ptr++;
45,053✔
999
            ovlen--;
45,053✔
1000
        }
45,053✔
1001
        /* skip more whitespace */
1002
        while (ovlen > 0) {
7,458,468✔
1003
            if (!isblank(*ptr))
7,458,260✔
1004
                break;
7,455,748✔
1005
            ptr++;
2,512✔
1006
            ovlen--;
2,512✔
1007
        }
2,512✔
1008
        if (ovlen == 0) {
7,455,956✔
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 != '"') {
7,455,748✔
1015
            SCLogError("invalid formatting to %s keyword: "
10,767✔
1016
                       "value must be double quoted \'%s\'",
10,767✔
1017
                    optname, optstr);
10,767✔
1018
            goto error;
10,767✔
1019
        }
10,767✔
1020

1021
        if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
7,444,981✔
1022
                && ovlen && *ptr == '"')
7,444,981✔
1023
        {
1,996,130✔
1024
            for (; ovlen > 0; ovlen--) {
1,996,130✔
1025
                if (isblank(ptr[ovlen - 1])) {
1,996,130✔
1026
                    ptr[ovlen - 1] = '\0';
×
1027
                } else {
1,996,130✔
1028
                    break;
1,996,130✔
1029
                }
1,996,130✔
1030
            }
1,996,130✔
1031
            if (ovlen && ptr[ovlen - 1] != '"') {
1,996,130✔
1032
                SCLogError("bad option value formatting (possible missing semicolon) "
48,680✔
1033
                           "for keyword %s: \'%s\'",
48,680✔
1034
                        optname, optvalue);
48,680✔
1035
                goto error;
48,680✔
1036
            }
48,680✔
1037
            if (ovlen > 1) {
1,947,450✔
1038
                /* strip leading " */
1039
                ptr++;
1,928,915✔
1040
                ovlen--;
1,928,915✔
1041
                ptr[ovlen - 1] = '\0';
1,928,915✔
1042
                ovlen--;
1,928,915✔
1043
            }
1,928,915✔
1044
            if (ovlen == 0) {
1,947,450✔
1045
                SCLogError("bad input "
614✔
1046
                           "for keyword %s: \'%s\'",
614✔
1047
                        optname, optvalue);
614✔
1048
                goto error;
614✔
1049
            }
614✔
1050
        } else {
5,448,851✔
1051
            if (*ptr == '"') {
5,448,851✔
1052
                SCLogError(
1,282✔
1053
                        "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1,282✔
1054
                goto error;
1,282✔
1055
            }
1,282✔
1056
        }
5,448,851✔
1057
        /* setup may or may not add a new SigMatch to the list */
1058
        if (st->flags & SIGMATCH_SUPPORT_DIR) {
7,394,405✔
1059
            if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1,443✔
1060
                SCLogError("%s failed to setup direction", st->name);
50✔
1061
                goto error;
50✔
1062
            }
50✔
1063
        }
1,443✔
1064
        setup_ret = st->Setup(de_ctx, s, ptr);
7,394,355✔
1065
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
7,394,355✔
1066
        s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
7,394,355✔
1067
    } else {
7,394,355✔
1068
        /* setup may or may not add a new SigMatch to the list */
1069
        setup_ret = st->Setup(de_ctx, s, NULL);
1,044,524✔
1070
    }
1,044,524✔
1071
    if (setup_ret < 0) {
8,438,879✔
1072
        SCLogDebug("\"%s\" failed to setup", st->name);
635,937✔
1073

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

1086
finish:
20,426,777✔
1087
    if (strlen(optend) > 0) {
20,426,777✔
1088
        strlcpy(output, optend, output_size);
16,512,003✔
1089
        return 1;
16,512,003✔
1090
    }
16,512,003✔
1091

1092
    return 0;
3,914,774✔
1093

1094
error:
577,864✔
1095
    return -1;
577,864✔
1096
}
20,426,777✔
1097

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

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
4,220,528✔
1109
        if (strcasecmp(addrstr, "any") == 0)
2,133,561✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
1,754,457✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
2,133,561✔
1113
                &s->init_data->src_contains_negation);
2,133,561✔
1114
        if (s->init_data->src == NULL)
2,133,561✔
1115
            goto error;
46,594✔
1116
    } else {
2,133,561✔
1117
        if (strcasecmp(addrstr, "any") == 0)
2,086,967✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
1,719,830✔
1119

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

1126
    return 0;
4,095,165✔
1127

1128
error:
125,363✔
1129
    return -1;
125,363✔
1130
}
4,220,528✔
1131

1132
static bool IsBuiltIn(const char *n)
1133
{
68,479✔
1134
    if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
68,479✔
1135
        return true;
4,418✔
1136
    }
4,418✔
1137
    if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
64,061✔
1138
        return true;
4,418✔
1139
    }
4,418✔
1140
    return false;
59,643✔
1141
}
64,061✔
1142

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

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

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

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

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

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

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

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

1216
                DetectAppLayerInspectEngineRegister(
30,926✔
1217
                        list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
30,926✔
1218
            }
30,926✔
1219
        }
198,806✔
1220
    }
83,941✔
1221
}
2,209✔
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
{
418✔
1240
    if (strcmp(str, "flow_start") == 0) {
418✔
1241
        return SIGNATURE_HOOK_PKT_FLOW_START;
44✔
1242
    } else if (strcmp(str, "pre_flow") == 0) {
374✔
1243
        return SIGNATURE_HOOK_PKT_PRE_FLOW;
10✔
1244
    } else if (strcmp(str, "pre_stream") == 0) {
364✔
1245
        return SIGNATURE_HOOK_PKT_PRE_STREAM;
6✔
1246
    } else if (strcmp(str, "all") == 0) {
358✔
1247
        return SIGNATURE_HOOK_PKT_ALL;
236✔
1248
    }
236✔
1249
    return SIGNATURE_HOOK_PKT_NOT_SET;
122✔
1250
}
418✔
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
{
148✔
1273
    SignatureHook h = {
148✔
1274
        .type = SIGNATURE_HOOK_TYPE_PKT,
148✔
1275
        .t.pkt.ph = HookPktFromString(hook_str),
148✔
1276
    };
148✔
1277
    return h;
148✔
1278
}
148✔
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
{
270✔
1285
    enum SignatureHookPkt hook = HookPktFromString(h);
270✔
1286
    if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
270✔
1287
        s->init_data->hook = SetPktHook(h);
148✔
1288
        if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
148✔
1289
            return -1; // TODO unreachable?
×
1290
        }
×
1291
    } else {
266✔
1292
        SCLogError("unknown pkt hook %s", h);
122✔
1293
        return -1;
122✔
1294
    }
122✔
1295

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

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

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

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

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

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

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

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

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

1409
    int r = DetectProtoParse(&s->proto, p);
2,286,648✔
1410
    if (r < 0) {
2,286,648✔
1411
        s->alproto = AppLayerGetProtoByName(p);
1,116,131✔
1412
        /* indicate that the signature is app-layer */
1413
        if (s->alproto != ALPROTO_UNKNOWN) {
1,116,131✔
1414
            s->flags |= SIG_FLAG_APPLAYER;
1,056,360✔
1415

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
1,056,360✔
1417

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

1437
        if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
270✔
1438
            SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
122✔
1439
            SCReturnInt(-1);
122✔
1440
        }
122✔
1441
    }
270✔
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,226,618✔
1446
        s->flags |= SIG_FLAG_REQUIRE_PACKET;
165,762✔
1447
    } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
2,060,856✔
1448
        s->flags |= SIG_FLAG_REQUIRE_STREAM;
21,483✔
1449
    }
21,483✔
1450

1451
    SCReturnInt(0);
2,226,618✔
1452
}
2,286,648✔
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,997,146✔
1469
    int r = 0;
3,997,146✔
1470

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

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

1475
    if (flag == 0) {
3,997,146✔
1476
        if (strcasecmp(portstr, "any") == 0)
2,008,198✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
1,589,165✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
2,008,198✔
1480
    } else if (flag == 1) {
2,008,198✔
1481
        if (strcasecmp(portstr, "any") == 0)
1,988,948✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
1,505,167✔
1483

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

1487
    if (r < 0)
3,997,146✔
1488
        return -1;
94,578✔
1489

1490
    return 0;
3,902,568✔
1491
}
3,997,146✔
1492

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

1516
/** \retval 0 on error
1517
 *  \retval flags on success
1518
 */
1519
static uint8_t ActionStringToFlags(const char *action)
1520
{
2,358,350✔
1521
    if (strcasecmp(action, "alert") == 0) {
2,358,350✔
1522
        return ACTION_ALERT;
1,903,150✔
1523
    } else if (strcasecmp(action, "drop") == 0) {
1,903,156✔
1524
        return ACTION_DROP | ACTION_ALERT;
73,588✔
1525
    } else if (strcasecmp(action, "pass") == 0) {
381,621✔
1526
        return ACTION_PASS;
308,777✔
1527
    } else if (strcasecmp(action, "reject") == 0 ||
308,984✔
1528
               strcasecmp(action, "rejectsrc") == 0)
72,835✔
1529
    {
512✔
1530
        if (!(SigParseActionRejectValidate(action)))
512✔
1531
            return 0;
×
1532
        return ACTION_REJECT | ACTION_DROP | ACTION_ALERT;
512✔
1533
    } else if (strcasecmp(action, "rejectdst") == 0) {
72,325✔
1534
        if (!(SigParseActionRejectValidate(action)))
16✔
1535
            return 0;
×
1536
        return ACTION_REJECT_DST | ACTION_DROP | ACTION_ALERT;
16✔
1537
    } else if (strcasecmp(action, "rejectboth") == 0) {
72,307✔
1538
        if (!(SigParseActionRejectValidate(action)))
144✔
1539
            return 0;
×
1540
        return ACTION_REJECT_BOTH | ACTION_DROP | ACTION_ALERT;
144✔
1541
    } else if (strcasecmp(action, "config") == 0) {
72,163✔
1542
        return ACTION_CONFIG;
2,035✔
1543
    } else if (strcasecmp(action, "accept") == 0) {
70,129✔
1544
        return ACTION_ACCEPT;
316✔
1545
    } else {
70,091✔
1546
        SCLogError("An invalid action \"%s\" was given", action);
69,812✔
1547
        return 0;
69,812✔
1548
    }
69,812✔
1549
}
2,358,350✔
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,358,356✔
1564
    char action[32];
2,358,356✔
1565
    strlcpy(action, action_in, sizeof(action));
2,358,356✔
1566
    const char *a = action;
2,358,356✔
1567
    const char *o = NULL;
2,358,356✔
1568

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

1581
    uint8_t flags = ActionStringToFlags(a);
2,358,350✔
1582
    if (flags == 0)
2,358,350✔
1583
        return -1;
69,812✔
1584

1585
    /* parse scope, if any */
1586
    if (o) {
2,288,538✔
1587
        uint8_t scope_flags = 0;
370✔
1588
        if (flags & (ACTION_DROP | ACTION_PASS)) {
370✔
1589
            if (strcmp(o, "packet") == 0) {
46✔
1590
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
9✔
1591
            } else if (strcmp(o, "flow") == 0) {
37✔
1592
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
26✔
1593
            } else {
33✔
1594
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
11✔
1595
                           "allowed",
11✔
1596
                        o, action_in);
11✔
1597
                return -1;
11✔
1598
            }
11✔
1599
            s->action_scope = scope_flags;
35✔
1600
        } else if (flags & (ACTION_ACCEPT)) {
324✔
1601
            if (strcmp(o, "packet") == 0) {
314✔
1602
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
36✔
1603
            } else if (strcmp(o, "hook") == 0) {
278✔
1604
                scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
223✔
1605
            } else if (strcmp(o, "tx") == 0) {
223✔
1606
                scope_flags = (uint8_t)ACTION_SCOPE_TX;
7✔
1607
            } else if (strcmp(o, "flow") == 0) {
48✔
1608
                scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
37✔
1609
            } else {
47✔
1610
                SCLogError(
11✔
1611
                        "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
11✔
1612
                        "'hook' allowed",
11✔
1613
                        o, action_in);
11✔
1614
                return -1;
11✔
1615
            }
11✔
1616
            s->action_scope = scope_flags;
303✔
1617
        } else if (flags & (ACTION_CONFIG)) {
303✔
1618
            if (strcmp(o, "packet") == 0) {
5✔
1619
                scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
2✔
1620
            } else {
5✔
1621
                SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
3✔
1622
                        action_in);
3✔
1623
                return -1;
3✔
1624
            }
3✔
1625
            s->action_scope = scope_flags;
2✔
1626
        } else {
7✔
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
    }
370✔
1633

1634
    /* require explicit action scope for fw rules */
1635
    if (s->init_data->firewall_rule && s->action_scope == 0) {
2,288,508✔
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,288,508✔
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,288,482✔
1646
        SCLogError("'pass' action not supported for firewall rules");
×
1647
        return -1;
×
1648
    }
×
1649

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

1670
    if (!len) {
12,952,004✔
1671
        return 0;
606,651✔
1672
    }
606,651✔
1673

1674
    while (len && isblank(**input)) {
12,454,170✔
1675
        (*input)++;
108,817✔
1676
        len--;
108,817✔
1677
    }
108,817✔
1678

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

1686
    return 1;
12,345,353✔
1687
}
12,952,004✔
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
{
32,380,010✔
1703
    int in_list = 0;
32,380,010✔
1704
    size_t len = *input != NULL ? strlen(*input) : 0;
32,380,010✔
1705

1706
    if (len == 0) {
32,380,010✔
1707
        return 0;
2,552,839✔
1708
    }
2,552,839✔
1709

1710
    while (len && isblank(**input)) {
30,424,544✔
1711
        (*input)++;
597,373✔
1712
        len--;
597,373✔
1713
    }
597,373✔
1714

1715
    size_t i = 0;
29,827,171✔
1716
    for (i = 0; i < len; i++) {
167,482,095✔
1717
        char c = (*input)[i];
166,927,786✔
1718
        if (c == '[') {
166,927,786✔
1719
            in_list++;
475,537✔
1720
        } else if (c == ']') {
166,452,249✔
1721
            in_list--;
533,530✔
1722
        } else if (c == ' ') {
165,918,719✔
1723
            if (!in_list) {
29,758,756✔
1724
                break;
29,272,862✔
1725
            }
29,272,862✔
1726
        }
29,758,756✔
1727
    }
166,927,786✔
1728
    if (i == len) {
29,827,171✔
1729
        *input = NULL;
554,309✔
1730
        return 0;
554,309✔
1731
    }
554,309✔
1732
    (*input)[i] = '\0';
29,272,862✔
1733
    strlcpy(output, *input, output_size);
29,272,862✔
1734
    *input = *input + i + 1;
29,272,862✔
1735

1736
    return 1;
29,272,862✔
1737
}
29,827,171✔
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,476,002✔
1748
    char *index, dup[DETECT_MAX_RULE_SIZE];
6,476,002✔
1749

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
6,476,002✔
1751
    index = dup;
6,476,002✔
1752

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

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

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

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

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

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

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

1774
    /* Options. */
1775
    if (index == NULL) {
6,476,002✔
1776
        SCLogError("no rule options.");
833,124✔
1777
        goto error;
833,124✔
1778
    }
833,124✔
1779
    while (isspace(*index) || *index == '(') {
9,692,321✔
1780
        index++;
4,049,443✔
1781
    }
4,049,443✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
11,158,129✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
11,088,570✔
1784
            index[i - 1] = '\0';
5,515,251✔
1785
        } else {
5,573,486✔
1786
            break;
5,573,319✔
1787
        }
5,573,319✔
1788
    }
11,088,570✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
5,642,878✔
1790

1791
    if (scan_only) {
5,642,878✔
1792
        return 0;
3,284,522✔
1793
    }
3,284,522✔
1794

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

1799
    if (SigParseProto(s, parser->protocol) < 0)
2,288,482✔
1800
        goto error;
61,864✔
1801

1802
    if (strcmp(parser->direction, "<>") == 0) {
2,226,618✔
1803
        s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC;
518,904✔
1804
    } else if (strcmp(parser->direction, "=>") == 0) {
1,707,714✔
1805
        if (s->flags & SIG_FLAG_FIREWALL) {
1,170✔
1806
            SCLogError("transactional bidirectional rules not supported for firewall rules");
×
1807
            goto error;
×
1808
        }
×
1809

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

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

1822
    if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
2,086,967✔
1823
        goto error;
78,769✔
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)
2,008,198✔
1830
        goto error;
19,250✔
1831
    if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1,988,948✔
1832
        goto error;
75,328✔
1833

1834
    return 0;
1,913,620✔
1835

1836
error:
1,277,860✔
1837
    return -1;
1,277,860✔
1838
}
1,988,948✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
6,774,051✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
1,012,356,973✔
1843
        if (str[i] < 0x20) {
1,005,880,971✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1,680,168✔
1846
                continue;
1,404,319✔
1847
            }
1,404,319✔
1848
            return false;
275,849✔
1849
        } else if (str[i] == 0x7f) {
1,004,200,803✔
1850
            return false;
22,200✔
1851
        }
22,200✔
1852
    }
1,005,880,971✔
1853
    return true;
6,476,002✔
1854
}
6,774,051✔
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,668,952✔
1871
    SCEnter();
7,668,952✔
1872

1873
    if (!SCCheckUtf8(sigstr)) {
7,668,952✔
1874
        SCLogError("rule is not valid UTF-8");
894,901✔
1875
        SCReturnInt(-1);
894,901✔
1876
    }
894,901✔
1877

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

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

1889
    /* we can have no options, so make sure we have them */
1890
    if (strlen(parser->opts) > 0) {
5,198,142✔
1891
        size_t buffer_size = strlen(parser->opts) + 1;
5,128,583✔
1892
        DEBUG_VALIDATE_BUG_ON(buffer_size > DETECT_MAX_RULE_SIZE);
5,128,583✔
1893
        char input[buffer_size];
5,128,583✔
1894
        char output[buffer_size];
5,128,583✔
1895
        memset(input, 0x00, buffer_size);
5,128,583✔
1896
        memcpy(input, parser->opts, strlen(parser->opts) + 1);
5,128,583✔
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 {
21,640,586✔
1902
            memset(output, 0x00, buffer_size);
21,640,586✔
1903
            ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
21,640,586✔
1904
            if (ret == 1) {
21,640,586✔
1905
                memcpy(input, output, buffer_size);
16,512,003✔
1906
            }
16,512,003✔
1907

1908
        } while (ret == 1);
21,640,586✔
1909

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

1916
end:
5,198,134✔
1917
    DetectIPProtoRemoveAllSMs(de_ctx, s);
5,198,134✔
1918

1919
    SCReturnInt(ret);
5,198,134✔
1920
}
5,198,142✔
1921

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

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

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

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

1957
    sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
5,310,647✔
1958
    if (sig->init_data->buffers == NULL) {
5,310,647✔
1959
        SCFree(sig->init_data);
×
1960
        SCFree(sig);
×
1961
        return NULL;
×
UNCOV
1962
    }
×
1963
    sig->init_data->buffers_size = 8;
5,310,647✔
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,310,647✔
1969

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

1975
    sig->init_data->list = DETECT_SM_LIST_NOTSET;
5,310,647✔
1976
    return sig;
5,310,647✔
1977
}
5,310,647✔
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,310,611✔
1987
    SCEnter();
5,310,611✔
1988

1989
    DetectMetadata *mdata = NULL;
5,310,611✔
1990
    DetectMetadata *next_mdata = NULL;
5,310,611✔
1991

1992
    if (s == NULL || s->metadata == NULL) {
5,310,611✔
1993
        SCReturn;
5,257,099✔
1994
    }
5,257,099✔
1995

1996
    SCLogDebug("s %p, s->metadata %p", s, s->metadata);
53,512✔
1997

1998
    for (mdata = s->metadata->list; mdata != NULL;)   {
365,225✔
1999
        next_mdata = mdata->next;
311,713✔
2000
        DetectMetadataFree(mdata);
311,713✔
2001
        mdata = next_mdata;
311,713✔
2002
    }
311,713✔
2003
    SCFree(s->metadata->json_str);
53,512✔
2004
    SCFree(s->metadata);
53,512✔
2005
    s->metadata = NULL;
53,512✔
2006

2007
    SCReturn;
53,512✔
2008
}
5,310,611✔
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,310,611✔
2018
    SCEnter();
5,310,611✔
2019

2020
    DetectReference *ref = NULL;
5,310,611✔
2021
    DetectReference *next_ref = NULL;
5,310,611✔
2022

2023
    if (s == NULL) {
5,310,611✔
2024
        SCReturn;
×
UNCOV
2025
    }
×
2026

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

2029
    for (ref = s->references; ref != NULL;)   {
5,419,192✔
2030
        next_ref = ref->next;
108,581✔
2031
        DetectReferenceFree(ref);
108,581✔
2032
        ref = next_ref;
108,581✔
2033
    }
108,581✔
2034

2035
    s->references = NULL;
5,310,611✔
2036

2037
    SCReturn;
5,310,611✔
2038
}
5,310,611✔
2039

2040
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041
{
5,310,611✔
2042
    if (s != NULL) {
5,310,611✔
2043
        int type;
5,310,611✔
2044
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
42,484,888✔
2045
            if (s->sm_arrays[type] != NULL) {
37,174,277✔
2046
                if (ctxs) {
149,447✔
2047
                    SigMatchData *smd = s->sm_arrays[type];
149,447✔
2048
                    while(1) {
192,576✔
2049
                        if (sigmatch_table[smd->type].Free != NULL) {
192,576✔
2050
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
192,254✔
2051
                        }
192,254✔
2052
                        if (smd->is_last)
192,576✔
2053
                            break;
149,447✔
2054
                        smd++;
43,129✔
2055
                    }
43,129✔
2056
                }
149,447✔
2057

2058
                SCFree(s->sm_arrays[type]);
149,447✔
2059
            }
149,447✔
2060
        }
37,174,277✔
2061
    }
5,310,611✔
2062
}
5,310,611✔
2063

2064
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
2065
{
5,325,184✔
2066
    if (s == NULL)
5,325,184✔
2067
        return;
14,573✔
2068

2069
    int i;
5,310,611✔
2070

2071
    if (s->init_data && s->init_data->transforms.cnt) {
5,310,611✔
2072
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
57,389✔
2073
            if (s->init_data->transforms.transforms[i].options) {
32,580✔
2074
                int transform = s->init_data->transforms.transforms[i].transform;
12,200✔
2075
                sigmatch_table[transform].Free(
12,200✔
2076
                        de_ctx, s->init_data->transforms.transforms[i].options);
12,200✔
2077
                s->init_data->transforms.transforms[i].options = NULL;
12,200✔
2078
            }
12,200✔
2079
        }
32,580✔
2080
    }
24,809✔
2081
    if (s->init_data) {
5,310,611✔
2082
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
40,356,712✔
2083
            SigMatch *sm = s->init_data->smlists[i];
35,312,123✔
2084
            while (sm != NULL) {
36,159,210✔
2085
                SigMatch *nsm = sm->next;
847,087✔
2086
                SigMatchFree(de_ctx, sm);
847,087✔
2087
                sm = nsm;
847,087✔
2088
            }
847,087✔
2089
        }
35,312,123✔
2090

2091
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
5,909,760✔
2092
            SigMatch *sm = s->init_data->buffers[x].head;
865,171✔
2093
            while (sm != NULL) {
1,746,286✔
2094
                SigMatch *nsm = sm->next;
881,115✔
2095
                SigMatchFree(de_ctx, sm);
881,115✔
2096
                sm = nsm;
881,115✔
2097
            }
881,115✔
2098
        }
865,171✔
2099
        if (s->init_data->cidr_dst != NULL)
5,044,589✔
2100
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
74,719✔
2101

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

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

2114
    if (s->sp != NULL) {
5,310,611✔
2115
        DetectPortCleanupList(NULL, s->sp);
1,988,917✔
2116
    }
1,988,917✔
2117
    if (s->dp != NULL) {
5,310,611✔
2118
        DetectPortCleanupList(NULL, s->dp);
1,915,867✔
2119
    }
1,915,867✔
2120

2121
    if (s->msg != NULL)
5,310,611✔
2122
        SCFree(s->msg);
1,005,690✔
2123

2124
    if (s->addr_src_match4 != NULL) {
5,310,611✔
2125
        SCFree(s->addr_src_match4);
978,075✔
2126
    }
978,075✔
2127
    if (s->addr_dst_match4 != NULL) {
5,310,611✔
2128
        SCFree(s->addr_dst_match4);
978,195✔
2129
    }
978,195✔
2130
    if (s->addr_src_match6 != NULL) {
5,310,611✔
2131
        SCFree(s->addr_src_match6);
1,000,585✔
2132
    }
1,000,585✔
2133
    if (s->addr_dst_match6 != NULL) {
5,310,611✔
2134
        SCFree(s->addr_dst_match6);
948,717✔
2135
    }
948,717✔
2136
    if (s->sig_str != NULL) {
5,310,611✔
2137
        SCFree(s->sig_str);
5,310,560✔
2138
    }
5,310,560✔
2139

2140
    SigRefFree(s);
5,310,611✔
2141
    SigMetadataFree(s);
5,310,611✔
2142

2143
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
5,310,611✔
2144

2145
    SCFree(s);
5,310,611✔
2146
}
5,310,611✔
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,692✔
2160
    if (s->alproto != ALPROTO_UNKNOWN) {
9,692✔
2161
        // One alproto was set, check if it matches the new ones proposed
2162
        while (*alprotos != ALPROTO_UNKNOWN) {
9,269✔
2163
            if (s->alproto == *alprotos) {
8,766✔
2164
                // alproto already set to only one
2165
                return 0;
5,382✔
2166
            }
5,382✔
2167
            alprotos++;
3,384✔
2168
        }
3,384✔
2169
        // alproto already set and not matching the new set of alprotos
2170
        return -1;
503✔
2171
    }
5,885✔
2172
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
3,807✔
2173
        // check intersection of already used alprotos and new ones
2174
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,655✔
2175
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,655✔
2176
                break;
2,884✔
2177
            }
2,884✔
2178
            // first disable the ones that do not match
2179
            bool found = false;
8,655✔
2180
            const AppProto *args = alprotos;
5,771✔
2181
            while (*args != ALPROTO_UNKNOWN) {
8,667✔
2182
                if (s->init_data->alprotos[i] == *args) {
8,661✔
2183
                    found = true;
5,765✔
2184
                    break;
5,765✔
2185
                }
5,765✔
2186
                args++;
2,896✔
2187
            }
2,896✔
2188
            if (!found) {
5,771✔
2189
                s->init_data->alprotos[i] = ALPROTO_UNKNOWN;
6✔
2190
            }
6✔
2191
        }
5,771✔
2192
        // Then put at the beginning every defined protocol
2193
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
8,649✔
2194
            if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
8,649✔
2195
                for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
5,775✔
2196
                    if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2,891✔
2197
                        s->init_data->alprotos[i] = s->init_data->alprotos[j];
2✔
2198
                        s->init_data->alprotos[j] = ALPROTO_UNKNOWN;
2✔
2199
                        break;
2✔
2200
                    }
2✔
2201
                }
2,891✔
2202
                if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2,886✔
2203
                    if (i == 0) {
2,884✔
2204
                        // there was no intersection
2205
                        return -1;
1✔
2206
                    } else if (i == 1) {
2,883✔
2207
                        // intersection is singleton, set it as usual
2208
                        AppProto alproto = s->init_data->alprotos[0];
1✔
2209
                        s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
2210
                        return SCDetectSignatureSetAppProto(s, alproto);
1✔
2211
                    }
1✔
2212
                    break;
2,882✔
2213
                }
2,884✔
2214
            }
2,886✔
2215
        }
8,649✔
2216
    } else {
2,890✔
2217
        if (alprotos[0] == ALPROTO_UNKNOWN) {
923✔
2218
            // do not allow empty set
2219
            return -1;
×
UNCOV
2220
        }
×
2221
        if (alprotos[1] == ALPROTO_UNKNOWN) {
923✔
2222
            // allow singleton, but call traditional setter
2223
            return SCDetectSignatureSetAppProto(s, alprotos[0]);
×
UNCOV
2224
        }
×
2225
        // first time we enforce alprotos
2226
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2,773✔
2227
            if (alprotos[i] == ALPROTO_UNKNOWN) {
2,773✔
2228
                break;
923✔
2229
            }
923✔
2230
            s->init_data->alprotos[i] = alprotos[i];
1,850✔
2231
        }
1,850✔
2232
    }
923✔
2233
    return 0;
3,805✔
2234
}
3,807✔
2235

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

2243
    if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
955,157✔
2244
        // Multiple alprotos were set, check if we restrict to one
2245
        bool found = false;
48✔
2246
        for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
150✔
2247
            if (s->init_data->alprotos[i] == alproto) {
126✔
2248
                found = true;
24✔
2249
                break;
24✔
2250
            }
24✔
2251
        }
126✔
2252
        if (!found) {
48✔
2253
            // fail if we set to a alproto which was not in the set
2254
            return -1;
24✔
2255
        }
24✔
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) {
955,133✔
2262
        alproto = AppProtoCommon(s->alproto, alproto);
711,853✔
2263
        if (alproto == ALPROTO_FAILED) {
711,853✔
2264
            SCLogError("can't set rule app proto to %s: already set to %s",
26,534✔
2265
                    AppProtoToString(alproto), AppProtoToString(s->alproto));
26,534✔
2266
            return -1;
26,534✔
2267
        }
26,534✔
2268
    }
711,853✔
2269

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

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

2284
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
4,504,451✔
2285
        cnt++;
2,337,019✔
2286
    }
2,337,019✔
2287
    if (cnt == 0) {
2,167,432✔
2288
        return NULL;
211,106✔
2289
    }
211,106✔
2290
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
1,956,326✔
2291
    if (addr_match4 == NULL) {
1,956,326✔
2292
        return NULL;
×
UNCOV
2293
    }
×
2294

2295
    uint16_t idx = 0;
1,956,326✔
2296
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
4,293,345✔
2297
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2,337,019✔
2298
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2,337,019✔
2299
        idx++;
2,337,019✔
2300
    }
2,337,019✔
2301
    *match4_cnt = cnt;
1,956,326✔
2302
    return addr_match4;
1,956,326✔
2303
}
1,956,326✔
2304

2305
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2306
        const DetectAddress *head, uint16_t *match6_cnt)
2307
{
2,167,432✔
2308
    uint16_t cnt = 0;
2,167,432✔
2309
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
4,389,654✔
2310
        cnt++;
2,222,222✔
2311
    }
2,222,222✔
2312
    if (cnt == 0) {
2,167,432✔
2313
        return NULL;
218,096✔
2314
    }
218,096✔
2315

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

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

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

2360
static int SigMatchListLen(SigMatch *sm)
2361
{
1,912,050✔
2362
    int len = 0;
1,912,050✔
2363
    for (; sm != NULL; sm = sm->next)
2,377,290✔
2364
        len++;
465,240✔
2365

2366
    return len;
1,912,050✔
2367
}
1,912,050✔
2368

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

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

2384
    /* Copy sm type and Context into array */
2385
    SigMatch *sm = head;
327,111✔
2386
    for (; sm != NULL; sm = sm->next, smd++) {
792,351✔
2387
        smd->type = sm->type;
465,240✔
2388
        smd->ctx = sm->ctx;
465,240✔
2389
        sm->ctx = NULL; // SigMatch no longer owns the ctx
465,240✔
2390
        smd->is_last = (sm->next == NULL);
465,240✔
2391
    }
465,240✔
2392
    return out;
327,111✔
2393
}
327,111✔
2394

2395
extern int g_skip_prefilter;
2396

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

2403
    if (s->init_data->prefilter_sm != NULL) {
1,083,716✔
2404
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
42,803✔
2405
            RetrieveFPForSig(de_ctx, s);
1,367✔
2406
            if (s->init_data->mpm_sm != NULL) {
1,367✔
2407
                s->flags |= SIG_FLAG_PREFILTER;
1,364✔
2408
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
1,364✔
2409
                SCReturn;
1,364✔
2410
            }
1,364✔
2411
            /* fall through, this can happen if the mpm doesn't support the pattern */
2412
        } else {
41,437✔
2413
            s->flags |= SIG_FLAG_PREFILTER;
41,436✔
2414
            SCReturn;
41,436✔
2415
        }
41,436✔
2416
    } else {
1,040,913✔
2417
        SCLogDebug("%u: RetrieveFPForSig", s->id);
1,040,913✔
2418
        RetrieveFPForSig(de_ctx, s);
1,040,913✔
2419
        if (s->init_data->mpm_sm != NULL) {
1,040,913✔
2420
            s->flags |= SIG_FLAG_PREFILTER;
381,884✔
2421
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
381,884✔
2422
            SCReturn;
381,884✔
2423
        }
381,884✔
2424
    }
1,040,913✔
2425

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

2430
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
659,032✔
2431
        SCReturn;
655,969✔
2432

2433
    DEBUG_VALIDATE_BUG_ON(s->flags & SIG_FLAG_PREFILTER);
3,063✔
2434
    if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) {
3,063✔
UNCOV
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
            }
×
UNCOV
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
        }
×
UNCOV
2461
    }
×
2462
    SCReturn;
3,063✔
2463
}
659,032✔
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
{
1,052,759✔
2470
    if (s->detect_table == 0)
1,052,759✔
UNCOV
2471
        return true;
×
2472

2473
    const uint8_t table_as_flag = BIT_U8(s->detect_table);
1,052,759✔
2474

2475
    for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
1,388,511✔
2476
        const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
335,752✔
2477
        if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
335,752✔
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;
×
UNCOV
2481
        }
×
2482
    }
335,752✔
2483
    return true;
1,052,759✔
2484
}
1,052,759✔
2485

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

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

2524
    s->detect_table = (uint8_t)table;
1,054,101✔
2525
}
1,054,101✔
2526

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

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

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

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

2557
    /* run buffer type validation callbacks if any */
2558
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
1,081,392✔
2559
        if (!DetectContentPMATCHValidateCallback(s))
178,102✔
2560
            SCReturnInt(0);
1,712✔
2561

2562
        has_pmatch = true;
176,390✔
2563
    }
176,390✔
2564

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

2572
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,765,396✔
2573
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
709,862✔
2574
        const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
709,862✔
2575
        if (bt == NULL) {
709,862✔
2576
            DEBUG_VALIDATE_BUG_ON(1); // should be impossible
×
2577
            continue;
×
UNCOV
2578
        }
×
2579
        SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
709,862✔
2580
        for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
1,648,685✔
2581
            SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
938,823✔
2582
        }
938,823✔
2583

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

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

2593
        if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
709,816✔
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;
708,954✔
2602
        for (; app != NULL; app = app->next) {
574,072,705✔
2603
            if (app->sm_list == b->id &&
573,363,751✔
2604
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
573,363,751✔
2605
                SCLogDebug("engine %s dir %d alproto %d",
1,744,117✔
2606
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
1,744,117✔
2607
                        app->alproto);
1,744,117✔
2608
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
1,744,117✔
2609

2610
                if (b->only_tc) {
1,744,117✔
2611
                    if (app->dir == 1)
4,376✔
2612
                        (*tc_excl)++;
2,069✔
2613
                } else if (b->only_ts) {
1,739,741✔
2614
                    if (app->dir == 0)
1,703✔
2615
                        (*ts_excl)++;
896✔
2616
                } else {
1,738,038✔
2617
                    bufdir[b->id].ts += (app->dir == 0);
1,738,038✔
2618
                    bufdir[b->id].tc += (app->dir == 1);
1,738,038✔
2619
                }
1,738,038✔
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,744,117✔
2624
                    if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
96✔
2625
                            app->progress != s->init_data->hook.t.app.app_progress) {
96✔
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);
×
UNCOV
2629
                    }
×
2630
                    if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
96✔
2631
                            app->progress != s->init_data->hook.t.app.app_progress) {
96✔
2632
                        SCLogError("engine progress value doesn't match hook");
×
2633
                        SCReturnInt(0);
×
UNCOV
2634
                    }
×
2635
                }
96✔
2636
            }
1,744,117✔
2637
        }
573,363,751✔
2638

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

2643
        if (!DetectBsizeValidateContentCallback(s, b)) {
698,003✔
2644
            SCReturnInt(0);
12,274✔
2645
        }
12,274✔
2646
        if (!DetectAbsentValidateContentCallback(s, b)) {
685,729✔
2647
            SCReturnInt(0);
13✔
2648
        }
13✔
2649
    }
685,729✔
2650

2651
    if (has_pmatch && has_frame) {
1,055,534✔
2652
        SCLogError("can't mix pure content and frame inspection");
96✔
2653
        SCReturnInt(0);
96✔
2654
    }
96✔
2655
    if (has_app && has_frame) {
1,055,438✔
2656
        SCLogError("can't mix app-layer buffer and frame inspection");
24✔
2657
        SCReturnInt(0);
24✔
2658
    }
24✔
2659
    if (has_pkt && has_frame) {
1,055,414✔
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++) {
166,204,474✔
2665
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
165,149,061✔
2666
            continue;
164,571,330✔
2667
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
577,731✔
2668
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
577,731✔
2669
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
577,731✔
2670

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

2675
    SCReturnInt(1);
1,055,413✔
2676
}
1,055,414✔
2677

2678
static int SigValidatePacketStream(const Signature *s)
2679
{
1,083,716✔
2680
    if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1,083,716✔
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);
1,083,716✔
2686
}
1,083,716✔
2687

2688
static int SigConsolidateDirection(
2689
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2690
{
1,055,413✔
2691
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
1,055,413✔
2692
        if (!ts_excl || !tc_excl) {
745✔
2693
            SCLogError("rule %u should use both directions, but does not", s->id);
405✔
2694
            SCReturnInt(0);
405✔
2695
        }
405✔
2696
        if (dir_amb) {
340✔
2697
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
6✔
2698
                       "directions",
6✔
2699
                    s->id);
6✔
2700
            SCReturnInt(0);
6✔
2701
        }
6✔
2702
    } else if (ts_excl && tc_excl) {
1,054,668✔
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) {
1,054,414✔
2709
        SCLogDebug("%u: implied rule direction is toserver", s->id);
322,185✔
2710
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
322,185✔
2711
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
635✔
2712
            SCReturnInt(0);
635✔
2713
        }
635✔
2714
    } else if (tc_excl) {
750,014✔
2715
        SCLogDebug("%u: implied rule direction is toclient", s->id);
48,382✔
2716
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
48,382✔
2717
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
12✔
2718
            SCReturnInt(0);
12✔
2719
        }
12✔
2720
    } else if (dir_amb) {
683,847✔
2721
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
129,721✔
2722
    }
129,721✔
2723
    SCReturnInt(1);
1,055,413✔
2724
}
1,055,413✔
2725

2726
static void SigConsolidateTcpBuffer(Signature *s)
2727
{
1,054,101✔
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))) {
1,054,101✔
2733
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
1,020,960✔
2734
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
173,268✔
2735
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
119,129✔
2736
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
325,182✔
2737
                        sm = sm->next) {
222,218✔
2738
                    if (sm->type == DETECT_CONTENT &&
222,218✔
2739
                            (((DetectContentData *)(sm->ctx))->flags &
222,218✔
2740
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
100,533✔
2741
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
16,165✔
2742
                        break;
16,165✔
2743
                    }
16,165✔
2744
                }
222,218✔
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;
160,697✔
2747
                        sm = sm->next) {
119,303✔
2748
                    if (sm->type == DETECT_STREAM_SIZE) {
43,478✔
2749
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
1,910✔
2750
                        break;
1,910✔
2751
                    }
1,910✔
2752
                }
43,478✔
2753
            }
119,129✔
2754
        }
173,268✔
2755
    }
1,020,960✔
2756
}
1,054,101✔
2757

2758
static bool SigInspectsFiles(const Signature *s)
2759
{
2,106,860✔
2760
    return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2,106,860✔
2761
            (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA));
2,106,860✔
2762
}
2,106,860✔
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
{
1,054,101✔
2771
    if (!SigInspectsFiles(s)) {
1,054,101✔
2772
        SCReturnInt(1);
993,976✔
2773
    }
993,976✔
2774

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

2821
    if (SigValidateFirewall(de_ctx, s) == 0)
1,083,716✔
UNCOV
2822
        SCReturnInt(0);
×
2823

2824
    if (SigValidatePacketStream(s) == 0) {
1,083,716✔
2825
        SCReturnInt(0);
108✔
2826
    }
108✔
2827

2828
    int ts_excl = 0;
1,083,608✔
2829
    int tc_excl = 0;
1,083,608✔
2830
    int dir_amb = 0;
1,083,608✔
2831

2832
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
1,083,608✔
2833
        SCReturnInt(0);
28,195✔
2834
    }
28,195✔
2835

2836
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
1,055,413✔
2837
        SCReturnInt(0);
1,312✔
2838
    }
1,312✔
2839

2840
    SigConsolidateTcpBuffer(s);
1,054,101✔
2841

2842
    SignatureSetType(de_ctx, s);
1,054,101✔
2843
    DetectRuleSetTable(s);
1,054,101✔
2844

2845
    int r = SigValidateFileHandling(s);
1,054,101✔
2846
    if (r == 0) {
1,054,101✔
2847
        SCReturnInt(0);
1,342✔
2848
    }
1,342✔
2849
    if (SigInspectsFiles(s)) {
1,052,759✔
2850
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
58,783✔
2851
            AppLayerHtpNeedFileInspection();
14,482✔
2852
        }
14,482✔
2853
    }
58,783✔
2854
    if (DetectRuleValidateTable(s) == false) {
1,052,759✔
2855
        SCReturnInt(0);
×
UNCOV
2856
    }
×
2857

2858
    if (s->type == SIG_TYPE_IPONLY) {
1,052,759✔
2859
        /* For IPOnly */
2860
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
82,926✔
2861
            SCReturnInt(0);
556✔
2862

2863
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
82,370✔
2864
            SCReturnInt(0);
1,701✔
2865
    }
82,370✔
2866
    SCReturnInt(1);
1,052,759✔
2867
}
1,052,759✔
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,310,596✔
2876
    SignatureParser parser;
5,310,596✔
2877
    memset(&parser, 0x00, sizeof(parser));
5,310,596✔
2878

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

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

2892
    /* default gid to 1 */
2893
    sig->gid = 1;
5,310,596✔
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,310,596✔
2900
    if (ret == -4) {
5,310,596✔
2901
        /* Rule requirements not met. */
2902
        de_ctx->sigerror_silent = true;
10,560✔
2903
        de_ctx->sigerror_ok = true;
10,560✔
2904
        de_ctx->sigerror_requires = true;
10,560✔
2905
        goto error;
10,560✔
2906
    } else if (ret < 0) {
5,300,036✔
2907
        goto error;
2,399,419✔
2908
    }
2,399,419✔
2909

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

2916
    /* Now completely parse the rule. */
2917
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2,358,356✔
2918
    BUG_ON(ret == -4);
2,358,356✔
2919
    if (ret == -3) {
2,358,348✔
2920
        de_ctx->sigerror_silent = true;
17,959✔
2921
        de_ctx->sigerror_ok = true;
17,959✔
2922
        goto error;
17,959✔
2923
    } else if (ret == -2) {
2,340,389✔
2924
        de_ctx->sigerror_silent = true;
1✔
2925
        goto error;
1✔
2926
    } else if (ret < 0) {
2,340,388✔
2927
        goto error;
1,256,672✔
2928
    }
1,256,672✔
2929

2930
    /* signature priority hasn't been overwritten.  Using default priority */
2931
    if (sig->prio == -1)
1,083,716✔
2932
        sig->prio = DETECT_DEFAULT_PRIO;
880,221✔
2933

2934
    sig->iid = de_ctx->signum;
1,083,716✔
2935
    de_ctx->signum++;
1,083,716✔
2936

2937
    if (sig->alproto != ALPROTO_UNKNOWN) {
1,083,716✔
2938
        int override_needed = 0;
681,253✔
2939
        if (sig->proto.flags & DETECT_PROTO_ANY) {
681,253✔
2940
            sig->proto.flags &= ~DETECT_PROTO_ANY;
152,275✔
2941
            memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
152,275✔
2942
            override_needed = 1;
152,275✔
2943
        } else {
528,978✔
2944
            override_needed = 1;
528,978✔
2945
            size_t s = 0;
528,978✔
2946
            for (s = 0; s < sizeof(sig->proto.proto); s++) {
575,293✔
2947
                if (sig->proto.proto[s] != 0x00) {
575,290✔
2948
                    override_needed = 0;
528,975✔
2949
                    break;
528,975✔
2950
                }
528,975✔
2951
            }
575,290✔
2952
        }
528,978✔
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)
681,253✔
2958
            AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->proto.proto);
152,278✔
2959
    }
681,253✔
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)) {
1,083,716✔
2965
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
400,414✔
2966
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
114,447✔
2967
            for ( ; sm != NULL; sm = sm->next) {
281,273✔
2968
                if (sigmatch_table[sm->type].Match != NULL)
166,826✔
2969
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
166,826✔
2970
            }
166,826✔
2971
        } else {
289,077✔
2972
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
285,967✔
2973
        }
285,967✔
2974
    }
400,414✔
2975

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

2984
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
1,083,716✔
2985
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
944,883✔
2986
            sig->flags |= SIG_FLAG_TOSERVER;
913,524✔
2987
            sig->flags |= SIG_FLAG_TOCLIENT;
913,524✔
2988
        }
913,524✔
2989
    }
944,883✔
2990

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

2995
    SigBuildAddressMatchArray(sig);
1,083,716✔
2996

2997
    /* run buffer type callbacks if any */
2998
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
8,669,728✔
2999
        if (sig->init_data->smlists[x])
7,586,012✔
3000
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
524,587✔
3001
    }
7,586,012✔
3002
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
1,797,361✔
3003
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
713,645✔
3004
    }
713,645✔
3005

3006
    SigSetupPrefilter(de_ctx, sig);
1,083,716✔
3007

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

3013
    return sig;
1,050,502✔
3014

3015
error:
4,260,086✔
3016
    if (sig != NULL) {
4,260,086✔
3017
        SigFree(de_ctx, sig);
4,260,086✔
3018
    }
4,260,086✔
3019
    return NULL;
4,260,086✔
3020
}
1,083,716✔
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,073✔
3030
    if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
162,073✔
3031
        if (!DetectPortListsAreEqual(s->sp, s->dp)) {
146,148✔
3032
            return false;
143,342✔
3033
        }
143,342✔
3034
    }
146,148✔
3035

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

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

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

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

3052
    return true;
2,747✔
3053
}
18,731✔
3054

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

3059
    uint32_t oldsignum = de_ctx->signum;
5,151,270✔
3060
    de_ctx->sigerror_ok = false;
5,151,270✔
3061
    de_ctx->sigerror_silent = false;
5,151,270✔
3062
    de_ctx->sigerror_requires = false;
5,151,270✔
3063

3064
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
5,151,270✔
3065
    if (sig == NULL) {
5,151,270✔
3066
        goto error;
4,260,086✔
3067
    }
4,260,086✔
3068

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

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

3083
    SCReturnPtr(sig, "Signature");
891,184✔
3084

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

3093
    SCReturnPtr(NULL, "Signature");
4,260,086✔
3094
}
891,184✔
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
{
5,151,011✔
3107
    return SigInitDo(de_ctx, sigstr, false);
5,151,011✔
3108
}
5,151,011✔
3109

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

3115
/**
3116
 * \brief The hash free function to be the used by the hash table -
3117
 *        DetectEngineCtx->dup_sig_hash_table.
3118
 *
3119
 * \param data    Pointer to the data, in our case SigDuplWrapper to be freed.
3120
 */
3121
static void DetectParseDupSigFreeFunc(void *data)
3122
{
253,715✔
3123
    if (data != NULL)
253,715✔
3124
        SCFree(data);
253,715✔
3125
}
253,715✔
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
{
1,361,747✔
3139
    SigDuplWrapper *sw = (SigDuplWrapper *)data;
1,361,747✔
3140

3141
    return (sw->s->id % ht->array_size);
1,361,747✔
3142
}
1,361,747✔
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
{
1,038,792✔
3159
    SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
1,038,792✔
3160
    SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
1,038,792✔
3161

3162
    if (sw1 == NULL || sw2 == NULL ||
1,038,792✔
3163
        sw1->s == NULL || sw2->s == NULL)
1,038,792✔
UNCOV
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;
1,038,792✔
3168

3169
    return 0;
184,475✔
3170
}
1,038,792✔
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
{
38,847✔
3182
    de_ctx->dup_sig_hash_table = HashListTableInit(15000,
38,847✔
3183
                                                   DetectParseDupSigHashFunc,
38,847✔
3184
                                                   DetectParseDupSigCompareFunc,
38,847✔
3185
                                                   DetectParseDupSigFreeFunc);
38,847✔
3186
    if (de_ctx->dup_sig_hash_table == NULL)
38,847✔
UNCOV
3187
        return -1;
×
3188

3189
    return 0;
38,847✔
3190
}
38,847✔
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
{
76,085✔
3199
    if (de_ctx->dup_sig_hash_table != NULL)
76,085✔
3200
        HashListTableFree(de_ctx->dup_sig_hash_table);
38,838✔
3201

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

3230
    /* return value */
3231
    int ret = 0;
875,565✔
3232

3233
    SigDuplWrapper *sw_dup = NULL;
875,565✔
3234
    SigDuplWrapper *sw = NULL;
875,565✔
3235

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

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

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

3264
        ret = 0;
253,715✔
3265
        goto end;
253,715✔
3266
    }
253,715✔
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,850✔
3272
        ret = 1;
620,628✔
3273
        SCFree(sw);
620,628✔
3274
        sw = NULL;
620,628✔
3275
        goto end;
620,628✔
3276
    }
620,628✔
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,222✔
3281
        SigDuplWrapper sw_temp;
193✔
3282
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
193✔
3283
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
193✔
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 {
155✔
3288
            sw_temp.s = sw_dup->s->next;
155✔
3289
            de_ctx->sig_list = sw_dup->s->next;
155✔
3290
        }
155✔
3291
        SigDuplWrapper *sw_next = NULL;
193✔
3292
        if (sw_temp.s != NULL) {
193✔
3293
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
134✔
3294
                                          (void *)&sw_temp, 0);
134✔
3295
            sw_next->s_prev = sw_dup->s_prev;
134✔
3296
        }
134✔
3297
        SigFree(de_ctx, sw_dup->s);
193✔
3298
    } else {
1,031✔
3299
        SigDuplWrapper sw_temp;
1,029✔
3300
        memset(&sw_temp, 0, sizeof(SigDuplWrapper));
1,029✔
3301
        if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
1,029✔
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 {
767✔
3314
            sw_temp.s = sw_dup->s->next;
767✔
3315
            if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
767✔
3316
                sw_dup->s_prev->next->next = sw_dup->s->next;
115✔
3317
            } else {
652✔
3318
                sw_dup->s_prev->next = sw_dup->s->next;
652✔
3319
            }
652✔
3320
        }
767✔
3321
        SigDuplWrapper *sw_next = NULL;
1,029✔
3322
        if (sw_temp.s != NULL) {
1,029✔
3323
            sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
778✔
3324
                                          (void *)&sw_temp, 0);
778✔
3325
            sw_next->s_prev = sw_dup->s_prev;
778✔
3326
        }
778✔
3327
        SigFree(de_ctx, sw_dup->s);
1,029✔
3328
    }
1,029✔
3329

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

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

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

3349
    SCFree(sw);
1,222✔
3350

3351
end:
875,565✔
3352
    return ret;
875,565✔
3353
}
1,222✔
3354

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

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

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

3406
    de_ctx->sig_list = sig;
259✔
3407

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

UNCOV
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
    }
×
UNCOV
3424
    return NULL;
×
3425
}
259✔
3426

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

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

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

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

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

3511
void DetectParseFreeRegex(DetectParseRegex *r)
3512
{
500,168✔
3513
    if (r->regex) {
500,168✔
3514
        pcre2_code_free(r->regex);
450,298✔
3515
    }
450,298✔
3516
    if (r->context) {
500,168✔
3517
        pcre2_match_context_free(r->context);
356,710✔
3518
    }
356,710✔
3519
}
500,168✔
3520

3521
void DetectParseFreeRegexes(void)
3522
{
2,127✔
3523
    DetectParseRegex *r = g_detect_parse_regex_list;
2,127✔
3524
    while (r) {
95,715✔
3525
        DetectParseRegex *next = r->next;
93,588✔
3526

3527
        DetectParseFreeRegex(r);
93,588✔
3528

3529
        SCFree(r);
93,588✔
3530
        r = next;
93,588✔
3531
    }
93,588✔
3532
    g_detect_parse_regex_list = NULL;
2,127✔
3533
}
2,127✔
3534

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

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

3553
    detect_parse->regex =
83,942✔
3554
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
83,942✔
3555
    if (detect_parse->regex == NULL) {
83,942✔
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;
×
UNCOV
3562
    }
×
3563
    detect_parse->context = pcre2_match_context_create(NULL);
83,942✔
3564
    if (detect_parse->context == NULL) {
83,942✔
3565
        SCLogError("pcre2 could not create match context");
×
3566
        pcre2_code_free(detect_parse->regex);
×
3567
        detect_parse->regex = NULL;
×
3568
        return false;
×
UNCOV
3569
    }
×
3570
    pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
83,942✔
3571
    pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
83,942✔
3572
    DetectParseRegexAddToFreeList(detect_parse);
83,942✔
3573

3574
    return true;
83,942✔
3575
}
83,942✔
3576

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

3586
    detect_parse->regex =
13,266✔
3587
            pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
13,266✔
3588
    if (detect_parse->regex == NULL) {
13,266✔
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;
×
UNCOV
3596
    }
×
3597

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

3603
int SC_Pcre2SubstringCopy(
3604
        pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3605
{
240,142✔
3606
    int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
240,142✔
3607
    if (r == PCRE2_ERROR_UNSET) {
240,142✔
3608
        buffer[0] = 0;
863✔
3609
        *bufflen = 0;
863✔
3610
        return 0;
863✔
3611
    }
863✔
3612
    return r;
239,279✔
3613
}
240,142✔
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;
×
UNCOV
3625
}
×
3626

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

3634
/*
3635
 * TESTS
3636
 */
3637

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3931
    Signature *s = NULL;
1✔
3932

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

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

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

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

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

3965
    Signature *s = NULL;
1✔
3966

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

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

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

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

3991
    Signature *s = NULL;
1✔
3992

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

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

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

4009
    result = 1;
1✔
4010

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

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

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

4028
    Signature *s = NULL;
1✔
4029

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

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

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

4046
    result = 1;
1✔
4047

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

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

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

4065
    Signature *s = NULL;
1✔
4066

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

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

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

4083
    result = 1;
1✔
4084

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

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

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

4102
    Signature *s = NULL;
1✔
4103

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

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

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

4120
    result = 1;
1✔
4121

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

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

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

4139
    Signature *s = NULL;
1✔
4140

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

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

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

4157
    result = 1;
1✔
4158

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4268
    Signature *s = NULL;
1✔
4269

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4477
    result = 1;
1✔
4478

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

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

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

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

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

4518
    result = 1;
1✔
4519

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

4527
    return result;
1✔
4528
}
1✔
4529

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4807
/**
4808
 * \test check that we don't allow invalid negation options
4809
 */
4810
static int SigParseTestNegation02 (void)
4811
{
1✔
4812
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4813
    FAIL_IF_NULL(de_ctx);
1✔
4814
    de_ctx->flags |= DE_QUIET;
1✔
4815
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
4816
            "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
1✔
4817
            "classtype:misc-activity; sid:410002; rev:1;)");
1✔
4818
    FAIL_IF_NOT_NULL(s);
1✔
4819
    DetectEngineCtxFree(de_ctx);
1✔
4820
    PASS;
1✔
4821
}
1✔
4822
/**
4823
 * \test check that we don't allow invalid negation options
4824
 */
4825
static int SigParseTestNegation03 (void)
4826
{
1✔
4827
    int result = 0;
1✔
4828
    DetectEngineCtx *de_ctx;
1✔
4829
    Signature *s=NULL;
1✔
4830

4831
    de_ctx = DetectEngineCtxInit();
1✔
4832
    if (de_ctx == NULL)
1✔
4833
        goto end;
4834
    de_ctx->flags |= DE_QUIET;
1✔
4835

4836
    s = SigInit(de_ctx,"alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
1✔
4837
    if (s != NULL) {
1✔
4838
        SigFree(de_ctx, s);
4839
        goto end;
4840
    }
4841

4842
    result = 1;
1✔
4843
end:
1✔
4844
    if (de_ctx != NULL)
1✔
4845
        DetectEngineCtxFree(de_ctx);
1✔
4846
    return result;
1✔
4847
}
1✔
4848
/**
4849
 * \test check that we don't allow invalid negation options
4850
 */
4851
static int SigParseTestNegation04 (void)
4852
{
1✔
4853
    int result = 0;
1✔
4854
    DetectEngineCtx *de_ctx;
1✔
4855
    Signature *s=NULL;
1✔
4856

4857
    de_ctx = DetectEngineCtxInit();
1✔
4858
    if (de_ctx == NULL)
1✔
4859
        goto end;
4860
    de_ctx->flags |= DE_QUIET;
1✔
4861

4862
    s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
1✔
4863
    if (s != NULL) {
1✔
4864
        SigFree(de_ctx, s);
4865
        goto end;
4866
    }
4867

4868
    result = 1;
1✔
4869
end:
1✔
4870
    if (de_ctx != NULL)
1✔
4871
        DetectEngineCtxFree(de_ctx);
1✔
4872
    return result;
1✔
4873
}
1✔
4874
/**
4875
 * \test check that we don't allow invalid negation options
4876
 */
4877
static int SigParseTestNegation05 (void)
4878
{
1✔
4879
    int result = 0;
1✔
4880
    DetectEngineCtx *de_ctx;
1✔
4881
    Signature *s=NULL;
1✔
4882

4883
    de_ctx = DetectEngineCtxInit();
1✔
4884
    if (de_ctx == NULL)
1✔
4885
        goto end;
4886
    de_ctx->flags |= DE_QUIET;
1✔
4887

4888
    s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
1✔
4889
    if (s != NULL) {
1✔
4890
        SigFree(de_ctx, s);
4891
        goto end;
4892
    }
4893

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

4909
    de_ctx = DetectEngineCtxInit();
1✔
4910
    if (de_ctx == NULL)
1✔
4911
        goto end;
4912
    de_ctx->flags |= DE_QUIET;
1✔
4913

4914
    s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
1✔
4915
    if (s != NULL) {
1✔
4916
        SigFree(de_ctx, s);
4917
        goto end;
4918
    }
4919

4920
    result = 1;
1✔
4921
end:
1✔
4922
    if (de_ctx != NULL)
1✔
4923
        DetectEngineCtxFree(de_ctx);
1✔
4924
    return result;
1✔
4925
}
1✔
4926

4927
/**
4928
 * \test check that we don't allow invalid negation options
4929
 */
4930
static int SigParseTestNegation07 (void)
4931
{
1✔
4932
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4933
    FAIL_IF_NULL(de_ctx);
1✔
4934
    de_ctx->flags |= DE_QUIET;
1✔
4935
    Signature *s = DetectEngineAppendSig(
1✔
4936
            de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
1✔
4937
    FAIL_IF_NOT_NULL(s);
1✔
4938
    DetectEngineCtxFree(de_ctx);
1✔
4939
    PASS;
1✔
4940
}
1✔
4941

4942
/**
4943
 * \test check valid negation bug 1079
4944
 */
4945
static int SigParseTestNegation08 (void)
4946
{
1✔
4947
    int result = 0;
1✔
4948
    DetectEngineCtx *de_ctx;
1✔
4949
    Signature *s=NULL;
1✔
4950

4951
    de_ctx = DetectEngineCtxInit();
1✔
4952
    if (de_ctx == NULL)
1✔
4953
        goto end;
4954
    de_ctx->flags |= DE_QUIET;
1✔
4955

4956
    s = DetectEngineAppendSig(de_ctx,
1✔
4957
            "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
1✔
4958
    if (s == NULL) {
1✔
4959
        goto end;
4960
    }
4961

4962
    result = 1;
1✔
4963
end:
1✔
4964
    if (de_ctx != NULL)
1✔
4965
        DetectEngineCtxFree(de_ctx);
1✔
4966
    return result;
1✔
4967
}
1✔
4968

4969
/**
4970
 * \test mpm
4971
 */
4972
static int SigParseTestMpm01 (void)
4973
{
1✔
4974
    int result = 0;
1✔
4975
    Signature *sig = NULL;
1✔
4976

4977
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
4978
    if (de_ctx == NULL)
1✔
4979
        goto end;
4980

4981
    sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
1✔
4982
    if (sig == NULL) {
1✔
4983
        printf("sig failed to init: ");
4984
        goto end;
4985
    }
4986

4987
    if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
1✔
4988
        printf("sig doesn't have content list: ");
4989
        goto end;
4990
    }
4991

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

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

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

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

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

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

5031
/**
5032
 * \test test tls (app layer) rule
5033
 */
5034
static int SigParseTestAppLayerTLS01(void)
5035
{
1✔
5036
    int result = 0;
1✔
5037
    DetectEngineCtx *de_ctx;
1✔
5038
    Signature *s=NULL;
1✔
5039

5040
    de_ctx = DetectEngineCtxInit();
1✔
5041
    if (de_ctx == NULL)
1✔
5042
        goto end;
5043
    de_ctx->flags |= DE_QUIET;
1✔
5044

5045
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
1✔
5046
    if (s == NULL) {
1✔
5047
        printf("parsing sig failed: ");
5048
        goto end;
5049
    }
5050

5051
    if (s->alproto == 0) {
1✔
5052
        printf("alproto not set: ");
5053
        goto end;
5054
    }
5055

5056
    result = 1;
1✔
5057
end:
1✔
5058
    if (s != NULL)
1✔
5059
        SigFree(de_ctx, s);
1✔
5060
    if (de_ctx != NULL)
1✔
5061
        DetectEngineCtxFree(de_ctx);
1✔
5062

5063
    return result;
1✔
5064
}
1✔
5065

5066
/**
5067
 * \test test tls (app layer) rule
5068
 */
5069
static int SigParseTestAppLayerTLS02(void)
5070
{
1✔
5071
    int result = 0;
1✔
5072
    DetectEngineCtx *de_ctx;
1✔
5073
    Signature *s=NULL;
1✔
5074

5075
    de_ctx = DetectEngineCtxInit();
1✔
5076
    if (de_ctx == NULL)
1✔
5077
        goto end;
5078
    de_ctx->flags |= DE_QUIET;
1✔
5079

5080
    s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
1✔
5081
    if (s == NULL) {
1✔
5082
        printf("parsing sig failed: ");
5083
        goto end;
5084
    }
5085

5086
    if (s->alproto == 0) {
1✔
5087
        printf("alproto not set: ");
5088
        goto end;
5089
    }
5090

5091
    result = 1;
1✔
5092
end:
1✔
5093
    if (s != NULL)
1✔
5094
        SigFree(de_ctx, s);
1✔
5095
    if (de_ctx != NULL)
1✔
5096
        DetectEngineCtxFree(de_ctx);
1✔
5097
    return result;
1✔
5098
}
1✔
5099

5100
/**
5101
 * \test test tls (app layer) rule
5102
 */
5103
static int SigParseTestAppLayerTLS03(void)
5104
{
1✔
5105
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5106
    FAIL_IF_NULL(de_ctx);
1✔
5107
    de_ctx->flags |= DE_QUIET;
1✔
5108

5109
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5110
            "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
1✔
5111
            "tls.version:2.5; sid:410006; rev:1;)");
1✔
5112
    FAIL_IF_NOT_NULL(s);
1✔
5113
    DetectEngineCtxFree(de_ctx);
1✔
5114
    PASS;
1✔
5115
}
1✔
5116

5117
static int SigParseTestUnbalancedQuotes01(void)
5118
{
1✔
5119
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5120
    FAIL_IF_NULL(de_ctx);
1✔
5121
    de_ctx->flags |= DE_QUIET;
1✔
5122
    Signature *s = DetectEngineAppendSig(de_ctx,
1✔
5123
            "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
1✔
5124
            "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
1✔
5125
            "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
1✔
5126
    FAIL_IF_NOT_NULL(s);
1✔
5127
    DetectEngineCtxFree(de_ctx);
1✔
5128
    PASS;
1✔
5129
}
1✔
5130

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

5145
static int SigParseTestContentGtDsize02(void)
5146
{
1✔
5147
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5148
    FAIL_IF_NULL(de_ctx);
1✔
5149
    de_ctx->flags |= DE_QUIET;
1✔
5150
    Signature *s =
1✔
5151
            DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
1✔
5152
                                          "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
1✔
5153
                                          "sid:1; rev:1;)");
1✔
5154
    FAIL_IF_NOT_NULL(s);
1✔
5155
    DetectEngineCtxFree(de_ctx);
1✔
5156
    PASS;
1✔
5157
}
1✔
5158

5159
static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5160
{
8✔
5161
    int cnt = 0;
8✔
5162
    for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
42✔
5163
        if (sid == s->id)
34✔
5164
            cnt++;
12✔
5165
    }
34✔
5166
    return cnt;
8✔
5167
}
8✔
5168

5169
static int SigParseBidirWithSameSrcAndDest01(void)
5170
{
1✔
5171
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5172
    FAIL_IF_NULL(de_ctx);
1✔
5173
    de_ctx->flags |= DE_QUIET;
1✔
5174

5175
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
1✔
5176
    FAIL_IF_NULL(s);
1✔
5177
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
1✔
5178
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5179

5180
    s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
1✔
5181
    FAIL_IF_NULL(s);
1✔
5182
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
1✔
5183
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5184

5185
    s = DetectEngineAppendSig(de_ctx,
1✔
5186
            "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
1✔
5187
    FAIL_IF_NULL(s);
1✔
5188
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
1✔
5189
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5190

5191
    DetectEngineCtxFree(de_ctx);
1✔
5192
    PASS;
1✔
5193
}
1✔
5194

5195
static int SigParseBidirWithSameSrcAndDest02(void)
5196
{
1✔
5197
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5198
    FAIL_IF_NULL(de_ctx);
1✔
5199
    de_ctx->flags |= DE_QUIET;
1✔
5200

5201
    // Source is a subset of destination
5202
    Signature *s = DetectEngineAppendSig(
1✔
5203
            de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
1✔
5204
    FAIL_IF_NULL(s);
1✔
5205
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
1✔
5206
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5207

5208
    // Source is a subset of destination
5209
    s = DetectEngineAppendSig(
1✔
5210
            de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
1✔
5211
    FAIL_IF_NULL(s);
1✔
5212
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
1✔
5213
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5214

5215
    // Source intersects with destination
5216
    s = DetectEngineAppendSig(de_ctx,
1✔
5217
            "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
1✔
5218
    FAIL_IF_NULL(s);
1✔
5219
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
1✔
5220
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5221

5222
    // mix in negation, these are the same
5223
    s = DetectEngineAppendSig(
1✔
5224
            de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
1✔
5225
    FAIL_IF_NULL(s);
1✔
5226
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
1✔
5227
    FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5228

5229
    // mix in negation, these are not the same
5230
    s = DetectEngineAppendSig(
1✔
5231
            de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
1✔
5232
    FAIL_IF_NULL(s);
1✔
5233
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
1✔
5234
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5235

5236
    DetectEngineCtxFree(de_ctx);
1✔
5237
    PASS;
1✔
5238
}
1✔
5239

5240
static int SigParseTestActionReject(void)
5241
{
1✔
5242
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5243
    FAIL_IF_NULL(de_ctx);
1✔
5244

5245
    Signature *sig = DetectEngineAppendSig(
1✔
5246
            de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5247
#ifdef HAVE_LIBNET11
1✔
5248
    FAIL_IF_NULL(sig);
1✔
5249
    FAIL_IF_NOT((sig->action & (ACTION_DROP | ACTION_REJECT)) == (ACTION_DROP | ACTION_REJECT));
1✔
5250
#else
5251
    FAIL_IF_NOT_NULL(sig);
5252
#endif
5253

5254
    DetectEngineCtxFree(de_ctx);
1✔
5255
    PASS;
1✔
5256
}
1✔
5257

5258
static int SigParseTestActionDrop(void)
5259
{
1✔
5260
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
5261
    FAIL_IF_NULL(de_ctx);
1✔
5262

5263
    Signature *sig = DetectEngineAppendSig(
1✔
5264
            de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
1✔
5265
    FAIL_IF_NULL(sig);
1✔
5266
    FAIL_IF_NOT(sig->action & ACTION_DROP);
1✔
5267

5268
    DetectEngineCtxFree(de_ctx);
1✔
5269
    PASS;
1✔
5270
}
1✔
5271

5272
static int SigSetMultiAppProto(void)
5273
{
1✔
5274
    Signature *s = SigAlloc();
1✔
5275
    FAIL_IF_NULL(s);
1✔
5276

5277
    AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
1✔
5278
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5279

5280
    // check intersection gives multiple entries
5281
    alprotos[0] = 3;
1✔
5282
    alprotos[1] = 2;
1✔
5283
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5284
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5285
    FAIL_IF(s->init_data->alprotos[0] != 3);
1✔
5286
    FAIL_IF(s->init_data->alprotos[1] != 2);
1✔
5287
    FAIL_IF(s->init_data->alprotos[2] != ALPROTO_UNKNOWN);
1✔
5288

5289
    // check single after multiple
5290
    FAIL_IF(SCDetectSignatureSetAppProto(s, 3) < 0);
1✔
5291
    FAIL_IF(s->init_data->alprotos[0] != ALPROTO_UNKNOWN);
1✔
5292
    FAIL_IF(s->alproto != 3);
1✔
5293
    alprotos[0] = 4;
1✔
5294
    alprotos[1] = 3;
1✔
5295
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5296
    // check multiple containing singleton
5297
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5298
    FAIL_IF(s->alproto != 3);
1✔
5299

5300
    // reset
5301
    s->alproto = ALPROTO_UNKNOWN;
1✔
5302
    alprotos[0] = 1;
1✔
5303
    alprotos[1] = 2;
1✔
5304
    alprotos[2] = 3;
1✔
5305
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5306
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5307
    // fail if set single not in multiple
5308
    FAIL_IF(SCDetectSignatureSetAppProto(s, 4) >= 0);
1✔
5309

5310
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5311
    s->alproto = ALPROTO_UNKNOWN;
1✔
5312
    alprotos[0] = 1;
1✔
5313
    alprotos[1] = 2;
1✔
5314
    alprotos[2] = 3;
1✔
5315
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5316
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5317
    alprotos[0] = 4;
1✔
5318
    alprotos[1] = 5;
1✔
5319
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5320
    // fail if multiple do not have intersection
5321
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5322

5323
    s->init_data->alprotos[0] = ALPROTO_UNKNOWN;
1✔
5324
    s->alproto = ALPROTO_UNKNOWN;
1✔
5325
    alprotos[0] = 1;
1✔
5326
    alprotos[1] = 2;
1✔
5327
    alprotos[2] = 3;
1✔
5328
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5329
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5330
    alprotos[0] = 3;
1✔
5331
    alprotos[1] = 4;
1✔
5332
    alprotos[2] = 5;
1✔
5333
    alprotos[3] = ALPROTO_UNKNOWN;
1✔
5334
    // check multiple intersect to singleton
5335
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
1✔
5336
    FAIL_IF(s->alproto != 3);
1✔
5337
    alprotos[0] = 5;
1✔
5338
    alprotos[1] = 4;
1✔
5339
    alprotos[2] = ALPROTO_UNKNOWN;
1✔
5340
    // fail if multiple do not belong to singleton
5341
    FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
1✔
5342

5343
    SigFree(NULL, s);
1✔
5344
    PASS;
1✔
5345
}
1✔
5346

5347
static int DetectSetupDirection01(void)
5348
{
1✔
5349
    Signature *s = SigAlloc();
1✔
5350
    FAIL_IF_NULL(s);
1✔
5351
    // Basic case : ok
5352
    char *str = (char *)"to_client";
1✔
5353
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5354
    SigFree(NULL, s);
1✔
5355
    PASS;
1✔
5356
}
1✔
5357

5358
static int DetectSetupDirection02(void)
5359
{
1✔
5360
    Signature *s = SigAlloc();
1✔
5361
    FAIL_IF_NULL(s);
1✔
5362
    char *str = (char *)"to_server";
1✔
5363
    FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
1✔
5364
    // ok so far
5365
    str = (char *)"to_client";
1✔
5366
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5367
    // fails because we cannot have both to_client and to_server for same signature
5368
    SigFree(NULL, s);
1✔
5369
    PASS;
1✔
5370
}
1✔
5371

5372
static int DetectSetupDirection03(void)
5373
{
1✔
5374
    Signature *s = SigAlloc();
1✔
5375
    FAIL_IF_NULL(s);
1✔
5376
    char *str = (char *)"to_client , something";
1✔
5377
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5378
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5379
    str = (char *)"to_client,something";
1✔
5380
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5381
    FAIL_IF(strcmp(str, "something") != 0);
1✔
5382
    SigFree(NULL, s);
1✔
5383
    PASS;
1✔
5384
}
1✔
5385

5386
static int DetectSetupDirection04(void)
5387
{
1✔
5388
    Signature *s = SigAlloc();
1✔
5389
    FAIL_IF_NULL(s);
1✔
5390
    // invalid case
5391
    char *str = (char *)"to_client_toto";
1✔
5392
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5393
    // test we do not change the string pointer if only_dir is false
5394
    str = (char *)"to_client_toto";
1✔
5395
    FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
1✔
5396
    FAIL_IF(strcmp(str, "to_client_toto") != 0);
1✔
5397
    str = (char *)"to_client,something";
1✔
5398
    // fails because we call with only_dir=true
5399
    FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
1✔
5400
    SigFree(NULL, s);
1✔
5401
    PASS;
1✔
5402
}
1✔
5403

5404
#endif /* UNITTESTS */
5405

5406
#ifdef UNITTESTS
5407
void DetectParseRegisterTests (void);
5408
#include "tests/detect-parse.c"
5409
#endif
5410

5411
void SigParseRegisterTests(void)
5412
{
1✔
5413
#ifdef UNITTESTS
1✔
5414
    DetectParseRegisterTests();
1✔
5415

5416
    UtRegisterTest("SigParseTest01", SigParseTest01);
1✔
5417
    UtRegisterTest("SigParseTest02", SigParseTest02);
1✔
5418
    UtRegisterTest("SigParseTest03", SigParseTest03);
1✔
5419
    UtRegisterTest("SigParseTest04", SigParseTest04);
1✔
5420
    UtRegisterTest("SigParseTest05", SigParseTest05);
1✔
5421
    UtRegisterTest("SigParseTest06", SigParseTest06);
1✔
5422
    UtRegisterTest("SigParseTest07", SigParseTest07);
1✔
5423
    UtRegisterTest("SigParseTest08", SigParseTest08);
1✔
5424
    UtRegisterTest("SigParseTest09", SigParseTest09);
1✔
5425
    UtRegisterTest("SigParseTest10", SigParseTest10);
1✔
5426
    UtRegisterTest("SigParseTest11", SigParseTest11);
1✔
5427
    UtRegisterTest("SigParseTest12", SigParseTest12);
1✔
5428
    UtRegisterTest("SigParseTest13", SigParseTest13);
1✔
5429
    UtRegisterTest("SigParseTest14", SigParseTest14);
1✔
5430
    UtRegisterTest("SigParseTest15", SigParseTest15);
1✔
5431
    UtRegisterTest("SigParseTest16", SigParseTest16);
1✔
5432
    UtRegisterTest("SigParseTest17", SigParseTest17);
1✔
5433
    UtRegisterTest("SigParseTest18", SigParseTest18);
1✔
5434
    UtRegisterTest("SigParseTest19", SigParseTest19);
1✔
5435
    UtRegisterTest("SigParseTest20", SigParseTest20);
1✔
5436
    UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
1✔
5437
    UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
1✔
5438
    UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
1✔
5439

5440
    UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
1✔
5441
    UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
1✔
5442
    UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
1✔
5443
    UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
1✔
5444
    UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
1✔
5445
    UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
1✔
5446
    UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
1✔
5447
    UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
1✔
5448
    UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
1✔
5449
    UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
1✔
5450
    UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
1✔
5451
    UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
1✔
5452
    UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
1✔
5453
    UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
1✔
5454
    UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
1✔
5455
    UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
1✔
5456
    UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
1✔
5457
    UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
1✔
5458
    UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
1✔
5459
    UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
1✔
5460
    UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
1✔
5461
    UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
1✔
5462
    UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
1✔
5463
    UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
1✔
5464
    UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
1✔
5465
    UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
1✔
5466
    UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
1✔
5467

5468
    UtRegisterTest("SigParseTestContentGtDsize01",
1✔
5469
            SigParseTestContentGtDsize01);
1✔
5470
    UtRegisterTest("SigParseTestContentGtDsize02",
1✔
5471
            SigParseTestContentGtDsize02);
1✔
5472

5473
    UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
1✔
5474
            SigParseBidirWithSameSrcAndDest01);
1✔
5475
    UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
1✔
5476
            SigParseBidirWithSameSrcAndDest02);
1✔
5477
    UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
1✔
5478
    UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
1✔
5479

5480
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
1✔
5481

5482
    UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
1✔
5483
    UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
1✔
5484
    UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
1✔
5485
    UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
1✔
5486

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

© 2026 Coveralls, Inc