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

OISF / suricata / 22550902417

01 Mar 2026 07:32PM UTC coverage: 68.401% (-5.3%) from 73.687%
22550902417

Pull #14922

github

web-flow
github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14922: github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

218243 of 319063 relevant lines covered (68.4%)

3284926.58 hits per line

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

82.33
/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
{
×
114
#define CASE_CODE_STRING(E, S)  case E: return S; break
×
115
    switch (list) {
×
116
        CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet");
×
117
        CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload");
×
118
        CASE_CODE_STRING(DETECT_SM_LIST_BASE64_DATA, "base64_data");
×
119
        CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch");
×
120
        CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag");
×
121
        CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress");
×
122
        CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold");
×
123
        CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
×
124
    }
×
125
#undef CASE_CODE_STRING
×
126
    return "unknown";
×
127
}
×
128

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

316
    for (i = 0; i < DETECT_TBLSIZE; i++) {
24,873,087✔
317
        st = &sigmatch_table[i];
24,873,086✔
318

319
        if (st->name != NULL) {
24,873,086✔
320
            if (strcasecmp(name,st->name) == 0)
24,872,992✔
321
                return st;
515,174✔
322
            if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
24,357,818✔
323
                return st;
1,568✔
324
        }
24,357,818✔
325
    }
24,873,086✔
326

327
    return NULL;
1✔
328
}
516,743✔
329

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

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

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

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

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

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

377
    SCFree(copy);
×
378
}
×
379

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

394
    new->type = type;
141,321✔
395
    new->ctx = ctx;
141,321✔
396

397
    if (new->type == DETECT_CONTENT) {
141,321✔
398
        s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list);
92,990✔
399
    }
92,990✔
400

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

405
    if (list < DETECT_SM_LIST_MAX) {
141,321✔
406
        if (s->init_data->smlists[list] == NULL) {
48,569✔
407
            s->init_data->smlists[list] = new;
36,643✔
408
            s->init_data->smlists_tail[list] = new;
36,643✔
409
            new->next = NULL;
36,643✔
410
            new->prev = NULL;
36,643✔
411
        } else {
36,643✔
412
            SigMatch *cur = s->init_data->smlists_tail[list];
11,926✔
413
            cur->next = new;
11,926✔
414
            new->prev = cur;
11,926✔
415
            new->next = NULL;
11,926✔
416
            s->init_data->smlists_tail[list] = new;
11,926✔
417
        }
11,926✔
418
        new->idx = s->init_data->sm_cnt;
48,569✔
419
        s->init_data->sm_cnt++;
48,569✔
420

421
    } else {
95,297✔
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) {
92,752✔
427
            SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
13✔
428
            s->init_data->list = DETECT_SM_LIST_NOTSET;
13✔
429
        }
13✔
430

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

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

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

478
        for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
276,316✔
479
            SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
183,564✔
480
                    sigmatch_table[sm->type].name, sm->idx);
183,564✔
481
        }
183,564✔
482
    }
92,752✔
483
    return new;
141,321✔
484
}
141,321✔
485

486
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487
{
12✔
488
    if (sm == s->init_data->smlists[sm_list]) {
12✔
489
        s->init_data->smlists[sm_list] = sm->next;
12✔
490
    }
12✔
491
    if (sm == s->init_data->smlists_tail[sm_list]) {
12✔
492
        s->init_data->smlists_tail[sm_list] = sm->prev;
12✔
493
    }
12✔
494
    if (sm->prev != NULL)
12✔
495
        sm->prev->next = sm->next;
×
496
    if (sm->next != NULL)
12✔
497
        sm->next->prev = sm->prev;
×
498
}
12✔
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
{
225,601✔
511
    while (sm != NULL) {
383,466✔
512
        if (sm->type == type) {
319,920✔
513
            return sm;
162,055✔
514
        }
162,055✔
515
        sm = sm->prev;
157,865✔
516
    }
157,865✔
517

518
    return NULL;
63,546✔
519
}
225,601✔
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
{
18,588✔
528
    SigMatch *sm_last = NULL;
18,588✔
529
    SigMatch *sm_new;
18,588✔
530
    uint32_t sm_type;
18,588✔
531

532
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
44,795✔
533
        const int id = s->init_data->buffers[i].id;
26,207✔
534
        if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) {
26,207✔
535
            sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1);
26,197✔
536
            if (sm_new == NULL)
26,197✔
537
                continue;
365✔
538
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
25,832✔
539
                sm_last = sm_new;
25,522✔
540
        }
25,832✔
541
    }
26,207✔
542
    /* otherwise brute force it */
543
    for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
148,704✔
544
        if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type))
130,116✔
545
            continue;
130,116✔
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;
18,588✔
555
}
18,588✔
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
{
104,429✔
565
    SigMatch *sm_last = NULL;
104,429✔
566
    SigMatch *sm_new;
104,429✔
567

568
    SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
104,429✔
569
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
238,074✔
570
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
133,645✔
571
                s->init_data->list != (int)s->init_data->buffers[x].id) {
133,645✔
572
            SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
48,460✔
573
                    s->init_data->list, (int)s->init_data->buffers[x].id);
48,460✔
574

575
            continue;
48,460✔
576
        }
48,460✔
577
        int sm_type;
85,185✔
578
        va_list ap;
85,185✔
579
        va_start(ap, s);
85,185✔
580

581
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
171,458✔
582
            sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
86,273✔
583
            if (sm_new == NULL)
86,273✔
584
                continue;
1,530✔
585
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
84,743✔
586
                sm_last = sm_new;
84,732✔
587
        }
84,743✔
588
        va_end(ap);
85,185✔
589
    }
85,185✔
590

591
    for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
835,432✔
592
        if (s->init_data->smlists[buf_type] == NULL)
731,003✔
593
            continue;
624,890✔
594
        if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
106,113✔
595
            buf_type != s->init_data->list)
106,113✔
596
            continue;
70,991✔
597

598
        int sm_type;
35,122✔
599
        va_list ap;
35,122✔
600
        va_start(ap, s);
35,122✔
601

602
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
93,941✔
603
        {
58,819✔
604
            sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
58,819✔
605
            if (sm_new == NULL)
58,819✔
606
                continue;
38,261✔
607
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
20,558✔
608
                sm_last = sm_new;
18,499✔
609
        }
20,558✔
610
        va_end(ap);
35,122✔
611
    }
35,122✔
612

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

631
    va_list ap;
52,710✔
632
    va_start(ap, sm_list);
52,710✔
633

634
    for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
131,933✔
635
    {
79,223✔
636
        sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
79,223✔
637
        if (sm_new == NULL)
79,223✔
638
            continue;
23,667✔
639
        if (sm_last == NULL || sm_new->idx > sm_last->idx)
55,556✔
640
            sm_last = sm_new;
53,129✔
641
    }
55,556✔
642

643
    va_end(ap);
52,710✔
644

645
    return sm_last;
52,710✔
646
}
52,710✔
647

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

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

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

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

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

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

690
        for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
2,494✔
691
            sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
1,247✔
692
            if (sm_new == NULL)
1,247✔
693
                continue;
59✔
694
            if (sm_last == NULL || sm_new->idx > sm_last->idx)
1,188✔
695
                sm_last = sm_new;
1,188✔
696
        }
1,188✔
697

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

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

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

729
    return sm_last;
1✔
730
}
1✔
731

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

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

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

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

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

767
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
29,757✔
768
        const SigMatch *sm = s->init_data->buffers[x].head;
25,622✔
769
        while (sm != NULL) {
42,897✔
770
            if (sm == key_sm)
33,300✔
771
                return s->init_data->buffers[x].id;
16,025✔
772
            sm = sm->next;
17,275✔
773
        }
17,275✔
774
    }
25,622✔
775

776
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
8,270✔
777
        const SigMatch *sm = s->init_data->smlists[list];
8,270✔
778
        while (sm != NULL) {
21,717✔
779
            if (sm == key_sm)
17,582✔
780
                return list;
4,135✔
781
            sm = sm->next;
13,447✔
782
        }
13,447✔
783
    }
8,270✔
784

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

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

878
    /* Trim leading space. */
879
    while (isblank(*optstr)) {
1,033,087✔
880
        optstr++;
957,517✔
881
    }
957,517✔
882

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

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

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

913
        optvalue = optvalptr;
789,767✔
914
    }
789,767✔
915

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

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

940
    if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
516,742✔
941
        if (optvalue == NULL || strlen(optvalue) == 0) {
394,617✔
942
            SCLogError(
×
943
                    "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
×
944
            goto error;
×
945
        }
×
946
    } else if (st->flags & SIGMATCH_NOOPT) {
394,617✔
947
        if (optvalue && strlen(optvalue)) {
99,576✔
948
            SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
3✔
949
            goto error;
3✔
950
        }
3✔
951
    }
99,576✔
952
    s->init_data->negated = false;
516,739✔
953

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

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

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

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

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

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

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

1086
finish:
1,032,621✔
1087
    if (strlen(optend) > 0) {
1,032,621✔
1088
        strlcpy(output, optend, output_size);
957,082✔
1089
        return 1;
957,082✔
1090
    }
957,082✔
1091

1092
    return 0;
75,539✔
1093

1094
error:
9✔
1095
    return -1;
9✔
1096
}
1,032,621✔
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
{
75,995✔
1105
    SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
75,995✔
1106

1107
    /* pass on to the address(list) parser */
1108
    if (flag == 0) {
75,995✔
1109
        if (strcasecmp(addrstr, "any") == 0)
38,000✔
1110
            s->flags |= SIG_FLAG_SRC_ANY;
3,887✔
1111

1112
        s->init_data->src = DetectParseAddress(de_ctx, addrstr,
38,000✔
1113
                &s->init_data->src_contains_negation);
38,000✔
1114
        if (s->init_data->src == NULL)
38,000✔
1115
            goto error;
5✔
1116
    } else {
38,000✔
1117
        if (strcasecmp(addrstr, "any") == 0)
37,995✔
1118
            s->flags |= SIG_FLAG_DST_ANY;
10,532✔
1119

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

1126
    return 0;
75,988✔
1127

1128
error:
7✔
1129
    return -1;
7✔
1130
}
75,995✔
1131

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

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

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

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

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

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

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

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

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

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

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

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

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

1363
    s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
8✔
1364
    return 0;
8✔
1365
}
8✔
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
{
38,008✔
1388
    SCEnter();
38,008✔
1389
    if (strlen(protostr) > 32)
38,008✔
1390
        return -1;
×
1391

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

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

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

1416
            AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
32,429✔
1417

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

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

1451
    SCReturnInt(0);
38,008✔
1452
}
38,008✔
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
{
75,984✔
1469
    int r = 0;
75,984✔
1470

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

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

1475
    if (flag == 0) {
75,984✔
1476
        if (strcasecmp(portstr, "any") == 0)
37,993✔
1477
            s->flags |= SIG_FLAG_SP_ANY;
37,433✔
1478

1479
        r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
37,993✔
1480
    } else if (flag == 1) {
37,993✔
1481
        if (strcasecmp(portstr, "any") == 0)
37,991✔
1482
            s->flags |= SIG_FLAG_DP_ANY;
36,056✔
1483

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

1487
    if (r < 0)
75,984✔
1488
        return -1;
5✔
1489

1490
    return 0;
75,979✔
1491
}
75,984✔
1492

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

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

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

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

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

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

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

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

1670
    if (!len) {
152,050✔
1671
        return 0;
×
1672
    }
×
1673

1674
    while (len && isblank(**input)) {
152,052✔
1675
        (*input)++;
2✔
1676
        len--;
2✔
1677
    }
2✔
1678

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

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

1706
    if (len == 0) {
380,125✔
1707
        return 0;
×
1708
    }
×
1709

1710
    while (len && isblank(**input)) {
380,127✔
1711
        (*input)++;
2✔
1712
        len--;
2✔
1713
    }
2✔
1714

1715
    size_t i = 0;
380,125✔
1716
    for (i = 0; i < len; i++) {
2,607,039✔
1717
        char c = (*input)[i];
2,607,039✔
1718
        if (c == '[') {
2,607,039✔
1719
            in_list++;
2,408✔
1720
        } else if (c == ']') {
2,604,631✔
1721
            in_list--;
2,408✔
1722
        } else if (c == ' ') {
2,602,223✔
1723
            if (!in_list) {
380,281✔
1724
                break;
380,125✔
1725
            }
380,125✔
1726
        }
380,281✔
1727
    }
2,607,039✔
1728
    if (i == len) {
380,125✔
1729
        *input = NULL;
×
1730
        return 0;
×
1731
    }
×
1732
    (*input)[i] = '\0';
380,125✔
1733
    strlcpy(output, *input, output_size);
380,125✔
1734
    *input = *input + i + 1;
380,125✔
1735

1736
    return 1;
380,125✔
1737
}
380,125✔
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
{
76,025✔
1748
    char *index, dup[DETECT_MAX_RULE_SIZE];
76,025✔
1749

1750
    strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
76,025✔
1751
    index = dup;
76,025✔
1752

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

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

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

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

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

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

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

1774
    /* Options. */
1775
    if (index == NULL) {
76,025✔
1776
        SCLogError("no rule options.");
×
1777
        goto error;
×
1778
    }
×
1779
    while (isspace(*index) || *index == '(') {
152,069✔
1780
        index++;
76,044✔
1781
    }
76,044✔
1782
    for (size_t i = strlen(index); i > 0; i--) {
152,067✔
1783
        if (isspace(index[i - 1]) || index[i - 1] == ')') {
152,067✔
1784
            index[i - 1] = '\0';
76,042✔
1785
        } else {
76,042✔
1786
            break;
76,025✔
1787
        }
76,025✔
1788
    }
152,067✔
1789
    strlcpy(parser->opts, index, sizeof(parser->opts));
76,025✔
1790

1791
    if (scan_only) {
76,025✔
1792
        return 0;
38,017✔
1793
    }
38,017✔
1794

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

1799
    if (SigParseProto(s, parser->protocol) < 0)
38,008✔
1800
        goto error;
×
1801

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

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

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

1822
    if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
37,995✔
1823
        goto error;
2✔
1824

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

1834
    return 0;
37,988✔
1835

1836
error:
20✔
1837
    return -1;
20✔
1838
}
37,991✔
1839

1840
static inline bool CheckAscii(const char *str)
1841
{
76,025✔
1842
    for (size_t i = 0; i < strlen(str); i++) {
43,331,731✔
1843
        if (str[i] < 0x20) {
43,255,706✔
1844
            // LF CR TAB
1845
            if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
2✔
1846
                continue;
2✔
1847
            }
2✔
1848
            return false;
×
1849
        } else if (str[i] == 0x7f) {
43,255,704✔
1850
            return false;
×
1851
        }
×
1852
    }
43,255,706✔
1853
    return true;
76,025✔
1854
}
76,025✔
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
{
76,025✔
1871
    SCEnter();
76,025✔
1872

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

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

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

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

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

1907
        } while (ret == 1);
1,033,087✔
1908

1909
        if (ret < 0) {
76,005✔
1910
            /* Suricata didn't meet the rule requirements, skip. */
1911
            goto end;
466✔
1912
        }
466✔
1913
    }
76,005✔
1914

1915
end:
76,005✔
1916
    DetectIPProtoRemoveAllSMs(de_ctx, s);
76,005✔
1917

1918
    SCReturnInt(ret);
76,005✔
1919
}
76,005✔
1920

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

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

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

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

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

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

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

1974
    sig->init_data->list = DETECT_SM_LIST_NOTSET;
38,068✔
1975
    return sig;
38,068✔
1976
}
38,068✔
1977

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

1988
    DetectMetadata *mdata = NULL;
38,068✔
1989
    DetectMetadata *next_mdata = NULL;
38,068✔
1990

1991
    if (s == NULL || s->metadata == NULL) {
38,068✔
1992
        SCReturn;
38,067✔
1993
    }
38,067✔
1994

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

1997
    for (mdata = s->metadata->list; mdata != NULL;)   {
4✔
1998
        next_mdata = mdata->next;
3✔
1999
        DetectMetadataFree(mdata);
3✔
2000
        mdata = next_mdata;
3✔
2001
    }
3✔
2002
    SCFree(s->metadata->json_str);
1✔
2003
    SCFree(s->metadata);
1✔
2004
    s->metadata = NULL;
1✔
2005

2006
    SCReturn;
1✔
2007
}
38,068✔
2008

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

2019
    DetectReference *ref = NULL;
38,068✔
2020
    DetectReference *next_ref = NULL;
38,068✔
2021

2022
    if (s == NULL) {
38,068✔
2023
        SCReturn;
×
2024
    }
×
2025

2026
    SCLogDebug("s %p, s->references %p", s, s->references);
38,068✔
2027

2028
    for (ref = s->references; ref != NULL;)   {
76,390✔
2029
        next_ref = ref->next;
38,322✔
2030
        DetectReferenceFree(ref);
38,322✔
2031
        ref = next_ref;
38,322✔
2032
    }
38,322✔
2033

2034
    s->references = NULL;
38,068✔
2035

2036
    SCReturn;
38,068✔
2037
}
38,068✔
2038

2039
static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2040
{
38,068✔
2041
    if (s != NULL) {
38,068✔
2042
        int type;
38,068✔
2043
        for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
304,544✔
2044
            if (s->sm_arrays[type] != NULL) {
266,476✔
2045
                if (ctxs) {
34,569✔
2046
                    SigMatchData *smd = s->sm_arrays[type];
34,569✔
2047
                    while(1) {
46,061✔
2048
                        if (sigmatch_table[smd->type].Free != NULL) {
46,061✔
2049
                            sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
46,044✔
2050
                        }
46,044✔
2051
                        if (smd->is_last)
46,061✔
2052
                            break;
34,569✔
2053
                        smd++;
11,492✔
2054
                    }
11,492✔
2055
                }
34,569✔
2056

2057
                SCFree(s->sm_arrays[type]);
34,569✔
2058
            }
34,569✔
2059
        }
266,476✔
2060
    }
38,068✔
2061
}
38,068✔
2062

2063
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
2064
{
38,068✔
2065
    if (s == NULL)
38,068✔
2066
        return;
×
2067

2068
    int i;
38,068✔
2069

2070
    if (s->init_data && s->init_data->transforms.cnt) {
38,068✔
2071
        for(i = 0; i < s->init_data->transforms.cnt; i++) {
2✔
2072
            if (s->init_data->transforms.transforms[i].options) {
1✔
2073
                int transform = s->init_data->transforms.transforms[i].transform;
×
2074
                sigmatch_table[transform].Free(
×
2075
                        de_ctx, s->init_data->transforms.transforms[i].options);
×
2076
                s->init_data->transforms.transforms[i].options = NULL;
×
2077
            }
×
2078
        }
1✔
2079
    }
1✔
2080
    if (s->init_data) {
38,068✔
2081
        for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
10,424✔
2082
            SigMatch *sm = s->init_data->smlists[i];
9,121✔
2083
            while (sm != NULL) {
9,951✔
2084
                SigMatch *nsm = sm->next;
830✔
2085
                SigMatchFree(de_ctx, sm);
830✔
2086
                sm = nsm;
830✔
2087
            }
830✔
2088
        }
9,121✔
2089

2090
        for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1,992✔
2091
            SigMatch *sm = s->init_data->buffers[x].head;
689✔
2092
            while (sm != NULL) {
1,678✔
2093
                SigMatch *nsm = sm->next;
989✔
2094
                SigMatchFree(de_ctx, sm);
989✔
2095
                sm = nsm;
989✔
2096
            }
989✔
2097
        }
689✔
2098
        if (s->init_data->cidr_dst != NULL)
1,303✔
2099
            IPOnlyCIDRListFree(s->init_data->cidr_dst);
76✔
2100

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

2104
        SCFree(s->init_data->buffers);
1,303✔
2105
        s->init_data->buffers = NULL;
1,303✔
2106
    }
1,303✔
2107
    SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
38,068✔
2108
    if (s->init_data) {
38,068✔
2109
        SCFree(s->init_data);
1,303✔
2110
        s->init_data = NULL;
1,303✔
2111
    }
1,303✔
2112

2113
    if (s->sp != NULL) {
38,068✔
2114
        DetectPortCleanupList(NULL, s->sp);
37,991✔
2115
    }
37,991✔
2116
    if (s->dp != NULL) {
38,068✔
2117
        DetectPortCleanupList(NULL, s->dp);
37,988✔
2118
    }
37,988✔
2119

2120
    if (s->msg != NULL)
38,068✔
2121
        SCFree(s->msg);
36,719✔
2122

2123
    if (s->addr_src_match4 != NULL) {
38,068✔
2124
        SCFree(s->addr_src_match4);
37,515✔
2125
    }
37,515✔
2126
    if (s->addr_dst_match4 != NULL) {
38,068✔
2127
        SCFree(s->addr_dst_match4);
37,516✔
2128
    }
37,516✔
2129
    if (s->addr_src_match6 != NULL) {
38,068✔
2130
        SCFree(s->addr_src_match6);
3,446✔
2131
    }
3,446✔
2132
    if (s->addr_dst_match6 != NULL) {
38,068✔
2133
        SCFree(s->addr_dst_match6);
10,090✔
2134
    }
10,090✔
2135
    if (s->sig_str != NULL) {
38,068✔
2136
        SCFree(s->sig_str);
38,017✔
2137
    }
38,017✔
2138

2139
    SigRefFree(s);
38,068✔
2140
    SigMetadataFree(s);
38,068✔
2141

2142
    DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
38,068✔
2143

2144
    SCFree(s);
38,068✔
2145
}
38,068✔
2146

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

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

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

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

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

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

2283
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
299,036✔
2284
        cnt++;
223,984✔
2285
    }
223,984✔
2286
    if (cnt == 0) {
75,052✔
2287
        return NULL;
21✔
2288
    }
21✔
2289
    DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
75,031✔
2290
    if (addr_match4 == NULL) {
75,031✔
2291
        return NULL;
×
2292
    }
×
2293

2294
    uint16_t idx = 0;
75,031✔
2295
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
299,015✔
2296
        addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
223,984✔
2297
        addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
223,984✔
2298
        idx++;
223,984✔
2299
    }
223,984✔
2300
    *match4_cnt = cnt;
75,031✔
2301
    return addr_match4;
75,031✔
2302
}
75,031✔
2303

2304
static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2305
        const DetectAddress *head, uint16_t *match6_cnt)
2306
{
75,052✔
2307
    uint16_t cnt = 0;
75,052✔
2308
    for (const DetectAddress *da = head; da != NULL; da = da->next) {
88,600✔
2309
        cnt++;
13,548✔
2310
    }
13,548✔
2311
    if (cnt == 0) {
75,052✔
2312
        return NULL;
61,516✔
2313
    }
61,516✔
2314

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

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

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

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

2359
static int SigMatchListLen(SigMatch *sm)
2360
{
276,201✔
2361
    int len = 0;
276,201✔
2362
    for (; sm != NULL; sm = sm->next)
415,691✔
2363
        len++;
139,490✔
2364

2365
    return len;
276,201✔
2366
}
276,201✔
2367

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

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

2383
    /* Copy sm type and Context into array */
2384
    SigMatch *sm = head;
85,038✔
2385
    for (; sm != NULL; sm = sm->next, smd++) {
224,528✔
2386
        smd->type = sm->type;
139,490✔
2387
        smd->ctx = sm->ctx;
139,490✔
2388
        sm->ctx = NULL; // SigMatch no longer owns the ctx
139,490✔
2389
        smd->is_last = (sm->next == NULL);
139,490✔
2390
    }
139,490✔
2391
    return out;
85,038✔
2392
}
85,038✔
2393

2394
extern int g_skip_prefilter;
2395

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

2402
    if (s->init_data->prefilter_sm != NULL) {
37,526✔
2403
        if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
1✔
2404
            RetrieveFPForSig(de_ctx, s);
1✔
2405
            if (s->init_data->mpm_sm != NULL) {
1✔
2406
                s->flags |= SIG_FLAG_PREFILTER;
1✔
2407
                SCLogDebug("%u: RetrieveFPForSig set", s->id);
1✔
2408
                SCReturn;
1✔
2409
            }
1✔
2410
            /* fall through, this can happen if the mpm doesn't support the pattern */
2411
        } else {
1✔
2412
            s->flags |= SIG_FLAG_PREFILTER;
×
2413
            SCReturn;
×
2414
        }
×
2415
    } else {
37,525✔
2416
        SCLogDebug("%u: RetrieveFPForSig", s->id);
37,525✔
2417
        RetrieveFPForSig(de_ctx, s);
37,525✔
2418
        if (s->init_data->mpm_sm != NULL) {
37,525✔
2419
            s->flags |= SIG_FLAG_PREFILTER;
36,989✔
2420
            SCLogDebug("%u: RetrieveFPForSig set", s->id);
36,989✔
2421
            SCReturn;
36,989✔
2422
        }
36,989✔
2423
    }
37,525✔
2424

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

2429
    if (!s->init_data->has_possible_prefilter || g_skip_prefilter)
536✔
2430
        SCReturn;
536✔
2431

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

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

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

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

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

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

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

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

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

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

2543
    int nlists = 0;
37,526✔
2544
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
87,937✔
2545
        nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
50,411✔
2546
    }
50,411✔
2547
    nlists += (nlists > 0);
37,526✔
2548
    SCLogDebug("nlists %d", nlists);
37,526✔
2549

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

2556
    /* run buffer type validation callbacks if any */
2557
    if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
37,521✔
2558
        if (!DetectContentPMATCHValidateCallback(s))
5,556✔
2559
            SCReturnInt(0);
2✔
2560

2561
        has_pmatch = true;
5,554✔
2562
    }
5,554✔
2563

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

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

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

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

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

2600
        const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
50,404✔
2601
        for (; app != NULL; app = app->next) {
34,790,760✔
2602
            if (app->sm_list == b->id &&
34,740,356✔
2603
                    (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
34,740,356✔
2604
                SCLogDebug("engine %s dir %d alproto %d",
113,331✔
2605
                        DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
113,331✔
2606
                        app->alproto);
113,331✔
2607
                SCLogDebug("b->id %d nlists %d", b->id, nlists);
113,331✔
2608

2609
                if (b->only_tc) {
113,331✔
2610
                    if (app->dir == 1)
×
2611
                        (*tc_excl)++;
×
2612
                } else if (b->only_ts) {
113,331✔
2613
                    if (app->dir == 0)
×
2614
                        (*ts_excl)++;
×
2615
                } else {
113,331✔
2616
                    bufdir[b->id].ts += (app->dir == 0);
113,331✔
2617
                    bufdir[b->id].tc += (app->dir == 1);
113,331✔
2618
                }
113,331✔
2619

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

2638
        if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) {
50,404✔
2639
            SCReturnInt(0);
2✔
2640
        }
2✔
2641

2642
        if (!DetectBsizeValidateContentCallback(s, b)) {
50,402✔
2643
            SCReturnInt(0);
10✔
2644
        }
10✔
2645
        if (!DetectAbsentValidateContentCallback(s, b)) {
50,392✔
2646
            SCReturnInt(0);
1✔
2647
        }
1✔
2648
    }
50,392✔
2649

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

2663
    for (int x = 0; x < nlists; x++) {
8,298,221✔
2664
        if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
8,260,719✔
2665
            continue;
8,210,388✔
2666
        (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
50,331✔
2667
        (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
50,331✔
2668
        (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
50,331✔
2669

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

2674
    SCReturnInt(1);
37,502✔
2675
}
37,502✔
2676

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

2687
static int SigConsolidateDirection(
2688
        Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2689
{
37,502✔
2690
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
37,502✔
2691
        if (!ts_excl || !tc_excl) {
×
2692
            SCLogError("rule %u should use both directions, but does not", s->id);
×
2693
            SCReturnInt(0);
×
2694
        }
×
2695
        if (dir_amb) {
×
2696
            SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
×
2697
                       "directions",
×
2698
                    s->id);
×
2699
            SCReturnInt(0);
×
2700
        }
×
2701
    } else if (ts_excl && tc_excl) {
37,502✔
2702
        SCLogError(
×
2703
                "rule %u mixes keywords with conflicting directions, a transactional rule with => "
×
2704
                "should be used",
×
2705
                s->id);
×
2706
        SCReturnInt(0);
×
2707
    } else if (ts_excl) {
37,502✔
2708
        SCLogDebug("%u: implied rule direction is toserver", s->id);
27,079✔
2709
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
27,079✔
2710
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
×
2711
            SCReturnInt(0);
×
2712
        }
×
2713
    } else if (tc_excl) {
28,208✔
2714
        SCLogDebug("%u: implied rule direction is toclient", s->id);
1,082✔
2715
        if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
1,082✔
2716
            SCLogError("rule %u mixes keywords with conflicting directions", s->id);
×
2717
            SCReturnInt(0);
×
2718
        }
×
2719
    } else if (dir_amb) {
9,341✔
2720
        SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
3,762✔
2721
    }
3,762✔
2722
    SCReturnInt(1);
37,502✔
2723
}
37,502✔
2724

2725
static void SigConsolidateTcpBuffer(Signature *s)
2726
{
37,502✔
2727
    /* TCP: corner cases:
2728
     * - pkt vs stream vs depth/offset
2729
     * - pkt vs stream vs stream_size
2730
     */
2731
    if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
37,502✔
2732
        if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
36,949✔
2733
            if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
5,093✔
2734
                s->flags |= SIG_FLAG_REQUIRE_STREAM;
4,267✔
2735
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
9,394✔
2736
                        sm = sm->next) {
7,187✔
2737
                    if (sm->type == DETECT_CONTENT &&
7,187✔
2738
                            (((DetectContentData *)(sm->ctx))->flags &
7,187✔
2739
                             (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
6,364✔
2740
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
2,060✔
2741
                        break;
2,060✔
2742
                    }
2,060✔
2743
                }
7,187✔
2744
                /* if stream_size is in use, also inspect packets */
2745
                for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
8,122✔
2746
                        sm = sm->next) {
4,441✔
2747
                    if (sm->type == DETECT_STREAM_SIZE) {
3,892✔
2748
                        s->flags |= SIG_FLAG_REQUIRE_PACKET;
37✔
2749
                        break;
37✔
2750
                    }
37✔
2751
                }
3,892✔
2752
            }
4,267✔
2753
        }
5,093✔
2754
    }
36,949✔
2755
}
37,502✔
2756

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

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

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

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

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

2823
    if (SigValidatePacketStream(s) == 0) {
37,526✔
2824
        SCReturnInt(0);
×
2825
    }
×
2826

2827
    int ts_excl = 0;
37,526✔
2828
    int tc_excl = 0;
37,526✔
2829
    int dir_amb = 0;
37,526✔
2830

2831
    if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
37,526✔
2832
        SCReturnInt(0);
24✔
2833
    }
24✔
2834

2835
    if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
37,502✔
2836
        SCReturnInt(0);
×
2837
    }
×
2838

2839
    SigConsolidateTcpBuffer(s);
37,502✔
2840

2841
    SignatureSetType(de_ctx, s);
37,502✔
2842
    DetectRuleSetTable(s);
37,502✔
2843

2844
    int r = SigValidateFileHandling(s);
37,502✔
2845
    if (r == 0) {
37,502✔
2846
        SCReturnInt(0);
2✔
2847
    }
2✔
2848
    if (SigInspectsFiles(s)) {
37,500✔
2849
        if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2,557✔
2850
            AppLayerHtpNeedFileInspection();
2,510✔
2851
        }
2,510✔
2852
    }
2,557✔
2853
    if (DetectRuleValidateTable(s) == false) {
37,500✔
2854
        SCReturnInt(0);
×
2855
    }
×
2856

2857
    if (s->type == SIG_TYPE_IPONLY) {
37,500✔
2858
        /* For IPOnly */
2859
        if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
196✔
2860
            SCReturnInt(0);
×
2861

2862
        if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
196✔
2863
            SCReturnInt(0);
×
2864
    }
196✔
2865
    SCReturnInt(1);
37,500✔
2866
}
37,500✔
2867

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

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

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

2891
    /* default gid to 1 */
2892
    sig->gid = 1;
38,017✔
2893

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

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

2915
    /* Now completely parse the rule. */
2916
    ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
38,008✔
2917
    BUG_ON(ret == -4);
38,008✔
2918
    if (ret == -3) {
38,008✔
2919
        de_ctx->sigerror_silent = true;
×
2920
        de_ctx->sigerror_ok = true;
×
2921
        goto error;
×
2922
    } else if (ret == -2) {
38,008✔
2923
        de_ctx->sigerror_silent = true;
×
2924
        goto error;
×
2925
    } else if (ret < 0) {
38,008✔
2926
        goto error;
482✔
2927
    }
482✔
2928

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

2933
    sig->iid = de_ctx->signum;
37,526✔
2934
    de_ctx->signum++;
37,526✔
2935

2936
    if (sig->alproto != ALPROTO_UNKNOWN) {
37,526✔
2937
        int override_needed = 0;
32,696✔
2938
        if (sig->proto.flags & DETECT_PROTO_ANY) {
32,696✔
2939
            sig->proto.flags &= ~DETECT_PROTO_ANY;
4✔
2940
            memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
4✔
2941
            override_needed = 1;
4✔
2942
        } else {
32,692✔
2943
            override_needed = 1;
32,692✔
2944
            size_t s = 0;
32,692✔
2945
            for (s = 0; s < sizeof(sig->proto.proto); s++) {
32,694✔
2946
                if (sig->proto.proto[s] != 0x00) {
32,694✔
2947
                    override_needed = 0;
32,692✔
2948
                    break;
32,692✔
2949
                }
32,692✔
2950
            }
32,694✔
2951
        }
32,692✔
2952

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

2960
    /* set the packet and app layer flags, but only if the
2961
     * app layer flag wasn't already set in which case we
2962
     * only consider the app layer */
2963
    if (!(sig->flags & SIG_FLAG_APPLAYER)) {
37,526✔
2964
        if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
4,830✔
2965
            SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
3,658✔
2966
            for ( ; sm != NULL; sm = sm->next) {
8,612✔
2967
                if (sigmatch_table[sm->type].Match != NULL)
4,954✔
2968
                    sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
4,954✔
2969
            }
4,954✔
2970
        } else {
4,282✔
2971
            sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
1,172✔
2972
        }
1,172✔
2973
    }
4,830✔
2974

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

2983
    if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
37,526✔
2984
        if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
10,323✔
2985
            sig->flags |= SIG_FLAG_TOSERVER;
10,159✔
2986
            sig->flags |= SIG_FLAG_TOCLIENT;
10,159✔
2987
        }
10,159✔
2988
    }
10,323✔
2989

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

2994
    SigBuildAddressMatchArray(sig);
37,526✔
2995

2996
    /* run buffer type callbacks if any */
2997
    for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
300,208✔
2998
        if (sig->init_data->smlists[x])
262,682✔
2999
            DetectEngineBufferRunSetupCallback(de_ctx, x, sig);
35,385✔
3000
    }
262,682✔
3001
    for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
87,937✔
3002
        DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig);
50,411✔
3003
    }
50,411✔
3004

3005
    SigSetupPrefilter(de_ctx, sig);
37,526✔
3006

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

3012
    return sig;
37,500✔
3013

3014
error:
517✔
3015
    if (sig != NULL) {
517✔
3016
        SigFree(de_ctx, sig);
517✔
3017
    }
517✔
3018
    return NULL;
517✔
3019
}
37,526✔
3020

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

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

3039
        if (!DetectAddressListsAreEqual(src, dst)) {
10✔
3040
            return false;
8✔
3041
        }
8✔
3042

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

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

3051
    return true;
4✔
3052
}
12✔
3053

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

3058
    uint32_t oldsignum = de_ctx->signum;
38,006✔
3059
    de_ctx->sigerror_ok = false;
38,006✔
3060
    de_ctx->sigerror_silent = false;
38,006✔
3061
    de_ctx->sigerror_requires = false;
38,006✔
3062

3063
    Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
38,006✔
3064
    if (sig == NULL) {
38,006✔
3065
        goto error;
517✔
3066
    }
517✔
3067

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

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

3082
    SCReturnPtr(sig, "Signature");
37,489✔
3083

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

3092
    SCReturnPtr(NULL, "Signature");
517✔
3093
}
37,489✔
3094

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

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

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

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

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

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

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

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

3168
    return 0;
30,041✔
3169
}
66,182✔
3170

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

3188
    return 0;
1,563✔
3189
}
1,563✔
3190

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

3201
    de_ctx->dup_sig_hash_table = NULL;
1,610✔
3202
}
1,610✔
3203

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

3229
    /* return value */
3230
    int ret = 0;
37,218✔
3231

3232
    SigDuplWrapper *sw_dup = NULL;
37,218✔
3233
    SigDuplWrapper *sw = NULL;
37,218✔
3234

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

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

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

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

3263
        ret = 0;
37,207✔
3264
        goto end;
37,207✔
3265
    }
37,207✔
3266

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

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

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

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

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

3348
    SCFree(sw);
8✔
3349

3350
end:
37,218✔
3351
    return ret;
37,218✔
3352
}
8✔
3353

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

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

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

3405
    de_ctx->sig_list = sig;
×
3406

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

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

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

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

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

3477
    de_ctx->sig_list = sig;
37,215✔
3478

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

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

3498
static DetectParseRegex *g_detect_parse_regex_list = NULL;
3499

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

3510
void DetectParseFreeRegex(DetectParseRegex *r)
3511
{
8,345✔
3512
    if (r->regex) {
8,345✔
3513
        pcre2_code_free(r->regex);
8,337✔
3514
    }
8,337✔
3515
    if (r->context) {
8,345✔
3516
        pcre2_match_context_free(r->context);
7,017✔
3517
    }
7,017✔
3518
}
8,345✔
3519

3520
void DetectParseFreeRegexes(void)
3521
{
30✔
3522
    DetectParseRegex *r = g_detect_parse_regex_list;
30✔
3523
    while (r) {
1,350✔
3524
        DetectParseRegex *next = r->next;
1,320✔
3525

3526
        DetectParseFreeRegex(r);
1,320✔
3527

3528
        SCFree(r);
1,320✔
3529
        r = next;
1,320✔
3530
    }
1,320✔
3531
    g_detect_parse_regex_list = NULL;
30✔
3532
}
30✔
3533

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

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

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

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

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

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

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

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

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

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

3633
/*
3634
 * TESTS
3635
 */
3636

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3930
    Signature *s = NULL;
1✔
3931

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

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

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

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

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

3964
    Signature *s = NULL;
1✔
3965

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

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

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

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

3990
    Signature *s = NULL;
1✔
3991

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

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

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

4008
    result = 1;
1✔
4009

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

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

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

4027
    Signature *s = NULL;
1✔
4028

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

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

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

4045
    result = 1;
1✔
4046

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

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

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

4064
    Signature *s = NULL;
1✔
4065

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

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

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

4082
    result = 1;
1✔
4083

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

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

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

4101
    Signature *s = NULL;
1✔
4102

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

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

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

4119
    result = 1;
1✔
4120

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

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

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

4138
    Signature *s = NULL;
1✔
4139

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

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

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

4156
    result = 1;
1✔
4157

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4267
    Signature *s = NULL;
1✔
4268

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4476
    result = 1;
1✔
4477

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

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

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

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

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

4517
    result = 1;
1✔
4518

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

4526
    return result;
1✔
4527
}
1✔
4528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4872
    s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
1✔
4873
    if (s != NULL) {
1✔
4874
        SigFree(de_ctx, s);
4875
        goto end;
4876
    }
4877

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

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

4898
    s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
1✔
4899
    if (s != NULL) {
1✔
4900
        SigFree(de_ctx, s);
4901
        goto end;
4902
    }
4903

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

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

4924
    s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
1✔
4925
    if (s != NULL) {
1✔
4926
        SigFree(de_ctx, s);
4927
        goto end;
4928
    }
4929

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5073
    return result;
1✔
5074
}
1✔
5075

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5239
    // mix in negation, these are not the same
5240
    s = DetectEngineAppendSig(
1✔
5241
            de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
1✔
5242
    FAIL_IF_NULL(s);
1✔
5243
    FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
1✔
5244
    FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
1✔
5245

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

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

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

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

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

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

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

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

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

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

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

5310
    // reset
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
    // fail if set single not in multiple
5318
    FAIL_IF(SCDetectSignatureSetAppProto(s, 4) >= 0);
1✔
5319

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

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

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

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

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

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

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

5414
#endif /* UNITTESTS */
5415

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

5421
void SigParseRegisterTests(void)
5422
{
1✔
5423
#ifdef UNITTESTS
1✔
5424
    DetectParseRegisterTests();
1✔
5425

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

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

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

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

5490
    UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
1✔
5491

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

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