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