Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-engine.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 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
24
#include "suricata-common.h"
25
#include "suricata.h"
26
#include "detect.h"
27
#include "flow.h"
28
#include "flow-private.h"
29
#include "flow-util.h"
30
#include "flow-worker.h"
31
#include "conf.h"
32
#include "conf-yaml-loader.h"
33
#include "datasets.h"
34
35
#include "app-layer-parser.h"
36
#include "app-layer-htp.h"
37
38
#include "detect-parse.h"
39
#include "detect-engine-sigorder.h"
40
41
#include "detect-engine-build.h"
42
#include "detect-engine-siggroup.h"
43
#include "detect-engine-address.h"
44
#include "detect-engine-port.h"
45
#include "detect-engine-prefilter.h"
46
#include "detect-engine-mpm.h"
47
#include "detect-engine-iponly.h"
48
#include "detect-engine-tag.h"
49
#include "detect-engine-frame.h"
50
51
#include "detect-engine-file.h"
52
53
#include "detect-engine.h"
54
#include "detect-engine-state.h"
55
#include "detect-engine-payload.h"
56
#include "detect-fast-pattern.h"
57
#include "detect-byte-extract.h"
58
#include "detect-content.h"
59
#include "detect-uricontent.h"
60
#include "detect-tcphdr.h"
61
#include "detect-engine-threshold.h"
62
#include "detect-engine-content-inspection.h"
63
64
#include "detect-engine-loader.h"
65
66
#include "util-classification-config.h"
67
#include "util-reference-config.h"
68
#include "util-threshold-config.h"
69
#include "util-error.h"
70
#include "util-hash.h"
71
#include "util-byte.h"
72
#include "util-debug.h"
73
#include "util-unittest.h"
74
#include "util-action.h"
75
#include "util-magic.h"
76
#include "util-signal.h"
77
#include "util-spm.h"
78
#include "util-device.h"
79
#include "util-var-name.h"
80
#include "util-path.h"
81
#include "util-profiling.h"
82
#include "util-validate.h"
83
#include "util-hash-string.h"
84
#include "util-enum.h"
85
#include "util-conf.h"
86
87
#include "tm-threads.h"
88
#include "runmodes.h"
89
90
#include "reputation.h"
91
92
67.5k
#define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000
93
94
static int DetectEngineCtxLoadConf(DetectEngineCtx *);
95
96
static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
97
    0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0};
98
99
static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
100
static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
101
static void TenantIdFree(void *d);
102
static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet *p);
103
static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p);
104
static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p);
105
106
static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL;
107
static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL;
108
static DetectEngineFrameInspectionEngine *g_frame_inspect_engines = NULL;
109
110
// clang-format off
111
const struct SignatureProperties signature_properties[SIG_TYPE_MAX] = {
112
    /* SIG_TYPE_NOT_SET */      { SIG_PROP_FLOW_ACTION_PACKET, },
113
    /* SIG_TYPE_IPONLY */       { SIG_PROP_FLOW_ACTION_FLOW, },
114
    /* SIG_TYPE_LIKE_IPONLY */  { SIG_PROP_FLOW_ACTION_FLOW, },
115
    /* SIG_TYPE_PDONLY */       { SIG_PROP_FLOW_ACTION_FLOW, },
116
    /* SIG_TYPE_DEONLY */       { SIG_PROP_FLOW_ACTION_PACKET, },
117
    /* SIG_TYPE_PKT */          { SIG_PROP_FLOW_ACTION_PACKET, },
118
    /* SIG_TYPE_PKT_STREAM */   { SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL, },
119
    /* SIG_TYPE_STREAM */       { SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL, },
120
    /* SIG_TYPE_APPLAYER */     { SIG_PROP_FLOW_ACTION_FLOW, },
121
    /* SIG_TYPE_APP_TX */       { SIG_PROP_FLOW_ACTION_FLOW, },
122
};
123
// clang-format on
124
125
/** \brief register inspect engine at start up time
126
 *
127
 *  \note errors are fatal */
128
void DetectPktInspectEngineRegister(const char *name,
129
        InspectionBufferGetPktDataPtr GetPktData,
130
        InspectionBufferPktInspectFunc Callback)
131
584
{
132
584
    DetectBufferTypeRegister(name);
133
584
    const int sm_list = DetectBufferTypeGetByName(name);
134
584
    if (sm_list == -1) {
135
0
        FatalError("failed to register inspect engine %s", name);
136
0
    }
137
138
584
    if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
139
584
        (Callback == NULL))
140
0
    {
141
0
        SCLogError("Invalid arguments");
142
0
        BUG_ON(1);
143
0
    }
144
145
584
    DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
146
584
    if (unlikely(new_engine == NULL)) {
147
0
        FatalError("failed to register inspect engine %s: %s", name, strerror(errno));
148
0
    }
149
584
    new_engine->sm_list = (uint16_t)sm_list;
150
584
    new_engine->sm_list_base = (uint16_t)sm_list;
151
584
    new_engine->v1.Callback = Callback;
152
584
    new_engine->v1.GetData = GetPktData;
153
154
584
    if (g_pkt_inspect_engines == NULL) {
155
73
        g_pkt_inspect_engines = new_engine;
156
511
    } else {
157
511
        DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
158
2.04k
        while (t->next != NULL) {
159
1.53k
            t = t->next;
160
1.53k
        }
161
162
511
        t->next = new_engine;
163
511
    }
164
584
}
165
166
/** \brief register inspect engine at start up time
167
 *
168
 *  \note errors are fatal */
169
void DetectFrameInspectEngineRegister(const char *name, int dir,
170
        InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type)
171
0
{
172
0
    DetectBufferTypeRegister(name);
173
0
    const int sm_list = DetectBufferTypeGetByName(name);
174
0
    if (sm_list == -1) {
175
0
        FatalError("failed to register inspect engine %s", name);
176
0
    }
177
178
0
    if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) {
179
0
        SCLogError("Invalid arguments");
180
0
        BUG_ON(1);
181
0
    }
182
183
0
    uint8_t direction;
184
0
    if (dir == SIG_FLAG_TOSERVER) {
185
0
        direction = 0;
186
0
    } else {
187
0
        direction = 1;
188
0
    }
189
190
0
    DetectEngineFrameInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
191
0
    if (unlikely(new_engine == NULL)) {
192
0
        FatalError("failed to register inspect engine %s: %s", name, strerror(errno));
193
0
    }
194
0
    new_engine->sm_list = (uint16_t)sm_list;
195
0
    new_engine->sm_list_base = (uint16_t)sm_list;
196
0
    new_engine->dir = direction;
197
0
    new_engine->v1.Callback = Callback;
198
0
    new_engine->alproto = alproto;
199
0
    new_engine->type = type;
200
201
0
    if (g_frame_inspect_engines == NULL) {
202
0
        g_frame_inspect_engines = new_engine;
203
0
    } else {
204
0
        DetectEngineFrameInspectionEngine *t = g_frame_inspect_engines;
205
0
        while (t->next != NULL) {
206
0
            t = t->next;
207
0
        }
208
209
0
        t->next = new_engine;
210
0
    }
211
0
}
212
213
/** \brief register inspect engine at start up time
214
 *
215
 *  \note errors are fatal */
216
void DetectAppLayerInspectEngineRegister2(const char *name,
217
        AppProto alproto, uint32_t dir, int progress,
218
        InspectEngineFuncPtr2 Callback2,
219
        InspectionBufferGetDataPtr GetData)
220
8.93k
{
221
8.93k
    BUG_ON(progress >= 48);
222
223
8.93k
    DetectBufferTypeRegister(name);
224
8.93k
    const int sm_list = DetectBufferTypeGetByName(name);
225
8.93k
    if (sm_list == -1) {
226
0
        FatalError("failed to register inspect engine %s", name);
227
0
    }
228
8.93k
    SCLogDebug("name %s id %d", name, sm_list);
229
230
8.93k
    if ((alproto >= ALPROTO_FAILED) ||
231
8.93k
        (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
232
8.93k
        (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
233
8.93k
        (progress < 0 || progress >= SHRT_MAX) ||
234
8.93k
        (Callback2 == NULL))
235
0
    {
236
0
        SCLogError("Invalid arguments");
237
0
        BUG_ON(1);
238
8.93k
    } else if (Callback2 == DetectEngineInspectBufferGeneric && GetData == NULL) {
239
0
        SCLogError("Invalid arguments: must register "
240
0
                   "GetData with DetectEngineInspectBufferGeneric");
241
0
        BUG_ON(1);
242
0
    }
243
244
8.93k
    uint8_t direction;
245
8.93k
    if (dir == SIG_FLAG_TOSERVER) {
246
5.09k
        direction = 0;
247
5.09k
    } else {
248
3.84k
        direction = 1;
249
3.84k
    }
250
251
8.93k
    DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine));
252
8.93k
    if (unlikely(new_engine == NULL)) {
253
0
        exit(EXIT_FAILURE);
254
0
    }
255
8.93k
    memset(new_engine, 0, sizeof(*new_engine));
256
8.93k
    new_engine->alproto = alproto;
257
8.93k
    new_engine->dir = direction;
258
8.93k
    new_engine->sm_list = (uint16_t)sm_list;
259
8.93k
    new_engine->sm_list_base = (uint16_t)sm_list;
260
8.93k
    new_engine->progress = (int16_t)progress;
261
8.93k
    new_engine->v2.Callback = Callback2;
262
8.93k
    new_engine->v2.GetData = GetData;
263
264
8.93k
    if (g_app_inspect_engines == NULL) {
265
34
        g_app_inspect_engines = new_engine;
266
8.90k
    } else {
267
8.90k
        DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
268
1.17M
        while (t->next != NULL) {
269
1.16M
            t = t->next;
270
1.16M
        }
271
272
8.90k
        t->next = new_engine;
273
8.90k
    }
274
8.93k
}
275
276
/* copy an inspect engine with transforms to a new list id. */
277
static void DetectAppLayerInspectEngineCopy(
278
        DetectEngineCtx *de_ctx,
279
        int sm_list, int new_list,
280
        const DetectEngineTransforms *transforms)
281
92.0k
{
282
92.0k
    const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
283
50.6M
    while (t) {
284
50.5M
        if (t->sm_list == sm_list) {
285
690k
            DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
286
690k
            if (unlikely(new_engine == NULL)) {
287
0
                exit(EXIT_FAILURE);
288
0
            }
289
690k
            new_engine->alproto = t->alproto;
290
690k
            new_engine->dir = t->dir;
291
690k
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
292
690k
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
293
690k
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
294
690k
            new_engine->sm_list_base = (uint16_t)sm_list;
295
690k
            new_engine->progress = t->progress;
296
690k
            new_engine->v2 = t->v2;
297
690k
            new_engine->v2.transforms = transforms; /* assign transforms */
298
299
690k
            if (de_ctx->app_inspect_engines == NULL) {
300
0
                de_ctx->app_inspect_engines = new_engine;
301
690k
            } else {
302
690k
                DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
303
1.24G
                while (list->next != NULL) {
304
1.24G
                    list = list->next;
305
1.24G
                }
306
307
690k
                list->next = new_engine;
308
690k
            }
309
690k
        }
310
50.5M
        t = t->next;
311
50.5M
    }
312
92.0k
}
313
314
/* copy inspect engines from global registrations to de_ctx list */
315
static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
316
140k
{
317
140k
    const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
318
140k
    DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
319
67.1M
    while (t) {
320
66.9M
        DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
321
66.9M
        if (unlikely(new_engine == NULL)) {
322
0
            exit(EXIT_FAILURE);
323
0
        }
324
66.9M
        new_engine->alproto = t->alproto;
325
66.9M
        new_engine->dir = t->dir;
326
66.9M
        new_engine->sm_list = t->sm_list;
327
66.9M
        new_engine->sm_list_base = t->sm_list;
328
66.9M
        new_engine->progress = t->progress;
329
66.9M
        new_engine->v2 = t->v2;
330
331
66.9M
        if (list == NULL) {
332
140k
            de_ctx->app_inspect_engines = new_engine;
333
66.8M
        } else {
334
66.8M
            list->next = new_engine;
335
66.8M
        }
336
66.9M
        list = new_engine;
337
338
66.9M
        t = t->next;
339
66.9M
    }
340
140k
}
341
342
/* copy an inspect engine with transforms to a new list id. */
343
static void DetectPktInspectEngineCopy(
344
        DetectEngineCtx *de_ctx,
345
        int sm_list, int new_list,
346
        const DetectEngineTransforms *transforms)
347
1.84k
{
348
1.84k
    const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
349
16.5k
    while (t) {
350
14.7k
        if (t->sm_list == sm_list) {
351
1.84k
            DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
352
1.84k
            if (unlikely(new_engine == NULL)) {
353
0
                exit(EXIT_FAILURE);
354
0
            }
355
1.84k
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
356
1.84k
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
357
1.84k
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
358
1.84k
            new_engine->sm_list_base = (uint16_t)sm_list;
359
1.84k
            new_engine->v1 = t->v1;
360
1.84k
            new_engine->v1.transforms = transforms; /* assign transforms */
361
362
1.84k
            if (de_ctx->pkt_inspect_engines == NULL) {
363
0
                de_ctx->pkt_inspect_engines = new_engine;
364
1.84k
            } else {
365
1.84k
                DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
366
85.3k
                while (list->next != NULL) {
367
83.5k
                    list = list->next;
368
83.5k
                }
369
370
1.84k
                list->next = new_engine;
371
1.84k
            }
372
1.84k
        }
373
14.7k
        t = t->next;
374
14.7k
    }
375
1.84k
}
376
377
/* copy inspect engines from global registrations to de_ctx list */
378
static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
379
140k
{
380
140k
    const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
381
1.26M
    while (t) {
382
1.12M
        SCLogDebug("engine %p", t);
383
1.12M
        DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
384
1.12M
        if (unlikely(new_engine == NULL)) {
385
0
            exit(EXIT_FAILURE);
386
0
        }
387
1.12M
        new_engine->sm_list = t->sm_list;
388
1.12M
        new_engine->sm_list_base = t->sm_list;
389
1.12M
        new_engine->v1 = t->v1;
390
391
1.12M
        if (de_ctx->pkt_inspect_engines == NULL) {
392
140k
            de_ctx->pkt_inspect_engines = new_engine;
393
984k
        } else {
394
984k
            DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
395
3.93M
            while (list->next != NULL) {
396
2.95M
                list = list->next;
397
2.95M
            }
398
399
984k
            list->next = new_engine;
400
984k
        }
401
402
1.12M
        t = t->next;
403
1.12M
    }
404
140k
}
405
406
/** \brief register inspect engine at start up time
407
 *
408
 *  \note errors are fatal */
409
void DetectEngineFrameInspectEngineRegister(DetectEngineCtx *de_ctx, const char *name, int dir,
410
        InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type)
411
11.0k
{
412
11.0k
    const int sm_list = DetectEngineBufferTypeRegister(de_ctx, name);
413
11.0k
    if (sm_list < 0) {
414
0
        FatalError("failed to register inspect engine %s", name);
415
0
    }
416
417
11.0k
    if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) {
418
0
        SCLogError("Invalid arguments");
419
0
        BUG_ON(1);
420
0
    }
421
422
11.0k
    uint8_t direction;
423
11.0k
    if (dir == SIG_FLAG_TOSERVER) {
424
5.51k
        direction = 0;
425
5.51k
    } else {
426
5.51k
        direction = 1;
427
5.51k
    }
428
429
11.0k
    DetectEngineFrameInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
430
11.0k
    if (unlikely(new_engine == NULL)) {
431
0
        FatalError("failed to register inspect engine %s: %s", name, strerror(errno));
432
0
    }
433
11.0k
    new_engine->sm_list = (uint16_t)sm_list;
434
11.0k
    new_engine->sm_list_base = (uint16_t)sm_list;
435
11.0k
    new_engine->dir = direction;
436
11.0k
    new_engine->v1.Callback = Callback;
437
11.0k
    new_engine->alproto = alproto;
438
11.0k
    new_engine->type = type;
439
440
11.0k
    if (de_ctx->frame_inspect_engines == NULL) {
441
3.14k
        de_ctx->frame_inspect_engines = new_engine;
442
7.89k
    } else {
443
7.89k
        DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
444
22.9k
        while (list->next != NULL) {
445
15.0k
            list = list->next;
446
15.0k
        }
447
448
7.89k
        list->next = new_engine;
449
7.89k
    }
450
11.0k
}
451
452
/* copy an inspect engine with transforms to a new list id. */
453
static void DetectFrameInspectEngineCopy(DetectEngineCtx *de_ctx, int sm_list, int new_list,
454
        const DetectEngineTransforms *transforms)
455
435
{
456
    /* take the list from the detect engine as the buffers can be registered
457
     * dynamically. */
458
435
    DetectEngineFrameInspectionEngine *t = de_ctx->frame_inspect_engines;
459
8.57k
    while (t) {
460
8.14k
        if (t->sm_list == sm_list) {
461
870
            DetectEngineFrameInspectionEngine *new_engine =
462
870
                    SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
463
870
            if (unlikely(new_engine == NULL)) {
464
0
                exit(EXIT_FAILURE);
465
0
            }
466
870
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
467
870
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
468
870
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
469
870
            new_engine->sm_list_base = (uint16_t)sm_list;
470
870
            new_engine->dir = t->dir;
471
870
            new_engine->alproto = t->alproto;
472
870
            new_engine->type = t->type;
473
870
            new_engine->v1 = t->v1;
474
870
            new_engine->v1.transforms = transforms; /* assign transforms */
475
476
            /* append to the list */
477
870
            DetectEngineFrameInspectionEngine *list = t;
478
11.9k
            while (list->next != NULL) {
479
11.0k
                list = list->next;
480
11.0k
            }
481
482
870
            list->next = new_engine;
483
870
        }
484
8.14k
        t = t->next;
485
8.14k
    }
486
435
}
487
488
/* copy inspect engines from global registrations to de_ctx list */
489
static void DetectFrameInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
490
140k
{
491
140k
    const DetectEngineFrameInspectionEngine *t = g_frame_inspect_engines;
492
140k
    while (t) {
493
0
        SCLogDebug("engine %p", t);
494
0
        DetectEngineFrameInspectionEngine *new_engine =
495
0
                SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
496
0
        if (unlikely(new_engine == NULL)) {
497
0
            exit(EXIT_FAILURE);
498
0
        }
499
0
        new_engine->sm_list = t->sm_list;
500
0
        new_engine->sm_list_base = t->sm_list;
501
0
        new_engine->dir = t->dir;
502
0
        new_engine->alproto = t->alproto;
503
0
        new_engine->type = t->type;
504
0
        new_engine->v1 = t->v1;
505
506
0
        if (de_ctx->frame_inspect_engines == NULL) {
507
0
            de_ctx->frame_inspect_engines = new_engine;
508
0
        } else {
509
0
            DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
510
0
            while (list->next != NULL) {
511
0
                list = list->next;
512
0
            }
513
514
0
            list->next = new_engine;
515
0
        }
516
517
0
        t = t->next;
518
0
    }
519
140k
}
520
521
/** \internal
522
 *  \brief append the stream inspection
523
 *
524
 *  If stream inspection is MPM, then prepend it.
525
 */
526
static void AppendStreamInspectEngine(
527
        Signature *s, SigMatchData *stream, uint8_t direction, uint8_t id)
528
17.3k
{
529
17.3k
    bool prepend = false;
530
531
17.3k
    DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
532
17.3k
    if (unlikely(new_engine == NULL)) {
533
0
        exit(EXIT_FAILURE);
534
0
    }
535
17.3k
    if (s->init_data->mpm_sm_list == DETECT_SM_LIST_PMATCH) {
536
6.28k
        SCLogDebug("stream is mpm");
537
6.28k
        prepend = true;
538
6.28k
        new_engine->mpm = true;
539
6.28k
    }
540
17.3k
    new_engine->alproto = ALPROTO_UNKNOWN; /* all */
541
17.3k
    new_engine->dir = direction;
542
17.3k
    new_engine->stream = true;
543
17.3k
    new_engine->sm_list = DETECT_SM_LIST_PMATCH;
544
17.3k
    new_engine->sm_list_base = DETECT_SM_LIST_PMATCH;
545
17.3k
    new_engine->smd = stream;
546
17.3k
    new_engine->v2.Callback = DetectEngineInspectStream;
547
17.3k
    new_engine->progress = 0;
548
549
    /* append */
550
17.3k
    if (s->app_inspect == NULL) {
551
2
        s->app_inspect = new_engine;
552
2
        new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
553
17.3k
    } else if (prepend) {
554
6.27k
        new_engine->next = s->app_inspect;
555
6.27k
        s->app_inspect = new_engine;
556
6.27k
        new_engine->id = id;
557
558
11.0k
    } else {
559
11.0k
        DetectEngineAppInspectionEngine *a = s->app_inspect;
560
166k
        while (a->next != NULL) {
561
155k
            a = a->next;
562
155k
        }
563
564
11.0k
        a->next = new_engine;
565
11.0k
        new_engine->id = id;
566
11.0k
    }
567
17.3k
    SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
568
17.3k
}
569
570
static void AppendFrameInspectEngine(DetectEngineCtx *de_ctx,
571
        const DetectEngineFrameInspectionEngine *u, Signature *s, SigMatchData *smd,
572
        const int mpm_list)
573
9.93k
{
574
9.93k
    bool prepend = false;
575
576
9.93k
    if (u->alproto == ALPROTO_UNKNOWN) {
577
        /* special case, inspect engine applies to all protocols */
578
9.93k
    } else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, u->alproto))
579
0
        return;
580
581
9.93k
    if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
582
3.44k
        if (u->dir == 1)
583
1.72k
            return;
584
6.48k
    } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
585
2.05k
        if (u->dir == 0)
586
1.02k
            return;
587
2.05k
    }
588
589
7.17k
    DetectEngineFrameInspectionEngine *new_engine =
590
7.17k
            SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
591
7.17k
    if (unlikely(new_engine == NULL)) {
592
0
        exit(EXIT_FAILURE);
593
0
    }
594
7.17k
    if (mpm_list == u->sm_list) {
595
6.05k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, u->sm_list));
596
6.05k
        prepend = true;
597
6.05k
        new_engine->mpm = true;
598
6.05k
    }
599
600
7.17k
    new_engine->type = u->type;
601
7.17k
    new_engine->sm_list = u->sm_list;
602
7.17k
    new_engine->sm_list_base = u->sm_list_base;
603
7.17k
    new_engine->smd = smd;
604
7.17k
    new_engine->v1 = u->v1;
605
7.17k
    SCLogDebug("sm_list %d new_engine->v1 %p/%p", new_engine->sm_list, new_engine->v1.Callback,
606
7.17k
            new_engine->v1.transforms);
607
608
7.17k
    if (s->frame_inspect == NULL) {
609
4.96k
        s->frame_inspect = new_engine;
610
4.96k
    } else if (prepend) {
611
1.65k
        new_engine->next = s->frame_inspect;
612
1.65k
        s->frame_inspect = new_engine;
613
1.65k
    } else {
614
558
        DetectEngineFrameInspectionEngine *a = s->frame_inspect;
615
558
        while (a->next != NULL) {
616
0
            a = a->next;
617
0
        }
618
558
        new_engine->next = a->next;
619
558
        a->next = new_engine;
620
558
    }
621
7.17k
}
622
623
static void AppendPacketInspectEngine(DetectEngineCtx *de_ctx,
624
        const DetectEnginePktInspectionEngine *e, Signature *s, SigMatchData *smd,
625
        const int mpm_list)
626
2.15k
{
627
2.15k
    bool prepend = false;
628
629
2.15k
    DetectEnginePktInspectionEngine *new_engine =
630
2.15k
            SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
631
2.15k
    if (unlikely(new_engine == NULL)) {
632
0
        exit(EXIT_FAILURE);
633
0
    }
634
2.15k
    if (mpm_list == e->sm_list) {
635
1.03k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, e->sm_list));
636
1.03k
        prepend = true;
637
1.03k
        new_engine->mpm = true;
638
1.03k
    }
639
640
2.15k
    new_engine->sm_list = e->sm_list;
641
2.15k
    new_engine->sm_list_base = e->sm_list_base;
642
2.15k
    new_engine->smd = smd;
643
2.15k
    new_engine->v1 = e->v1;
644
2.15k
    SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p", new_engine->sm_list, new_engine->v1.Callback,
645
2.15k
            new_engine->v1.GetData, new_engine->v1.transforms);
646
647
2.15k
    if (s->pkt_inspect == NULL) {
648
1.80k
        s->pkt_inspect = new_engine;
649
1.80k
    } else if (prepend) {
650
22
        new_engine->next = s->pkt_inspect;
651
22
        s->pkt_inspect = new_engine;
652
323
    } else {
653
323
        DetectEnginePktInspectionEngine *a = s->pkt_inspect;
654
2.33k
        while (a->next != NULL) {
655
2.01k
            a = a->next;
656
2.01k
        }
657
323
        new_engine->next = a->next;
658
323
        a->next = new_engine;
659
323
    }
660
2.15k
}
661
662
static void AppendAppInspectEngine(DetectEngineCtx *de_ctx,
663
        const DetectEngineAppInspectionEngine *t, Signature *s, SigMatchData *smd,
664
        const int mpm_list, const int files_id, uint8_t *last_id, bool *head_is_mpm)
665
196k
{
666
196k
    if (t->alproto == ALPROTO_UNKNOWN) {
667
        /* special case, inspect engine applies to all protocols */
668
181k
    } else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, t->alproto))
669
37.2k
        return;
670
671
158k
    if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
672
38.9k
        if (t->dir == 1)
673
9.98k
            return;
674
119k
    } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
675
10.1k
        if (t->dir == 0)
676
2.88k
            return;
677
10.1k
    }
678
146k
    SCLogDebug("app engine: t %p t->id %u => alproto:%s files:%s", t, t->id,
679
146k
            AppProtoToString(t->alproto), BOOL2STR(t->sm_list == files_id));
680
681
146k
    DetectEngineAppInspectionEngine *new_engine =
682
146k
            SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
683
146k
    if (unlikely(new_engine == NULL)) {
684
0
        exit(EXIT_FAILURE);
685
0
    }
686
146k
    bool prepend = false;
687
146k
    if (mpm_list == t->sm_list) {
688
72.3k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
689
72.3k
        prepend = true;
690
72.3k
        *head_is_mpm = true;
691
72.3k
        new_engine->mpm = true;
692
72.3k
    }
693
694
146k
    new_engine->alproto = t->alproto;
695
146k
    new_engine->dir = t->dir;
696
146k
    new_engine->sm_list = t->sm_list;
697
146k
    new_engine->sm_list_base = t->sm_list_base;
698
146k
    new_engine->smd = smd;
699
146k
    new_engine->progress = t->progress;
700
146k
    new_engine->v2 = t->v2;
701
146k
    SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p", new_engine->sm_list, new_engine->v2.Callback,
702
146k
            new_engine->v2.GetData, new_engine->v2.transforms);
703
704
146k
    if (s->app_inspect == NULL) {
705
35.6k
        s->app_inspect = new_engine;
706
35.6k
        if (new_engine->sm_list == files_id) {
707
3.15k
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
708
3.15k
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
709
32.4k
        } else {
710
32.4k
            new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
711
32.4k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
712
32.4k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
713
32.4k
        }
714
715
        /* prepend engine if forced or if our engine has a lower progress. */
716
110k
    } else if (prepend || (!(*head_is_mpm) && s->app_inspect->progress > new_engine->progress)) {
717
59.1k
        new_engine->next = s->app_inspect;
718
59.1k
        s->app_inspect = new_engine;
719
59.1k
        if (new_engine->sm_list == files_id) {
720
0
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
721
0
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
722
59.1k
        } else {
723
59.1k
            new_engine->id = ++(*last_id);
724
59.1k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
725
59.1k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
726
59.1k
        }
727
728
59.1k
    } else {
729
51.2k
        DetectEngineAppInspectionEngine *a = s->app_inspect;
730
347k
        while (a->next != NULL) {
731
310k
            if (a->next && a->next->progress > new_engine->progress) {
732
14.3k
                break;
733
14.3k
            }
734
296k
            a = a->next;
735
296k
        }
736
737
51.2k
        new_engine->next = a->next;
738
51.2k
        a->next = new_engine;
739
51.2k
        if (new_engine->sm_list == files_id) {
740
35.9k
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
741
35.9k
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
742
35.9k
        } else {
743
15.3k
            new_engine->id = ++(*last_id);
744
15.3k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
745
15.3k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
746
15.3k
        }
747
51.2k
    }
748
749
146k
    SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
750
751
146k
    s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
752
146k
}
753
754
/**
755
 *  \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
756
 *        is assigned.
757
 */
758
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
759
87.9k
{
760
87.9k
    const int mpm_list = s->init_data->mpm_sm ? s->init_data->mpm_sm_list : -1;
761
87.9k
    const int files_id = DetectBufferTypeGetByName("files");
762
87.9k
    bool head_is_mpm = false;
763
87.9k
    uint8_t last_id = DE_STATE_FLAG_BASE;
764
765
131k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
766
43.4k
        SigMatchData *smd = SigMatchList2DataArray(s->init_data->buffers[x].head);
767
43.4k
        SCLogDebug("smd %p, id %u", smd, s->init_data->buffers[x].id);
768
769
43.4k
        const DetectBufferType *b =
770
43.4k
                DetectEngineBufferTypeGetById(de_ctx, s->init_data->buffers[x].id);
771
43.4k
        if (b == NULL)
772
0
            FatalError("unknown buffer");
773
774
43.4k
        if (b->frame) {
775
1.36k
            for (const DetectEngineFrameInspectionEngine *u = de_ctx->frame_inspect_engines;
776
9.96k
                    u != NULL; u = u->next) {
777
8.59k
                if (u->sm_list == s->init_data->buffers[x].id) {
778
2.72k
                    AppendFrameInspectEngine(de_ctx, u, s, smd, mpm_list);
779
2.72k
                }
780
8.59k
            }
781
42.0k
        } else if (b->packet) {
782
            /* set up pkt inspect engines */
783
8.10k
            for (const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines; e != NULL;
784
7.22k
                    e = e->next) {
785
7.22k
                SCLogDebug("e %p sm_list %u", e, e->sm_list);
786
7.22k
                if (e->sm_list == s->init_data->buffers[x].id) {
787
872
                    AppendPacketInspectEngine(de_ctx, e, s, smd, mpm_list);
788
872
                }
789
7.22k
            }
790
41.1k
        } else {
791
41.1k
            SCLogDebug("app %s id %u parent %u rule %u xforms %u", b->name, b->id, b->parent_id,
792
41.1k
                    s->init_data->buffers[x].id, b->transforms.cnt);
793
12.6M
            for (const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines; t != NULL;
794
12.6M
                    t = t->next) {
795
12.6M
                if (t->sm_list == s->init_data->buffers[x].id) {
796
196k
                    AppendAppInspectEngine(
797
196k
                            de_ctx, t, s, smd, mpm_list, files_id, &last_id, &head_is_mpm);
798
196k
                }
799
12.6M
            }
800
41.1k
        }
801
43.4k
    }
802
803
87.9k
    if ((s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) &&
804
35.6k
            s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
805
6.33k
    {
806
        /* if engine is added multiple times, we pass it the same list */
807
6.33k
        SigMatchData *stream = SigMatchList2DataArray(s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
808
6.33k
        BUG_ON(stream == NULL);
809
6.33k
        if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
810
2.22k
            AppendStreamInspectEngine(s, stream, 0, last_id + 1);
811
4.11k
        } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
812
273
            AppendStreamInspectEngine(s, stream, 1, last_id + 1);
813
3.84k
        } else {
814
3.84k
            AppendStreamInspectEngine(s, stream, 0, last_id + 1);
815
3.84k
            AppendStreamInspectEngine(s, stream, 1, last_id + 1);
816
3.84k
        }
817
818
6.33k
        if (s->init_data->init_flags & SIG_FLAG_INIT_NEED_FLUSH) {
819
1.96k
            SCLogDebug("set SIG_FLAG_FLUSH on %u", s->id);
820
1.96k
            s->flags |= SIG_FLAG_FLUSH;
821
1.96k
        }
822
6.33k
    }
823
824
#ifdef DEBUG
825
    const DetectEngineAppInspectionEngine *iter = s->app_inspect;
826
    while (iter) {
827
        SCLogDebug("%u: engine %s id %u progress %d %s", s->id,
828
                DetectEngineBufferTypeGetNameById(de_ctx, iter->sm_list), iter->id, iter->progress,
829
                iter->sm_list == mpm_list ? "MPM" : "");
830
        iter = iter->next;
831
    }
832
#endif
833
87.9k
    return 0;
834
87.9k
}
835
836
/** \brief free app inspect engines for a signature
837
 *
838
 *  For lists that are registered multiple times, like http_header and
839
 *  http_cookie, making the engines owner of the lists is complicated.
840
 *  Multiple engines in a sig may be pointing to the same list. To
841
 *  address this the 'free' code needs to be extra careful about not
842
 *  double freeing, so it takes an approach to first fill an array
843
 *  of the to-free pointers before freeing them.
844
 */
845
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
846
8.86M
{
847
8.86M
    int engines = 0;
848
849
8.86M
    DetectEngineAppInspectionEngine *ie = s->app_inspect;
850
9.22M
    while (ie) {
851
355k
        ie = ie->next;
852
355k
        engines++;
853
355k
    }
854
8.86M
    DetectEnginePktInspectionEngine *e = s->pkt_inspect;
855
8.98M
    while (e) {
856
121k
        e = e->next;
857
121k
        engines++;
858
121k
    }
859
8.86M
    DetectEngineFrameInspectionEngine *u = s->frame_inspect;
860
8.87M
    while (u) {
861
7.17k
        u = u->next;
862
7.17k
        engines++;
863
7.17k
    }
864
8.86M
    if (engines == 0) {
865
8.67M
        BUG_ON(s->pkt_inspect);
866
8.67M
        BUG_ON(s->frame_inspect);
867
8.67M
        return;
868
8.67M
    }
869
870
188k
    SigMatchData *bufs[engines];
871
188k
    memset(&bufs, 0, (engines * sizeof(SigMatchData *)));
872
188k
    int arrays = 0;
873
874
    /* free engines and put smd in the array */
875
188k
    ie = s->app_inspect;
876
543k
    while (ie) {
877
355k
        DetectEngineAppInspectionEngine *next = ie->next;
878
879
355k
        bool skip = false;
880
539k
        for (int i = 0; i < arrays; i++) {
881
422k
            if (bufs[i] == ie->smd) {
882
237k
                skip = true;
883
237k
                break;
884
237k
            }
885
422k
        }
886
355k
        if (!skip) {
887
117k
            bufs[arrays++] = ie->smd;
888
117k
        }
889
355k
        SCFree(ie);
890
355k
        ie = next;
891
355k
    }
892
188k
    e = s->pkt_inspect;
893
309k
    while (e) {
894
121k
        DetectEnginePktInspectionEngine *next = e->next;
895
896
121k
        bool skip = false;
897
151k
        for (int i = 0; i < arrays; i++) {
898
39.9k
            if (bufs[i] == e->smd) {
899
9.93k
                skip = true;
900
9.93k
                break;
901
9.93k
            }
902
39.9k
        }
903
121k
        if (!skip) {
904
111k
            bufs[arrays++] = e->smd;
905
111k
        }
906
121k
        SCFree(e);
907
121k
        e = next;
908
121k
    }
909
188k
    u = s->frame_inspect;
910
195k
    while (u) {
911
7.17k
        DetectEngineFrameInspectionEngine *next = u->next;
912
913
7.17k
        bool skip = false;
914
7.30k
        for (int i = 0; i < arrays; i++) {
915
2.33k
            if (bufs[i] == u->smd) {
916
2.21k
                skip = true;
917
2.21k
                break;
918
2.21k
            }
919
2.33k
        }
920
7.17k
        if (!skip) {
921
4.96k
            bufs[arrays++] = u->smd;
922
4.96k
        }
923
7.17k
        SCFree(u);
924
7.17k
        u = next;
925
7.17k
    }
926
927
672k
    for (int i = 0; i < engines; i++) {
928
483k
        if (bufs[i] == NULL)
929
359k
            continue;
930
124k
        SigMatchData *smd = bufs[i];
931
170k
        while (1) {
932
170k
            if (sigmatch_table[smd->type].Free != NULL) {
933
170k
                sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
934
170k
            }
935
170k
            if (smd->is_last)
936
124k
                break;
937
45.8k
            smd++;
938
45.8k
        }
939
124k
        SCFree(bufs[i]);
940
124k
    }
941
188k
}
942
943
/* code for registering buffers */
944
945
#include "util-hash-lookup3.h"
946
947
static HashListTable *g_buffer_type_hash = NULL;
948
static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START;
949
static int g_buffer_type_reg_closed = 0;
950
951
int DetectBufferTypeMaxId(void)
952
0
{
953
0
    return g_buffer_type_id;
954
0
}
955
956
static uint32_t DetectBufferTypeHashNameFunc(HashListTable *ht, void *data, uint16_t datalen)
957
9.58M
{
958
9.58M
    const DetectBufferType *map = (DetectBufferType *)data;
959
9.58M
    uint32_t hash = hashlittle_safe(map->name, strlen(map->name), 0);
960
9.58M
    hash += hashlittle_safe((uint8_t *)&map->transforms, sizeof(map->transforms), 0);
961
9.58M
    hash %= ht->array_size;
962
9.58M
    return hash;
963
9.58M
}
964
965
static uint32_t DetectBufferTypeHashIdFunc(HashListTable *ht, void *data, uint16_t datalen)
966
47.3M
{
967
47.3M
    const DetectBufferType *map = (DetectBufferType *)data;
968
47.3M
    uint32_t hash = map->id;
969
47.3M
    hash %= ht->array_size;
970
47.3M
    return hash;
971
47.3M
}
972
973
static char DetectBufferTypeCompareNameFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
974
566k
{
975
566k
    DetectBufferType *map1 = (DetectBufferType *)data1;
976
566k
    DetectBufferType *map2 = (DetectBufferType *)data2;
977
978
566k
    char r = (strcmp(map1->name, map2->name) == 0);
979
566k
    r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, sizeof(map2->transforms)) == 0);
980
566k
    return r;
981
566k
}
982
983
static char DetectBufferTypeCompareIdFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
984
8.37M
{
985
8.37M
    DetectBufferType *map1 = (DetectBufferType *)data1;
986
8.37M
    DetectBufferType *map2 = (DetectBufferType *)data2;
987
8.37M
    return map1->id == map2->id;
988
8.37M
}
989
990
static void DetectBufferTypeFreeFunc(void *data)
991
39.1M
{
992
39.1M
    DetectBufferType *map = (DetectBufferType *)data;
993
994
39.1M
    if (map == NULL) {
995
0
        return;
996
0
    }
997
998
    /* Release transformation option memory, if any */
999
39.2M
    for (int i = 0; i < map->transforms.cnt; i++) {
1000
131k
        if (map->transforms.transforms[i].options == NULL)
1001
43.1k
            continue;
1002
88.6k
        if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) {
1003
0
            SCLogError("%s allocates transform option memory but has no free routine",
1004
0
                    sigmatch_table[map->transforms.transforms[i].transform].name);
1005
0
            continue;
1006
0
        }
1007
88.6k
        sigmatch_table[map->transforms.transforms[i].transform].Free(NULL, map->transforms.transforms[i].options);
1008
88.6k
    }
1009
1010
39.1M
    SCFree(map);
1011
39.1M
}
1012
1013
static int DetectBufferTypeInit(void)
1014
73
{
1015
73
    BUG_ON(g_buffer_type_hash);
1016
73
    g_buffer_type_hash = HashListTableInit(256, DetectBufferTypeHashNameFunc,
1017
73
            DetectBufferTypeCompareNameFunc, DetectBufferTypeFreeFunc);
1018
73
    if (g_buffer_type_hash == NULL)
1019
0
        return -1;
1020
1021
73
    return 0;
1022
73
}
1023
#if 0
1024
static void DetectBufferTypeFree(void)
1025
{
1026
    if (g_buffer_type_hash == NULL)
1027
        return;
1028
1029
    HashListTableFree(g_buffer_type_hash);
1030
    g_buffer_type_hash = NULL;
1031
    return;
1032
}
1033
#endif
1034
static int DetectBufferTypeAdd(const char *string)
1035
20.5k
{
1036
20.5k
    BUG_ON(string == NULL || strlen(string) >= 32);
1037
1038
20.5k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1039
20.5k
    if (map == NULL)
1040
0
        return -1;
1041
1042
20.5k
    strlcpy(map->name, string, sizeof(map->name));
1043
20.5k
    map->id = g_buffer_type_id++;
1044
1045
20.5k
    BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0);
1046
20.5k
    SCLogDebug("buffer %s registered with id %d", map->name, map->id);
1047
20.5k
    return map->id;
1048
20.5k
}
1049
1050
static DetectBufferType *DetectBufferTypeLookupByName(const char *string)
1051
7.69M
{
1052
7.69M
    DetectBufferType map;
1053
7.69M
    memset(&map, 0, sizeof(map));
1054
7.69M
    strlcpy(map.name, string, sizeof(map.name));
1055
1056
7.69M
    DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0);
1057
7.69M
    return res;
1058
7.69M
}
1059
1060
int DetectBufferTypeRegister(const char *name)
1061
87.4k
{
1062
87.4k
    BUG_ON(g_buffer_type_reg_closed);
1063
87.4k
    if (g_buffer_type_hash == NULL)
1064
73
        DetectBufferTypeInit();
1065
1066
87.4k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1067
87.4k
    if (!exists) {
1068
20.5k
        return DetectBufferTypeAdd(name);
1069
66.9k
    } else {
1070
66.9k
        return exists->id;
1071
66.9k
    }
1072
87.4k
}
1073
1074
void DetectBufferTypeSupportsMultiInstance(const char *name)
1075
2.42k
{
1076
2.42k
    BUG_ON(g_buffer_type_reg_closed);
1077
2.42k
    DetectBufferTypeRegister(name);
1078
2.42k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1079
2.42k
    BUG_ON(!exists);
1080
2.42k
    exists->multi_instance = true;
1081
2.42k
    SCLogDebug("%p %s -- %d supports multi instance", exists, name, exists->id);
1082
2.42k
}
1083
1084
void DetectBufferTypeSupportsFrames(const char *name)
1085
0
{
1086
0
    BUG_ON(g_buffer_type_reg_closed);
1087
0
    DetectBufferTypeRegister(name);
1088
0
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1089
0
    BUG_ON(!exists);
1090
0
    exists->frame = true;
1091
0
    SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
1092
0
}
1093
1094
void DetectBufferTypeSupportsPacket(const char *name)
1095
584
{
1096
584
    BUG_ON(g_buffer_type_reg_closed);
1097
584
    DetectBufferTypeRegister(name);
1098
584
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1099
584
    BUG_ON(!exists);
1100
584
    exists->packet = true;
1101
584
    SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
1102
584
}
1103
1104
void DetectBufferTypeSupportsMpm(const char *name)
1105
21.2k
{
1106
21.2k
    BUG_ON(g_buffer_type_reg_closed);
1107
21.2k
    DetectBufferTypeRegister(name);
1108
21.2k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1109
21.2k
    BUG_ON(!exists);
1110
21.2k
    exists->mpm = true;
1111
21.2k
    SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
1112
21.2k
}
1113
1114
void DetectBufferTypeSupportsTransformations(const char *name)
1115
21.2k
{
1116
21.2k
    BUG_ON(g_buffer_type_reg_closed);
1117
21.2k
    DetectBufferTypeRegister(name);
1118
21.2k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1119
21.2k
    BUG_ON(!exists);
1120
21.2k
    exists->supports_transforms = true;
1121
21.2k
    SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
1122
21.2k
}
1123
1124
int DetectBufferTypeGetByName(const char *name)
1125
7.54M
{
1126
7.54M
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1127
7.54M
    if (!exists) {
1128
3.51M
        return -1;
1129
3.51M
    }
1130
4.03M
    return exists->id;
1131
7.54M
}
1132
1133
static DetectBufferType *DetectEngineBufferTypeLookupByName(
1134
        const DetectEngineCtx *de_ctx, const char *string)
1135
106k
{
1136
106k
    DetectBufferType map;
1137
106k
    memset(&map, 0, sizeof(map));
1138
106k
    strlcpy(map.name, string, sizeof(map.name));
1139
1140
106k
    DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &map, 0);
1141
106k
    return res;
1142
106k
}
1143
1144
const DetectBufferType *DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
1145
8.20M
{
1146
8.20M
    DetectBufferType lookup;
1147
8.20M
    memset(&lookup, 0, sizeof(lookup));
1148
8.20M
    lookup.id = id;
1149
8.20M
    const DetectBufferType *res =
1150
8.20M
            HashListTableLookup(de_ctx->buffer_type_hash_id, (void *)&lookup, 0);
1151
8.20M
    return res;
1152
8.20M
}
1153
1154
const char *DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
1155
46.4k
{
1156
46.4k
    const DetectBufferType *res = DetectEngineBufferTypeGetById(de_ctx, id);
1157
46.4k
    return res ? res->name : NULL;
1158
46.4k
}
1159
1160
static int DetectEngineBufferTypeAdd(DetectEngineCtx *de_ctx, const char *string)
1161
5.51k
{
1162
5.51k
    BUG_ON(string == NULL || strlen(string) >= 32);
1163
1164
5.51k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1165
5.51k
    if (map == NULL)
1166
0
        return -1;
1167
1168
5.51k
    strlcpy(map->name, string, sizeof(map->name));
1169
5.51k
    map->id = de_ctx->buffer_type_id++;
1170
1171
5.51k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)map, 0) != 0);
1172
5.51k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)map, 0) != 0);
1173
5.51k
    SCLogDebug("buffer %s registered with id %d", map->name, map->id);
1174
5.51k
    return map->id;
1175
5.51k
}
1176
1177
int DetectEngineBufferTypeRegisterWithFrameEngines(DetectEngineCtx *de_ctx, const char *name,
1178
        const int direction, const AppProto alproto, const uint8_t frame_type)
1179
51.5k
{
1180
51.5k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1181
51.5k
    if (exists) {
1182
46.0k
        return exists->id;
1183
46.0k
    }
1184
1185
5.51k
    const int buffer_id = DetectEngineBufferTypeAdd(de_ctx, name);
1186
5.51k
    if (buffer_id < 0) {
1187
0
        return -1;
1188
0
    }
1189
1190
    /* TODO hack we need the map to get the name. Should we return the map at reg? */
1191
5.51k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, buffer_id);
1192
5.51k
    BUG_ON(!map);
1193
1194
    /* register MPM/inspect engines */
1195
5.51k
    if (direction & SIG_FLAG_TOSERVER) {
1196
5.51k
        DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOSERVER, 2,
1197
5.51k
                PrefilterGenericMpmFrameRegister, alproto, frame_type);
1198
5.51k
        DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOSERVER,
1199
5.51k
                DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
1200
5.51k
    }
1201
5.51k
    if (direction & SIG_FLAG_TOCLIENT) {
1202
5.51k
        DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT, 2,
1203
5.51k
                PrefilterGenericMpmFrameRegister, alproto, frame_type);
1204
5.51k
        DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT,
1205
5.51k
                DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
1206
5.51k
    }
1207
1208
5.51k
    return buffer_id;
1209
5.51k
}
1210
1211
int DetectEngineBufferTypeRegister(DetectEngineCtx *de_ctx, const char *name)
1212
22.0k
{
1213
22.0k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1214
22.0k
    if (!exists) {
1215
0
        return DetectEngineBufferTypeAdd(de_ctx, name);
1216
22.0k
    } else {
1217
22.0k
        return exists->id;
1218
22.0k
    }
1219
22.0k
}
1220
1221
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
1222
8.76k
{
1223
8.76k
    BUG_ON(desc == NULL || strlen(desc) >= 128);
1224
1225
8.76k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1226
8.76k
    if (!exists) {
1227
73
        return;
1228
73
    }
1229
8.69k
    strlcpy(exists->description, desc, sizeof(exists->description));
1230
8.69k
}
1231
1232
const char *DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
1233
1.43k
{
1234
1.43k
    const DetectBufferType *exists = DetectEngineBufferTypeGetById(de_ctx, id);
1235
1.43k
    if (!exists) {
1236
0
        return NULL;
1237
0
    }
1238
1.43k
    return exists->description;
1239
1.43k
}
1240
1241
const char *DetectBufferTypeGetDescriptionByName(const char *name)
1242
0
{
1243
0
    const DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1244
0
    if (!exists) {
1245
0
        return NULL;
1246
0
    }
1247
0
    return exists->description;
1248
0
}
1249
1250
void DetectEngineBufferTypeSupportsFrames(DetectEngineCtx *de_ctx, const char *name)
1251
11.0k
{
1252
11.0k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1253
11.0k
    BUG_ON(!exists);
1254
11.0k
    exists->frame = true;
1255
11.0k
    SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
1256
11.0k
}
1257
1258
void DetectEngineBufferTypeSupportsPacket(DetectEngineCtx *de_ctx, const char *name)
1259
0
{
1260
0
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1261
0
    BUG_ON(!exists);
1262
0
    exists->packet = true;
1263
0
    SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
1264
0
}
1265
1266
void DetectEngineBufferTypeSupportsMpm(DetectEngineCtx *de_ctx, const char *name)
1267
11.0k
{
1268
11.0k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1269
11.0k
    BUG_ON(!exists);
1270
11.0k
    exists->mpm = true;
1271
11.0k
    SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
1272
11.0k
}
1273
1274
void DetectEngineBufferTypeSupportsTransformations(DetectEngineCtx *de_ctx, const char *name)
1275
11.0k
{
1276
11.0k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1277
11.0k
    BUG_ON(!exists);
1278
11.0k
    exists->supports_transforms = true;
1279
11.0k
    SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
1280
11.0k
}
1281
1282
bool DetectEngineBufferTypeSupportsMultiInstanceGetById(const DetectEngineCtx *de_ctx, const int id)
1283
844k
{
1284
844k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1285
844k
    if (map == NULL)
1286
0
        return false;
1287
844k
    SCLogDebug("map %p id %d multi_instance? %s", map, id, BOOL2STR(map->multi_instance));
1288
844k
    return map->multi_instance;
1289
844k
}
1290
1291
bool DetectEngineBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id)
1292
848k
{
1293
848k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1294
848k
    if (map == NULL)
1295
0
        return false;
1296
848k
    SCLogDebug("map %p id %d packet? %d", map, id, map->packet);
1297
848k
    return map->packet;
1298
848k
}
1299
1300
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
1301
1.05M
{
1302
1.05M
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1303
1.05M
    if (map == NULL)
1304
343k
        return false;
1305
711k
    SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm);
1306
711k
    return map->mpm;
1307
1.05M
}
1308
1309
bool DetectEngineBufferTypeSupportsFramesGetById(const DetectEngineCtx *de_ctx, const int id)
1310
835k
{
1311
835k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1312
835k
    if (map == NULL)
1313
0
        return false;
1314
835k
    SCLogDebug("map %p id %d frame? %d", map, id, map->frame);
1315
835k
    return map->frame;
1316
835k
}
1317
1318
void DetectBufferTypeRegisterSetupCallback(const char *name,
1319
        void (*SetupCallback)(const DetectEngineCtx *, Signature *))
1320
842
{
1321
842
    BUG_ON(g_buffer_type_reg_closed);
1322
842
    DetectBufferTypeRegister(name);
1323
842
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1324
842
    BUG_ON(!exists);
1325
842
    exists->SetupCallback = SetupCallback;
1326
842
}
1327
1328
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
1329
1.98M
{
1330
1.98M
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1331
1.98M
    if (map && map->SetupCallback) {
1332
202k
        map->SetupCallback(de_ctx, s);
1333
202k
    }
1334
1.98M
}
1335
1336
void DetectBufferTypeRegisterValidateCallback(const char *name,
1337
        bool (*ValidateCallback)(const Signature *, const char **sigerror))
1338
1.10k
{
1339
1.10k
    BUG_ON(g_buffer_type_reg_closed);
1340
1.10k
    DetectBufferTypeRegister(name);
1341
1.10k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1342
1.10k
    BUG_ON(!exists);
1343
1.10k
    exists->ValidateCallback = ValidateCallback;
1344
1.10k
}
1345
1346
bool DetectEngineBufferRunValidateCallback(
1347
        const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
1348
297k
{
1349
297k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1350
297k
    if (map && map->ValidateCallback) {
1351
85.1k
        return map->ValidateCallback(s, sigerror);
1352
85.1k
    }
1353
212k
    return true;
1354
297k
}
1355
1356
SigMatch *DetectBufferGetFirstSigMatch(const Signature *s, const uint32_t buf_id)
1357
0
{
1358
0
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
1359
0
        if (buf_id == s->init_data->buffers[i].id) {
1360
0
            return s->init_data->buffers[i].head;
1361
0
        }
1362
0
    }
1363
0
    return NULL;
1364
0
}
1365
1366
SigMatch *DetectBufferGetLastSigMatch(const Signature *s, const uint32_t buf_id)
1367
0
{
1368
0
    SigMatch *last = NULL;
1369
0
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
1370
0
        if (buf_id == s->init_data->buffers[i].id) {
1371
0
            last = s->init_data->buffers[i].tail;
1372
0
        }
1373
0
    }
1374
0
    return last;
1375
0
}
1376
1377
bool DetectBufferIsPresent(const Signature *s, const uint32_t buf_id)
1378
175k
{
1379
261k
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
1380
86.3k
        if (buf_id == s->init_data->buffers[i].id) {
1381
496
            return true;
1382
496
        }
1383
86.3k
    }
1384
174k
    return false;
1385
175k
}
1386
1387
int DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int list)
1388
258k
{
1389
258k
    BUG_ON(s->init_data == NULL);
1390
1391
258k
    if (s->init_data->list == DETECT_SM_LIST_BASE64_DATA) {
1392
2
        SCLogError("Rule buffer cannot be reset after base64_data.");
1393
2
        return -1;
1394
2
    }
1395
1396
258k
    if (s->init_data->list && s->init_data->transforms.cnt) {
1397
1.79k
        SCLogError("no matches following transform(s)");
1398
1.79k
        return -1;
1399
1.79k
    }
1400
256k
    s->init_data->list = list;
1401
256k
    s->init_data->list_set = true;
1402
1403
    // check if last has matches -> if no, error
1404
256k
    if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
1405
996
        SCLogError("previous sticky buffer has no matches");
1406
996
        return -1;
1407
996
    }
1408
1409
2.23M
    for (uint32_t x = 0; x < s->init_data->buffers_size; x++) {
1410
1.99M
        SignatureInitDataBuffer *b = &s->init_data->buffers[x];
1411
2.34M
        for (SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
1412
347k
            SCLogDebug(
1413
347k
                    "buf:%p: id:%u: '%s' pos %u", b, b->id, sigmatch_table[sm->type].name, sm->idx);
1414
347k
        }
1415
1.99M
        if ((uint32_t)list == b->id) {
1416
49.3k
            SCLogDebug("found buffer %p for list %d", b, list);
1417
49.3k
            if (s->init_data->buffers[x].sm_init) {
1418
107
                s->init_data->buffers[x].sm_init = false;
1419
107
                SCLogDebug("sm_init was true for %p list %d", b, list);
1420
107
                s->init_data->curbuf = b;
1421
107
                return 0;
1422
1423
49.2k
            } else if (DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, list)) {
1424
                // fall through
1425
35.9k
            } else {
1426
13.3k
                SCLogWarning("duplicate instance for %s in '%s'",
1427
13.3k
                        DetectEngineBufferTypeGetNameById(de_ctx, list), s->sig_str);
1428
13.3k
                s->init_data->curbuf = b;
1429
13.3k
                return 0;
1430
13.3k
            }
1431
49.3k
        }
1432
1.99M
    }
1433
1434
241k
    if (list < DETECT_SM_LIST_MAX)
1435
0
        return 0;
1436
1437
241k
    if (SignatureInitDataBufferCheckExpand(s) < 0) {
1438
2
        SCLogError("failed to expand rule buffer array");
1439
2
        return -1;
1440
2
    }
1441
1442
    /* initialize new buffer */
1443
241k
    s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
1444
241k
    s->init_data->curbuf->id = list;
1445
241k
    s->init_data->curbuf->head = NULL;
1446
241k
    s->init_data->curbuf->tail = NULL;
1447
241k
    s->init_data->curbuf->multi_capable =
1448
241k
            DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, list);
1449
241k
    SCLogDebug("new: idx %u list %d set up curbuf %p", s->init_data->buffer_index - 1, list,
1450
241k
            s->init_data->curbuf);
1451
1452
241k
    return 0;
1453
241k
}
1454
1455
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
1456
1.38M
{
1457
1.38M
    BUG_ON(s->init_data == NULL);
1458
1459
1.38M
    if (s->init_data->list && s->init_data->transforms.cnt) {
1460
145k
        if (s->init_data->list == DETECT_SM_LIST_NOTSET ||
1461
145k
            s->init_data->list < DETECT_SM_LIST_DYNAMIC_START) {
1462
18
            SCLogError("previous transforms not consumed "
1463
18
                       "(list: %u, transform_cnt %u)",
1464
18
                    s->init_data->list, s->init_data->transforms.cnt);
1465
18
            SCReturnInt(-1);
1466
18
        }
1467
1468
145k
        SCLogDebug("buffer %d has transform(s) registered: %d",
1469
145k
                s->init_data->list, s->init_data->transforms.cnt);
1470
145k
        int new_list = DetectEngineBufferTypeGetByIdTransforms(de_ctx, s->init_data->list,
1471
145k
                s->init_data->transforms.transforms, s->init_data->transforms.cnt);
1472
145k
        if (new_list == -1) {
1473
0
            SCReturnInt(-1);
1474
0
        }
1475
145k
        int base_list = s->init_data->list;
1476
145k
        SCLogDebug("new_list %d", new_list);
1477
145k
        s->init_data->list = new_list;
1478
145k
        s->init_data->list_set = false;
1479
        // reset transforms now that we've set up the list
1480
145k
        s->init_data->transforms.cnt = 0;
1481
1482
145k
        if (s->init_data->curbuf && s->init_data->curbuf->head != NULL) {
1483
7.63k
            if (SignatureInitDataBufferCheckExpand(s) < 0) {
1484
4
                SCLogError("failed to expand rule buffer array");
1485
4
                return -1;
1486
4
            }
1487
7.63k
            s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++];
1488
7.63k
            s->init_data->curbuf->multi_capable =
1489
7.63k
                    DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, base_list);
1490
7.63k
        }
1491
145k
        if (s->init_data->curbuf == NULL) {
1492
0
            SCLogError("failed to setup buffer");
1493
0
            DEBUG_VALIDATE_BUG_ON(1);
1494
0
            SCReturnInt(-1);
1495
0
        }
1496
145k
        s->init_data->curbuf->id = new_list;
1497
145k
        SCLogDebug("new list after applying transforms: %u", new_list);
1498
145k
    }
1499
1500
1.38M
    SCReturnInt(0);
1501
1.38M
}
1502
1503
void InspectionBufferClean(DetectEngineThreadCtx *det_ctx)
1504
79.5M
{
1505
    /* single buffers */
1506
79.7M
    for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++)
1507
205k
    {
1508
205k
        const uint32_t idx = det_ctx->inspect.to_clear_queue[i];
1509
205k
        InspectionBuffer *buffer = &det_ctx->inspect.buffers[idx];
1510
205k
        buffer->inspect = NULL;
1511
205k
        buffer->initialized = false;
1512
205k
    }
1513
79.5M
    det_ctx->inspect.to_clear_idx = 0;
1514
1515
    /* multi buffers */
1516
79.8M
    for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++)
1517
360k
    {
1518
360k
        const uint32_t idx = det_ctx->multi_inspect.to_clear_queue[i];
1519
360k
        InspectionBufferMultipleForList *mbuffer = &det_ctx->multi_inspect.buffers[idx];
1520
815k
        for (uint32_t x = 0; x <= mbuffer->max; x++) {
1521
454k
            InspectionBuffer *buffer = &mbuffer->inspection_buffers[x];
1522
454k
            buffer->inspect = NULL;
1523
454k
            buffer->initialized = false;
1524
454k
        }
1525
360k
        mbuffer->init = 0;
1526
360k
        mbuffer->max = 0;
1527
360k
    }
1528
79.5M
    det_ctx->multi_inspect.to_clear_idx = 0;
1529
79.5M
}
1530
1531
InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
1532
547k
{
1533
547k
    return &det_ctx->inspect.buffers[list_id];
1534
547k
}
1535
1536
static InspectionBufferMultipleForList *InspectionBufferGetMulti(
1537
        DetectEngineThreadCtx *det_ctx, const int list_id)
1538
79.7k
{
1539
79.7k
    InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
1540
79.7k
    if (!buffer->init) {
1541
60.3k
        det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
1542
60.3k
        buffer->init = 1;
1543
60.3k
    }
1544
79.7k
    return buffer;
1545
79.7k
}
1546
1547
/** \brief for a InspectionBufferMultipleForList get a InspectionBuffer
1548
 *  \param fb the multiple buffer array
1549
 *  \param local_id the index to get a buffer
1550
 *  \param buffer the inspect buffer or NULL in case of error */
1551
InspectionBuffer *InspectionBufferMultipleForListGet(
1552
        DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
1553
495k
{
1554
495k
    if (unlikely(local_id >= 1024)) {
1555
0
        DetectEngineSetEvent(det_ctx, DETECT_EVENT_TOO_MANY_BUFFERS);
1556
0
        return NULL;
1557
0
    }
1558
1559
495k
    InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
1560
1561
495k
    if (local_id >= fb->size) {
1562
7.24k
        uint32_t old_size = fb->size;
1563
7.24k
        uint32_t new_size = local_id + 1;
1564
7.24k
        uint32_t grow_by = new_size - old_size;
1565
7.24k
        SCLogDebug("size is %u, need %u, so growing by %u", old_size, new_size, grow_by);
1566
1567
7.24k
        SCLogDebug("fb->inspection_buffers %p", fb->inspection_buffers);
1568
7.24k
        void *ptr = SCRealloc(fb->inspection_buffers, (local_id + 1) * sizeof(InspectionBuffer));
1569
7.24k
        if (ptr == NULL)
1570
0
            return NULL;
1571
1572
7.24k
        InspectionBuffer *to_zero = (InspectionBuffer *)ptr + old_size;
1573
7.24k
        SCLogDebug("ptr %p to_zero %p", ptr, to_zero);
1574
7.24k
        memset((uint8_t *)to_zero, 0, (grow_by * sizeof(InspectionBuffer)));
1575
7.24k
        fb->inspection_buffers = ptr;
1576
7.24k
        fb->size = new_size;
1577
7.24k
    }
1578
1579
495k
    fb->max = MAX(fb->max, local_id);
1580
495k
    InspectionBuffer *buffer = &fb->inspection_buffers[local_id];
1581
495k
    SCLogDebug("using buffer %p", buffer);
1582
495k
#ifdef DEBUG_VALIDATION
1583
495k
    buffer->multi = true;
1584
495k
#endif
1585
495k
    return buffer;
1586
495k
}
1587
1588
void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
1589
0
{
1590
0
    memset(buffer, 0, sizeof(*buffer));
1591
0
    buffer->buf = SCCalloc(initial_size, sizeof(uint8_t));
1592
0
    if (buffer->buf != NULL) {
1593
0
        buffer->size = initial_size;
1594
0
    }
1595
0
}
1596
1597
/** \brief setup the buffer empty */
1598
void InspectionBufferSetupMultiEmpty(InspectionBuffer *buffer)
1599
302k
{
1600
302k
#ifdef DEBUG_VALIDATION
1601
302k
    DEBUG_VALIDATE_BUG_ON(buffer->initialized);
1602
302k
    DEBUG_VALIDATE_BUG_ON(!buffer->multi);
1603
302k
#endif
1604
302k
    buffer->inspect = NULL;
1605
302k
    buffer->inspect_len = 0;
1606
302k
    buffer->len = 0;
1607
302k
    buffer->initialized = true;
1608
302k
}
1609
1610
/** \brief setup the buffer with our initial data */
1611
void InspectionBufferSetupMulti(InspectionBuffer *buffer, const DetectEngineTransforms *transforms,
1612
        const uint8_t *data, const uint32_t data_len)
1613
152k
{
1614
152k
#ifdef DEBUG_VALIDATION
1615
152k
    DEBUG_VALIDATE_BUG_ON(!buffer->multi);
1616
152k
#endif
1617
152k
    buffer->inspect = buffer->orig = data;
1618
152k
    buffer->inspect_len = buffer->orig_len = data_len;
1619
152k
    buffer->len = 0;
1620
152k
    buffer->initialized = true;
1621
1622
152k
    InspectionBufferApplyTransforms(buffer, transforms);
1623
152k
}
1624
1625
/** \brief setup the buffer with our initial data */
1626
void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
1627
        InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
1628
69.9k
{
1629
69.9k
#ifdef DEBUG_VALIDATION
1630
69.9k
    DEBUG_VALIDATE_BUG_ON(buffer->multi);
1631
69.9k
    DEBUG_VALIDATE_BUG_ON(buffer != InspectionBufferGet(det_ctx, list_id));
1632
69.9k
#endif
1633
69.9k
    if (buffer->inspect == NULL) {
1634
#ifdef UNITTESTS
1635
        if (det_ctx && list_id != -1)
1636
#endif
1637
69.9k
            det_ctx->inspect.to_clear_queue[det_ctx->inspect.to_clear_idx++] = list_id;
1638
69.9k
    }
1639
69.9k
    buffer->inspect = buffer->orig = data;
1640
69.9k
    buffer->inspect_len = buffer->orig_len = data_len;
1641
69.9k
    buffer->len = 0;
1642
69.9k
    buffer->initialized = true;
1643
69.9k
}
1644
1645
void InspectionBufferFree(InspectionBuffer *buffer)
1646
40.0M
{
1647
40.0M
    if (buffer->buf != NULL) {
1648
1.34k
        SCFree(buffer->buf);
1649
1.34k
    }
1650
40.0M
    memset(buffer, 0, sizeof(*buffer));
1651
40.0M
}
1652
1653
/**
1654
 * \brief make sure that the buffer has at least 'min_size' bytes
1655
 * Expand the buffer if necessary
1656
 *
1657
 * \retval pointer to inner buffer to use, or NULL if realloc failed
1658
 */
1659
uint8_t *InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
1660
2.60k
{
1661
2.60k
    if (likely(buffer->size >= min_size))
1662
2.21k
        return buffer->buf;
1663
1664
389
    uint32_t new_size = (buffer->size == 0) ? 4096 : buffer->size;
1665
421
    while (new_size < min_size) {
1666
32
        new_size *= 2;
1667
32
    }
1668
1669
389
    void *ptr = SCRealloc(buffer->buf, new_size);
1670
389
    if (ptr != NULL) {
1671
389
        buffer->buf = ptr;
1672
389
        buffer->size = new_size;
1673
389
    } else {
1674
0
        return NULL;
1675
0
    }
1676
389
    return buffer->buf;
1677
389
}
1678
1679
/**
1680
 * \brief set inspect length of inspect buffer
1681
 * The inspect buffer may have been overallocated (by strip_whitespace for example)
1682
 * so, this sets the final length
1683
 */
1684
void InspectionBufferTruncate(InspectionBuffer *buffer, uint32_t buf_len)
1685
2.12k
{
1686
2.12k
    DEBUG_VALIDATE_BUG_ON(buffer->buf == NULL);
1687
2.12k
    DEBUG_VALIDATE_BUG_ON(buf_len > buffer->size);
1688
2.12k
    buffer->inspect = buffer->buf;
1689
2.12k
    buffer->inspect_len = buf_len;
1690
2.12k
    buffer->initialized = true;
1691
2.12k
}
1692
1693
void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len)
1694
470
{
1695
470
    InspectionBufferCheckAndExpand(buffer, buf_len);
1696
1697
470
    if (buffer->size) {
1698
470
        uint32_t copy_size = MIN(buf_len, buffer->size);
1699
470
        memcpy(buffer->buf, buf, copy_size);
1700
470
        buffer->inspect = buffer->buf;
1701
470
        buffer->inspect_len = copy_size;
1702
470
        buffer->initialized = true;
1703
470
    }
1704
470
}
1705
1706
/** \brief Check content byte array compatibility with transforms
1707
 *
1708
 *  The "content" array is presented to the transforms so that each
1709
 *  transform may validate that it's compatible with the transform.
1710
 *
1711
 *  When a transform indicates the byte array is incompatible, none of the
1712
 *  subsequent transforms, if any, are invoked. This means the first validation
1713
 *  failure terminates the loop.
1714
 *
1715
 *  \param de_ctx Detection engine context.
1716
 *  \param sm_list The SM list id.
1717
 *  \param content The byte array being validated
1718
 *  \param namestr returns the name of the transform that is incompatible with
1719
 *  content.
1720
 *
1721
 *  \retval true (false) If any of the transforms indicate the byte array is
1722
 *  (is not) compatible.
1723
 **/
1724
bool DetectEngineBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list,
1725
        const uint8_t *content, uint16_t content_len, const char **namestr)
1726
433k
{
1727
433k
    const DetectBufferType *dbt = DetectEngineBufferTypeGetById(de_ctx, sm_list);
1728
433k
    BUG_ON(dbt == NULL);
1729
1730
611k
    for (int i = 0; i < dbt->transforms.cnt; i++) {
1731
184k
        const TransformData *t = &dbt->transforms.transforms[i];
1732
184k
        if (!sigmatch_table[t->transform].TransformValidate)
1733
132k
            continue;
1734
1735
51.6k
        if (sigmatch_table[t->transform].TransformValidate(content, content_len, t->options)) {
1736
44.7k
            continue;
1737
44.7k
        }
1738
1739
6.92k
        if (namestr) {
1740
6.92k
            *namestr = sigmatch_table[t->transform].name;
1741
6.92k
        }
1742
1743
6.92k
        return false;
1744
51.6k
    }
1745
1746
426k
    return true;
1747
433k
}
1748
1749
void InspectionBufferApplyTransforms(InspectionBuffer *buffer,
1750
        const DetectEngineTransforms *transforms)
1751
101k
{
1752
101k
    if (transforms) {
1753
67.4k
        for (int i = 0; i < DETECT_TRANSFORMS_MAX; i++) {
1754
67.4k
            const int id = transforms->transforms[i].transform;
1755
67.4k
            if (id == 0)
1756
64.1k
                break;
1757
3.33k
            BUG_ON(sigmatch_table[id].Transform == NULL);
1758
3.33k
            sigmatch_table[id].Transform(buffer, transforms->transforms[i].options);
1759
3.33k
            SCLogDebug("applied transform %s", sigmatch_table[id].name);
1760
3.33k
        }
1761
64.1k
    }
1762
101k
}
1763
1764
static void DetectBufferTypeSetupDetectEngine(DetectEngineCtx *de_ctx)
1765
140k
{
1766
140k
    const int size = g_buffer_type_id;
1767
140k
    BUG_ON(!(size > 0));
1768
1769
140k
    de_ctx->buffer_type_hash_name = HashListTableInit(256, DetectBufferTypeHashNameFunc,
1770
140k
            DetectBufferTypeCompareNameFunc, DetectBufferTypeFreeFunc);
1771
140k
    BUG_ON(de_ctx->buffer_type_hash_name == NULL);
1772
140k
    de_ctx->buffer_type_hash_id =
1773
140k
            HashListTableInit(256, DetectBufferTypeHashIdFunc, DetectBufferTypeCompareIdFunc,
1774
140k
                    NULL); // entries owned by buffer_type_hash_name
1775
140k
    BUG_ON(de_ctx->buffer_type_hash_id == NULL);
1776
140k
    de_ctx->buffer_type_id = g_buffer_type_id;
1777
1778
140k
    SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START);
1779
140k
    HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash);
1780
39.1M
    while (b) {
1781
39.0M
        DetectBufferType *map = HashListTableGetListData(b);
1782
1783
39.0M
        DetectBufferType *copy = SCCalloc(1, sizeof(*copy));
1784
39.0M
        BUG_ON(!copy);
1785
39.0M
        memcpy(copy, map, sizeof(*copy));
1786
39.0M
        int r = HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)copy, 0);
1787
39.0M
        BUG_ON(r != 0);
1788
39.0M
        r = HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)copy, 0);
1789
39.0M
        BUG_ON(r != 0);
1790
1791
39.0M
        SCLogDebug("name %s id %d mpm %s packet %s -- %s. "
1792
39.0M
                   "Callbacks: Setup %p Validate %p",
1793
39.0M
                map->name, map->id, map->mpm ? "true" : "false", map->packet ? "true" : "false",
1794
39.0M
                map->description, map->SetupCallback, map->ValidateCallback);
1795
39.0M
        b = HashListTableGetListNext(b);
1796
39.0M
    }
1797
1798
140k
    PrefilterInit(de_ctx);
1799
140k
    DetectMpmInitializeAppMpms(de_ctx);
1800
140k
    DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
1801
140k
    DetectMpmInitializeFrameMpms(de_ctx);
1802
140k
    DetectFrameInspectEngineCopyListToDetectCtx(de_ctx);
1803
140k
    DetectMpmInitializePktMpms(de_ctx);
1804
140k
    DetectPktInspectEngineCopyListToDetectCtx(de_ctx);
1805
140k
}
1806
1807
static void DetectBufferTypeFreeDetectEngine(DetectEngineCtx *de_ctx)
1808
140k
{
1809
140k
    if (de_ctx) {
1810
140k
        if (de_ctx->buffer_type_hash_name)
1811
140k
            HashListTableFree(de_ctx->buffer_type_hash_name);
1812
140k
        if (de_ctx->buffer_type_hash_id)
1813
140k
            HashListTableFree(de_ctx->buffer_type_hash_id);
1814
1815
140k
        DetectEngineAppInspectionEngine *ilist = de_ctx->app_inspect_engines;
1816
67.7M
        while (ilist) {
1817
67.6M
            DetectEngineAppInspectionEngine *next = ilist->next;
1818
67.6M
            SCFree(ilist);
1819
67.6M
            ilist = next;
1820
67.6M
        }
1821
140k
        DetectBufferMpmRegistry *mlist = de_ctx->app_mpms_list;
1822
40.3M
        while (mlist) {
1823
40.2M
            DetectBufferMpmRegistry *next = mlist->next;
1824
40.2M
            SCFree(mlist);
1825
40.2M
            mlist = next;
1826
40.2M
        }
1827
140k
        DetectEnginePktInspectionEngine *plist = de_ctx->pkt_inspect_engines;
1828
1.26M
        while (plist) {
1829
1.12M
            DetectEnginePktInspectionEngine *next = plist->next;
1830
1.12M
            SCFree(plist);
1831
1.12M
            plist = next;
1832
1.12M
        }
1833
140k
        DetectBufferMpmRegistry *pmlist = de_ctx->pkt_mpms_list;
1834
1.26M
        while (pmlist) {
1835
1.12M
            DetectBufferMpmRegistry *next = pmlist->next;
1836
1.12M
            SCFree(pmlist);
1837
1.12M
            pmlist = next;
1838
1.12M
        }
1839
140k
        DetectEngineFrameInspectionEngine *framelist = de_ctx->frame_inspect_engines;
1840
152k
        while (framelist) {
1841
11.9k
            DetectEngineFrameInspectionEngine *next = framelist->next;
1842
11.9k
            SCFree(framelist);
1843
11.9k
            framelist = next;
1844
11.9k
        }
1845
140k
        DetectBufferMpmRegistry *framemlist = de_ctx->frame_mpms_list;
1846
152k
        while (framemlist) {
1847
11.9k
            DetectBufferMpmRegistry *next = framemlist->next;
1848
11.9k
            SCFree(framemlist);
1849
11.9k
            framemlist = next;
1850
11.9k
        }
1851
140k
        PrefilterDeinit(de_ctx);
1852
140k
    }
1853
140k
}
1854
1855
void DetectBufferTypeCloseRegistration(void)
1856
73
{
1857
73
    BUG_ON(g_buffer_type_hash == NULL);
1858
1859
73
    g_buffer_type_reg_closed = 1;
1860
73
}
1861
1862
int DetectEngineBufferTypeGetByIdTransforms(
1863
        DetectEngineCtx *de_ctx, const int id, TransformData *transforms, int transform_cnt)
1864
44.8k
{
1865
44.8k
    const DetectBufferType *base_map = DetectEngineBufferTypeGetById(de_ctx, id);
1866
44.8k
    if (!base_map) {
1867
0
        return -1;
1868
0
    }
1869
44.8k
    if (!base_map->supports_transforms) {
1870
0
        SCLogError("buffer '%s' does not support transformations", base_map->name);
1871
0
        return -1;
1872
0
    }
1873
1874
44.8k
    SCLogDebug("base_map %s", base_map->name);
1875
1876
44.8k
    DetectEngineTransforms t;
1877
44.8k
    memset(&t, 0, sizeof(t));
1878
101k
    for (int i = 0; i < transform_cnt; i++) {
1879
57.0k
        t.transforms[i] = transforms[i];
1880
57.0k
    }
1881
44.8k
    t.cnt = transform_cnt;
1882
1883
44.8k
    DetectBufferType lookup_map;
1884
44.8k
    memset(&lookup_map, 0, sizeof(lookup_map));
1885
44.8k
    strlcpy(lookup_map.name, base_map->name, sizeof(lookup_map.name));
1886
44.8k
    lookup_map.transforms = t;
1887
44.8k
    DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &lookup_map, 0);
1888
1889
44.8k
    SCLogDebug("res %p", res);
1890
44.8k
    if (res != NULL) {
1891
16.5k
        return res->id;
1892
16.5k
    }
1893
1894
28.3k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1895
28.3k
    if (map == NULL)
1896
0
        return -1;
1897
1898
28.3k
    strlcpy(map->name, base_map->name, sizeof(map->name));
1899
28.3k
    map->id = de_ctx->buffer_type_id++;
1900
28.3k
    map->parent_id = base_map->id;
1901
28.3k
    map->transforms = t;
1902
28.3k
    map->mpm = base_map->mpm;
1903
28.3k
    map->packet = base_map->packet;
1904
28.3k
    map->frame = base_map->frame;
1905
28.3k
    map->SetupCallback = base_map->SetupCallback;
1906
28.3k
    map->ValidateCallback = base_map->ValidateCallback;
1907
28.3k
    if (map->frame) {
1908
103
        DetectFrameMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms);
1909
28.2k
    } else if (map->packet) {
1910
429
        DetectPktMpmRegisterByParentId(de_ctx,
1911
429
                map->id, map->parent_id, &map->transforms);
1912
27.8k
    } else {
1913
27.8k
        DetectAppLayerMpmRegisterByParentId(de_ctx,
1914
27.8k
                map->id, map->parent_id, &map->transforms);
1915
27.8k
    }
1916
1917
28.3k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)map, 0) != 0);
1918
28.3k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)map, 0) != 0);
1919
28.3k
    SCLogDebug("buffer %s registered with id %d, parent %d", map->name, map->id, map->parent_id);
1920
1921
28.3k
    if (map->frame) {
1922
103
        DetectFrameInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1923
28.2k
    } else if (map->packet) {
1924
429
        DetectPktInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1925
27.8k
    } else {
1926
27.8k
        DetectAppLayerInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1927
27.8k
    }
1928
28.3k
    return map->id;
1929
28.3k
}
1930
1931
/* returns false if no match, true if match */
1932
static int DetectEngineInspectRulePacketMatches(
1933
    DetectEngineThreadCtx *det_ctx,
1934
    const DetectEnginePktInspectionEngine *engine,
1935
    const Signature *s,
1936
    Packet *p, uint8_t *_alert_flags)
1937
1.69M
{
1938
1.69M
    SCEnter();
1939
1940
    /* run the packet match functions */
1941
1.69M
    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
1942
1.69M
    const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
1943
1944
1.69M
    SCLogDebug("running match functions, sm %p", smd);
1945
1.75M
    while (1) {
1946
1.75M
        KEYWORD_PROFILING_START;
1947
1.75M
        if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) <= 0) {
1948
1.13M
            KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
1949
1.13M
            SCLogDebug("no match");
1950
1.13M
            return false;
1951
1.13M
        }
1952
621k
        KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
1953
621k
        if (smd->is_last) {
1954
560k
            SCLogDebug("match and is_last");
1955
560k
            break;
1956
560k
        }
1957
61.6k
        smd++;
1958
61.6k
    }
1959
560k
    return true;
1960
1.69M
}
1961
1962
static int DetectEngineInspectRulePayloadMatches(
1963
     DetectEngineThreadCtx *det_ctx,
1964
     const DetectEnginePktInspectionEngine *engine,
1965
     const Signature *s, Packet *p, uint8_t *alert_flags)
1966
534k
{
1967
534k
    SCEnter();
1968
1969
534k
    DetectEngineCtx *de_ctx = det_ctx->de_ctx;
1970
1971
534k
    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH);
1972
    /* if we have stream msgs, inspect against those first,
1973
     * but not for a "dsize" signature */
1974
534k
    if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1975
421k
        int pmatch = 0;
1976
421k
        if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
1977
55.9k
            pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, p);
1978
55.9k
            if (pmatch) {
1979
35.8k
                det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH;
1980
35.8k
                *alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
1981
35.8k
            }
1982
55.9k
        }
1983
        /* no match? then inspect packet payload */
1984
421k
        if (pmatch == 0) {
1985
385k
            SCLogDebug("no match in stream, fall back to packet payload");
1986
1987
            /* skip if we don't have to inspect the packet and segment was
1988
             * added to stream */
1989
385k
            if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
1990
305k
                return false;
1991
305k
            }
1992
79.9k
            if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1993
28.2k
                return false;
1994
28.2k
            }
1995
79.9k
        }
1996
421k
    } else {
1997
112k
        if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1998
37.8k
            return false;
1999
37.8k
        }
2000
112k
    }
2001
162k
    return true;
2002
534k
}
2003
2004
bool DetectEnginePktInspectionRun(ThreadVars *tv,
2005
        DetectEngineThreadCtx *det_ctx, const Signature *s,
2006
        Flow *f, Packet *p,
2007
        uint8_t *alert_flags)
2008
1.83M
{
2009
1.83M
    SCEnter();
2010
2011
2.39M
    for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) {
2012
1.54M
        if (e->v1.Callback(det_ctx, e, s, p, alert_flags) == false) {
2013
977k
            SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
2014
977k
            return false;
2015
977k
        }
2016
563k
        SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
2017
563k
    }
2018
2019
857k
    SCLogDebug("sid %u: returning true", s->id);
2020
857k
    return true;
2021
1.83M
}
2022
2023
/**
2024
 * \param data pointer to SigMatchData. Allowed to be NULL.
2025
 */
2026
static int DetectEnginePktInspectionAppend(Signature *s, InspectionBufferPktInspectFunc Callback,
2027
        SigMatchData *data, const int list_id)
2028
119k
{
2029
119k
    DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e));
2030
119k
    if (e == NULL)
2031
0
        return -1;
2032
2033
119k
    e->mpm = s->init_data->mpm_sm_list == list_id;
2034
119k
    DEBUG_VALIDATE_BUG_ON(list_id < 0 || list_id > UINT16_MAX);
2035
119k
    e->sm_list = (uint16_t)list_id;
2036
119k
    e->sm_list_base = (uint16_t)list_id;
2037
119k
    e->v1.Callback = Callback;
2038
119k
    e->smd = data;
2039
2040
119k
    if (s->pkt_inspect == NULL) {
2041
108k
        s->pkt_inspect = e;
2042
108k
    } else {
2043
10.6k
        DetectEnginePktInspectionEngine *a = s->pkt_inspect;
2044
11.0k
        while (a->next != NULL) {
2045
403
            a = a->next;
2046
403
        }
2047
10.6k
        a->next = e;
2048
10.6k
    }
2049
119k
    return 0;
2050
119k
}
2051
2052
int DetectEnginePktInspectionSetup(Signature *s)
2053
212k
{
2054
    /* only handle PMATCH here if we're not an app inspect rule */
2055
212k
    if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) {
2056
44.6k
        if (DetectEnginePktInspectionAppend(
2057
44.6k
                    s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0)
2058
0
            return -1;
2059
44.6k
        SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
2060
44.6k
    }
2061
2062
212k
    if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
2063
74.4k
        if (DetectEnginePktInspectionAppend(
2064
74.4k
                    s, DetectEngineInspectRulePacketMatches, NULL, DETECT_SM_LIST_MATCH) < 0)
2065
0
            return -1;
2066
74.4k
        SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
2067
74.4k
    }
2068
2069
212k
    return 0;
2070
212k
}
2071
2072
/* code to control the main thread to do a reload */
2073
2074
enum DetectEngineSyncState {
2075
    IDLE,   /**< ready to start a reload */
2076
    RELOAD, /**< command main thread to do the reload */
2077
};
2078
2079
2080
typedef struct DetectEngineSyncer_ {
2081
    SCMutex m;
2082
    enum DetectEngineSyncState state;
2083
} DetectEngineSyncer;
2084
2085
static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE };
2086
2087
/* tell main to start reloading */
2088
int DetectEngineReloadStart(void)
2089
0
{
2090
0
    int r = 0;
2091
0
    SCMutexLock(&detect_sync.m);
2092
0
    if (detect_sync.state == IDLE) {
2093
0
        detect_sync.state = RELOAD;
2094
0
    } else {
2095
0
        r = -1;
2096
0
    }
2097
0
    SCMutexUnlock(&detect_sync.m);
2098
0
    return r;
2099
0
}
2100
2101
/* main thread checks this to see if it should start */
2102
int DetectEngineReloadIsStart(void)
2103
0
{
2104
0
    int r = 0;
2105
0
    SCMutexLock(&detect_sync.m);
2106
0
    if (detect_sync.state == RELOAD) {
2107
0
        r = 1;
2108
0
    }
2109
0
    SCMutexUnlock(&detect_sync.m);
2110
0
    return r;
2111
0
}
2112
2113
/* main thread sets done when it's done */
2114
void DetectEngineReloadSetIdle(void)
2115
0
{
2116
0
    SCMutexLock(&detect_sync.m);
2117
0
    detect_sync.state = IDLE;
2118
0
    SCMutexUnlock(&detect_sync.m);
2119
0
}
2120
2121
/* caller loops this until it returns 1 */
2122
int DetectEngineReloadIsIdle(void)
2123
0
{
2124
0
    int r = 0;
2125
0
    SCMutexLock(&detect_sync.m);
2126
0
    if (detect_sync.state == IDLE) {
2127
0
        r = 1;
2128
0
    }
2129
0
    SCMutexUnlock(&detect_sync.m);
2130
0
    return r;
2131
0
}
2132
2133
/** \brief Do the content inspection & validation for a signature
2134
 *
2135
 *  \param de_ctx Detection engine context
2136
 *  \param det_ctx Detection engine thread context
2137
 *  \param s Signature to inspect
2138
 *  \param sm SigMatch to inspect
2139
 *  \param f Flow
2140
 *  \param flags app layer flags
2141
 *  \param state App layer state
2142
 *
2143
 *  \retval 0 no match
2144
 *  \retval 1 match
2145
 */
2146
uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2147
        const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
2148
        uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
2149
100k
{
2150
100k
    SigMatchData *smd = engine->smd;
2151
100k
    SCLogDebug("running match functions, sm %p", smd);
2152
100k
    if (smd != NULL) {
2153
101k
        while (1) {
2154
101k
            int match = 0;
2155
101k
            KEYWORD_PROFILING_START;
2156
101k
            match = sigmatch_table[smd->type].
2157
101k
                AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx);
2158
101k
            KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1));
2159
101k
            if (match == 0)
2160
77.9k
                return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2161
23.4k
            if (match == 2) {
2162
0
                return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
2163
0
            }
2164
2165
23.4k
            if (smd->is_last)
2166
22.8k
                break;
2167
624
            smd++;
2168
624
        }
2169
100k
    }
2170
2171
22.8k
    return DETECT_ENGINE_INSPECT_SIG_MATCH;
2172
100k
}
2173
2174
2175
/**
2176
 * \brief Do the content inspection & validation for a signature
2177
 *
2178
 * \param de_ctx Detection engine context
2179
 * \param det_ctx Detection engine thread context
2180
 * \param s Signature to inspect
2181
 * \param f Flow
2182
 * \param flags app layer flags
2183
 * \param state App layer state
2184
 *
2185
 * \retval 0 no match.
2186
 * \retval 1 match.
2187
 * \retval 2 Sig can't match.
2188
 */
2189
uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2190
        const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags,
2191
        void *alstate, void *txv, uint64_t tx_id)
2192
24.6k
{
2193
24.6k
    const int list_id = engine->sm_list;
2194
24.6k
    SCLogDebug("running inspect on %d", list_id);
2195
2196
24.6k
    const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
2197
2198
24.6k
    SCLogDebug("list %d mpm? %s transforms %p",
2199
24.6k
            engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms);
2200
2201
    /* if prefilter didn't already run, we need to consider transformations */
2202
24.6k
    const DetectEngineTransforms *transforms = NULL;
2203
24.6k
    if (!engine->mpm) {
2204
1.91k
        transforms = engine->v2.transforms;
2205
1.91k
    }
2206
2207
24.6k
    const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms,
2208
24.6k
            f, flags, txv, list_id);
2209
24.6k
    if (unlikely(buffer == NULL)) {
2210
11.5k
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
2211
11.5k
                     DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2212
11.5k
    }
2213
2214
13.0k
    const uint32_t data_len = buffer->inspect_len;
2215
13.0k
    const uint8_t *data = buffer->inspect;
2216
13.0k
    const uint64_t offset = buffer->inspect_offset;
2217
2218
13.0k
    uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
2219
13.0k
    ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
2220
13.0k
    ci_flags |= buffer->flags;
2221
2222
13.0k
    det_ctx->discontinue_matching = 0;
2223
13.0k
    det_ctx->buffer_offset = 0;
2224
13.0k
    det_ctx->inspection_recursion_counter = 0;
2225
2226
    /* Inspect all the uricontents fetched on each
2227
     * transaction at the app layer */
2228
13.0k
    int r = DetectEngineContentInspection(de_ctx, det_ctx,
2229
13.0k
                                          s, engine->smd,
2230
13.0k
                                          NULL, f,
2231
13.0k
                                          (uint8_t *)data, data_len, offset, ci_flags,
2232
13.0k
                                          DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
2233
13.0k
    if (r == 1) {
2234
11.8k
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
2235
11.8k
    } else {
2236
1.22k
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
2237
1.22k
                     DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2238
1.22k
    }
2239
13.0k
}
2240
2241
/**
2242
 * \brief Do the content inspection & validation for a signature
2243
 *
2244
 * \param de_ctx Detection engine context
2245
 * \param det_ctx Detection engine thread context
2246
 * \param s Signature to inspect
2247
 * \param p Packet
2248
 *
2249
 * \retval 0 no match.
2250
 * \retval 1 match.
2251
 */
2252
int DetectEngineInspectPktBufferGeneric(
2253
        DetectEngineThreadCtx *det_ctx,
2254
        const DetectEnginePktInspectionEngine *engine,
2255
        const Signature *s, Packet *p, uint8_t *_alert_flags)
2256
34.4k
{
2257
34.4k
    const int list_id = engine->sm_list;
2258
34.4k
    SCLogDebug("running inspect on %d", list_id);
2259
2260
34.4k
    SCLogDebug("list %d transforms %p",
2261
34.4k
            engine->sm_list, engine->v1.transforms);
2262
2263
    /* if prefilter didn't already run, we need to consider transformations */
2264
34.4k
    const DetectEngineTransforms *transforms = NULL;
2265
34.4k
    if (!engine->mpm) {
2266
20.1k
        transforms = engine->v1.transforms;
2267
20.1k
    }
2268
2269
34.4k
    const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p,
2270
34.4k
            list_id);
2271
34.4k
    if (unlikely(buffer == NULL)) {
2272
1.83k
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2273
1.83k
    }
2274
2275
32.5k
    const uint32_t data_len = buffer->inspect_len;
2276
32.5k
    const uint8_t *data = buffer->inspect;
2277
32.5k
    const uint64_t offset = 0;
2278
2279
32.5k
    uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END;
2280
32.5k
    ci_flags |= buffer->flags;
2281
2282
32.5k
    det_ctx->discontinue_matching = 0;
2283
32.5k
    det_ctx->buffer_offset = 0;
2284
32.5k
    det_ctx->inspection_recursion_counter = 0;
2285
2286
    /* Inspect all the uricontents fetched on each
2287
     * transaction at the app layer */
2288
32.5k
    int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx,
2289
32.5k
                                          s, engine->smd,
2290
32.5k
                                          p, p->flow,
2291
32.5k
                                          (uint8_t *)data, data_len, offset, ci_flags,
2292
32.5k
                                          DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER);
2293
32.5k
    if (r == 1) {
2294
12.0k
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
2295
20.4k
    } else {
2296
20.4k
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2297
20.4k
    }
2298
32.5k
}
2299
2300
/** \internal
2301
 *  \brief inject a pseudo packet into each detect thread that doesn't use the
2302
 *         new det_ctx yet
2303
 */
2304
static void InjectPackets(ThreadVars **detect_tvs,
2305
                          DetectEngineThreadCtx **new_det_ctx,
2306
                          int no_of_detect_tvs)
2307
0
{
2308
    /* inject a fake packet if the detect thread isn't using the new ctx yet,
2309
     * this speeds up the process */
2310
0
    for (int i = 0; i < no_of_detect_tvs; i++) {
2311
0
        if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
2312
0
            if (detect_tvs[i]->inq != NULL) {
2313
0
                Packet *p = PacketGetFromAlloc();
2314
0
                if (p != NULL) {
2315
0
                    p->flags |= PKT_PSEUDO_STREAM_END;
2316
0
                    PKT_SET_SRC(p, PKT_SRC_DETECT_RELOAD_FLUSH);
2317
0
                    PacketQueue *q = detect_tvs[i]->inq->pq;
2318
0
                    SCMutexLock(&q->mutex_q);
2319
0
                    PacketEnqueue(q, p);
2320
0
                    SCCondSignal(&q->cond_q);
2321
0
                    SCMutexUnlock(&q->mutex_q);
2322
0
                }
2323
0
            }
2324
0
        }
2325
0
    }
2326
0
}
2327
2328
/** \internal
2329
 *  \brief Update detect threads with new detect engine
2330
 *
2331
 *  Atomically update each detect thread with a new thread context
2332
 *  that is associated to the new detection engine(s).
2333
 *
2334
 *  If called in unix socket mode, it's possible that we don't have
2335
 *  detect threads yet.
2336
 *
2337
 *  \retval -1 error
2338
 *  \retval 0 no detection threads
2339
 *  \retval 1 successful reload
2340
 */
2341
static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
2342
140k
{
2343
140k
    SCEnter();
2344
140k
    uint32_t i = 0;
2345
2346
    /* count detect threads in use */
2347
140k
    uint32_t no_of_detect_tvs = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM);
2348
    /* can be zero in unix socket mode */
2349
140k
    if (no_of_detect_tvs == 0) {
2350
140k
        return 0;
2351
140k
    }
2352
2353
    /* prepare swap structures */
2354
0
    DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
2355
0
    DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
2356
0
    ThreadVars *detect_tvs[no_of_detect_tvs];
2357
0
    memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
2358
0
    memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
2359
0
    memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
2360
2361
    /* start the process of swapping detect threads ctxs */
2362
2363
    /* get reference to tv's and setup new_det_ctx array */
2364
0
    SCMutexLock(&tv_root_lock);
2365
0
    for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2366
0
        if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
2367
0
            continue;
2368
0
        }
2369
0
        for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
2370
0
            TmModule *tm = TmModuleGetById(s->tm_id);
2371
0
            if (!(tm->flags & TM_FLAG_DETECT_TM)) {
2372
0
                continue;
2373
0
            }
2374
2375
0
            if (suricata_ctl_flags != 0) {
2376
0
                SCMutexUnlock(&tv_root_lock);
2377
0
                goto error;
2378
0
            }
2379
2380
0
            old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(s->slot_data));
2381
0
            detect_tvs[i] = tv;
2382
2383
0
            new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
2384
0
            if (new_det_ctx[i] == NULL) {
2385
0
                SCLogError("Detect engine thread init "
2386
0
                           "failure in live rule swap.  Let's get out of here");
2387
0
                SCMutexUnlock(&tv_root_lock);
2388
0
                goto error;
2389
0
            }
2390
0
            SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
2391
0
                       "- %p\n", new_det_ctx[i], new_de_ctx);
2392
0
            i++;
2393
0
            break;
2394
0
        }
2395
0
    }
2396
0
    BUG_ON(i != no_of_detect_tvs);
2397
2398
    /* atomically replace the det_ctx data */
2399
0
    i = 0;
2400
0
    for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2401
0
        if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
2402
0
            continue;
2403
0
        }
2404
0
        for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
2405
0
            TmModule *tm = TmModuleGetById(s->tm_id);
2406
0
            if (!(tm->flags & TM_FLAG_DETECT_TM)) {
2407
0
                continue;
2408
0
            }
2409
0
            SCLogDebug("swapping new det_ctx - %p with older one - %p",
2410
0
                       new_det_ctx[i], SC_ATOMIC_GET(s->slot_data));
2411
0
            FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]);
2412
0
            break;
2413
0
        }
2414
0
    }
2415
0
    SCMutexUnlock(&tv_root_lock);
2416
2417
    /* threads now all have new data, however they may not have started using
2418
     * it and may still use the old data */
2419
2420
0
    SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
2421
0
               "along with the new de_ctx", no_of_detect_tvs);
2422
2423
0
    InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
2424
2425
    /* loop waiting for detect threads to switch to the new det_ctx. Try to
2426
     * wake up capture if needed (break loop). */
2427
0
    uint32_t threads_done = 0;
2428
0
retry:
2429
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2430
0
        if (suricata_ctl_flags != 0) {
2431
0
            threads_done = no_of_detect_tvs;
2432
0
            break;
2433
0
        }
2434
0
        usleep(1000);
2435
0
        if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) == 1) {
2436
0
            SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
2437
0
            threads_done++;
2438
0
        } else {
2439
0
            TmThreadsCaptureBreakLoop(detect_tvs[i]);
2440
0
        }
2441
0
    }
2442
0
    if (threads_done < no_of_detect_tvs) {
2443
0
        threads_done = 0;
2444
0
        SleepMsec(250);
2445
0
        goto retry;
2446
0
    }
2447
2448
    /* this is to make sure that if someone initiated shutdown during a live
2449
     * rule swap, the live rule swap won't clean up the old det_ctx and
2450
     * de_ctx, till all detect threads have stopped working and sitting
2451
     * silently after setting RUNNING_DONE flag and while waiting for
2452
     * THV_DEINIT flag */
2453
0
    if (i != no_of_detect_tvs) { // not all threads we swapped
2454
0
        for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2455
0
            if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
2456
0
                continue;
2457
0
            }
2458
2459
0
            while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
2460
0
                usleep(100);
2461
0
            }
2462
0
        }
2463
0
    }
2464
2465
    /* free all the ctxs */
2466
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2467
0
        SCLogDebug("Freeing old_det_ctx - %p used by detect",
2468
0
                   old_det_ctx[i]);
2469
0
        DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
2470
0
    }
2471
2472
0
    SRepReloadComplete();
2473
2474
0
    return 1;
2475
2476
0
 error:
2477
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2478
0
        if (new_det_ctx[i] != NULL)
2479
0
            DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
2480
0
    }
2481
0
    return -1;
2482
0
}
2483
2484
static DetectEngineCtx *DetectEngineCtxInitReal(enum DetectEngineType type, const char *prefix)
2485
67.5k
{
2486
67.5k
    DetectEngineCtx *de_ctx = SCMalloc(sizeof(DetectEngineCtx));
2487
67.5k
    if (unlikely(de_ctx == NULL))
2488
0
        goto error;
2489
2490
67.5k
    memset(de_ctx,0,sizeof(DetectEngineCtx));
2491
67.5k
    memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
2492
67.5k
    TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
2493
67.5k
    de_ctx->sigerror = NULL;
2494
67.5k
    de_ctx->type = type;
2495
67.5k
    de_ctx->filemagic_thread_ctx_id = -1;
2496
2497
67.5k
    if (type == DETECT_ENGINE_TYPE_DD_STUB || type == DETECT_ENGINE_TYPE_MT_STUB) {
2498
0
        de_ctx->version = DetectEngineGetVersion();
2499
0
        SCLogDebug("stub %u with version %u", type, de_ctx->version);
2500
0
        return de_ctx;
2501
0
    }
2502
2503
67.5k
    if (prefix != NULL) {
2504
0
        strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
2505
0
    }
2506
2507
67.5k
    int failure_fatal = 0;
2508
67.5k
    if (ConfGetBool("engine.init-failure-fatal", (int *)&failure_fatal) != 1) {
2509
67.5k
        SCLogDebug("ConfGetBool could not load the value.");
2510
67.5k
    }
2511
67.5k
    de_ctx->failure_fatal = (failure_fatal == 1);
2512
2513
67.5k
    de_ctx->mpm_matcher = PatternMatchDefaultMatcher();
2514
67.5k
    de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher();
2515
67.5k
    SCLogConfig("pattern matchers: MPM: %s, SPM: %s",
2516
67.5k
        mpm_table[de_ctx->mpm_matcher].name,
2517
67.5k
        spm_table[de_ctx->spm_matcher].name);
2518
2519
67.5k
    de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher);
2520
67.5k
    if (de_ctx->spm_global_thread_ctx == NULL) {
2521
0
        SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
2522
0
        goto error;
2523
0
    }
2524
2525
67.5k
    if (DetectEngineCtxLoadConf(de_ctx) == -1) {
2526
0
        goto error;
2527
0
    }
2528
2529
67.5k
    SigGroupHeadHashInit(de_ctx);
2530
67.5k
    MpmStoreInit(de_ctx);
2531
67.5k
    ThresholdHashInit(de_ctx);
2532
67.5k
    DetectParseDupSigHashInit(de_ctx);
2533
67.5k
    DetectAddressMapInit(de_ctx);
2534
67.5k
    DetectMetadataHashInit(de_ctx);
2535
67.5k
    DetectBufferTypeSetupDetectEngine(de_ctx);
2536
67.5k
    DetectEngineInitializeFastPatternList(de_ctx);
2537
2538
    /* init iprep... ignore errors for now */
2539
67.5k
    (void)SRepInit(de_ctx);
2540
2541
67.5k
    SCClassConfInit(de_ctx);
2542
67.5k
    if (!SCClassConfLoadClassificationConfigFile(de_ctx, NULL)) {
2543
67.5k
        if (RunmodeGetCurrent() == RUNMODE_CONF_TEST)
2544
0
            goto error;
2545
67.5k
    }
2546
2547
67.5k
    if (ActionInitConfig() < 0) {
2548
0
        goto error;
2549
0
    }
2550
67.5k
    SCReferenceConfInit(de_ctx);
2551
67.5k
    if (SCRConfLoadReferenceConfigFile(de_ctx, NULL) < 0) {
2552
67.5k
        if (RunmodeGetCurrent() == RUNMODE_CONF_TEST)
2553
0
            goto error;
2554
67.5k
    }
2555
2556
67.5k
    de_ctx->version = DetectEngineGetVersion();
2557
67.5k
    SCLogDebug("dectx with version %u", de_ctx->version);
2558
67.5k
    return de_ctx;
2559
0
error:
2560
0
    if (de_ctx != NULL) {
2561
0
        DetectEngineCtxFree(de_ctx);
2562
0
    }
2563
0
    return NULL;
2564
2565
67.5k
}
2566
2567
DetectEngineCtx *DetectEngineCtxInitStubForMT(void)
2568
0
{
2569
0
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL);
2570
0
}
2571
2572
DetectEngineCtx *DetectEngineCtxInitStubForDD(void)
2573
0
{
2574
0
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL);
2575
0
}
2576
2577
DetectEngineCtx *DetectEngineCtxInit(void)
2578
140k
{
2579
140k
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL);
2580
140k
}
2581
2582
DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix)
2583
140k
{
2584
140k
    if (prefix == NULL || strlen(prefix) == 0)
2585
140k
        return DetectEngineCtxInit();
2586
0
    else
2587
0
        return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix);
2588
140k
}
2589
2590
static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
2591
140k
{
2592
140k
    HashListTableFree(de_ctx->keyword_hash);
2593
140k
}
2594
2595
static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
2596
140k
{
2597
140k
    SigString *item = NULL;
2598
140k
    SigString *sitem;
2599
2600
8.31M
    TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
2601
8.31M
        SCFree(item->filename);
2602
8.31M
        SCFree(item->sig_str);
2603
8.31M
        if (item->sig_error) {
2604
17.0k
            SCFree(item->sig_error);
2605
17.0k
        }
2606
8.31M
        TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
2607
8.31M
        SCFree(item);
2608
8.31M
    }
2609
140k
}
2610
2611
/**
2612
 * \brief Free a DetectEngineCtx::
2613
 *
2614
 * \param de_ctx DetectEngineCtx:: to be freed
2615
 */
2616
void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
2617
67.5k
{
2618
2619
67.5k
    if (de_ctx == NULL)
2620
0
        return;
2621
2622
#ifdef PROFILE_RULES
2623
    if (de_ctx->profile_ctx != NULL) {
2624
        SCProfilingRuleDestroyCtx(de_ctx->profile_ctx);
2625
        de_ctx->profile_ctx = NULL;
2626
    }
2627
#endif
2628
#ifdef PROFILING
2629
    if (de_ctx->profile_keyword_ctx != NULL) {
2630
        SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
2631
//        de_ctx->profile_keyword_ctx = NULL;
2632
    }
2633
    if (de_ctx->profile_sgh_ctx != NULL) {
2634
        SCProfilingSghDestroyCtx(de_ctx);
2635
    }
2636
    SCProfilingPrefilterDestroyCtx(de_ctx);
2637
#endif
2638
2639
    /* Normally the hashes are freed elsewhere, but
2640
     * to be sure look at them again here.
2641
     */
2642
67.5k
    SigGroupHeadHashFree(de_ctx);
2643
67.5k
    MpmStoreFree(de_ctx);
2644
67.5k
    DetectParseDupSigHashFree(de_ctx);
2645
67.5k
    SCSigSignatureOrderingModuleCleanup(de_ctx);
2646
67.5k
    ThresholdContextDestroy(de_ctx);
2647
67.5k
    SigCleanSignatures(de_ctx);
2648
67.5k
    if (de_ctx->sig_array)
2649
67.5k
        SCFree(de_ctx->sig_array);
2650
2651
67.5k
    DetectEngineFreeFastPatternList(de_ctx);
2652
67.5k
    SCClassConfDeInitContext(de_ctx);
2653
67.5k
    SCRConfDeInitContext(de_ctx);
2654
2655
67.5k
    SigGroupCleanup(de_ctx);
2656
2657
67.5k
    SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx);
2658
2659
67.5k
    MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx);
2660
2661
67.5k
    DetectEngineCtxFreeThreadKeywordData(de_ctx);
2662
67.5k
    SRepDestroy(de_ctx);
2663
67.5k
    DetectEngineCtxFreeFailedSigs(de_ctx);
2664
2665
67.5k
    DetectAddressMapFree(de_ctx);
2666
67.5k
    DetectMetadataHashFree(de_ctx);
2667
2668
    /* if we have a config prefix, remove the config from the tree */
2669
67.5k
    if (strlen(de_ctx->config_prefix) > 0) {
2670
        /* remove config */
2671
0
        ConfNode *node = ConfGetNode(de_ctx->config_prefix);
2672
0
        if (node != NULL) {
2673
0
            ConfNodeRemove(node); /* frees node */
2674
0
        }
2675
#if 0
2676
        ConfDump();
2677
#endif
2678
0
    }
2679
2680
67.5k
    DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
2681
67.5k
    DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
2682
2683
67.5k
    DetectBufferTypeFreeDetectEngine(de_ctx);
2684
67.5k
    SCClassConfDeinit(de_ctx);
2685
67.5k
    SCReferenceConfDeinit(de_ctx);
2686
2687
67.5k
    if (de_ctx->tenant_path) {
2688
0
        SCFree(de_ctx->tenant_path);
2689
0
    }
2690
2691
67.5k
    if (de_ctx->requirements) {
2692
883
        SCDetectRequiresStatusFree(de_ctx->requirements);
2693
883
    }
2694
2695
67.5k
    SCFree(de_ctx);
2696
    //DetectAddressGroupPrintMemory();
2697
    //DetectSigGroupPrintMemory();
2698
    //DetectPortPrintMemory();
2699
67.5k
}
2700
2701
/** \brief  Function that load DetectEngineCtx config for grouping sigs
2702
 *          used by the engine
2703
 *  \retval 0 if no config provided, 1 if config was provided
2704
 *          and loaded successfully
2705
 */
2706
static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
2707
67.5k
{
2708
67.5k
    uint8_t profile = ENGINE_PROFILE_MEDIUM;
2709
67.5k
    const char *max_uniq_toclient_groups_str = NULL;
2710
67.5k
    const char *max_uniq_toserver_groups_str = NULL;
2711
67.5k
    const char *sgh_mpm_context = NULL;
2712
67.5k
    const char *de_ctx_profile = NULL;
2713
2714
67.5k
    (void)ConfGet("detect.profile", &de_ctx_profile);
2715
67.5k
    (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
2716
2717
67.5k
    ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
2718
67.5k
    ConfNode *opt = NULL;
2719
2720
67.5k
    if (de_ctx_custom != NULL) {
2721
0
        TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2722
0
            if (de_ctx_profile == NULL) {
2723
0
                if (opt->val && strcmp(opt->val, "profile") == 0) {
2724
0
                    de_ctx_profile = opt->head.tqh_first->val;
2725
0
                }
2726
0
            }
2727
2728
0
            if (sgh_mpm_context == NULL) {
2729
0
                if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
2730
0
                    sgh_mpm_context = opt->head.tqh_first->val;
2731
0
                }
2732
0
            }
2733
0
        }
2734
0
    }
2735
2736
67.5k
    if (de_ctx_profile != NULL) {
2737
0
        if (strcmp(de_ctx_profile, "low") == 0 ||
2738
0
            strcmp(de_ctx_profile, "lowest") == 0) {        // legacy
2739
0
            profile = ENGINE_PROFILE_LOW;
2740
0
        } else if (strcmp(de_ctx_profile, "medium") == 0) {
2741
0
            profile = ENGINE_PROFILE_MEDIUM;
2742
0
        } else if (strcmp(de_ctx_profile, "high") == 0 ||
2743
0
                   strcmp(de_ctx_profile, "highest") == 0) { // legacy
2744
0
            profile = ENGINE_PROFILE_HIGH;
2745
0
        } else if (strcmp(de_ctx_profile, "custom") == 0) {
2746
0
            profile = ENGINE_PROFILE_CUSTOM;
2747
0
        } else {
2748
0
            SCLogError("invalid value for detect.profile: '%s'. "
2749
0
                       "Valid options: low, medium, high and custom.",
2750
0
                    de_ctx_profile);
2751
0
            return -1;
2752
0
        }
2753
2754
0
        SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
2755
67.5k
    } else {
2756
67.5k
        SCLogDebug("Profile for detection engine groups not provided "
2757
67.5k
                   "at suricata.yaml. Using default (\"medium\").");
2758
67.5k
    }
2759
2760
    /* detect-engine.sgh-mpm-context option parsing */
2761
67.5k
    if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
2762
        /* for now, since we still haven't implemented any intelligence into
2763
         * understanding the patterns and distributing mpm_ctx across sgh */
2764
67.5k
        if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_KS ||
2765
#ifdef BUILD_HYPERSCAN
2766
            de_ctx->mpm_matcher == MPM_HS ||
2767
#endif
2768
67.5k
            de_ctx->mpm_matcher == MPM_AC_BS) {
2769
67.5k
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2770
67.5k
        } else {
2771
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2772
0
        }
2773
67.5k
    } else {
2774
0
        if (strcmp(sgh_mpm_context, "single") == 0) {
2775
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2776
0
        } else if (strcmp(sgh_mpm_context, "full") == 0) {
2777
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2778
0
        } else {
2779
0
            SCLogError("You have supplied an "
2780
0
                       "invalid conf value for detect-engine.sgh-mpm-context-"
2781
0
                       "%s",
2782
0
                    sgh_mpm_context);
2783
0
            exit(EXIT_FAILURE);
2784
0
        }
2785
0
    }
2786
2787
67.5k
    if (run_mode == RUNMODE_UNITTEST) {
2788
29
        de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2789
29
    }
2790
2791
    /* parse profile custom-values */
2792
67.5k
    opt = NULL;
2793
67.5k
    switch (profile) {
2794
0
        case ENGINE_PROFILE_LOW:
2795
0
            de_ctx->max_uniq_toclient_groups = 15;
2796
0
            de_ctx->max_uniq_toserver_groups = 25;
2797
0
            break;
2798
2799
0
        case ENGINE_PROFILE_HIGH:
2800
0
            de_ctx->max_uniq_toclient_groups = 75;
2801
0
            de_ctx->max_uniq_toserver_groups = 75;
2802
0
            break;
2803
2804
0
        case ENGINE_PROFILE_CUSTOM:
2805
0
            (void)ConfGet("detect.custom-values.toclient-groups",
2806
0
                    &max_uniq_toclient_groups_str);
2807
0
            (void)ConfGet("detect.custom-values.toserver-groups",
2808
0
                    &max_uniq_toserver_groups_str);
2809
2810
0
            if (de_ctx_custom != NULL) {
2811
0
                TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2812
0
                    if (opt->val && strcmp(opt->val, "custom-values") == 0) {
2813
0
                        if (max_uniq_toclient_groups_str == NULL) {
2814
0
                            max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2815
0
                                (opt->head.tqh_first, "toclient-sp-groups");
2816
0
                        }
2817
0
                        if (max_uniq_toclient_groups_str == NULL) {
2818
0
                            max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2819
0
                                (opt->head.tqh_first, "toclient-groups");
2820
0
                        }
2821
0
                        if (max_uniq_toserver_groups_str == NULL) {
2822
0
                            max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2823
0
                                (opt->head.tqh_first, "toserver-dp-groups");
2824
0
                        }
2825
0
                        if (max_uniq_toserver_groups_str == NULL) {
2826
0
                            max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2827
0
                                (opt->head.tqh_first, "toserver-groups");
2828
0
                        }
2829
0
                    }
2830
0
                }
2831
0
            }
2832
0
            if (max_uniq_toclient_groups_str != NULL) {
2833
0
                if (StringParseUint16(&de_ctx->max_uniq_toclient_groups, 10,
2834
0
                            (uint16_t)strlen(max_uniq_toclient_groups_str),
2835
0
                            (const char *)max_uniq_toclient_groups_str) <= 0) {
2836
0
                    de_ctx->max_uniq_toclient_groups = 20;
2837
2838
0
                    SCLogWarning("parsing '%s' for "
2839
0
                                 "toclient-groups failed, using %u",
2840
0
                            max_uniq_toclient_groups_str, de_ctx->max_uniq_toclient_groups);
2841
0
                }
2842
0
            } else {
2843
0
                de_ctx->max_uniq_toclient_groups = 20;
2844
0
            }
2845
0
            SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
2846
2847
0
            if (max_uniq_toserver_groups_str != NULL) {
2848
0
                if (StringParseUint16(&de_ctx->max_uniq_toserver_groups, 10,
2849
0
                            (uint16_t)strlen(max_uniq_toserver_groups_str),
2850
0
                            (const char *)max_uniq_toserver_groups_str) <= 0) {
2851
0
                    de_ctx->max_uniq_toserver_groups = 40;
2852
2853
0
                    SCLogWarning("parsing '%s' for "
2854
0
                                 "toserver-groups failed, using %u",
2855
0
                            max_uniq_toserver_groups_str, de_ctx->max_uniq_toserver_groups);
2856
0
                }
2857
0
            } else {
2858
0
                de_ctx->max_uniq_toserver_groups = 40;
2859
0
            }
2860
0
            SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
2861
0
            break;
2862
2863
        /* Default (or no config provided) is profile medium */
2864
67.5k
        case ENGINE_PROFILE_MEDIUM:
2865
67.5k
        case ENGINE_PROFILE_UNKNOWN:
2866
67.5k
        default:
2867
67.5k
            de_ctx->max_uniq_toclient_groups = 20;
2868
67.5k
            de_ctx->max_uniq_toserver_groups = 40;
2869
67.5k
            break;
2870
67.5k
    }
2871
2872
67.5k
    intmax_t value = 0;
2873
67.5k
    de_ctx->inspection_recursion_limit = DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
2874
67.5k
    if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1)
2875
67.5k
    {
2876
67.5k
        if (value >= 0 && value <= INT_MAX) {
2877
67.5k
            de_ctx->inspection_recursion_limit = (int)value;
2878
67.5k
        }
2879
2880
    /* fall back to old config parsing */
2881
67.5k
    } else {
2882
29
        ConfNode *insp_recursion_limit_node = NULL;
2883
29
        char *insp_recursion_limit = NULL;
2884
2885
29
        if (de_ctx_custom != NULL) {
2886
0
            opt = NULL;
2887
0
            TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2888
0
                if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
2889
0
                    continue;
2890
2891
0
                insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val);
2892
0
                if (insp_recursion_limit_node == NULL) {
2893
0
                    SCLogError("Error retrieving conf "
2894
0
                               "entry for detect-engine:inspection-recursion-limit");
2895
0
                    break;
2896
0
                }
2897
0
                insp_recursion_limit = insp_recursion_limit_node->val;
2898
0
                SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
2899
0
                        insp_recursion_limit_node->name, insp_recursion_limit_node->val);
2900
0
                break;
2901
0
            }
2902
2903
0
            if (insp_recursion_limit != NULL) {
2904
0
                if (StringParseInt32(&de_ctx->inspection_recursion_limit, 10,
2905
0
                                     0, (const char *)insp_recursion_limit) < 0) {
2906
0
                    SCLogWarning("Invalid value for "
2907
0
                                 "detect-engine.inspection-recursion-limit: %s "
2908
0
                                 "resetting to %d",
2909
0
                            insp_recursion_limit, DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
2910
0
                    de_ctx->inspection_recursion_limit =
2911
0
                        DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
2912
0
                }
2913
0
            }
2914
0
        }
2915
29
    }
2916
2917
67.5k
    if (de_ctx->inspection_recursion_limit == 0)
2918
67.5k
        de_ctx->inspection_recursion_limit = -1;
2919
2920
67.5k
    SCLogDebug("de_ctx->inspection_recursion_limit: %d",
2921
67.5k
               de_ctx->inspection_recursion_limit);
2922
2923
67.5k
    int guess_applayer = 0;
2924
67.5k
    if ((ConfGetBool("detect.guess-applayer-tx", &guess_applayer)) == 1) {
2925
0
        if (guess_applayer == 1) {
2926
0
            de_ctx->guess_applayer = true;
2927
0
        }
2928
0
    }
2929
2930
    /* parse port grouping priority settings */
2931
2932
67.5k
    const char *ports = NULL;
2933
67.5k
    (void)ConfGet("detect.grouping.tcp-whitelist", &ports);
2934
67.5k
    if (ports) {
2935
0
        SCLogConfig("grouping: tcp-whitelist %s", ports);
2936
67.5k
    } else {
2937
67.5k
        ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
2938
67.5k
        SCLogConfig("grouping: tcp-whitelist (default) %s", ports);
2939
2940
67.5k
    }
2941
67.5k
    if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) {
2942
0
        SCLogWarning("'%s' is not a valid value "
2943
0
                     "for detect.grouping.tcp-whitelist",
2944
0
                ports);
2945
0
    }
2946
67.5k
    DetectPort *x = de_ctx->tcp_whitelist;
2947
810k
    for ( ; x != NULL;  x = x->next) {
2948
743k
        if (x->port != x->port2) {
2949
0
            SCLogWarning("'%s' is not a valid value "
2950
0
                         "for detect.grouping.tcp-whitelist: only single ports allowed",
2951
0
                    ports);
2952
0
            DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
2953
0
            de_ctx->tcp_whitelist = NULL;
2954
0
            break;
2955
0
        }
2956
743k
    }
2957
2958
67.5k
    ports = NULL;
2959
67.5k
    (void)ConfGet("detect.grouping.udp-whitelist", &ports);
2960
67.5k
    if (ports) {
2961
0
        SCLogConfig("grouping: udp-whitelist %s", ports);
2962
67.5k
    } else {
2963
67.5k
        ports = "53, 135, 5060";
2964
67.5k
        SCLogConfig("grouping: udp-whitelist (default) %s", ports);
2965
2966
67.5k
    }
2967
67.5k
    if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) {
2968
0
        SCLogWarning("'%s' is not a valid value "
2969
0
                     "for detect.grouping.udp-whitelist",
2970
0
                ports);
2971
0
    }
2972
270k
    for (x = de_ctx->udp_whitelist; x != NULL;  x = x->next) {
2973
202k
        if (x->port != x->port2) {
2974
0
            SCLogWarning("'%s' is not a valid value "
2975
0
                         "for detect.grouping.udp-whitelist: only single ports allowed",
2976
0
                    ports);
2977
0
            DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
2978
0
            de_ctx->udp_whitelist = NULL;
2979
0
            break;
2980
0
        }
2981
202k
    }
2982
2983
67.5k
    de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
2984
67.5k
    const char *pf_setting = NULL;
2985
67.5k
    if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
2986
0
        if (strcasecmp(pf_setting, "mpm") == 0) {
2987
0
            de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
2988
0
        } else if (strcasecmp(pf_setting, "auto") == 0) {
2989
0
            de_ctx->prefilter_setting = DETECT_PREFILTER_AUTO;
2990
0
        }
2991
0
    }
2992
67.5k
    switch (de_ctx->prefilter_setting) {
2993
67.5k
        case DETECT_PREFILTER_MPM:
2994
67.5k
            SCLogConfig("prefilter engines: MPM");
2995
67.5k
            break;
2996
0
        case DETECT_PREFILTER_AUTO:
2997
0
            SCLogConfig("prefilter engines: MPM and keywords");
2998
0
            break;
2999
67.5k
    }
3000
3001
67.5k
    return 0;
3002
67.5k
}
3003
3004
/*
3005
 * getting & (re)setting the internal sig i
3006
 */
3007
3008
//inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx)
3009
//{
3010
//    return de_ctx->signum;
3011
//}
3012
3013
void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx)
3014
140k
{
3015
140k
    de_ctx->signum = 0;
3016
140k
}
3017
3018
static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
3019
140k
{
3020
140k
    const DetectEngineMasterCtx *master = &g_master_de_ctx;
3021
3022
140k
    if (master->keyword_id > 0) {
3023
        // coverity[suspicious_sizeof : FALSE]
3024
140k
        det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
3025
140k
        if (det_ctx->global_keyword_ctxs_array == NULL) {
3026
0
            SCLogError("setting up thread local detect ctx");
3027
0
            return TM_ECODE_FAILED;
3028
0
        }
3029
140k
        det_ctx->global_keyword_ctxs_size = master->keyword_id;
3030
3031
140k
        const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3032
843k
        while (item) {
3033
703k
            det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
3034
703k
            if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
3035
0
                SCLogError("setting up thread local detect ctx "
3036
0
                           "for keyword \"%s\" failed",
3037
0
                        item->name);
3038
0
                return TM_ECODE_FAILED;
3039
0
            }
3040
703k
            item = item->next;
3041
703k
        }
3042
140k
    }
3043
140k
    return TM_ECODE_OK;
3044
140k
}
3045
3046
static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
3047
140k
{
3048
140k
    if (det_ctx->global_keyword_ctxs_array == NULL ||
3049
140k
        det_ctx->global_keyword_ctxs_size == 0) {
3050
0
        return;
3051
0
    }
3052
3053
140k
    const DetectEngineMasterCtx *master = &g_master_de_ctx;
3054
140k
    if (master->keyword_id > 0) {
3055
140k
        const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3056
843k
        while (item) {
3057
703k
            if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
3058
703k
                item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
3059
3060
703k
            item = item->next;
3061
703k
        }
3062
140k
        det_ctx->global_keyword_ctxs_size = 0;
3063
140k
        SCFree(det_ctx->global_keyword_ctxs_array);
3064
140k
        det_ctx->global_keyword_ctxs_array = NULL;
3065
140k
    }
3066
140k
}
3067
3068
static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3069
140k
{
3070
140k
    if (de_ctx->keyword_id > 0) {
3071
        // coverity[suspicious_sizeof : FALSE]
3072
23.7k
        det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *));
3073
23.7k
        if (det_ctx->keyword_ctxs_array == NULL) {
3074
0
            SCLogError("setting up thread local detect ctx");
3075
0
            return TM_ECODE_FAILED;
3076
0
        }
3077
3078
23.7k
        memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *));
3079
3080
23.7k
        det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
3081
3082
23.7k
        HashListTableBucket *hb = HashListTableGetListHead(de_ctx->keyword_hash);
3083
102k
        for (; hb != NULL; hb = HashListTableGetListNext(hb)) {
3084
78.6k
            DetectEngineThreadKeywordCtxItem *item = HashListTableGetListData(hb);
3085
3086
78.6k
            det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
3087
78.6k
            if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
3088
0
                SCLogError("setting up thread local detect ctx "
3089
0
                           "for keyword \"%s\" failed",
3090
0
                        item->name);
3091
0
                return TM_ECODE_FAILED;
3092
0
            }
3093
78.6k
        }
3094
23.7k
    }
3095
140k
    return TM_ECODE_OK;
3096
140k
}
3097
3098
static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3099
140k
{
3100
140k
    if (de_ctx->keyword_id > 0) {
3101
23.7k
        HashListTableBucket *hb = HashListTableGetListHead(de_ctx->keyword_hash);
3102
102k
        for (; hb != NULL; hb = HashListTableGetListNext(hb)) {
3103
78.6k
            DetectEngineThreadKeywordCtxItem *item = HashListTableGetListData(hb);
3104
3105
78.6k
            if (det_ctx->keyword_ctxs_array[item->id] != NULL)
3106
78.6k
                item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
3107
78.6k
        }
3108
23.7k
        det_ctx->keyword_ctxs_size = 0;
3109
23.7k
        SCFree(det_ctx->keyword_ctxs_array);
3110
23.7k
        det_ctx->keyword_ctxs_array = NULL;
3111
23.7k
    }
3112
140k
}
3113
3114
/** NOTE: master MUST be locked before calling this */
3115
static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
3116
0
{
3117
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3118
0
    DetectEngineTenantMapping *map_array = NULL;
3119
0
    uint32_t map_array_size = 0;
3120
0
    uint32_t map_cnt = 0;
3121
0
    uint32_t max_tenant_id = 0;
3122
0
    DetectEngineCtx *list = master->list;
3123
0
    HashTable *mt_det_ctxs_hash = NULL;
3124
3125
0
    if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
3126
0
        SCLogError("no tenant selector set: "
3127
0
                   "set using multi-detect.selector");
3128
0
        return TM_ECODE_FAILED;
3129
0
    }
3130
3131
0
    uint32_t tcnt = 0;
3132
0
    while (list) {
3133
0
        if (list->tenant_id > max_tenant_id)
3134
0
            max_tenant_id = list->tenant_id;
3135
3136
0
        list = list->next;
3137
0
        tcnt++;
3138
0
    }
3139
3140
0
    mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
3141
0
    if (mt_det_ctxs_hash == NULL) {
3142
0
        goto error;
3143
0
    }
3144
3145
0
    if (tcnt == 0) {
3146
0
        SCLogInfo("no tenants left, or none registered yet");
3147
0
    } else {
3148
0
        max_tenant_id++;
3149
3150
0
        DetectEngineTenantMapping *map = master->tenant_mapping_list;
3151
0
        while (map) {
3152
0
            map_cnt++;
3153
0
            map = map->next;
3154
0
        }
3155
3156
0
        if (map_cnt > 0) {
3157
0
            map_array_size = map_cnt + 1;
3158
3159
0
            map_array = SCCalloc(map_array_size, sizeof(*map_array));
3160
0
            if (map_array == NULL)
3161
0
                goto error;
3162
3163
            /* fill the array */
3164
0
            map_cnt = 0;
3165
0
            map = master->tenant_mapping_list;
3166
0
            while (map) {
3167
0
                if (map_cnt >= map_array_size) {
3168
0
                    goto error;
3169
0
                }
3170
0
                map_array[map_cnt].traffic_id = map->traffic_id;
3171
0
                map_array[map_cnt].tenant_id = map->tenant_id;
3172
0
                map_cnt++;
3173
0
                map = map->next;
3174
0
            }
3175
3176
0
        }
3177
3178
        /* set up hash for tenant lookup */
3179
0
        list = master->list;
3180
0
        while (list) {
3181
0
            SCLogDebug("tenant-id %u", list->tenant_id);
3182
0
            if (list->tenant_id != 0) {
3183
0
                DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
3184
0
                if (mt_det_ctx == NULL)
3185
0
                    goto error;
3186
0
                if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
3187
0
                    goto error;
3188
0
                }
3189
0
            }
3190
0
            list = list->next;
3191
0
        }
3192
0
    }
3193
3194
0
    det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
3195
0
    mt_det_ctxs_hash = NULL;
3196
3197
0
    det_ctx->mt_det_ctxs_cnt = max_tenant_id;
3198
3199
0
    det_ctx->tenant_array = map_array;
3200
0
    det_ctx->tenant_array_size = map_array_size;
3201
3202
0
    switch (master->tenant_selector) {
3203
0
        case TENANT_SELECTOR_UNKNOWN:
3204
0
            SCLogDebug("TENANT_SELECTOR_UNKNOWN");
3205
0
            break;
3206
0
        case TENANT_SELECTOR_VLAN:
3207
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromVlanId;
3208
0
            SCLogDebug("TENANT_SELECTOR_VLAN");
3209
0
            break;
3210
0
        case TENANT_SELECTOR_LIVEDEV:
3211
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromLivedev;
3212
0
            SCLogDebug("TENANT_SELECTOR_LIVEDEV");
3213
0
            break;
3214
0
        case TENANT_SELECTOR_DIRECT:
3215
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromPcap;
3216
0
            SCLogDebug("TENANT_SELECTOR_DIRECT");
3217
0
            break;
3218
0
    }
3219
3220
0
    return TM_ECODE_OK;
3221
0
error:
3222
0
    if (map_array != NULL)
3223
0
        SCFree(map_array);
3224
0
    if (mt_det_ctxs_hash != NULL)
3225
0
        HashTableFree(mt_det_ctxs_hash);
3226
3227
0
    return TM_ECODE_FAILED;
3228
0
}
3229
3230
/** \internal
3231
 *  \brief Helper for DetectThread setup functions
3232
 */
3233
static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3234
67.5k
{
3235
67.5k
    PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher);
3236
67.5k
    PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher);
3237
67.5k
    PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher);
3238
3239
67.5k
    PmqSetup(&det_ctx->pmq);
3240
3241
67.5k
    det_ctx->spm_thread_ctx = SpmMakeThreadCtx(de_ctx->spm_global_thread_ctx);
3242
67.5k
    if (det_ctx->spm_thread_ctx == NULL) {
3243
0
        return TM_ECODE_FAILED;
3244
0
    }
3245
3246
    /* sized to the max of our sgh settings. A max setting of 0 implies that all
3247
     * sgh's have: sgh->non_pf_store_cnt == 0 */
3248
67.5k
    if (de_ctx->non_pf_store_cnt_max > 0) {
3249
18.2k
        det_ctx->non_pf_id_array =  SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId));
3250
18.2k
        BUG_ON(det_ctx->non_pf_id_array == NULL);
3251
18.2k
    }
3252
3253
    /* DeState */
3254
67.5k
    if (de_ctx->sig_array_len > 0) {
3255
24.0k
        det_ctx->match_array_len = de_ctx->sig_array_len;
3256
24.0k
        det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
3257
24.0k
        if (det_ctx->match_array == NULL) {
3258
0
            return TM_ECODE_FAILED;
3259
0
        }
3260
24.0k
        memset(det_ctx->match_array, 0,
3261
24.0k
               det_ctx->match_array_len * sizeof(Signature *));
3262
3263
24.0k
        RuleMatchCandidateTxArrayInit(det_ctx, de_ctx->sig_array_len);
3264
24.0k
    }
3265
3266
    /* Alert processing queue */
3267
67.5k
    AlertQueueInit(det_ctx);
3268
3269
    /* byte_extract storage */
3270
67.5k
    det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) *
3271
67.5k
                                  (de_ctx->byte_extract_max_local_id + 1));
3272
67.5k
    if (det_ctx->byte_values == NULL) {
3273
0
        return TM_ECODE_FAILED;
3274
0
    }
3275
3276
    /* Allocate space for base64 decoded data. */
3277
67.5k
    if (de_ctx->base64_decode_max_len) {
3278
408
        det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len);
3279
408
        if (det_ctx->base64_decoded == NULL) {
3280
0
            return TM_ECODE_FAILED;
3281
0
        }
3282
408
        det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len;
3283
408
        det_ctx->base64_decoded_len = 0;
3284
408
    }
3285
3286
67.5k
    det_ctx->inspect.buffers_size = de_ctx->buffer_type_id;
3287
67.5k
    det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
3288
67.5k
    if (det_ctx->inspect.buffers == NULL) {
3289
0
        return TM_ECODE_FAILED;
3290
0
    }
3291
67.5k
    det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
3292
67.5k
    if (det_ctx->inspect.to_clear_queue == NULL) {
3293
0
        return TM_ECODE_FAILED;
3294
0
    }
3295
67.5k
    det_ctx->inspect.to_clear_idx = 0;
3296
3297
67.5k
    det_ctx->multi_inspect.buffers_size = de_ctx->buffer_type_id;
3298
67.5k
    det_ctx->multi_inspect.buffers = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(InspectionBufferMultipleForList));
3299
67.5k
    if (det_ctx->multi_inspect.buffers == NULL) {
3300
0
        return TM_ECODE_FAILED;
3301
0
    }
3302
67.5k
    det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
3303
67.5k
    if (det_ctx->multi_inspect.to_clear_queue == NULL) {
3304
0
        return TM_ECODE_FAILED;
3305
0
    }
3306
67.5k
    det_ctx->multi_inspect.to_clear_idx = 0;
3307
3308
3309
67.5k
    DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
3310
67.5k
    DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
3311
#ifdef PROFILE_RULES
3312
    SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx);
3313
#endif
3314
#ifdef PROFILING
3315
    SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx);
3316
    SCProfilingPrefilterThreadSetup(de_ctx->profile_prefilter_ctx, det_ctx);
3317
    SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx);
3318
#endif
3319
67.5k
    SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
3320
3321
67.5k
    return TM_ECODE_OK;
3322
67.5k
}
3323
3324
/** \brief initialize thread specific detection engine context
3325
 *
3326
 *  \note there is a special case when using delayed detect. In this case the
3327
 *        function is called twice per thread. The first time the rules are not
3328
 *        yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
3329
 *        time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
3330
 *        This is needed to do the per thread counter registration before the
3331
 *        packet runtime starts. In delayed detect mode, the first call will
3332
 *        return a NULL ptr through the data ptr.
3333
 *
3334
 *  \param tv ThreadVars for this thread
3335
 *  \param initdata pointer to de_ctx
3336
 *  \param data[out] pointer to store our thread detection ctx
3337
 *
3338
 *  \retval TM_ECODE_OK if all went well
3339
 *  \retval TM_ECODE_FAILED on serious errors
3340
 */
3341
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
3342
4
{
3343
4
    DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
3344
4
    if (unlikely(det_ctx == NULL))
3345
0
        return TM_ECODE_FAILED;
3346
4
    memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
3347
3348
4
    det_ctx->tv = tv;
3349
4
    det_ctx->de_ctx = DetectEngineGetCurrent();
3350
4
    if (det_ctx->de_ctx == NULL) {
3351
#ifdef UNITTESTS
3352
        if (RunmodeIsUnittests()) {
3353
            det_ctx->de_ctx = (DetectEngineCtx *)initdata;
3354
        } else {
3355
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3356
            return TM_ECODE_FAILED;
3357
        }
3358
#else
3359
0
        DetectEngineThreadCtxDeinit(tv, det_ctx);
3360
0
        return TM_ECODE_FAILED;
3361
0
#endif
3362
0
    }
3363
3364
4
    if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3365
0
        det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
3366
4
    {
3367
4
        if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
3368
0
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3369
0
            return TM_ECODE_FAILED;
3370
0
        }
3371
4
    }
3372
3373
    /** alert counter setup */
3374
4
    det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
3375
4
    det_ctx->counter_alerts_overflow = StatsRegisterCounter("detect.alert_queue_overflow", tv);
3376
4
    det_ctx->counter_alerts_suppressed = StatsRegisterCounter("detect.alerts_suppressed", tv);
3377
#ifdef PROFILING
3378
    det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
3379
    det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
3380
    det_ctx->counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
3381
    det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
3382
#endif
3383
3384
4
    if (DetectEngineMultiTenantEnabled()) {
3385
0
        if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
3386
0
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3387
0
            return TM_ECODE_FAILED;
3388
0
        }
3389
0
    }
3390
3391
    /* pass thread data back to caller */
3392
4
    *data = (void *)det_ctx;
3393
3394
4
    return TM_ECODE_OK;
3395
4
}
3396
3397
/**
3398
 * \internal
3399
 * \brief initialize a det_ctx for reload cases
3400
 * \param new_de_ctx the new detection engine
3401
 * \param mt flag to indicate if MT should be set up for this det_ctx
3402
 *           this should only be done for the 'root' det_ctx
3403
 *
3404
 * \retval det_ctx detection engine thread ctx or NULL in case of error
3405
 */
3406
DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
3407
        ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
3408
140k
{
3409
140k
    DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
3410
140k
    if (unlikely(det_ctx == NULL))
3411
0
        return NULL;
3412
140k
    memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
3413
3414
140k
    det_ctx->tenant_id = new_de_ctx->tenant_id;
3415
140k
    det_ctx->tv = tv;
3416
140k
    det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
3417
140k
    if (det_ctx->de_ctx == NULL) {
3418
0
        SCFree(det_ctx);
3419
0
        return NULL;
3420
0
    }
3421
3422
    /* most of the init happens here */
3423
140k
    if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3424
0
        det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
3425
140k
    {
3426
140k
        if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
3427
0
            DetectEngineDeReference(&det_ctx->de_ctx);
3428
0
            SCFree(det_ctx);
3429
0
            return NULL;
3430
0
        }
3431
140k
    }
3432
3433
    /** alert counter setup */
3434
140k
    det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
3435
140k
    det_ctx->counter_alerts_overflow = StatsRegisterCounter("detect.alert_queue_overflow", tv);
3436
140k
    det_ctx->counter_alerts_suppressed = StatsRegisterCounter("detect.alerts_suppressed", tv);
3437
#ifdef PROFILING
3438
    uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
3439
    uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
3440
    uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
3441
    uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
3442
    det_ctx->counter_mpm_list = counter_mpm_list;
3443
    det_ctx->counter_nonmpm_list = counter_nonmpm_list;
3444
    det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
3445
    det_ctx->counter_match_list = counter_match_list;
3446
#endif
3447
3448
140k
    if (mt && DetectEngineMultiTenantEnabled()) {
3449
0
        if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
3450
0
            DetectEngineDeReference(&det_ctx->de_ctx);
3451
0
            SCFree(det_ctx);
3452
0
            return NULL;
3453
0
        }
3454
0
    }
3455
3456
140k
    return det_ctx;
3457
140k
}
3458
3459
static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
3460
67.5k
{
3461
#if  DEBUG
3462
    SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
3463
3464
    SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
3465
    SCLogDebug("STREAM  MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
3466
3467
    SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
3468
    SCLogDebug("STREAM  SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
3469
#endif
3470
3471
67.5k
    if (det_ctx->tenant_array != NULL) {
3472
0
        SCFree(det_ctx->tenant_array);
3473
0
        det_ctx->tenant_array = NULL;
3474
0
    }
3475
3476
#ifdef PROFILE_RULES
3477
    SCProfilingRuleThreadCleanup(det_ctx);
3478
#endif
3479
#ifdef PROFILING
3480
    SCProfilingKeywordThreadCleanup(det_ctx);
3481
    SCProfilingPrefilterThreadCleanup(det_ctx);
3482
    SCProfilingSghThreadCleanup(det_ctx);
3483
#endif
3484
3485
    /** \todo get rid of this static */
3486
67.5k
    if (det_ctx->de_ctx != NULL) {
3487
67.5k
        PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
3488
67.5k
        PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher);
3489
67.5k
        PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
3490
67.5k
    }
3491
3492
67.5k
    PmqFree(&det_ctx->pmq);
3493
3494
67.5k
    if (det_ctx->spm_thread_ctx != NULL) {
3495
67.5k
        SpmDestroyThreadCtx(det_ctx->spm_thread_ctx);
3496
67.5k
    }
3497
3498
67.5k
    if (det_ctx->non_pf_id_array != NULL)
3499
18.2k
        SCFree(det_ctx->non_pf_id_array);
3500
3501
67.5k
    if (det_ctx->match_array != NULL)
3502
24.0k
        SCFree(det_ctx->match_array);
3503
3504
67.5k
    RuleMatchCandidateTxArrayFree(det_ctx);
3505
3506
67.5k
    AlertQueueFree(det_ctx);
3507
3508
67.5k
    if (det_ctx->byte_values != NULL)
3509
67.5k
        SCFree(det_ctx->byte_values);
3510
3511
    /* Decoded base64 data. */
3512
67.5k
    if (det_ctx->base64_decoded != NULL) {
3513
408
        SCFree(det_ctx->base64_decoded);
3514
408
    }
3515
3516
67.5k
    if (det_ctx->inspect.buffers) {
3517
9.68M
        for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
3518
9.62M
            InspectionBufferFree(&det_ctx->inspect.buffers[i]);
3519
9.62M
        }
3520
67.5k
        SCFree(det_ctx->inspect.buffers);
3521
67.5k
    }
3522
67.5k
    if (det_ctx->inspect.to_clear_queue) {
3523
67.5k
        SCFree(det_ctx->inspect.to_clear_queue);
3524
67.5k
    }
3525
67.5k
    if (det_ctx->multi_inspect.buffers) {
3526
9.68M
        for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
3527
9.62M
            InspectionBufferMultipleForList *fb = &det_ctx->multi_inspect.buffers[i];
3528
9.62M
            for (uint32_t x = 0; x < fb->size; x++) {
3529
2.28k
                InspectionBufferFree(&fb->inspection_buffers[x]);
3530
2.28k
            }
3531
9.62M
            SCFree(fb->inspection_buffers);
3532
9.62M
        }
3533
67.5k
        SCFree(det_ctx->multi_inspect.buffers);
3534
67.5k
    }
3535
67.5k
    if (det_ctx->multi_inspect.to_clear_queue) {
3536
67.5k
        SCFree(det_ctx->multi_inspect.to_clear_queue);
3537
67.5k
    }
3538
3539
67.5k
    DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
3540
67.5k
    if (det_ctx->de_ctx != NULL) {
3541
67.5k
        DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
3542
#ifdef UNITTESTS
3543
        if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
3544
            DetectEngineDeReference(&det_ctx->de_ctx);
3545
#else
3546
67.5k
        DetectEngineDeReference(&det_ctx->de_ctx);
3547
67.5k
#endif
3548
67.5k
    }
3549
3550
67.5k
    AppLayerDecoderEventsFreeEvents(&det_ctx->decoder_events);
3551
3552
67.5k
    SCFree(det_ctx);
3553
67.5k
}
3554
3555
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
3556
140k
{
3557
140k
    DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
3558
3559
140k
    if (det_ctx == NULL) {
3560
0
        SCLogWarning("argument \"data\" NULL");
3561
0
        return TM_ECODE_OK;
3562
0
    }
3563
3564
140k
    if (det_ctx->mt_det_ctxs_hash != NULL) {
3565
0
        HashTableFree(det_ctx->mt_det_ctxs_hash);
3566
0
        det_ctx->mt_det_ctxs_hash = NULL;
3567
0
    }
3568
140k
    DetectEngineThreadCtxFree(det_ctx);
3569
3570
140k
    return TM_ECODE_OK;
3571
140k
}
3572
3573
void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx)
3574
0
{
3575
    /* XXX */
3576
0
    PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
3577
0
    PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
3578
0
}
3579
3580
static uint32_t DetectKeywordCtxHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3581
1.43M
{
3582
1.43M
    DetectEngineThreadKeywordCtxItem *ctx = data;
3583
1.43M
    const char *name = ctx->name;
3584
1.43M
    uint64_t hash = StringHashDjb2((const uint8_t *)name, strlen(name)) + (ptrdiff_t)ctx->data;
3585
1.43M
    hash %= ht->array_size;
3586
1.43M
    return hash;
3587
1.43M
}
3588
3589
static char DetectKeywordCtxCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
3590
697k
{
3591
697k
    DetectEngineThreadKeywordCtxItem *ctx1 = data1;
3592
697k
    DetectEngineThreadKeywordCtxItem *ctx2 = data2;
3593
697k
    const char *name1 = ctx1->name;
3594
697k
    const char *name2 = ctx2->name;
3595
697k
    return (strcmp(name1, name2) == 0 && ctx1->data == ctx2->data);
3596
697k
}
3597
3598
static void DetectKeywordCtxFreeFunc(void *ptr)
3599
672k
{
3600
672k
    SCFree(ptr);
3601
672k
}
3602
3603
/** \brief Register Thread keyword context Funcs
3604
 *
3605
 *  \param de_ctx detection engine to register in
3606
 *  \param name keyword name for error printing
3607
 *  \param InitFunc function ptr
3608
 *  \param data keyword init data to pass to Func. Can be NULL.
3609
 *  \param FreeFunc function ptr
3610
 *  \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
3611
 *
3612
 *  \retval id for retrieval of ctx at runtime
3613
 *  \retval -1 on error
3614
 *
3615
 *  \note make sure "data" remains valid and it free'd elsewhere. It's
3616
 *        recommended to store it in the keywords global ctx so that
3617
 *        it's freed when the de_ctx is freed.
3618
 */
3619
int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
3620
672k
{
3621
672k
    BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL);
3622
3623
672k
    if (de_ctx->keyword_hash == NULL) {
3624
23.7k
        de_ctx->keyword_hash = HashListTableInit(4096, // TODO
3625
23.7k
                DetectKeywordCtxHashFunc, DetectKeywordCtxCompareFunc, DetectKeywordCtxFreeFunc);
3626
23.7k
        BUG_ON(de_ctx->keyword_hash == NULL);
3627
23.7k
    }
3628
3629
672k
    if (mode) {
3630
0
        DetectEngineThreadKeywordCtxItem search = { .data = data, .name = name };
3631
3632
0
        DetectEngineThreadKeywordCtxItem *item =
3633
0
                HashListTableLookup(de_ctx->keyword_hash, (void *)&search, 0);
3634
0
        if (item)
3635
0
            return item->id;
3636
3637
        /* fall through */
3638
0
    }
3639
3640
672k
    DetectEngineThreadKeywordCtxItem *item = SCCalloc(1, sizeof(DetectEngineThreadKeywordCtxItem));
3641
672k
    if (unlikely(item == NULL))
3642
0
        return -1;
3643
3644
672k
    item->InitFunc = InitFunc;
3645
672k
    item->FreeFunc = FreeFunc;
3646
672k
    item->data = data;
3647
672k
    item->name = name;
3648
672k
    item->id = de_ctx->keyword_id++;
3649
3650
672k
    if (HashListTableAdd(de_ctx->keyword_hash, (void *)item, 0) < 0) {
3651
0
        SCFree(item);
3652
0
        return -1;
3653
0
    }
3654
672k
    return item->id;
3655
672k
}
3656
3657
/** \brief Remove Thread keyword context registration
3658
 *
3659
 *  \param de_ctx detection engine to deregister from
3660
 *  \param det_ctx detection engine thread context to deregister from
3661
 *  \param data keyword init data to pass to Func. Can be NULL.
3662
 *  \param name keyword name for error printing
3663
 *
3664
 *  \retval 1 Item unregistered
3665
 *  \retval 0 otherwise
3666
 *
3667
 *  \note make sure "data" remains valid and it free'd elsewhere. It's
3668
 *        recommended to store it in the keywords global ctx so that
3669
 *        it's freed when the de_ctx is freed.
3670
 */
3671
int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *de_ctx, void *data, const char *name)
3672
792k
{
3673
    /* might happen if we call this before a call to *Register* */
3674
792k
    if (de_ctx->keyword_hash == NULL)
3675
27.9k
        return 1;
3676
764k
    DetectEngineThreadKeywordCtxItem remove = { .data = data, .name = name };
3677
764k
    if (HashListTableRemove(de_ctx->keyword_hash, (void *)&remove, 0) == 0)
3678
672k
        return 1;
3679
92.6k
    return 0;
3680
764k
}
3681
/** \brief Retrieve thread local keyword ctx by id
3682
 *
3683
 *  \param det_ctx detection engine thread ctx to retrieve the ctx from
3684
 *  \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3685
 *            keyword init.
3686
 *
3687
 *  \retval ctx or NULL on error
3688
 */
3689
void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3690
368k
{
3691
368k
    if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
3692
0
        return NULL;
3693
3694
368k
    return det_ctx->keyword_ctxs_array[id];
3695
368k
}
3696
3697
3698
/** \brief Register Thread keyword context Funcs (Global)
3699
 *
3700
 *  IDs stay static over reloads and between tenants
3701
 *
3702
 *  \param name keyword name for error printing
3703
 *  \param InitFunc function ptr
3704
 *  \param FreeFunc function ptr
3705
 *
3706
 *  \retval id for retrieval of ctx at runtime
3707
 *  \retval -1 on error
3708
 */
3709
int DetectRegisterThreadCtxGlobalFuncs(const char *name,
3710
        void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
3711
365
{
3712
365
    int id;
3713
365
    BUG_ON(InitFunc == NULL || FreeFunc == NULL);
3714
3715
365
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3716
3717
    /* if already registered, return existing id */
3718
365
    DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3719
1.09k
    while (item != NULL) {
3720
730
        if (strcmp(name, item->name) == 0) {
3721
0
            id = item->id;
3722
0
            return id;
3723
0
        }
3724
3725
730
        item = item->next;
3726
730
    }
3727
3728
365
    item = SCCalloc(1, sizeof(*item));
3729
365
    if (unlikely(item == NULL)) {
3730
0
        return -1;
3731
0
    }
3732
365
    item->InitFunc = InitFunc;
3733
365
    item->FreeFunc = FreeFunc;
3734
365
    item->name = name;
3735
365
    item->data = data;
3736
3737
365
    item->next = master->keyword_list;
3738
365
    master->keyword_list = item;
3739
365
    item->id = master->keyword_id++;
3740
3741
365
    id = item->id;
3742
365
    return id;
3743
365
}
3744
3745
/** \brief Retrieve thread local keyword ctx by id
3746
 *
3747
 *  \param det_ctx detection engine thread ctx to retrieve the ctx from
3748
 *  \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3749
 *            keyword init.
3750
 *
3751
 *  \retval ctx or NULL on error
3752
 */
3753
void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3754
49.3k
{
3755
49.3k
    if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
3756
49.3k
        det_ctx->global_keyword_ctxs_array == NULL) {
3757
0
        return NULL;
3758
0
    }
3759
3760
49.3k
    return det_ctx->global_keyword_ctxs_array[id];
3761
49.3k
}
3762
3763
/** \brief Check if detection is enabled
3764
 *  \retval bool true or false */
3765
int DetectEngineEnabled(void)
3766
4
{
3767
4
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3768
4
    SCMutexLock(&master->lock);
3769
3770
4
    if (master->list == NULL) {
3771
0
        SCMutexUnlock(&master->lock);
3772
0
        return 0;
3773
0
    }
3774
3775
4
    SCMutexUnlock(&master->lock);
3776
4
    return 1;
3777
4
}
3778
3779
uint32_t DetectEngineGetVersion(void)
3780
140k
{
3781
140k
    uint32_t version;
3782
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3783
140k
    SCMutexLock(&master->lock);
3784
140k
    version = master->version;
3785
140k
    SCMutexUnlock(&master->lock);
3786
140k
    return version;
3787
140k
}
3788
3789
void DetectEngineBumpVersion(void)
3790
140k
{
3791
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3792
140k
    SCMutexLock(&master->lock);
3793
140k
    master->version++;
3794
140k
    SCLogDebug("master version now %u", master->version);
3795
140k
    SCMutexUnlock(&master->lock);
3796
140k
}
3797
3798
DetectEngineCtx *DetectEngineGetCurrent(void)
3799
354k
{
3800
354k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3801
354k
    SCMutexLock(&master->lock);
3802
3803
354k
    DetectEngineCtx *de_ctx = master->list;
3804
354k
    while (de_ctx) {
3805
354k
        if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3806
0
            de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB ||
3807
0
            de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB)
3808
354k
        {
3809
354k
            de_ctx->ref_cnt++;
3810
354k
            SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
3811
354k
            SCMutexUnlock(&master->lock);
3812
354k
            return de_ctx;
3813
354k
        }
3814
0
        de_ctx = de_ctx->next;
3815
0
    }
3816
3817
0
    SCMutexUnlock(&master->lock);
3818
0
    return NULL;
3819
354k
}
3820
3821
DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx)
3822
140k
{
3823
140k
    if (de_ctx == NULL)
3824
0
        return NULL;
3825
140k
    de_ctx->ref_cnt++;
3826
140k
    return de_ctx;
3827
140k
}
3828
3829
/** TODO locking? Not needed if this is a one time setting at startup */
3830
int DetectEngineMultiTenantEnabled(void)
3831
208k
{
3832
208k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3833
208k
    return (master->multi_tenant_enabled);
3834
208k
}
3835
3836
/** \internal
3837
 *  \brief load a tenant from a yaml file
3838
 *
3839
 *  \param tenant_id the tenant id by which the config is known
3840
 *  \param filename full path of a yaml file
3841
 *  \param loader_id id of loader thread or -1
3842
 *
3843
 *  \retval 0 ok
3844
 *  \retval -1 failed
3845
 */
3846
static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
3847
0
{
3848
0
    DetectEngineCtx *de_ctx = NULL;
3849
0
    char prefix[64];
3850
3851
0
    snprintf(prefix, sizeof(prefix), "multi-detect.%u", tenant_id);
3852
3853
0
    SCStat st;
3854
0
    if (SCStatFn(filename, &st) != 0) {
3855
0
        SCLogError("failed to stat file %s", filename);
3856
0
        goto error;
3857
0
    }
3858
3859
0
    de_ctx = DetectEngineGetByTenantId(tenant_id);
3860
0
    if (de_ctx != NULL) {
3861
0
        SCLogError("tenant %u already registered", tenant_id);
3862
0
        DetectEngineDeReference(&de_ctx);
3863
0
        goto error;
3864
0
    }
3865
3866
0
    ConfNode *node = ConfGetNode(prefix);
3867
0
    if (node == NULL) {
3868
0
        SCLogError("failed to properly setup yaml %s", filename);
3869
0
        goto error;
3870
0
    }
3871
3872
0
    de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3873
0
    if (de_ctx == NULL) {
3874
0
        SCLogError("initializing detection engine "
3875
0
                   "context failed.");
3876
0
        goto error;
3877
0
    }
3878
0
    SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
3879
3880
0
    de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3881
0
    de_ctx->tenant_id = tenant_id;
3882
0
    de_ctx->loader_id = loader_id;
3883
0
    de_ctx->tenant_path = SCStrdup(filename);
3884
0
    if (de_ctx->tenant_path == NULL) {
3885
0
        SCLogError("Failed to duplicate path");
3886
0
        goto error;
3887
0
    }
3888
3889
0
    if (SigLoadSignatures(de_ctx, NULL, 0) < 0) {
3890
0
        SCLogError("Loading signatures failed.");
3891
0
        goto error;
3892
0
    }
3893
3894
0
    DetectEngineAddToMaster(de_ctx);
3895
3896
0
    return 0;
3897
3898
0
error:
3899
0
    if (de_ctx != NULL) {
3900
0
        DetectEngineCtxFree(de_ctx);
3901
0
    }
3902
0
    return -1;
3903
0
}
3904
3905
static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
3906
0
{
3907
0
    DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3908
0
    if (old_de_ctx == NULL) {
3909
0
        SCLogError("tenant detect engine not found");
3910
0
        return -1;
3911
0
    }
3912
3913
0
    if (filename == NULL)
3914
0
        filename = old_de_ctx->tenant_path;
3915
3916
0
    char prefix[64];
3917
0
    snprintf(prefix, sizeof(prefix), "multi-detect.%u.reload.%d", tenant_id, reload_cnt);
3918
0
    reload_cnt++;
3919
0
    SCLogDebug("prefix %s", prefix);
3920
3921
0
    if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
3922
0
        SCLogError("failed to load yaml");
3923
0
        goto error;
3924
0
    }
3925
3926
0
    ConfNode *node = ConfGetNode(prefix);
3927
0
    if (node == NULL) {
3928
0
        SCLogError("failed to properly setup yaml %s", filename);
3929
0
        goto error;
3930
0
    }
3931
3932
0
    DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3933
0
    if (new_de_ctx == NULL) {
3934
0
        SCLogError("initializing detection engine "
3935
0
                   "context failed.");
3936
0
        goto error;
3937
0
    }
3938
0
    SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
3939
3940
0
    new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3941
0
    new_de_ctx->tenant_id = tenant_id;
3942
0
    new_de_ctx->loader_id = old_de_ctx->loader_id;
3943
0
    new_de_ctx->tenant_path = SCStrdup(filename);
3944
0
    if (new_de_ctx->tenant_path == NULL) {
3945
0
        SCLogError("Failed to duplicate path");
3946
0
        goto new_de_ctx_error;
3947
0
    }
3948
3949
0
    if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) {
3950
0
        SCLogError("Loading signatures failed.");
3951
0
        goto new_de_ctx_error;
3952
0
    }
3953
3954
0
    DetectEngineAddToMaster(new_de_ctx);
3955
3956
    /* move to free list */
3957
0
    DetectEngineMoveToFreeList(old_de_ctx);
3958
0
    DetectEngineDeReference(&old_de_ctx);
3959
0
    return 0;
3960
3961
0
new_de_ctx_error:
3962
0
    DetectEngineCtxFree(new_de_ctx);
3963
3964
0
error:
3965
0
    DetectEngineDeReference(&old_de_ctx);
3966
0
    return -1;
3967
0
}
3968
3969
3970
typedef struct TenantLoaderCtx_ {
3971
    uint32_t tenant_id;
3972
    int reload_cnt; /**< used by reload */
3973
    char *yaml;     /**< heap alloc'd copy of file path for the yaml */
3974
} TenantLoaderCtx;
3975
3976
static void DetectLoaderFreeTenant(void *ctx)
3977
0
{
3978
0
    TenantLoaderCtx *t = (TenantLoaderCtx *)ctx;
3979
0
    if (t->yaml != NULL) {
3980
0
        SCFree(t->yaml);
3981
0
    }
3982
0
    SCFree(t);
3983
0
}
3984
3985
static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
3986
0
{
3987
0
    TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3988
3989
0
    SCLogDebug("loader %d", loader_id);
3990
0
    if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
3991
0
        return -1;
3992
0
    }
3993
0
    return 0;
3994
0
}
3995
3996
static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
3997
0
{
3998
0
    TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3999
0
    if (t == NULL)
4000
0
        return -ENOMEM;
4001
4002
0
    t->tenant_id = tenant_id;
4003
0
    t->yaml = SCStrdup(yaml);
4004
0
    if (t->yaml == NULL) {
4005
0
        SCFree(t);
4006
0
        return -ENOMEM;
4007
0
    }
4008
4009
0
    return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t, DetectLoaderFreeTenant);
4010
0
}
4011
4012
static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
4013
0
{
4014
0
    TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
4015
4016
0
    SCLogDebug("loader_id %d", loader_id);
4017
4018
0
    if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
4019
0
        return -1;
4020
0
    }
4021
0
    return 0;
4022
0
}
4023
4024
static int DetectLoaderSetupReloadTenants(const int reload_cnt)
4025
0
{
4026
0
    int ret = 0;
4027
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4028
0
    SCMutexLock(&master->lock);
4029
4030
0
    DetectEngineCtx *de_ctx = master->list;
4031
0
    while (de_ctx) {
4032
0
        if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT) {
4033
0
            TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
4034
0
            if (t == NULL) {
4035
0
                ret = -1;
4036
0
                goto error;
4037
0
            }
4038
0
            t->tenant_id = de_ctx->tenant_id;
4039
0
            t->reload_cnt = reload_cnt;
4040
0
            int loader_id = de_ctx->loader_id;
4041
4042
0
            int r = DetectLoaderQueueTask(
4043
0
                    loader_id, DetectLoaderFuncReloadTenant, t, DetectLoaderFreeTenant);
4044
0
            if (r < 0) {
4045
0
                ret = -2;
4046
0
                goto error;
4047
0
            }
4048
0
        }
4049
4050
0
        de_ctx = de_ctx->next;
4051
0
    }
4052
0
error:
4053
0
    SCMutexUnlock(&master->lock);
4054
0
    return ret;
4055
0
}
4056
4057
static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
4058
0
{
4059
0
    DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
4060
0
    if (old_de_ctx == NULL)
4061
0
        return -ENOENT;
4062
0
    int loader_id = old_de_ctx->loader_id;
4063
0
    DetectEngineDeReference(&old_de_ctx);
4064
4065
0
    TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
4066
0
    if (t == NULL)
4067
0
        return -ENOMEM;
4068
4069
0
    t->tenant_id = tenant_id;
4070
0
    if (yaml != NULL) {
4071
0
        t->yaml = SCStrdup(yaml);
4072
0
        if (t->yaml == NULL) {
4073
0
            SCFree(t);
4074
0
            return -ENOMEM;
4075
0
        }
4076
0
    }
4077
0
    t->reload_cnt = reload_cnt;
4078
4079
0
    SCLogDebug("loader_id %d", loader_id);
4080
4081
0
    return DetectLoaderQueueTask(
4082
0
            loader_id, DetectLoaderFuncReloadTenant, t, DetectLoaderFreeTenant);
4083
0
}
4084
4085
/** \brief Load a tenant and wait for loading to complete
4086
 */
4087
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
4088
0
{
4089
0
    int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
4090
0
    if (r < 0)
4091
0
        return r;
4092
4093
0
    if (DetectLoadersSync() != 0)
4094
0
        return -1;
4095
4096
0
    return 0;
4097
0
}
4098
4099
/** \brief Reload a tenant and wait for loading to complete
4100
 */
4101
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
4102
0
{
4103
0
    int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
4104
0
    if (r < 0)
4105
0
        return r;
4106
4107
0
    if (DetectLoadersSync() != 0)
4108
0
        return -1;
4109
4110
0
    return 0;
4111
0
}
4112
4113
/** \brief Reload all tenants and wait for loading to complete
4114
 */
4115
int DetectEngineReloadTenantsBlocking(const int reload_cnt)
4116
0
{
4117
0
    int r = DetectLoaderSetupReloadTenants(reload_cnt);
4118
0
    if (r < 0)
4119
0
        return r;
4120
4121
0
    if (DetectLoadersSync() != 0)
4122
0
        return -1;
4123
4124
0
    return 0;
4125
0
}
4126
4127
static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
4128
        bool failure_fatal)
4129
0
{
4130
0
    ConfNode *mapping_node = NULL;
4131
4132
0
    int mapping_cnt = 0;
4133
0
    if (mappings_root_node != NULL) {
4134
0
        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
4135
0
            ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
4136
0
            if (tenant_id_node == NULL)
4137
0
                goto bad_mapping;
4138
0
            ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
4139
0
            if (device_node == NULL)
4140
0
                goto bad_mapping;
4141
4142
0
            uint32_t tenant_id = 0;
4143
0
            if (StringParseUint32(&tenant_id, 10, (uint16_t)strlen(tenant_id_node->val),
4144
0
                        tenant_id_node->val) < 0) {
4145
0
                SCLogError("tenant-id  "
4146
0
                           "of %s is invalid",
4147
0
                        tenant_id_node->val);
4148
0
                goto bad_mapping;
4149
0
            }
4150
4151
0
            const char *dev = device_node->val;
4152
0
            LiveDevice *ld = LiveGetDevice(dev);
4153
0
            if (ld == NULL) {
4154
0
                SCLogWarning("device %s not found", dev);
4155
0
                goto bad_mapping;
4156
0
            }
4157
4158
0
            if (ld->tenant_id_set) {
4159
0
                SCLogWarning("device %s already mapped to tenant-id %u", dev, ld->tenant_id);
4160
0
                goto bad_mapping;
4161
0
            }
4162
4163
0
            ld->tenant_id = tenant_id;
4164
0
            ld->tenant_id_set = true;
4165
4166
0
            if (DetectEngineTenantRegisterLivedev(tenant_id, ld->id) != 0) {
4167
0
                goto error;
4168
0
            }
4169
4170
0
            SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
4171
0
            mapping_cnt++;
4172
0
            continue;
4173
4174
0
        bad_mapping:
4175
0
            if (failure_fatal)
4176
0
                goto error;
4177
0
        }
4178
0
    }
4179
0
    SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
4180
0
    return mapping_cnt;
4181
4182
0
error:
4183
0
    return 0;
4184
0
}
4185
4186
static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
4187
        bool failure_fatal)
4188
0
{
4189
0
    ConfNode *mapping_node = NULL;
4190
4191
0
    int mapping_cnt = 0;
4192
0
    if (mappings_root_node != NULL) {
4193
0
        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
4194
0
            ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
4195
0
            if (tenant_id_node == NULL)
4196
0
                goto bad_mapping;
4197
0
            ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
4198
0
            if (vlan_id_node == NULL)
4199
0
                goto bad_mapping;
4200
4201
0
            uint32_t tenant_id = 0;
4202
0
            if (StringParseUint32(&tenant_id, 10, (uint16_t)strlen(tenant_id_node->val),
4203
0
                        tenant_id_node->val) < 0) {
4204
0
                SCLogError("tenant-id  "
4205
0
                           "of %s is invalid",
4206
0
                        tenant_id_node->val);
4207
0
                goto bad_mapping;
4208
0
            }
4209
4210
0
            uint16_t vlan_id = 0;
4211
0
            if (StringParseUint16(
4212
0
                        &vlan_id, 10, (uint16_t)strlen(vlan_id_node->val), vlan_id_node->val) < 0) {
4213
0
                SCLogError("vlan-id  "
4214
0
                           "of %s is invalid",
4215
0
                        vlan_id_node->val);
4216
0
                goto bad_mapping;
4217
0
            }
4218
0
            if (vlan_id == 0 || vlan_id >= 4095) {
4219
0
                SCLogError("vlan-id  "
4220
0
                           "of %s is invalid. Valid range 1-4094.",
4221
0
                        vlan_id_node->val);
4222
0
                goto bad_mapping;
4223
0
            }
4224
4225
0
            if (DetectEngineTenantRegisterVlanId(tenant_id, vlan_id) != 0) {
4226
0
                goto error;
4227
0
            }
4228
0
            SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
4229
0
            mapping_cnt++;
4230
0
            continue;
4231
4232
0
        bad_mapping:
4233
0
            if (failure_fatal)
4234
0
                goto error;
4235
0
        }
4236
0
    }
4237
0
    return mapping_cnt;
4238
4239
0
error:
4240
0
    return 0;
4241
0
}
4242
4243
/**
4244
 *  \brief setup multi-detect / multi-tenancy
4245
 *
4246
 *  See if MT is enabled. If so, setup the selector, tenants and mappings.
4247
 *  Tenants and mappings are optional, and can also dynamically be added
4248
 *  and removed from the unix socket.
4249
 */
4250
int DetectEngineMultiTenantSetup(const bool unix_socket)
4251
2
{
4252
2
    enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN;
4253
2
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4254
2
    int failure_fatal = 0;
4255
2
    (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
4256
4257
2
    int enabled = 0;
4258
2
    (void)ConfGetBool("multi-detect.enabled", &enabled);
4259
2
    if (enabled == 1) {
4260
0
        DetectLoadersInit();
4261
0
        TmModuleDetectLoaderRegister();
4262
0
        DetectLoaderThreadSpawn();
4263
0
        TmThreadContinueDetectLoaderThreads();
4264
4265
0
        SCMutexLock(&master->lock);
4266
0
        master->multi_tenant_enabled = 1;
4267
4268
0
        const char *handler = NULL;
4269
0
        if (ConfGet("multi-detect.selector", &handler) == 1) {
4270
0
            SCLogConfig("multi-tenant selector type %s", handler);
4271
4272
0
            if (strcmp(handler, "vlan") == 0) {
4273
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
4274
4275
0
                int vlanbool = 0;
4276
0
                if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
4277
0
                    SCLogError("vlan tracking is disabled, "
4278
0
                               "can't use multi-detect selector 'vlan'");
4279
0
                    SCMutexUnlock(&master->lock);
4280
0
                    goto error;
4281
0
                }
4282
4283
0
            } else if (strcmp(handler, "direct") == 0) {
4284
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
4285
0
            } else if (strcmp(handler, "device") == 0) {
4286
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
4287
0
                if (EngineModeIsIPS()) {
4288
0
                    SCLogWarning("multi-tenant 'device' mode not supported for IPS");
4289
0
                    SCMutexUnlock(&master->lock);
4290
0
                    goto error;
4291
0
                }
4292
4293
0
            } else {
4294
0
                SCLogError("unknown value %s "
4295
0
                           "multi-detect.selector",
4296
0
                        handler);
4297
0
                SCMutexUnlock(&master->lock);
4298
0
                goto error;
4299
0
            }
4300
0
        }
4301
0
        SCMutexUnlock(&master->lock);
4302
0
        SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
4303
4304
        /* traffic -- tenant mappings */
4305
0
        ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
4306
4307
0
        if (tenant_selector == TENANT_SELECTOR_VLAN) {
4308
0
            int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
4309
0
                    failure_fatal);
4310
0
            if (mapping_cnt == 0) {
4311
                /* no mappings are valid when we're in unix socket mode,
4312
                 * they can be added on the fly. Otherwise warn/error
4313
                 * depending on failure_fatal */
4314
4315
0
                if (unix_socket) {
4316
0
                    SCLogNotice("no tenant traffic mappings defined, "
4317
0
                            "tenants won't be used until mappings are added");
4318
0
                } else {
4319
0
                    if (failure_fatal) {
4320
0
                        SCLogError("no multi-detect mappings defined");
4321
0
                        goto error;
4322
0
                    } else {
4323
0
                        SCLogWarning("no multi-detect mappings defined");
4324
0
                    }
4325
0
                }
4326
0
            }
4327
0
        } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
4328
0
            int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
4329
0
                    failure_fatal);
4330
0
            if (mapping_cnt == 0) {
4331
0
                if (failure_fatal) {
4332
0
                    SCLogError("no multi-detect mappings defined");
4333
0
                    goto error;
4334
0
                } else {
4335
0
                    SCLogWarning("no multi-detect mappings defined");
4336
0
                }
4337
0
            }
4338
0
        }
4339
4340
        /* tenants */
4341
0
        ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
4342
0
        ConfNode *tenant_node = NULL;
4343
4344
0
        if (tenants_root_node != NULL) {
4345
0
            const char *path = NULL;
4346
0
            ConfNode *path_node = ConfGetNode("multi-detect.config-path");
4347
0
            if (path_node) {
4348
0
                path = path_node->val;
4349
0
                SCLogConfig("tenants config path: %s", path);
4350
0
            }
4351
4352
0
            TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
4353
0
                ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
4354
0
                if (id_node == NULL) {
4355
0
                    goto bad_tenant;
4356
0
                }
4357
0
                ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
4358
0
                if (yaml_node == NULL) {
4359
0
                    goto bad_tenant;
4360
0
                }
4361
4362
0
                uint32_t tenant_id = 0;
4363
0
                if (StringParseUint32(
4364
0
                            &tenant_id, 10, (uint16_t)strlen(id_node->val), id_node->val) < 0) {
4365
0
                    SCLogError("tenant_id  "
4366
0
                               "of %s is invalid",
4367
0
                            id_node->val);
4368
0
                    goto bad_tenant;
4369
0
                }
4370
0
                SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
4371
4372
0
                char yaml_path[PATH_MAX] = "";
4373
0
                if (path) {
4374
0
                    PathMerge(yaml_path, PATH_MAX, path, yaml_node->val);
4375
0
                } else {
4376
0
                    strlcpy(yaml_path, yaml_node->val, sizeof(yaml_path));
4377
0
                }
4378
0
                SCLogDebug("tenant path: %s", yaml_path);
4379
4380
                /* setup the yaml in this loop so that it's not done by the loader
4381
                 * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
4382
0
                char prefix[64];
4383
0
                snprintf(prefix, sizeof(prefix), "multi-detect.%u", tenant_id);
4384
0
                if (ConfYamlLoadFileWithPrefix(yaml_path, prefix) != 0) {
4385
0
                    SCLogError("failed to load yaml %s", yaml_path);
4386
0
                    goto bad_tenant;
4387
0
                }
4388
4389
0
                int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_path);
4390
0
                if (r < 0) {
4391
                    /* error logged already */
4392
0
                    goto bad_tenant;
4393
0
                }
4394
0
                continue;
4395
4396
0
            bad_tenant:
4397
0
                if (failure_fatal)
4398
0
                    goto error;
4399
0
            }
4400
0
        }
4401
4402
        /* wait for our loaders to complete their tasks */
4403
0
        if (DetectLoadersSync() != 0) {
4404
0
            goto error;
4405
0
        }
4406
4407
0
        VarNameStoreActivate();
4408
4409
2
    } else {
4410
2
        SCLogDebug("multi-detect not enabled (multi tenancy)");
4411
2
    }
4412
2
    return 0;
4413
0
error:
4414
0
    return -1;
4415
2
}
4416
4417
static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p)
4418
0
{
4419
0
    const DetectEngineThreadCtx *det_ctx = ctx;
4420
0
    uint32_t x = 0;
4421
0
    uint32_t vlan_id = 0;
4422
4423
0
    if (p->vlan_idx == 0)
4424
0
        return 0;
4425
4426
0
    vlan_id = p->vlan_id[0];
4427
4428
0
    if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
4429
0
        return 0;
4430
4431
    /* not very efficient, but for now we're targeting only limited amounts.
4432
     * Can use hash/tree approach later. */
4433
0
    for (x = 0; x < det_ctx->tenant_array_size; x++) {
4434
0
        if (det_ctx->tenant_array[x].traffic_id == vlan_id)
4435
0
            return det_ctx->tenant_array[x].tenant_id;
4436
0
    }
4437
4438
0
    return 0;
4439
0
}
4440
4441
static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet *p)
4442
0
{
4443
0
    const DetectEngineThreadCtx *det_ctx = ctx;
4444
0
    const LiveDevice *ld = p->livedev;
4445
4446
0
    if (ld == NULL || det_ctx == NULL)
4447
0
        return 0;
4448
4449
0
    SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
4450
0
    return ld->tenant_id;
4451
0
}
4452
4453
static int DetectEngineTenantRegisterSelector(
4454
        enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id)
4455
0
{
4456
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4457
0
    SCMutexLock(&master->lock);
4458
4459
0
    if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
4460
0
        SCLogInfo("conflicting selector already set");
4461
0
        SCMutexUnlock(&master->lock);
4462
0
        return -1;
4463
0
    }
4464
4465
0
    DetectEngineTenantMapping *m = master->tenant_mapping_list;
4466
0
    while (m) {
4467
0
        if (m->traffic_id == traffic_id) {
4468
0
            SCLogInfo("traffic id already registered");
4469
0
            SCMutexUnlock(&master->lock);
4470
0
            return -1;
4471
0
        }
4472
0
        m = m->next;
4473
0
    }
4474
4475
0
    DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
4476
0
    if (map == NULL) {
4477
0
        SCLogInfo("memory fail");
4478
0
        SCMutexUnlock(&master->lock);
4479
0
        return -1;
4480
0
    }
4481
0
    map->traffic_id = traffic_id;
4482
0
    map->tenant_id = tenant_id;
4483
4484
0
    map->next = master->tenant_mapping_list;
4485
0
    master->tenant_mapping_list = map;
4486
4487
0
    master->tenant_selector = selector;
4488
4489
0
    SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
4490
0
    SCMutexUnlock(&master->lock);
4491
0
    return 0;
4492
0
}
4493
4494
static int DetectEngineTenantUnregisterSelector(
4495
        enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id)
4496
0
{
4497
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4498
0
    SCMutexLock(&master->lock);
4499
4500
0
    if (master->tenant_mapping_list == NULL) {
4501
0
        SCMutexUnlock(&master->lock);
4502
0
        return -1;
4503
0
    }
4504
4505
0
    DetectEngineTenantMapping *prev = NULL;
4506
0
    DetectEngineTenantMapping *map = master->tenant_mapping_list;
4507
0
    while (map) {
4508
0
        if (map->traffic_id == traffic_id &&
4509
0
            map->tenant_id == tenant_id)
4510
0
        {
4511
0
            if (prev != NULL)
4512
0
                prev->next = map->next;
4513
0
            else
4514
0
                master->tenant_mapping_list = map->next;
4515
4516
0
            map->next = NULL;
4517
0
            SCFree(map);
4518
0
            SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
4519
0
            SCMutexUnlock(&master->lock);
4520
0
            return 0;
4521
0
        }
4522
0
        prev = map;
4523
0
        map = map->next;
4524
0
    }
4525
4526
0
    SCMutexUnlock(&master->lock);
4527
0
    return -1;
4528
0
}
4529
4530
int DetectEngineTenantRegisterLivedev(uint32_t tenant_id, int device_id)
4531
0
{
4532
0
    return DetectEngineTenantRegisterSelector(
4533
0
            TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
4534
0
}
4535
4536
int DetectEngineTenantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
4537
0
{
4538
0
    return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
4539
0
}
4540
4541
int DetectEngineTenantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
4542
0
{
4543
0
    return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
4544
0
}
4545
4546
int DetectEngineTenantRegisterPcapFile(uint32_t tenant_id)
4547
0
{
4548
0
    SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
4549
0
    return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
4550
0
}
4551
4552
int DetectEngineTenantUnregisterPcapFile(uint32_t tenant_id)
4553
0
{
4554
0
    SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
4555
0
    return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
4556
0
}
4557
4558
static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p)
4559
0
{
4560
0
    return p->pcap_v.tenant_id;
4561
0
}
4562
4563
DetectEngineCtx *DetectEngineGetByTenantId(uint32_t tenant_id)
4564
0
{
4565
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4566
0
    SCMutexLock(&master->lock);
4567
4568
0
    if (master->list == NULL) {
4569
0
        SCMutexUnlock(&master->lock);
4570
0
        return NULL;
4571
0
    }
4572
4573
0
    DetectEngineCtx *de_ctx = master->list;
4574
0
    while (de_ctx) {
4575
0
        if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT &&
4576
0
                de_ctx->tenant_id == tenant_id)
4577
0
        {
4578
0
            de_ctx->ref_cnt++;
4579
0
            break;
4580
0
        }
4581
4582
0
        de_ctx = de_ctx->next;
4583
0
    }
4584
4585
0
    SCMutexUnlock(&master->lock);
4586
0
    return de_ctx;
4587
0
}
4588
4589
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
4590
354k
{
4591
354k
    BUG_ON((*de_ctx)->ref_cnt == 0);
4592
354k
    (*de_ctx)->ref_cnt--;
4593
354k
    *de_ctx = NULL;
4594
354k
}
4595
4596
static int DetectEngineAddToList(DetectEngineCtx *instance)
4597
140k
{
4598
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4599
4600
140k
    if (instance == NULL)
4601
0
        return -1;
4602
4603
140k
    if (master->list == NULL) {
4604
4
        master->list = instance;
4605
140k
    } else {
4606
140k
        instance->next = master->list;
4607
140k
        master->list = instance;
4608
140k
    }
4609
4610
140k
    return 0;
4611
140k
}
4612
4613
int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
4614
140k
{
4615
140k
    int r;
4616
4617
140k
    if (de_ctx == NULL)
4618
0
        return -1;
4619
4620
140k
    SCLogDebug("adding de_ctx %p to master", de_ctx);
4621
4622
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4623
140k
    SCMutexLock(&master->lock);
4624
140k
    r = DetectEngineAddToList(de_ctx);
4625
140k
    SCMutexUnlock(&master->lock);
4626
140k
    return r;
4627
140k
}
4628
4629
static int DetectEngineMoveToFreeListNoLock(DetectEngineMasterCtx *master, DetectEngineCtx *de_ctx)
4630
140k
{
4631
140k
    DetectEngineCtx *instance = master->list;
4632
140k
    if (instance == NULL) {
4633
0
        return -1;
4634
0
    }
4635
4636
    /* remove from active list */
4637
140k
    if (instance == de_ctx) {
4638
0
        master->list = instance->next;
4639
140k
    } else {
4640
140k
        DetectEngineCtx *prev = instance;
4641
140k
        instance = instance->next; /* already checked first element */
4642
4643
140k
        while (instance) {
4644
140k
            DetectEngineCtx *next = instance->next;
4645
4646
140k
            if (instance == de_ctx) {
4647
140k
                prev->next = instance->next;
4648
140k
                break;
4649
140k
            }
4650
4651
0
            prev = instance;
4652
0
            instance = next;
4653
0
        }
4654
140k
        if (instance == NULL) {
4655
0
            return -1;
4656
0
        }
4657
140k
    }
4658
4659
    /* instance is now detached from list */
4660
140k
    instance->next = NULL;
4661
4662
    /* add to free list */
4663
140k
    if (master->free_list == NULL) {
4664
4
        master->free_list = instance;
4665
140k
    } else {
4666
140k
        instance->next = master->free_list;
4667
140k
        master->free_list = instance;
4668
140k
    }
4669
140k
    SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
4670
140k
    return 0;
4671
140k
}
4672
4673
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
4674
140k
{
4675
140k
    int ret = 0;
4676
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4677
140k
    SCMutexLock(&master->lock);
4678
140k
    ret = DetectEngineMoveToFreeListNoLock(master, de_ctx);
4679
140k
    SCMutexUnlock(&master->lock);
4680
140k
    return ret;
4681
140k
}
4682
4683
void DetectEnginePruneFreeList(void)
4684
140k
{
4685
140k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4686
140k
    SCMutexLock(&master->lock);
4687
4688
140k
    DetectEngineCtx *prev = NULL;
4689
140k
    DetectEngineCtx *instance = master->free_list;
4690
421k
    while (instance) {
4691
281k
        DetectEngineCtx *next = instance->next;
4692
4693
281k
        SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4694
4695
281k
        if (instance->ref_cnt == 0) {
4696
140k
            if (prev == NULL) {
4697
0
                master->free_list = next;
4698
140k
            } else {
4699
140k
                prev->next = next;
4700
140k
            }
4701
4702
140k
            SCLogDebug("freeing detect engine %p", instance);
4703
140k
            DetectEngineCtxFree(instance);
4704
140k
            instance = NULL;
4705
140k
        }
4706
4707
281k
        prev = instance;
4708
281k
        instance = next;
4709
281k
    }
4710
140k
    SCMutexUnlock(&master->lock);
4711
140k
}
4712
4713
void DetectEngineClearMaster(void)
4714
0
{
4715
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4716
0
    SCMutexLock(&master->lock);
4717
4718
0
    DetectEngineCtx *instance = master->list;
4719
0
    while (instance) {
4720
0
        DetectEngineCtx *next = instance->next;
4721
0
        DEBUG_VALIDATE_BUG_ON(instance->ref_cnt);
4722
0
        SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4723
0
        instance->ref_cnt = 0;
4724
0
        DetectEngineMoveToFreeListNoLock(master, instance);
4725
0
        instance = next;
4726
0
    }
4727
0
    SCMutexUnlock(&master->lock);
4728
0
    DetectEnginePruneFreeList();
4729
0
}
4730
4731
static int reloads = 0;
4732
4733
/** \brief Reload the detection engine
4734
 *
4735
 *  \param filename YAML file to load for the detect config
4736
 *
4737
 *  \retval -1 error
4738
 *  \retval 0 ok
4739
 */
4740
int DetectEngineReload(const SCInstance *suri)
4741
140k
{
4742
140k
    DetectEngineCtx *new_de_ctx = NULL;
4743
140k
    DetectEngineCtx *old_de_ctx = NULL;
4744
4745
140k
    char prefix[128];
4746
140k
    memset(prefix, 0, sizeof(prefix));
4747
4748
140k
    SCLogNotice("rule reload starting");
4749
4750
140k
    if (suri->conf_filename != NULL) {
4751
0
        snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
4752
0
        SCLogConfig("Reloading %s", suri->conf_filename);
4753
0
        if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
4754
0
            SCLogError("failed to load yaml %s", suri->conf_filename);
4755
0
            return -1;
4756
0
        }
4757
4758
0
        ConfNode *node = ConfGetNode(prefix);
4759
0
        if (node == NULL) {
4760
0
            SCLogError("failed to properly setup yaml %s", suri->conf_filename);
4761
0
            return -1;
4762
0
        }
4763
4764
0
        if (suri->additional_configs) {
4765
0
            for (int i = 0; suri->additional_configs[i] != NULL; i++) {
4766
0
                SCLogConfig("Reloading %s", suri->additional_configs[i]);
4767
0
                ConfYamlHandleInclude(node, suri->additional_configs[i]);
4768
0
            }
4769
0
        }
4770
4771
#if 0
4772
        ConfDump();
4773
#endif
4774
0
    }
4775
4776
    /* get a reference to the current de_ctx */
4777
140k
    old_de_ctx = DetectEngineGetCurrent();
4778
140k
    if (old_de_ctx == NULL)
4779
0
        return -1;
4780
140k
    SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
4781
140k
    DatasetReload();
4782
4783
    /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
4784
140k
    if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
4785
0
          old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
4786
0
    {
4787
0
        DetectEngineDeReference(&old_de_ctx);
4788
0
        SCLogNotice("rule reload complete");
4789
0
        return -1;
4790
0
    }
4791
4792
    /* get new detection engine */
4793
140k
    new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
4794
140k
    if (new_de_ctx == NULL) {
4795
0
        SCLogError("initializing detection engine "
4796
0
                   "context failed.");
4797
0
        DetectEngineDeReference(&old_de_ctx);
4798
0
        return -1;
4799
0
    }
4800
140k
    if (SigLoadSignatures(new_de_ctx,
4801
140k
                          suri->sig_file, suri->sig_file_exclusive) != 0) {
4802
0
        DetectEngineCtxFree(new_de_ctx);
4803
0
        DetectEngineDeReference(&old_de_ctx);
4804
0
        return -1;
4805
0
    }
4806
140k
    SCLogDebug("set up new_de_ctx %p", new_de_ctx);
4807
4808
    /* add to master */
4809
140k
    DetectEngineAddToMaster(new_de_ctx);
4810
4811
    /* move to old free list */
4812
140k
    DetectEngineMoveToFreeList(old_de_ctx);
4813
140k
    DetectEngineDeReference(&old_de_ctx);
4814
4815
140k
    SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
4816
    /* update the threads */
4817
140k
    DetectEngineReloadThreads(new_de_ctx);
4818
140k
    SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
4819
4820
    /* walk free list, freeing the old_de_ctx */
4821
140k
    DetectEnginePruneFreeList();
4822
4823
140k
    DatasetPostReloadCleanup();
4824
4825
140k
    DetectEngineBumpVersion();
4826
4827
140k
    SCLogDebug("old_de_ctx should have been freed");
4828
4829
140k
    SCLogNotice("rule reload complete");
4830
140k
    return 0;
4831
140k
}
4832
4833
static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
4834
0
{
4835
0
    DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
4836
0
    return det_ctx->tenant_id % h->array_size;
4837
0
}
4838
4839
static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
4840
0
{
4841
0
    DetectEngineThreadCtx *det1 = (DetectEngineThreadCtx *)d1;
4842
0
    DetectEngineThreadCtx *det2 = (DetectEngineThreadCtx *)d2;
4843
0
    return (det1->tenant_id == det2->tenant_id);
4844
0
}
4845
4846
static void TenantIdFree(void *d)
4847
0
{
4848
0
    DetectEngineThreadCtxFree(d);
4849
0
}
4850
4851
int DetectEngineMTApply(void)
4852
0
{
4853
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4854
0
    SCMutexLock(&master->lock);
4855
4856
0
    if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
4857
0
        SCLogInfo("error, no tenant selector");
4858
0
        SCMutexUnlock(&master->lock);
4859
0
        return -1;
4860
0
    }
4861
4862
0
    DetectEngineCtx *stub_de_ctx = NULL;
4863
0
    DetectEngineCtx *list = master->list;
4864
0
    for ( ; list != NULL; list = list->next) {
4865
0
        SCLogDebug("list %p tenant %u", list, list->tenant_id);
4866
4867
0
        if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
4868
0
            list->type == DETECT_ENGINE_TYPE_MT_STUB ||
4869
0
            list->type == DETECT_ENGINE_TYPE_DD_STUB)
4870
0
        {
4871
0
            stub_de_ctx = list;
4872
0
            break;
4873
0
        }
4874
0
    }
4875
0
    if (stub_de_ctx == NULL) {
4876
0
        stub_de_ctx = DetectEngineCtxInitStubForMT();
4877
0
        if (stub_de_ctx == NULL) {
4878
0
            SCMutexUnlock(&master->lock);
4879
0
            return -1;
4880
0
        }
4881
4882
0
        if (master->list == NULL) {
4883
0
            master->list = stub_de_ctx;
4884
0
        } else {
4885
0
            stub_de_ctx->next = master->list;
4886
0
            master->list = stub_de_ctx;
4887
0
        }
4888
0
    }
4889
4890
    /* update the threads */
4891
0
    SCLogDebug("MT reload starting");
4892
0
    DetectEngineReloadThreads(stub_de_ctx);
4893
0
    SCLogDebug("MT reload done");
4894
4895
0
    SCMutexUnlock(&master->lock);
4896
4897
    /* walk free list, freeing the old_de_ctx */
4898
0
    DetectEnginePruneFreeList();
4899
    // needed for VarNameStoreFree
4900
0
    DetectEngineBumpVersion();
4901
4902
0
    SCLogDebug("old_de_ctx should have been freed");
4903
0
    return 0;
4904
0
}
4905
4906
static int g_parse_metadata = 0;
4907
4908
void DetectEngineSetParseMetadata(void)
4909
4
{
4910
4
    g_parse_metadata = 1;
4911
4
}
4912
4913
void DetectEngineUnsetParseMetadata(void)
4914
0
{
4915
0
    g_parse_metadata = 0;
4916
0
}
4917
4918
int DetectEngineMustParseMetadata(void)
4919
279k
{
4920
279k
    return g_parse_metadata;
4921
279k
}
4922
4923
const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
4924
0
{
4925
0
    switch (type) {
4926
0
        case DETECT_SM_LIST_MATCH:
4927
0
            return "packet";
4928
0
        case DETECT_SM_LIST_PMATCH:
4929
0
            return "packet/stream payload";
4930
4931
0
        case DETECT_SM_LIST_TMATCH:
4932
0
            return "tag";
4933
4934
0
        case DETECT_SM_LIST_BASE64_DATA:
4935
0
            return "base64_data";
4936
4937
0
        case DETECT_SM_LIST_POSTMATCH:
4938
0
            return "post-match";
4939
4940
0
        case DETECT_SM_LIST_SUPPRESS:
4941
0
            return "suppress";
4942
0
        case DETECT_SM_LIST_THRESHOLD:
4943
0
            return "threshold";
4944
4945
0
        case DETECT_SM_LIST_MAX:
4946
0
            return "max (internal)";
4947
0
    }
4948
0
    return "error";
4949
0
}
4950
4951
/* events api */
4952
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
4953
0
{
4954
0
    AppLayerDecoderEventsSetEventRaw(&det_ctx->decoder_events, e);
4955
0
    det_ctx->events++;
4956
0
}
4957
4958
AppLayerDecoderEvents *DetectEngineGetEvents(DetectEngineThreadCtx *det_ctx)
4959
0
{
4960
0
    return det_ctx->decoder_events;
4961
0
}
4962
4963
/*************************************Unittest*********************************/
4964
4965
#ifdef UNITTESTS
4966
4967
static int DetectEngineInitYamlConf(const char *conf)
4968
{
4969
    ConfCreateContextBackup();
4970
    ConfInit();
4971
    return ConfYamlLoadString(conf, strlen(conf));
4972
}
4973
4974
static void DetectEngineDeInitYamlConf(void)
4975
{
4976
    ConfDeInit();
4977
    ConfRestoreContextBackup();
4978
4979
    return;
4980
}
4981
4982
static int DetectEngineTest01(void)
4983
{
4984
    const char *conf =
4985
        "%YAML 1.1\n"
4986
        "---\n"
4987
        "detect-engine:\n"
4988
        "  - profile: medium\n"
4989
        "  - custom-values:\n"
4990
        "      toclient_src_groups: 2\n"
4991
        "      toclient_dst_groups: 2\n"
4992
        "      toclient_sp_groups: 2\n"
4993
        "      toclient_dp_groups: 3\n"
4994
        "      toserver_src_groups: 2\n"
4995
        "      toserver_dst_groups: 4\n"
4996
        "      toserver_sp_groups: 2\n"
4997
        "      toserver_dp_groups: 25\n"
4998
        "  - inspection-recursion-limit: 0\n";
4999
5000
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5001
5002
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5003
    FAIL_IF_NULL(de_ctx);
5004
5005
    FAIL_IF_NOT(de_ctx->inspection_recursion_limit == -1);
5006
5007
    DetectEngineCtxFree(de_ctx);
5008
5009
    DetectEngineDeInitYamlConf();
5010
5011
    PASS;
5012
}
5013
5014
static int DetectEngineTest02(void)
5015
{
5016
    const char *conf =
5017
        "%YAML 1.1\n"
5018
        "---\n"
5019
        "detect-engine:\n"
5020
        "  - profile: medium\n"
5021
        "  - custom-values:\n"
5022
        "      toclient_src_groups: 2\n"
5023
        "      toclient_dst_groups: 2\n"
5024
        "      toclient_sp_groups: 2\n"
5025
        "      toclient_dp_groups: 3\n"
5026
        "      toserver_src_groups: 2\n"
5027
        "      toserver_dst_groups: 4\n"
5028
        "      toserver_sp_groups: 2\n"
5029
        "      toserver_dp_groups: 25\n"
5030
        "  - inspection-recursion-limit:\n";
5031
5032
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5033
5034
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5035
    FAIL_IF_NULL(de_ctx);
5036
5037
    FAIL_IF_NOT(
5038
            de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
5039
5040
    DetectEngineCtxFree(de_ctx);
5041
5042
    DetectEngineDeInitYamlConf();
5043
5044
    PASS;
5045
}
5046
5047
static int DetectEngineTest03(void)
5048
{
5049
    const char *conf =
5050
        "%YAML 1.1\n"
5051
        "---\n"
5052
        "detect-engine:\n"
5053
        "  - profile: medium\n"
5054
        "  - custom-values:\n"
5055
        "      toclient_src_groups: 2\n"
5056
        "      toclient_dst_groups: 2\n"
5057
        "      toclient_sp_groups: 2\n"
5058
        "      toclient_dp_groups: 3\n"
5059
        "      toserver_src_groups: 2\n"
5060
        "      toserver_dst_groups: 4\n"
5061
        "      toserver_sp_groups: 2\n"
5062
        "      toserver_dp_groups: 25\n";
5063
5064
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5065
5066
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5067
    FAIL_IF_NULL(de_ctx);
5068
5069
    FAIL_IF_NOT(
5070
            de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
5071
5072
    DetectEngineCtxFree(de_ctx);
5073
5074
    DetectEngineDeInitYamlConf();
5075
5076
    PASS;
5077
}
5078
5079
static int DetectEngineTest04(void)
5080
{
5081
    const char *conf =
5082
        "%YAML 1.1\n"
5083
        "---\n"
5084
        "detect-engine:\n"
5085
        "  - profile: medium\n"
5086
        "  - custom-values:\n"
5087
        "      toclient_src_groups: 2\n"
5088
        "      toclient_dst_groups: 2\n"
5089
        "      toclient_sp_groups: 2\n"
5090
        "      toclient_dp_groups: 3\n"
5091
        "      toserver_src_groups: 2\n"
5092
        "      toserver_dst_groups: 4\n"
5093
        "      toserver_sp_groups: 2\n"
5094
        "      toserver_dp_groups: 25\n"
5095
        "  - inspection-recursion-limit: 10\n";
5096
5097
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5098
5099
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5100
    FAIL_IF_NULL(de_ctx);
5101
5102
    FAIL_IF_NOT(de_ctx->inspection_recursion_limit == 10);
5103
5104
    DetectEngineCtxFree(de_ctx);
5105
5106
    DetectEngineDeInitYamlConf();
5107
5108
    PASS;
5109
}
5110
5111
static int DetectEngineTest08(void)
5112
{
5113
    const char *conf =
5114
        "%YAML 1.1\n"
5115
        "---\n"
5116
        "detect-engine:\n"
5117
        "  - profile: custom\n"
5118
        "  - custom-values:\n"
5119
        "      toclient-groups: 23\n"
5120
        "      toserver-groups: 27\n";
5121
5122
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5123
5124
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5125
    FAIL_IF_NULL(de_ctx);
5126
5127
    FAIL_IF_NOT(de_ctx->max_uniq_toclient_groups == 23);
5128
    FAIL_IF_NOT(de_ctx->max_uniq_toserver_groups == 27);
5129
5130
    DetectEngineCtxFree(de_ctx);
5131
5132
    DetectEngineDeInitYamlConf();
5133
5134
    PASS;
5135
}
5136
5137
/** \test bug 892 bad values */
5138
static int DetectEngineTest09(void)
5139
{
5140
    const char *conf =
5141
        "%YAML 1.1\n"
5142
        "---\n"
5143
        "detect-engine:\n"
5144
        "  - profile: custom\n"
5145
        "  - custom-values:\n"
5146
        "      toclient-groups: BA\n"
5147
        "      toserver-groups: BA\n"
5148
        "  - inspection-recursion-limit: 10\n";
5149
5150
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5151
5152
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5153
    FAIL_IF_NULL(de_ctx);
5154
5155
    FAIL_IF_NOT(de_ctx->max_uniq_toclient_groups == 20);
5156
    FAIL_IF_NOT(de_ctx->max_uniq_toserver_groups == 40);
5157
5158
    DetectEngineCtxFree(de_ctx);
5159
5160
    DetectEngineDeInitYamlConf();
5161
5162
    PASS;
5163
}
5164
5165
#endif
5166
5167
void DetectEngineRegisterTests(void)
5168
0
{
5169
#ifdef UNITTESTS
5170
    UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
5171
    UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
5172
    UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
5173
    UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
5174
    UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
5175
    UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
5176
#endif
5177
0
    return;
5178
0
}