suricata
detect-engine-mpm.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 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 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23 *
24 * Multi pattern matcher
25 */
26
27#include "suricata.h"
28#include "suricata-common.h"
29
30#include "app-layer-protos.h"
31
32#include "decode.h"
33#include "detect.h"
34#include "detect-engine.h"
36#include "detect-engine-mpm.h"
38#include "detect-parse.h"
40#include "util-mpm.h"
41#include "util-memcmp.h"
42#include "util-memcpy.h"
43#include "conf.h"
44#include "detect-fast-pattern.h"
45
46#include "detect-tcphdr.h"
47#include "detect-udphdr.h"
48
49#include "flow.h"
50#include "flow-var.h"
51#include "detect-flow.h"
52
53#include "detect-content.h"
54
56
57#include "stream.h"
58
59#include "util-misc.h"
60#include "util-enum.h"
61#include "util-debug.h"
62#include "util-print.h"
63#include "util-validate.h"
64#include "util-hash-string.h"
65
66const char *builtin_mpms[] = {
67 "toserver TCP packet",
68 "toclient TCP packet",
69 "toserver TCP stream",
70 "toclient TCP stream",
71 "toserver UDP packet",
72 "toclient UDP packet",
73 "other IP packet",
74
75 NULL };
76
77/* Registry for mpm keywords
78 *
79 * Keywords are registered at engine start up
80 */
81
82static DetectBufferMpmRegistry *g_mpm_list[DETECT_BUFFER_MPM_TYPE_SIZE] = { NULL, NULL, NULL };
83static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0, 0 };
84
85/** \brief register a MPM engine
86 *
87 * \note to be used at start up / registration only. Errors are fatal.
88 */
89static void RegisterInternal(const char *name, int direction, int priority,
90 PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData,
92 InspectionMultiBufferGetDataPtr GetMultiData, AppProto alproto, int tx_min_progress)
93{
94 SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority,
95 PrefilterRegister, GetData, alproto, tx_min_progress);
96
97 BUG_ON(tx_min_progress >= 48);
98
99 // must register GetData with PrefilterGenericMpmRegister
100 BUG_ON(PrefilterRegister == PrefilterGenericMpmRegister && GetData == NULL);
101
104 int sm_list = DetectBufferTypeGetByName(name);
105 if (sm_list == -1) {
106 FatalError("MPM engine registration for %s failed", name);
107 }
108
109 // every HTTP2 can be accessed from DOH2
110 if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) {
111 RegisterInternal(name, direction, priority, PrefilterRegister, GetData, GetDataSingle,
112 GetMultiData, ALPROTO_DOH2, tx_min_progress);
113 }
114 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
115 BUG_ON(am == NULL);
116 am->name = name;
117 snprintf(am->pname, sizeof(am->pname), "%s", am->name);
118 am->direction = direction;
119 DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > INT16_MAX);
120 am->sm_list = (int16_t)sm_list;
121 am->sm_list_base = (int16_t)sm_list;
122 am->priority = priority;
124
125 am->PrefilterRegisterWithListId = PrefilterRegister;
126 if (GetData != NULL) {
127 am->app_v2.GetData = GetData;
128 } else if (GetDataSingle != NULL) {
129 am->app_v2.GetDataSingle = GetDataSingle;
130 } else if (GetMultiData != NULL) {
131 am->app_v2.GetMultiData = GetMultiData;
132 }
133 am->app_v2.alproto = alproto;
134 am->app_v2.tx_min_progress = tx_min_progress;
135
136 if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] == NULL) {
137 g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] = am;
138 } else {
140 while (t->next != NULL) {
141 t = t->next;
142 }
143
144 t->next = am;
145 am->id = t->id + 1;
146 }
147 g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP]++;
148
149 SupportFastPatternForSigMatchList(sm_list, priority);
150}
151
152void DetectAppLayerMpmRegister(const char *name, int direction, int priority,
153 PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData,
154 AppProto alproto, int tx_min_progress)
155{
156 RegisterInternal(name, direction, priority, PrefilterRegister, GetData, NULL, NULL, alproto,
157 tx_min_progress);
158}
159
160void DetectAppLayerMpmRegisterSingle(const char *name, int direction, int priority,
162 AppProto alproto, int tx_min_progress)
163{
164 RegisterInternal(name, direction, priority, PrefilterRegister, NULL, GetData, NULL, alproto,
165 tx_min_progress);
166}
167
168void DetectAppLayerMpmMultiRegister(const char *name, int direction, int priority,
170 AppProto alproto, int tx_min_progress)
171{
172 RegisterInternal(name, direction, priority, PrefilterRegister, NULL, NULL, GetData, alproto,
173 tx_min_progress);
174}
175
176/** \brief copy a mpm engine from parent_id, add in transforms */
178 const int id, const int parent_id,
179 DetectEngineTransforms *transforms)
180{
181 SCLogDebug("registering %d/%d", id, parent_id);
182
184 while (t) {
185 if (t->sm_list == parent_id) {
186 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
187 BUG_ON(am == NULL);
188 am->name = t->name;
189 am->direction = t->direction;
190 DEBUG_VALIDATE_BUG_ON(id < 0 || id > INT16_MAX);
191 am->sm_list = (uint16_t)id; // use new id
192 am->sm_list_base = t->sm_list;
195 am->app_v2.GetData = t->app_v2.GetData;
196 am->app_v2.alproto = t->app_v2.alproto;
198 am->priority = t->priority;
201 de_ctx, am->name, am->sm_list, am->app_v2.alproto);
202 am->next = t->next;
203 if (transforms) {
204 memcpy(&am->transforms, transforms, sizeof(*transforms));
205
206 /* create comma separated string of the names of the
207 * transforms and then shorten it if necessary. Finally
208 * use it to construct the 'profile' name for the engine */
209 char xforms[1024] = "";
210 for (int i = 0; i < transforms->cnt; i++) {
211 char ttstr[64];
212 (void)snprintf(ttstr,sizeof(ttstr), "%s,",
213 sigmatch_table[transforms->transforms[i].transform].name);
214 strlcat(xforms, ttstr, sizeof(xforms));
215 }
216 xforms[strlen(xforms)-1] = '\0';
217
218 size_t space = sizeof(am->pname) - strlen(am->name) - 3;
219 char toprint[space + 1];
220 memset(toprint, 0x00, space + 1);
221 if (space < strlen(xforms)) {
222 ShortenString(xforms, toprint, space, '~');
223 } else {
224 strlcpy(toprint, xforms,sizeof(toprint));
225 }
226 (void)snprintf(am->pname, sizeof(am->pname), "%s#%d (%s)",
227 am->name, id, toprint);
228 } else {
229 (void)snprintf(am->pname, sizeof(am->pname), "%s#%d",
230 am->name, id);
231 }
232 am->id = de_ctx->app_mpms_list_cnt++;
233
235 t->next = am;
236 SCLogDebug("copied mpm registration for %s id %u "
237 "with parent %u and GetData %p",
238 t->name, id, parent_id, am->app_v2.GetData);
239 t = am;
240 }
241 t = t->next;
242 }
243}
244
246{
247 const DetectBufferMpmRegistry *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP];
249 while (list != NULL) {
250 DetectBufferMpmRegistry *n = SCCalloc(1, sizeof(*n));
251 BUG_ON(n == NULL);
252
253 *n = *list;
254 n->next = NULL;
255
256 if (toadd == NULL) {
257 toadd = n;
259 } else {
260 toadd->next = n;
261 toadd = toadd->next;
262 }
263
264 /* default to whatever the global setting is */
266
267 /* see if we use a unique or shared mpm ctx for this type */
268 int confshared = 0;
269 char confstring[256] = "detect.mpm.";
270 strlcat(confstring, n->name, sizeof(confstring));
271 strlcat(confstring, ".shared", sizeof(confstring));
272 if (SCConfGetBool(confstring, &confshared) == 1)
273 shared = confshared;
274
275 if (shared == 0) {
276 SCLogDebug("using unique mpm ctx' for %s", n->name);
278 } else {
279 SCLogDebug("using shared mpm ctx' for %s", n->name);
280 n->sgh_mpm_context =
282 }
283
284 list = list->next;
285 }
287 SCLogDebug("mpm: de_ctx app_mpms_list %p %u",
289}
290
291/**
292 * \brief initialize mpm contexts for applayer buffers that are in
293 * "single or "shared" mode.
294 */
296{
297 int r = 0;
299 while (am != NULL) {
300 int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0;
301
303 {
305 if (mpm_ctx != NULL) {
306 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
308 }
309 }
310 }
311 am = am->next;
312 }
313 return r;
314}
315
316/** \brief register a MPM engine
317 *
318 * \note to be used at start up / registration only. Errors are fatal.
319 */
320void DetectFrameMpmRegister(const char *name, int direction, int priority,
321 int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
322 const DetectBufferMpmRegistry *mpm_reg, int list_id),
323 AppProto alproto, uint8_t type)
324{
325 SCLogDebug("registering %s/%d/%p/%s/%u", name, priority, PrefilterRegister,
326 AppProtoToString(alproto), type);
327
331 int sm_list = DetectBufferTypeGetByName(name);
332 if (sm_list < 0 || sm_list > UINT16_MAX) {
333 FatalError("MPM engine registration for %s failed", name);
334 }
335
336 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
337 BUG_ON(am == NULL);
338 am->name = name;
339 snprintf(am->pname, sizeof(am->pname), "%s", am->name);
340 am->sm_list = (uint16_t)sm_list;
341 am->direction = direction;
342 am->priority = priority;
344
345 am->PrefilterRegisterWithListId = PrefilterRegister;
346 am->frame_v1.alproto = alproto;
347 am->frame_v1.type = type;
348 SCLogDebug("type %u", type);
349 SCLogDebug("am type %u", am->frame_v1.type);
350
351 if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME] == NULL) {
352 g_mpm_list[DETECT_BUFFER_MPM_TYPE_FRAME] = am;
353 } else {
355 while (t->next != NULL) {
356 t = t->next;
357 }
358 t->next = am;
359 am->id = t->id + 1;
360 }
361 g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_FRAME]++;
362
363 SupportFastPatternForSigMatchList(sm_list, priority);
364 SCLogDebug("%s/%d done", name, sm_list);
365}
366
367/** \brief copy a mpm engine from parent_id, add in transforms */
368void DetectFrameMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id,
369 DetectEngineTransforms *transforms)
370{
371 SCLogDebug("registering %d/%d", id, parent_id);
372
374 while (t) {
375 if (t->sm_list == parent_id) {
376 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
377 BUG_ON(am == NULL);
378 am->name = t->name;
379 snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id);
380 DEBUG_VALIDATE_BUG_ON(id < 0 || id > UINT16_MAX);
381 am->sm_list = (uint16_t)id; // use new id
382 am->sm_list_base = t->sm_list;
385 am->frame_v1 = t->frame_v1;
386 SCLogDebug("am type %u", am->frame_v1.type);
387 am->priority = t->priority;
388 am->direction = t->direction;
390 am->next = t->next;
391 if (transforms) {
392 memcpy(&am->transforms, transforms, sizeof(*transforms));
393 }
395
397 t->next = am;
398 SCLogDebug("copied mpm registration for %s id %u "
399 "with parent %u",
400 t->name, id, parent_id);
401 t = am;
402 }
403 t = t->next;
404 }
405}
406
407void DetectEngineFrameMpmRegister(DetectEngineCtx *de_ctx, const char *name, int direction,
408 int priority,
409 int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
410 const DetectBufferMpmRegistry *mpm_reg, int list_id),
411 AppProto alproto, uint8_t type)
412{
413 SCLogDebug("registering %s/%d/%p/%s/%u", name, priority, PrefilterRegister,
414 AppProtoToString(alproto), type);
415
416 const int sm_list = DetectEngineBufferTypeRegister(de_ctx, name);
417 if (sm_list < 0 || sm_list > UINT16_MAX) {
418 FatalError("MPM engine registration for %s failed", name);
419 }
420
424
425 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
426 BUG_ON(am == NULL);
427 am->name = name;
428 snprintf(am->pname, sizeof(am->pname), "%s", am->name);
429 am->sm_list = (uint16_t)sm_list;
430 am->direction = direction;
431 am->priority = priority;
433
434 am->PrefilterRegisterWithListId = PrefilterRegister;
435 am->frame_v1.alproto = alproto;
436 am->frame_v1.type = type;
437
438 // TODO is it ok to do this here?
439
440 /* default to whatever the global setting is */
442 /* see if we use a unique or shared mpm ctx for this type */
443 int confshared = 0;
444 if (SCConfGetBool("detect.mpm.frame.shared", &confshared) == 1)
445 shared = confshared;
446
447 if (shared == 0) {
449 } else {
450 am->sgh_mpm_context =
452 }
453
454 if (de_ctx->frame_mpms_list == NULL) {
456 } else {
458 while (t->next != NULL) {
459 t = t->next;
460 }
461
462 t->next = am;
463 }
465
467 SCLogDebug("%s/%d done", name, sm_list);
468}
469
471{
473 while (list != NULL) {
474 DetectBufferMpmRegistry *n = SCCalloc(1, sizeof(*n));
475 BUG_ON(n == NULL);
476
477 *n = *list;
478 n->next = NULL;
479
480 if (de_ctx->frame_mpms_list == NULL) {
482 } else {
484 while (t->next != NULL) {
485 t = t->next;
486 }
487
488 t->next = n;
489 }
490
491 /* default to whatever the global setting is */
493
494 /* see if we use a unique or shared mpm ctx for this type */
495 int confshared = 0;
496 char confstring[256] = "detect.mpm.";
497 strlcat(confstring, n->name, sizeof(confstring));
498 strlcat(confstring, ".shared", sizeof(confstring));
499 if (SCConfGetBool(confstring, &confshared) == 1)
500 shared = confshared;
501
502 if (shared == 0) {
503 SCLogDebug("using unique mpm ctx' for %s", n->name);
505 } else {
506 SCLogDebug("using shared mpm ctx' for %s", n->name);
508 de_ctx, n->name, n->sm_list, n->frame_v1.alproto);
509 }
510
511 list = list->next;
512 }
514 SCLogDebug("mpm: de_ctx frame_mpms_list %p %u", de_ctx->frame_mpms_list,
516}
517
518/**
519 * \brief initialize mpm contexts for applayer buffers that are in
520 * "single or "shared" mode.
521 */
523{
524 SCLogDebug("preparing frame mpm");
525 int r = 0;
527 while (am != NULL) {
528 SCLogDebug("am %p %s sgh_mpm_context %d", am, am->name, am->sgh_mpm_context);
529 SCLogDebug("%s", am->name);
531 int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0;
533 SCLogDebug("%s: %d mpm_Ctx %p", am->name, r, mpm_ctx);
534 if (mpm_ctx != NULL) {
535 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
537 SCLogDebug("%s: %d", am->name, r);
538 }
539 }
540 }
541 am = am->next;
542 }
543 return r;
544}
545
546/** \brief register a MPM engine
547 *
548 * \note to be used at start up / registration only. Errors are fatal.
549 */
550void DetectPktMpmRegister(const char *name, int priority,
551 int (*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
552 const DetectBufferMpmRegistry *mpm_reg, int list_id),
554{
555 SCLogDebug("registering %s/%d/%p/%p", name, priority,
556 PrefilterRegister, GetData);
557
558 // must register GetData with PrefilterGenericMpmRegister
559 BUG_ON(PrefilterRegister == PrefilterGenericMpmPktRegister && GetData == NULL);
560
563 int sm_list = DetectBufferTypeGetByName(name);
564 if (sm_list == -1) {
565 FatalError("MPM engine registration for %s failed", name);
566 }
567
568 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
569 BUG_ON(am == NULL);
570 am->name = name;
571 snprintf(am->pname, sizeof(am->pname), "%s", am->name);
572 DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > INT16_MAX);
573 am->sm_list = (uint16_t)sm_list;
574 am->priority = priority;
576
577 am->PrefilterRegisterWithListId = PrefilterRegister;
578 am->pkt_v1.GetData = GetData;
579
580 if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] == NULL) {
581 g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] = am;
582 } else {
584 while (t->next != NULL) {
585 t = t->next;
586 }
587 t->next = am;
588 am->id = t->id + 1;
589 }
590 g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT]++;
591
592 SupportFastPatternForSigMatchList(sm_list, priority);
593 SCLogDebug("%s/%d done", name, sm_list);
594}
595
596/** \brief copy a mpm engine from parent_id, add in transforms */
598 const int id, const int parent_id,
599 DetectEngineTransforms *transforms)
600{
601 SCLogDebug("registering %d/%d", id, parent_id);
602
604 while (t) {
605 if (t->sm_list == parent_id) {
606 DetectBufferMpmRegistry *am = SCCalloc(1, sizeof(*am));
607 BUG_ON(am == NULL);
608 am->name = t->name;
609 snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id);
610 DEBUG_VALIDATE_BUG_ON(id < 0 || id > INT16_MAX);
611 am->sm_list = (uint16_t)id; // use new id
612 am->sm_list_base = t->sm_list;
615 am->pkt_v1.GetData = t->pkt_v1.GetData;
616 am->priority = t->priority;
618 am->next = t->next;
619 if (transforms) {
620 memcpy(&am->transforms, transforms, sizeof(*transforms));
621 }
622 am->id = de_ctx->pkt_mpms_list_cnt++;
623
625 t->next = am;
626 SCLogDebug("copied mpm registration for %s id %u "
627 "with parent %u and GetData %p",
628 t->name, id, parent_id, am->pkt_v1.GetData);
629 t = am;
630 }
631 t = t->next;
632 }
633}
634
636{
637 const DetectBufferMpmRegistry *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT];
638 while (list != NULL) {
639 DetectBufferMpmRegistry *n = SCCalloc(1, sizeof(*n));
640 BUG_ON(n == NULL);
641
642 *n = *list;
643 n->next = NULL;
644
645 if (de_ctx->pkt_mpms_list == NULL) {
647 } else {
649 while (t->next != NULL) {
650 t = t->next;
651 }
652
653 t->next = n;
654 }
655
656 /* default to whatever the global setting is */
658
659 /* see if we use a unique or shared mpm ctx for this type */
660 int confshared = 0;
661 char confstring[256] = "detect.mpm.";
662 strlcat(confstring, n->name, sizeof(confstring));
663 strlcat(confstring, ".shared", sizeof(confstring));
664 if (SCConfGetBool(confstring, &confshared) == 1)
665 shared = confshared;
666
667 if (shared == 0) {
668 SCLogDebug("using unique mpm ctx' for %s", n->name);
670 } else {
671 SCLogDebug("using shared mpm ctx' for %s", n->name);
672 n->sgh_mpm_context =
674 }
675
676 list = list->next;
677 }
679 SCLogDebug("mpm: de_ctx pkt_mpms_list %p %u",
681}
682
683/**
684 * \brief initialize mpm contexts for applayer buffers that are in
685 * "single or "shared" mode.
686 */
688{
689 SCLogDebug("preparing pkt mpm");
690 int r = 0;
692 while (am != NULL) {
693 SCLogDebug("%s", am->name);
695 {
697 if (mpm_ctx != NULL) {
698 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
700 SCLogDebug("%s: %d", am->name, r);
701 }
702 }
703 }
704 am = am->next;
705 }
706 return r;
707}
708
709static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name)
710{
711 /* default to whatever the global setting is */
713
714 /* see if we use a unique or shared mpm ctx for this type */
715 int confshared = 0;
716 char confstring[256] = "detect.mpm.";
717 strlcat(confstring, name, sizeof(confstring));
718 strlcat(confstring, ".shared", sizeof(confstring));
719 if (SCConfGetBool(confstring, &confshared) == 1)
720 shared = confshared;
721
722 int32_t ctx;
723 if (shared == 0) {
725 SCLogDebug("using unique mpm ctx' for %s", name);
726 } else {
728 SCLogDebug("using shared mpm ctx' for %s", name);
729 }
730 return ctx;
731}
732
734{
735 de_ctx->sgh_mpm_context_proto_tcp_packet = SetupBuiltinMpm(de_ctx, "tcp-packet");
736 de_ctx->sgh_mpm_context_stream = SetupBuiltinMpm(de_ctx, "tcp-stream");
737
738 de_ctx->sgh_mpm_context_proto_udp_packet = SetupBuiltinMpm(de_ctx, "udp-packet");
739 de_ctx->sgh_mpm_context_proto_other_packet = SetupBuiltinMpm(de_ctx, "other-ip");
740}
741
742/**
743 * \brief initialize mpm contexts for builtin buffers that are in
744 * "single or "shared" mode.
745 */
747{
748 int r = 0;
749 MpmCtx *mpm_ctx = NULL;
750
753 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
755 }
757 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
759 }
760 }
761
764 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
766 }
768 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
770 }
771 }
772
775 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
777 }
778 }
779
782 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
784 }
786 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
788 }
789 }
790
791 return r;
792}
793
794/**
795 * \brief check if a signature has patterns that are to be inspected
796 * against a packets payload (as opposed to the stream payload)
797 *
798 * \param s signature
799 *
800 * \retval 1 true
801 * \retval 0 false
802 */
804{
805 SCEnter();
806
807 if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
808 SCReturnInt(1);
809 }
810
811 if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
812 SCLogDebug("no PMATCH");
813 SCReturnInt(0);
814 }
815
816 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
817 SCReturnInt(0);
818 }
819
820 SCReturnInt(1);
821}
822
823/**
824 * \brief check if a signature has patterns that are to be inspected
825 * against the stream payload (as opposed to the individual packets
826 * payload(s))
827 *
828 * \param s signature
829 *
830 * \retval 1 true
831 * \retval 0 false
832 */
834{
835 SCEnter();
836
837 if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
838 SCReturnInt(0);
839 }
840
841 if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
842 SCLogDebug("no PMATCH");
843 SCReturnInt(0);
844 }
845
846 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
847 SCReturnInt(0);
848 }
849
850 SCReturnInt(1);
851}
852
853
854/**
855 * \brief Function to return the multi pattern matcher algorithm to be
856 * used by the engine, based on the mpm-algo setting in yaml
857 * Use the default mpm if none is specified in the yaml file.
858 *
859 * \retval mpm algo value
860 */
862{
863 const char *mpm_algo;
864 uint8_t mpm_algo_val = mpm_default_matcher;
865
866 /* Get the mpm algo defined in config file by the user */
867 if ((SCConfGet("mpm-algo", &mpm_algo)) == 1) {
868 if (mpm_algo != NULL) {
869#if __BYTE_ORDER == __BIG_ENDIAN
870 if (strcmp(mpm_algo, "ac-ks") == 0) {
871 FatalError("ac-ks does "
872 "not work on big endian systems at this time.");
873 }
874#endif
875 if (strcmp("auto", mpm_algo) == 0) {
876 goto done;
877 } else if (strcmp("ac-bs", mpm_algo) == 0) {
878 SCLogWarning("mpm-algo \"ac-bs\" has been removed. See ticket #6586.");
879 goto done;
880 }
881 for (uint8_t u = 0; u < MPM_TABLE_SIZE; u++) {
882 if (mpm_table[u].name == NULL)
883 continue;
884
885 if (strcmp(mpm_table[u].name, mpm_algo) == 0) {
886 mpm_algo_val = u;
887 goto done;
888 }
889 }
890
891#ifndef BUILD_HYPERSCAN
892 if ((strcmp(mpm_algo, "hs") == 0)) {
893 FatalError("Hyperscan (hs) support for mpm-algo is "
894 "not compiled into Suricata.");
895 }
896#endif
897 }
898 FatalError("Invalid mpm algo supplied "
899 "in the yaml conf file: \"%s\"",
900 mpm_algo);
901 }
902
903 done:
904 return mpm_algo_val;
905}
906
907void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher)
908{
909 SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher);
910 mpm_table[mpm_matcher].DestroyCtx(mpm_ctx);
911}
912
913void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
914{
915 SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher);
916 MpmDestroyThreadCtx(mpm_thread_ctx, mpm_matcher);
917}
918void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
919{
920 SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher);
921 MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher);
922}
923
924/** \brief Predict a strength value for patterns
925 *
926 * Patterns with high character diversity score higher.
927 * Alpha chars score not so high
928 * Other printable + a few common codes a little higher
929 * Everything else highest.
930 * Longer patterns score better than short patters.
931 *
932 * \param pat pattern
933 * \param patlen length of the pattern
934 *
935 * \retval s pattern score
936 */
937uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
938{
939 uint8_t a[256];
940 memset(&a, 0 ,sizeof(a));
941
942 uint32_t s = 0;
943 uint16_t u = 0;
944 for (u = 0; u < patlen; u++) {
945 if (a[pat[u]] == 0) {
946 if (isalpha(pat[u]))
947 s += 3;
948 else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF)
949 s += 4;
950 else
951 s += 6;
952
953 a[pat[u]] = 1;
954 } else {
955 s++;
956 }
957 }
958
959 return s;
960}
961
962static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx, const DetectContentData *cd,
963 const Signature *s, const uint8_t flags, const int chop)
964{
965 uint16_t pat_offset = cd->offset;
966 uint16_t pat_depth = cd->depth;
967
968 /* recompute offset/depth to cope with chop */
969 if (chop && (pat_depth || pat_offset)) {
970 pat_offset += cd->fp_chop_offset;
971 if (pat_depth) {
972 pat_depth -= cd->content_len;
973 pat_depth += cd->fp_chop_offset + cd->fp_chop_len;
974 }
975 }
976
977 /* We have to effectively "wild card" values that will be coming from
978 * byte_extract variables
979 */
981 pat_depth = pat_offset = 0;
982 }
983
984 if (cd->flags & DETECT_CONTENT_NOCASE) {
985 if (chop) {
986 MpmAddPatternCI(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset,
987 pat_depth, cd->id, s->iid, flags | MPM_PATTERN_CTX_OWNS_ID);
988 } else {
989 MpmAddPatternCI(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, cd->id,
991 }
992 } else {
993 if (chop) {
994 MpmAddPatternCS(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset,
995 pat_depth, cd->id, s->iid, flags | MPM_PATTERN_CTX_OWNS_ID);
996 } else {
997 MpmAddPatternCS(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, cd->id,
999 }
1000 }
1001}
1002
1003#define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1)
1004#define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER)
1005#define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT)
1006
1007static void SetMpm(Signature *s, SigMatch *mpm_sm, const int mpm_sm_list)
1008{
1009 if (s == NULL || mpm_sm == NULL)
1010 return;
1011
1012 DetectContentData *cd = (DetectContentData *)mpm_sm->ctx;
1014 if (DETECT_CONTENT_IS_SINGLE(cd) &&
1015 !(cd->flags & DETECT_CONTENT_NEGATED) &&
1016 !(cd->flags & DETECT_CONTENT_REPLACE) &&
1017 cd->content_len == cd->fp_chop_len)
1018 {
1020 }
1021 } else {
1022 if (DETECT_CONTENT_IS_SINGLE(cd) &&
1023 !(cd->flags & DETECT_CONTENT_NEGATED) &&
1025 {
1027 }
1028 }
1030 s->init_data->mpm_sm_list = mpm_sm_list;
1031 s->init_data->mpm_sm = mpm_sm;
1032}
1033
1034static SigMatch *GetMpmForList(const Signature *s, SigMatch *list, SigMatch *mpm_sm,
1035 uint16_t max_len, bool skip_negated_content)
1036{
1037 for (SigMatch *sm = list; sm != NULL; sm = sm->next) {
1038 if (sm->type != DETECT_CONTENT)
1039 continue;
1040
1041 const DetectContentData *cd = (DetectContentData *)sm->ctx;
1042 /* skip_negated_content is only set if there's absolutely no
1043 * non-negated content present in the sig */
1044 if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
1045 continue;
1046 if (cd->content_len != max_len) {
1047 SCLogDebug("content_len %u != max_len %u", cd->content_len, max_len);
1048 continue;
1049 }
1050 if (mpm_sm == NULL) {
1051 mpm_sm = sm;
1052 } else {
1053 DetectContentData *data1 = (DetectContentData *)sm->ctx;
1054 DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
1055 uint32_t ls = PatternStrength(data1->content, data1->content_len);
1056 uint32_t ss = PatternStrength(data2->content, data2->content_len);
1057 if (ls > ss) {
1058 mpm_sm = sm;
1059 } else if (ls == ss) {
1060 /* if 2 patterns are of equal strength, we pick the longest */
1061 if (data1->content_len > data2->content_len)
1062 mpm_sm = sm;
1063 } else {
1064 SCLogDebug("sticking with mpm_sm");
1065 }
1066 }
1067 }
1068 return mpm_sm;
1069}
1070
1072
1073// tells if a buffer id is only used to client
1074bool DetectBufferToClient(const DetectEngineCtx *de_ctx, int buf_id, AppProto alproto)
1075{
1076 bool r = false;
1078 for (; app != NULL; app = app->next) {
1079 if (app->sm_list == buf_id &&
1080 (AppProtoEquals(alproto, app->alproto) || alproto == ALPROTO_UNKNOWN)) {
1081 if (app->dir == 1) {
1082 // do not return yet in case we have app engines on both sides
1083 r = true;
1084 } else {
1085 // ambiguous keywords have a app-engine to server
1086 return false;
1087 }
1088 }
1089 }
1090 return r;
1091}
1092
1094{
1095 if (g_skip_prefilter)
1096 return;
1097
1098 if (s->init_data->mpm_sm != NULL)
1099 return;
1100
1101 const int nlists = s->init_data->max_content_list_id + 1;
1102 int pos_sm_list[nlists];
1103 int neg_sm_list[nlists];
1104 memset(pos_sm_list, 0, nlists * sizeof(int));
1105 memset(neg_sm_list, 0, nlists * sizeof(int));
1106 int pos_sm_list_cnt = 0;
1107 int neg_sm_list_cnt = 0;
1108
1109 /* inspect rule to see if we have the fast_pattern reg to
1110 * force using a sig, otherwise keep stats about the patterns */
1111 if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) {
1113 for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
1114 sm = sm->next) {
1115 if (sm->type != DETECT_CONTENT)
1116 continue;
1117
1118 const DetectContentData *cd = (DetectContentData *)sm->ctx;
1119 /* fast_pattern set in rule, so using this pattern */
1120 if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
1121 SetMpm(s, sm, DETECT_SM_LIST_PMATCH);
1122 return;
1123 }
1124
1125 if (cd->flags & DETECT_CONTENT_NEGATED) {
1126 neg_sm_list[DETECT_SM_LIST_PMATCH] = 1;
1127 neg_sm_list_cnt++;
1128 } else {
1129 pos_sm_list[DETECT_SM_LIST_PMATCH] = 1;
1130 pos_sm_list_cnt++;
1131 }
1132 }
1133 }
1134 }
1135 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1136 const int list_id = s->init_data->buffers[x].id;
1137
1138 SCLogDebug("%u: list_id %d: %s", s->id, list_id,
1140
1142 SCLogDebug("skip");
1143 continue;
1144 }
1145
1146 for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
1147 // a buffer with absent keyword cannot be used as fast_pattern
1148 if (sm->type == DETECT_ABSENT)
1149 break;
1150 if (sm->type != DETECT_CONTENT)
1151 continue;
1152
1153 const DetectContentData *cd = (DetectContentData *)sm->ctx;
1154 /* fast_pattern set in rule, so using this pattern */
1155 if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
1156 SetMpm(s, sm, list_id);
1157 return;
1158 }
1159
1160 if (cd->flags & DETECT_CONTENT_NEGATED) {
1161 neg_sm_list[list_id] = 1;
1162 neg_sm_list_cnt++;
1163 } else {
1164 pos_sm_list[list_id] = 1;
1165 pos_sm_list_cnt++;
1166 SCLogDebug("pos added for %d", list_id);
1167 }
1168 }
1169 SCLogDebug("ok");
1170 }
1171
1172 SCLogDebug("neg_sm_list_cnt %d pos_sm_list_cnt %d", neg_sm_list_cnt, pos_sm_list_cnt);
1173
1174 /* prefer normal not-negated over negated */
1175 int *curr_sm_list = NULL;
1176 int skip_negated_content = 1;
1177 if (pos_sm_list_cnt > 0) {
1178 curr_sm_list = pos_sm_list;
1179 } else if (neg_sm_list_cnt > 0) {
1180 curr_sm_list = neg_sm_list;
1181 skip_negated_content = 0;
1182 } else {
1183 return;
1184 }
1185
1186 int final_sm_list[nlists];
1187 memset(&final_sm_list, 0, (nlists * sizeof(int)));
1188
1189 int count_final_sm_list = 0;
1190 int count_txbidir_toclient_sm_list = 0;
1191 int priority;
1192
1194 while (tmp != NULL) {
1195 for (priority = tmp->priority;
1196 tmp != NULL && priority == tmp->priority;
1197 tmp = tmp->next)
1198 {
1199 SCLogDebug("tmp->list_id %d tmp->priority %d", tmp->list_id, tmp->priority);
1200 if (tmp->list_id >= nlists)
1201 continue;
1202 if (curr_sm_list[tmp->list_id] == 0)
1203 continue;
1204 if (s->flags & SIG_FLAG_TXBOTHDIR) {
1205 // prefer to choose a fast_pattern to server by default
1206 if (DetectBufferToClient(de_ctx, tmp->list_id, s->alproto)) {
1207 if (count_final_sm_list == 0) {
1208 // still put it in in the case we do not have toserver buffer
1209 final_sm_list[count_txbidir_toclient_sm_list++] = tmp->list_id;
1210 }
1211 continue;
1212 }
1213 }
1214 // we may erase tx bidir toclient buffers here as intended if we have a better choice
1215 final_sm_list[count_final_sm_list++] = tmp->list_id;
1216 SCLogDebug("tmp->list_id %d", tmp->list_id);
1217 }
1218 if (count_final_sm_list != 0)
1219 break;
1220 }
1221
1222 if ((s->flags & SIG_FLAG_TXBOTHDIR) && count_final_sm_list == 0) {
1223 // forced to pick a fast_pattern to client for tx bidir signature
1224 count_final_sm_list = count_txbidir_toclient_sm_list;
1225 }
1226 BUG_ON(count_final_sm_list == 0);
1227 SCLogDebug("count_final_sm_list %d skip_negated_content %d", count_final_sm_list,
1228 skip_negated_content);
1229
1230 uint16_t max_len = 0;
1231 for (int i = 0; i < count_final_sm_list; i++) {
1232 SCLogDebug("i %d final_sm_list[i] %d", i, final_sm_list[i]);
1233
1234 if (final_sm_list[i] == DETECT_SM_LIST_PMATCH) {
1235 for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
1236 sm = sm->next) {
1237 if (sm->type != DETECT_CONTENT)
1238 continue;
1239
1240 const DetectContentData *cd = (DetectContentData *)sm->ctx;
1241 /* skip_negated_content is only set if there's absolutely no
1242 * non-negated content present in the sig */
1243 if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
1244 continue;
1245 max_len = MAX(max_len, cd->content_len);
1246 }
1247 } else {
1248 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1249 if (s->init_data->buffers[x].only_tc) {
1250 // prefer to choose a fast_pattern to server by default
1251 continue;
1252 }
1253 const int list_id = s->init_data->buffers[x].id;
1254
1255 if (final_sm_list[i] == list_id) {
1256 SCLogDebug("%u: list_id %d: %s", s->id, list_id,
1258
1259 for (SigMatch *sm = s->init_data->buffers[x].head; sm != NULL; sm = sm->next) {
1260 if (sm->type != DETECT_CONTENT)
1261 continue;
1262
1263 const DetectContentData *cd = (DetectContentData *)sm->ctx;
1264 /* skip_negated_content is only set if there's absolutely no
1265 * non-negated content present in the sig */
1266 if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
1267 continue;
1268 max_len = MAX(max_len, cd->content_len);
1269 }
1270 }
1271 }
1272 }
1273 }
1274
1275 SigMatch *mpm_sm = NULL;
1276 int mpm_sm_list = -1;
1277 for (int i = 0; i < count_final_sm_list; i++) {
1278 SCLogDebug("i %d", i);
1279 if (final_sm_list[i] == DETECT_SM_LIST_PMATCH) {
1280 /* GetMpmForList may keep `mpm_sm` the same, so track if it changed */
1281 SigMatch *prev_mpm_sm = mpm_sm;
1282 mpm_sm = GetMpmForList(s, s->init_data->smlists[DETECT_SM_LIST_PMATCH], mpm_sm, max_len,
1283 skip_negated_content);
1284 if (mpm_sm != prev_mpm_sm) {
1285 mpm_sm_list = final_sm_list[i];
1286 }
1287 } else {
1288 SCLogDebug(
1289 "%u: %s", s->id, DetectEngineBufferTypeGetNameById(de_ctx, final_sm_list[i]));
1290 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1291 const int list_id = s->init_data->buffers[x].id;
1292 if (final_sm_list[i] == list_id) {
1293 SCLogDebug("%u: list_id %d: %s", s->id, list_id,
1295 /* GetMpmForList may keep `mpm_sm` the same, so track if it changed */
1296 SigMatch *prev_mpm_sm = mpm_sm;
1297 mpm_sm = GetMpmForList(s, s->init_data->buffers[x].head, mpm_sm, max_len,
1298 skip_negated_content);
1299 SCLogDebug("mpm_sm %p from %p", mpm_sm, s->init_data->buffers[x].head);
1300 if (mpm_sm != prev_mpm_sm) {
1301 mpm_sm_list = list_id;
1302 }
1303 }
1304 }
1305 }
1306 }
1307
1308#ifdef DEBUG
1309 if (mpm_sm != NULL) {
1310 BUG_ON(mpm_sm_list == -1);
1311 int check_list = SigMatchListSMBelongsTo(s, mpm_sm);
1312 BUG_ON(check_list != mpm_sm_list);
1313 }
1314#endif
1315 /* assign to signature */
1316 SetMpm(s, mpm_sm, mpm_sm_list);
1317}
1318
1319/** \internal
1320 * \brief The hash function for MpmStore
1321 *
1322 * \param ht Pointer to the hash table.
1323 * \param data Pointer to the MpmStore.
1324 * \param datalen Not used in our case.
1325 *
1326 * \retval hash The generated hash value.
1327 */
1328static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
1329{
1330 const MpmStore *ms = (MpmStore *)data;
1331 uint32_t hash = ms->alproto;
1332
1333 for (uint32_t b = 0; b < ms->sid_array_size; b++)
1334 hash += ms->sid_array[b];
1335
1336 return hash % ht->array_size;
1337}
1338
1339/**
1340 * \brief The Compare function for MpmStore
1341 *
1342 * \param data1 Pointer to the first MpmStore.
1343 * \param len1 Not used.
1344 * \param data2 Pointer to the second MpmStore.
1345 * \param len2 Not used.
1346 *
1347 * \retval 1 If the 2 MpmStores sent as args match.
1348 * \retval 0 If the 2 MpmStores sent as args do not match.
1349 */
1350static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2,
1351 uint16_t len2)
1352{
1353 const MpmStore *ms1 = (MpmStore *)data1;
1354 const MpmStore *ms2 = (MpmStore *)data2;
1355
1356 if (ms1->alproto != ms2->alproto)
1357 return 0;
1358
1359 if (ms1->sid_array_size != ms2->sid_array_size)
1360 return 0;
1361
1362 if (ms1->buffer != ms2->buffer)
1363 return 0;
1364
1365 if (ms1->direction != ms2->direction)
1366 return 0;
1367
1368 if (ms1->sm_list != ms2->sm_list)
1369 return 0;
1370
1371 if (SCMemcmp(ms1->sid_array, ms2->sid_array,
1372 ms1->sid_array_size) != 0)
1373 {
1374 return 0;
1375 }
1376
1377 return 1;
1378}
1379
1380static void MpmStoreFreeFunc(void *ptr)
1381{
1382 MpmStore *ms = ptr;
1383 if (ms != NULL) {
1384 if (ms->mpm_ctx != NULL && !(ms->mpm_ctx->flags & MPMCTX_FLAGS_GLOBAL))
1385 {
1386 SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx);
1388 SCFree(ms->mpm_ctx);
1389 }
1390 ms->mpm_ctx = NULL;
1391
1392 SCFree(ms->sid_array);
1393 SCFree(ms);
1394 }
1395}
1396
1397/**
1398 * \brief Initializes the MpmStore mpm hash table to be used by the detection
1399 * engine context.
1400 *
1401 * \param de_ctx Pointer to the detection engine context.
1402 *
1403 * \retval 0 On success.
1404 * \retval -1 On failure.
1405 */
1407{
1409 MpmStoreHashFunc,
1410 MpmStoreCompareFunc,
1411 MpmStoreFreeFunc);
1412 if (de_ctx->mpm_hash_table == NULL)
1413 goto error;
1414
1415 return 0;
1416
1417error:
1418 return -1;
1419}
1420
1421/**
1422 * \brief Adds a MpmStore to the detection engine context MpmStore
1423 *
1424 * \param de_ctx Pointer to the detection engine context.
1425 * \param sgh Pointer to the MpmStore.
1426 *
1427 * \retval ret 0 on Successfully adding the argument sgh; -1 on failure.
1428 */
1429static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s)
1430{
1431 int ret = HashListTableAdd(de_ctx->mpm_hash_table, (void *)s, 0);
1432 return ret;
1433}
1434
1435/**
1436 * \brief Used to lookup a MpmStore from the MpmStore
1437 *
1438 * \param de_ctx Pointer to the detection engine context.
1439 * \param sgh Pointer to the MpmStore.
1440 *
1441 * \retval rsgh On success a pointer to the MpmStore if the MpmStore is
1442 * found in the hash table; NULL on failure.
1443 */
1444static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s)
1445{
1447 (void *)s, 0);
1448 return rs;
1449}
1450
1451static const DetectBufferMpmRegistry *GetByMpmStore(
1452 const DetectEngineCtx *de_ctx, const MpmStore *ms)
1453{
1455 while (am != NULL) {
1456 if (ms->sm_list == am->sm_list &&
1457 ms->direction == am->direction) {
1458 return am;
1459 }
1460 am = am->next;
1461 }
1462 am = de_ctx->pkt_mpms_list;
1463 while (am != NULL) {
1464 if (ms->sm_list == am->sm_list) {
1465 return am;
1466 }
1467 am = am->next;
1468 }
1469 return NULL;
1470}
1471
1473{
1474 HashListTableBucket *htb = NULL;
1475
1476 uint32_t stats[MPMB_MAX] = {0};
1477 int app_mpms_cnt = de_ctx->buffer_type_id;
1478 uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build
1479 memset(&appstats, 0x00, sizeof(appstats));
1480 int pkt_mpms_cnt = de_ctx->buffer_type_id;
1481 uint32_t pktstats[pkt_mpms_cnt + 1]; // +1 to silence scan-build
1482 memset(&pktstats, 0x00, sizeof(pktstats));
1483 int frame_mpms_cnt = de_ctx->buffer_type_id;
1484 uint32_t framestats[frame_mpms_cnt + 1]; // +1 to silence scan-build
1485 memset(&framestats, 0x00, sizeof(framestats));
1486
1488 htb != NULL;
1489 htb = HashListTableGetListNext(htb))
1490 {
1491 const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb);
1492 if (ms == NULL || ms->mpm_ctx == NULL) {
1493 continue;
1494 }
1495 if (ms->buffer < MPMB_MAX)
1496 stats[ms->buffer]++;
1497 else if (ms->sm_list != DETECT_SM_LIST_PMATCH) {
1498 const DetectBufferMpmRegistry *am = GetByMpmStore(de_ctx, ms);
1499 if (am != NULL) {
1500 switch (am->type) {
1502 SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p",
1503 am->name,
1504 ms->mpm_ctx->pattern_cnt,
1505 ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
1506 ms->mpm_ctx);
1507 pktstats[am->sm_list]++;
1508 break;
1510 SCLogDebug("%s %s %s: %u patterns. Min %u, Max %u. Ctx %p",
1511 AppProtoToString(ms->alproto), am->name,
1512 am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1514 ms->mpm_ctx);
1515 appstats[am->sm_list]++;
1516 break;
1518 SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p", am->name,
1520 ms->mpm_ctx);
1521 framestats[am->sm_list]++;
1522 break;
1524 break;
1525 }
1526 }
1527 }
1528 }
1529
1530 if (!(de_ctx->flags & DE_QUIET)) {
1531 for (int x = 0; x < MPMB_MAX; x++) {
1532 SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]);
1533 }
1535 while (am != NULL) {
1536 if (appstats[am->sm_list] > 0) {
1537 const char *name = am->name;
1538 const char *direction = am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient";
1539 SCLogPerf("AppLayer MPM \"%s %s (%s)\": %u", direction, name,
1540 AppProtoToString(am->app_v2.alproto), appstats[am->sm_list]);
1541 }
1542 am = am->next;
1543 }
1545 while (pm != NULL) {
1546 if (pktstats[pm->sm_list] > 0) {
1547 const char *name = pm->name;
1548 SCLogPerf("Pkt MPM \"%s\": %u", name, pktstats[pm->sm_list]);
1549 }
1550 pm = pm->next;
1551 }
1553 while (um != NULL) {
1554 if (framestats[um->sm_list] > 0) {
1555 const char *name = um->name;
1556 SCLogPerf("Frame MPM \"%s\": %u", name, framestats[um->sm_list]);
1557 }
1558 um = um->next;
1559 }
1560 }
1561}
1562
1563/**
1564 * \brief Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by
1565 * MpmStoreInit() function.
1566 *
1567 * \param de_ctx Pointer to the detection engine context.
1568 */
1570{
1571 if (de_ctx->mpm_hash_table == NULL)
1572 return;
1573
1575 de_ctx->mpm_hash_table = NULL;
1576}
1577
1578static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
1579{
1580 const Signature *s = NULL;
1581 uint32_t sig;
1582 int dir = 0;
1583
1584 if (ms->buffer != MPMB_MAX) {
1586
1587 switch (ms->buffer) {
1588 /* TS is 1 */
1589 case MPMB_TCP_PKT_TS:
1590 case MPMB_TCP_STREAM_TS:
1591 case MPMB_UDP_TS:
1592 dir = 1;
1593 break;
1594
1595 /* TC is 0 */
1596 default:
1597 case MPMB_UDP_TC:
1598 case MPMB_TCP_STREAM_TC:
1599 case MPMB_TCP_PKT_TC:
1600 case MPMB_OTHERIP: /**< use 0 for other */
1601 dir = 0;
1602 break;
1603 }
1604 } else {
1606
1607 if (ms->direction == SIG_FLAG_TOSERVER)
1608 dir = 1;
1609 else
1610 dir = 0;
1611 }
1612
1614 if (ms->mpm_ctx == NULL) {
1615 return;
1616 }
1617
1619
1622
1623 const bool mpm_supports_endswith =
1625
1626 /* add the patterns */
1627 for (sig = 0; sig < (ms->sid_array_size * 8); sig++) {
1628 if (ms->sid_array[sig / 8] & (1 << (sig % 8))) {
1629 s = de_ctx->sig_array[sig];
1630 DEBUG_VALIDATE_BUG_ON(s == NULL);
1631 if (s == NULL)
1632 continue;
1633
1634 SCLogDebug("%p: direction %d adding %u", ms, ms->direction, s->id);
1635
1637
1638 int skip = 0;
1639 /* negated logic: if mpm match can't be used to be sure about this
1640 * pattern, we have to inspect the rule fully regardless of mpm
1641 * match. So in this case there is no point of adding it at all.
1642 * The non-mpm list entry for the sig will make sure the sig is
1643 * inspected. */
1644 if ((cd->flags & DETECT_CONTENT_NEGATED) &&
1646 {
1647 skip = 1;
1648 SCLogDebug("not adding negated mpm as it's not 'single'");
1649 }
1650
1651 if (!skip) {
1652 uint8_t flags = 0;
1653 if ((cd->flags & DETECT_CONTENT_ENDS_WITH) && mpm_supports_endswith)
1655 PopulateMpmHelperAddPattern(ms->mpm_ctx, cd, s, flags,
1657 }
1658 }
1659 }
1660
1661 if (ms->mpm_ctx->pattern_cnt == 0) {
1663 ms->mpm_ctx = NULL;
1664 } else {
1666 if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) {
1668 }
1669 }
1670 }
1671}
1672
1673
1674/** \brief Get MpmStore for a built-in buffer type
1675 *
1676 */
1678 enum MpmBuiltinBuffers buf)
1679{
1680 const Signature *s = NULL;
1681 uint32_t sig;
1682 uint32_t cnt = 0;
1683 int direction = 0;
1684 uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1685 uint8_t sids_array[max_sid];
1686 memset(sids_array, 0x00, max_sid);
1687 int sgh_mpm_context = 0;
1688 int sm_list = DETECT_SM_LIST_PMATCH;
1689
1690 switch (buf) {
1691 case MPMB_TCP_PKT_TS:
1692 case MPMB_TCP_PKT_TC:
1693 sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet;
1694 break;
1695 case MPMB_TCP_STREAM_TS:
1696 case MPMB_TCP_STREAM_TC:
1697 sgh_mpm_context = de_ctx->sgh_mpm_context_stream;
1698 break;
1699 case MPMB_UDP_TS:
1700 case MPMB_UDP_TC:
1701 sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet;
1702 break;
1703 case MPMB_OTHERIP:
1704 sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet;
1705 break;
1706 default:
1707 break;
1708 }
1709
1710 switch(buf) {
1711 case MPMB_TCP_PKT_TS:
1712 case MPMB_TCP_STREAM_TS:
1713 case MPMB_UDP_TS:
1714 direction = SIG_FLAG_TOSERVER;
1715 break;
1716
1717 case MPMB_TCP_PKT_TC:
1718 case MPMB_TCP_STREAM_TC:
1719 case MPMB_UDP_TC:
1720 direction = SIG_FLAG_TOCLIENT;
1721 break;
1722
1723 case MPMB_OTHERIP:
1725 break;
1726
1727 case MPMB_MAX:
1728 BUG_ON(1);
1729 break;
1730 }
1731
1732 for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
1733 s = sgh->init->match_array[sig];
1734 if (s == NULL)
1735 continue;
1736
1737 if (s->init_data->mpm_sm == NULL)
1738 continue;
1739
1740 int list = s->init_data->mpm_sm_list;
1741 if (list < 0)
1742 continue;
1743
1744 if (list != DETECT_SM_LIST_PMATCH)
1745 continue;
1746
1747 switch (buf) {
1748 case MPMB_TCP_PKT_TS:
1749 case MPMB_TCP_PKT_TC:
1750 if (SignatureHasPacketContent(s) == 1)
1751 {
1752 sids_array[s->iid / 8] |= 1 << (s->iid % 8);
1753 cnt++;
1754 }
1755 break;
1756 case MPMB_TCP_STREAM_TS:
1757 case MPMB_TCP_STREAM_TC:
1758 if (SignatureHasStreamContent(s) == 1)
1759 {
1760 sids_array[s->iid / 8] |= 1 << (s->iid % 8);
1761 cnt++;
1762 }
1763 break;
1764 case MPMB_UDP_TS:
1765 case MPMB_UDP_TC:
1766 sids_array[s->iid / 8] |= 1 << (s->iid % 8);
1767 cnt++;
1768 break;
1769 case MPMB_OTHERIP:
1770 sids_array[s->iid / 8] |= 1 << (s->iid % 8);
1771 cnt++;
1772 break;
1773 default:
1774 break;
1775 }
1776 }
1777
1778 if (cnt == 0)
1779 return NULL;
1780
1781 MpmStore lookup = { sids_array, max_sid, direction, buf, sm_list, 0, 0, NULL };
1782
1783 MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1784 if (result == NULL) {
1785 MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1786 if (copy == NULL)
1787 return NULL;
1788 uint8_t *sids = SCCalloc(1, max_sid);
1789 if (sids == NULL) {
1790 SCFree(copy);
1791 return NULL;
1792 }
1793
1794 memcpy(sids, sids_array, max_sid);
1795 copy->sid_array = sids;
1796 copy->sid_array_size = max_sid;
1797 copy->buffer = buf;
1798 copy->direction = direction;
1799 copy->sm_list = sm_list;
1800 copy->sgh_mpm_context = sgh_mpm_context;
1801
1802 MpmStoreSetup(de_ctx, copy);
1803 MpmStoreAdd(de_ctx, copy);
1804 return copy;
1805 } else {
1806 return result;
1807 }
1808}
1809
1811 uint8_t *sids_array;
1813 /* indicates this has an active engine */
1815
1817};
1818
1819static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
1820 const DetectBufferMpmRegistry *am, const struct SidsArray *sa)
1821{
1822 if (sa->sids_array_size == 0 || sa->sids_array == NULL)
1823 return NULL;
1824
1825 SCLogDebug("handling %s direction %s for list %d", am->name,
1826 am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1827 am->sm_list);
1828
1829 MpmStore lookup = { sa->sids_array, sa->sids_array_size, am->direction, MPMB_MAX, am->sm_list,
1830 0, am->app_v2.alproto, NULL };
1831 SCLogDebug("am->direction %d am->sm_list %d sgh_mpm_context %d", am->direction, am->sm_list,
1832 am->sgh_mpm_context);
1833
1834 MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1835 if (result == NULL) {
1836 SCLogDebug("new unique mpm for %s %s", am->name,
1837 am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient");
1838
1839 MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1840 if (copy == NULL)
1841 return NULL;
1842 uint8_t *sids = SCCalloc(1, sa->sids_array_size);
1843 if (sids == NULL) {
1844 SCFree(copy);
1845 return NULL;
1846 }
1847
1848 memcpy(sids, sa->sids_array, sa->sids_array_size);
1849 copy->sid_array = sids;
1850 copy->sid_array_size = sa->sids_array_size;
1851 copy->buffer = MPMB_MAX;
1852 copy->direction = am->direction;
1853 copy->sm_list = am->sm_list;
1854 copy->sgh_mpm_context = am->sgh_mpm_context;
1855 copy->alproto = am->app_v2.alproto;
1856
1857 MpmStoreSetup(de_ctx, copy);
1858 MpmStoreAdd(de_ctx, copy);
1859 return copy;
1860 } else {
1861 SCLogDebug("using existing mpm %p", result);
1862 return result;
1863 }
1864 return NULL;
1865}
1866
1867static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
1868 const DetectBufferMpmRegistry *am, const struct SidsArray *sa)
1869{
1870 SCLogDebug("handling %s for list %d", am->name,
1871 am->sm_list);
1872
1873 if (sa->sids_array_size == 0 || sa->sids_array == NULL)
1874 return NULL;
1875
1877 MPMB_MAX, am->sm_list, 0, 0, NULL };
1878 SCLogDebug("am->sm_list %d", am->sm_list);
1879
1880 MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1881 if (result == NULL) {
1882 SCLogDebug("new unique mpm for %s", am->name);
1883
1884 MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1885 if (copy == NULL)
1886 return NULL;
1887 uint8_t *sids = SCCalloc(1, sa->sids_array_size);
1888 if (sids == NULL) {
1889 SCFree(copy);
1890 return NULL;
1891 }
1892
1893 memcpy(sids, sa->sids_array, sa->sids_array_size);
1894 copy->sid_array = sids;
1895 copy->sid_array_size = sa->sids_array_size;
1896 copy->buffer = MPMB_MAX;
1898 copy->sm_list = am->sm_list;
1899 copy->sgh_mpm_context = am->sgh_mpm_context;
1900
1901 MpmStoreSetup(de_ctx, copy);
1902 MpmStoreAdd(de_ctx, copy);
1903 return copy;
1904 } else {
1905 SCLogDebug("using existing mpm %p", result);
1906 return result;
1907 }
1908 return NULL;
1909}
1910
1911static MpmStore *MpmStorePrepareBufferFrame(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
1912 const DetectBufferMpmRegistry *am, const struct SidsArray *sa)
1913{
1914 SCLogDebug("handling %s for list %d", am->name, am->sm_list);
1915
1916 if (sa->sids_array_size == 0 || sa->sids_array == NULL)
1917 return NULL;
1918
1919 MpmStore lookup = { sa->sids_array, sa->sids_array_size, am->direction, MPMB_MAX, am->sm_list,
1920 0, am->frame_v1.alproto, NULL };
1921 SCLogDebug("am->sm_list %d", am->sm_list);
1922
1923 MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1924 if (result == NULL) {
1925 SCLogDebug("new unique mpm for %s", am->name);
1926
1927 MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1928 if (copy == NULL)
1929 return NULL;
1930 uint8_t *sids = SCCalloc(1, sa->sids_array_size);
1931 if (sids == NULL) {
1932 SCFree(copy);
1933 return NULL;
1934 }
1935
1936 memcpy(sids, sa->sids_array, sa->sids_array_size);
1937 copy->sid_array = sids;
1938 copy->sid_array_size = sa->sids_array_size;
1939 copy->buffer = MPMB_MAX;
1940 copy->direction = am->direction;
1941 copy->sm_list = am->sm_list;
1942 copy->sgh_mpm_context = am->sgh_mpm_context;
1943 copy->alproto = am->frame_v1.alproto;
1944
1945 MpmStoreSetup(de_ctx, copy);
1946 MpmStoreAdd(de_ctx, copy);
1947 return copy;
1948 } else {
1949 SCLogDebug("using existing mpm %p", result);
1950 return result;
1951 }
1952 return NULL;
1953}
1954
1955static void SetRawReassemblyFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1956{
1957 const Signature *s = NULL;
1958 uint32_t sig;
1959
1960 for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
1961 s = sgh->init->match_array[sig];
1962 if (s == NULL)
1963 continue;
1964
1965 if (SignatureHasStreamContent(s) == 1) {
1967 SCLogDebug("rule group %p has SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1968 return;
1969 }
1970 }
1971 SCLogDebug("rule group %p does NOT have SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1972}
1973
1982
1983static uint32_t DetectBufferInstanceHashFunc(HashListTable *ht, void *data, uint16_t datalen)
1984{
1985 const DetectBufferInstance *ms = (const DetectBufferInstance *)data;
1986 uint32_t hash = ms->list + ms->alproto;
1987 return hash % ht->array_size;
1988}
1989
1990static char DetectBufferInstanceCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
1991{
1992 const DetectBufferInstance *ms1 = (DetectBufferInstance *)data1;
1993 const DetectBufferInstance *ms2 = (DetectBufferInstance *)data2;
1994 return (ms1->list == ms2->list && ms1->alproto == ms2->alproto);
1995}
1996
1997static void DetectBufferInstanceFreeFunc(void *ptr)
1998{
1999 DetectBufferInstance *ms = ptr;
2000 if (ms->ts.sids_array != NULL)
2001 SCFree(ms->ts.sids_array);
2002 if (ms->tc.sids_array != NULL)
2003 SCFree(ms->tc.sids_array);
2004 SCFree(ms);
2005}
2006
2007static HashListTable *DetectBufferInstanceInit(void)
2008{
2009 return HashListTableInit(4096, DetectBufferInstanceHashFunc, DetectBufferInstanceCompareFunc,
2010 DetectBufferInstanceFreeFunc);
2011}
2012
2013static void PrepareMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
2014{
2015 HashListTable *bufs = DetectBufferInstanceInit();
2016 BUG_ON(bufs == NULL);
2017
2018 const int max_buffer_id = de_ctx->buffer_type_id + 1;
2019 const uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
2020
2021 AppProto engines[max_buffer_id][g_alproto_max];
2022 memset(engines, 0, sizeof(engines));
2023 int engines_idx[max_buffer_id];
2024 memset(engines_idx, 0, sizeof(engines_idx));
2025 int types[max_buffer_id];
2026 memset(types, 0, sizeof(types));
2027
2028 /* flag the list+directions we have engines for as active */
2029 for (DetectBufferMpmRegistry *a = de_ctx->pkt_mpms_list; a != NULL; a = a->next) {
2030 types[a->sm_list] = a->type;
2031
2032 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = ALPROTO_UNKNOWN };
2033 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2034 if (instance == NULL) {
2035 instance = SCCalloc(1, sizeof(*instance));
2036 BUG_ON(instance == NULL);
2037 instance->list = a->sm_list;
2038 instance->alproto = ALPROTO_UNKNOWN;
2039 HashListTableAdd(bufs, instance, 0);
2040 }
2041 instance->ts.active = true;
2042 instance->tc.active = true;
2043 }
2044 for (DetectBufferMpmRegistry *a = de_ctx->frame_mpms_list; a != NULL; a = a->next) {
2045 const bool add_ts = ((a->direction == SIG_FLAG_TOSERVER) && SGH_DIRECTION_TS(sh));
2046 const bool add_tc = ((a->direction == SIG_FLAG_TOCLIENT) && SGH_DIRECTION_TC(sh));
2047 if (add_ts || add_tc) {
2048 types[a->sm_list] = a->type;
2049 engines[a->sm_list][engines_idx[a->sm_list]++] = a->frame_v1.alproto;
2050
2051 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = a->frame_v1.alproto };
2052 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2053 if (instance == NULL) {
2054 instance = SCCalloc(1, sizeof(*instance));
2055 BUG_ON(instance == NULL);
2056 instance->list = a->sm_list;
2057 instance->alproto = a->frame_v1.alproto;
2058 HashListTableAdd(bufs, instance, 0);
2059 }
2060 instance->ts.active |= add_ts;
2061 instance->tc.active |= add_tc;
2062 }
2063 }
2064 for (DetectBufferMpmRegistry *a = de_ctx->app_mpms_list; a != NULL; a = a->next) {
2065 const bool add_ts = ((a->direction == SIG_FLAG_TOSERVER) && SGH_DIRECTION_TS(sh));
2066 const bool add_tc = ((a->direction == SIG_FLAG_TOCLIENT) && SGH_DIRECTION_TC(sh));
2067 if (add_ts || add_tc) {
2068 types[a->sm_list] = a->type;
2069 engines[a->sm_list][engines_idx[a->sm_list]++] = a->app_v2.alproto;
2070
2071 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = a->app_v2.alproto };
2072 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2073 if (instance == NULL) {
2074 instance = SCCalloc(1, sizeof(*instance));
2075 BUG_ON(instance == NULL);
2076 instance->list = a->sm_list;
2077 instance->alproto = a->app_v2.alproto;
2078 HashListTableAdd(bufs, instance, 0);
2079 }
2080 instance->ts.active |= add_ts;
2081 instance->tc.active |= add_tc;
2082 }
2083 }
2084
2085 for (uint32_t sig = 0; sig < sh->init->sig_cnt; sig++) {
2086 const Signature *s = sh->init->match_array[sig];
2087 if (s == NULL)
2088 continue;
2089 if (s->init_data->mpm_sm == NULL)
2090 continue;
2091 const int list = s->init_data->mpm_sm_list;
2092 if (list < 0)
2093 continue;
2094 if (list == DETECT_SM_LIST_PMATCH)
2095 continue;
2096
2097 switch (types[list]) {
2098 /* app engines are direction aware */
2101 for (int e = 0; e < engines_idx[list]; e++) {
2102 const AppProto alproto = engines[list][e];
2103 if (!(AppProtoEquals(s->alproto, alproto) || s->alproto == 0))
2104 continue;
2105
2106 DetectBufferInstance lookup = { .list = list, .alproto = alproto };
2107 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2108 if (instance == NULL)
2109 continue;
2110 if (s->flags & SIG_FLAG_TOSERVER) {
2111 struct SidsArray *sa = &instance->ts;
2112 if (sa->active) {
2113 if (sa->sids_array == NULL) {
2114 sa->sids_array = SCCalloc(1, max_sid);
2115 sa->sids_array_size = max_sid;
2116 BUG_ON(sa->sids_array == NULL); // TODO
2117 }
2118 sa->sids_array[s->iid / 8] |= 1 << (s->iid % 8);
2119 SCLogDebug("instance %p: stored %u/%u ts", instance, s->id, s->iid);
2120 }
2121 }
2122 if (s->flags & SIG_FLAG_TOCLIENT) {
2123 struct SidsArray *sa = &instance->tc;
2124 if (sa->active) {
2125 if (sa->sids_array == NULL) {
2126 sa->sids_array = SCCalloc(1, max_sid);
2127 sa->sids_array_size = max_sid;
2128 BUG_ON(sa->sids_array == NULL); // TODO
2129 }
2130 sa->sids_array[s->iid / 8] |= 1 << (s->iid % 8);
2131 SCLogDebug("instance %p: stored %u/%u tc", instance, s->id, s->iid);
2132 }
2133 }
2134 }
2135 break;
2136 }
2137 /* pkt engines are directionless, so only use ts */
2139 DetectBufferInstance lookup = { .list = list, .alproto = ALPROTO_UNKNOWN };
2140 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2141 if (instance == NULL)
2142 continue;
2143 struct SidsArray *sa = &instance->ts;
2144 if (sa->active) {
2145 if (sa->sids_array == NULL) {
2146 sa->sids_array = SCCalloc(1, max_sid);
2147 sa->sids_array_size = max_sid;
2148 BUG_ON(sa->sids_array == NULL); // TODO
2149 }
2150 sa->sids_array[s->iid / 8] |= 1 << (s->iid % 8);
2151 }
2152 break;
2153 }
2154 default:
2155 BUG_ON(1);
2156 }
2157 }
2158
2160 BUG_ON(sh->init->app_mpms == NULL);
2161
2163 BUG_ON(sh->init->pkt_mpms == NULL);
2164
2166 BUG_ON(sh->init->frame_mpms == NULL);
2167
2168 for (DetectBufferMpmRegistry *a = de_ctx->pkt_mpms_list; a != NULL; a = a->next) {
2169 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = ALPROTO_UNKNOWN };
2170 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2171 if (instance == NULL) {
2172 continue;
2173 }
2174 struct SidsArray *sa = &instance->ts;
2175 if (!sa->active)
2176 continue;
2177
2178 MpmStore *mpm_store = MpmStorePrepareBufferPkt(de_ctx, sh, a, sa);
2179 if (mpm_store != NULL) {
2180 sh->init->pkt_mpms[a->id] = mpm_store->mpm_ctx;
2181
2182 SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p "
2183 "mpm_store->mpm_ctx %p", a, a->name,
2184 a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
2185
2186 /* if we have just certain types of negated patterns,
2187 * mpm_ctx can be NULL */
2188 if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
2189 BUG_ON(a->PrefilterRegisterWithListId(de_ctx,
2190 sh, mpm_store->mpm_ctx,
2191 a, a->sm_list) != 0);
2192 SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
2193 }
2194 }
2195 }
2196 for (DetectBufferMpmRegistry *a = de_ctx->frame_mpms_list; a != NULL; a = a->next) {
2197 if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) ||
2198 (a->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) {
2199 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = a->frame_v1.alproto };
2200 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2201 if (instance == NULL) {
2202 continue;
2203 }
2204 struct SidsArray *sa =
2205 (a->direction == SIG_FLAG_TOSERVER) ? &instance->ts : &instance->tc;
2206 if (!sa->active)
2207 continue;
2208
2209 SCLogDebug("a %s direction %d PrefilterRegisterWithListId %p", a->name, a->direction,
2210 a->PrefilterRegisterWithListId);
2211 MpmStore *mpm_store = MpmStorePrepareBufferFrame(de_ctx, sh, a, sa);
2212 if (mpm_store != NULL) {
2213 sh->init->frame_mpms[a->id] = mpm_store->mpm_ctx;
2214
2215 SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p "
2216 "mpm_store->mpm_ctx %p",
2217 a, a->name, a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
2218
2219 /* if we have just certain types of negated patterns,
2220 * mpm_ctx can be NULL */
2221 SCLogDebug("mpm_store %p mpm_ctx %p", mpm_store, mpm_store->mpm_ctx);
2222 if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
2223 BUG_ON(a->PrefilterRegisterWithListId(
2224 de_ctx, sh, mpm_store->mpm_ctx, a, a->sm_list) != 0);
2225 SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
2226 }
2227 }
2228 }
2229 }
2230 for (DetectBufferMpmRegistry *a = de_ctx->app_mpms_list; a != NULL; a = a->next) {
2231 if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) ||
2232 (a->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) {
2233
2234 DetectBufferInstance lookup = { .list = a->sm_list, .alproto = a->app_v2.alproto };
2235 DetectBufferInstance *instance = HashListTableLookup(bufs, &lookup, 0);
2236 if (instance == NULL) {
2237 continue;
2238 }
2239 struct SidsArray *sa =
2240 (a->direction == SIG_FLAG_TOSERVER) ? &instance->ts : &instance->tc;
2241 if (!sa->active)
2242 continue;
2243
2244 MpmStore *mpm_store = MpmStorePrepareBufferAppLayer(de_ctx, sh, a, sa);
2245 if (mpm_store != NULL) {
2246 sh->init->app_mpms[a->id] = mpm_store->mpm_ctx;
2247
2248 SCLogDebug("a %p a->name %s a->PrefilterRegisterWithListId %p "
2249 "mpm_store->mpm_ctx %p",
2250 a, a->name, a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
2251
2252 /* if we have just certain types of negated patterns,
2253 * mpm_ctx can be NULL */
2254 if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
2255 BUG_ON(a->PrefilterRegisterWithListId(
2256 de_ctx, sh, mpm_store->mpm_ctx, a, a->sm_list) != 0);
2257 SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
2258 }
2259 }
2260 }
2261 }
2262 HashListTableFree(bufs);
2263}
2264
2265/** \brief Prepare the pattern matcher ctx in a sig group head.
2266 *
2267 */
2269{
2270 MpmStore *mpm_store = NULL;
2271 if (SGH_PROTO(sh, IPPROTO_TCP)) {
2272 if (SGH_DIRECTION_TS(sh)) {
2274 if (mpm_store != NULL) {
2276 }
2277
2279 if (mpm_store != NULL) {
2280 PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
2281 }
2282
2283 SetRawReassemblyFlag(de_ctx, sh);
2284 }
2285 if (SGH_DIRECTION_TC(sh)) {
2287 if (mpm_store != NULL) {
2289 }
2290
2292 if (mpm_store != NULL) {
2293 PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
2294 }
2295
2296 SetRawReassemblyFlag(de_ctx, sh);
2297 }
2298 } else if (SGH_PROTO(sh, IPPROTO_UDP)) {
2299 if (SGH_DIRECTION_TS(sh)) {
2300 mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS);
2301 if (mpm_store != NULL) {
2303 }
2304 }
2305 if (SGH_DIRECTION_TC(sh)) {
2306 mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC);
2307 if (mpm_store != NULL) {
2309 }
2310 }
2311 } else {
2312 mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP);
2313 if (mpm_store != NULL) {
2315 }
2316 }
2317
2318 PrepareMpms(de_ctx, sh);
2319 return 0;
2320}
2321
2322static inline uint32_t ContentFlagsForHash(const DetectContentData *cd)
2323{
2326}
2327
2328/** \internal
2329 * \brief The hash function for Pattern. Hashes pattern after chop is applied.
2330 *
2331 * \param ht Pointer to the hash table.
2332 * \param data Pointer to the Pattern.
2333 * \param datalen Not used in our case.
2334 *
2335 * \retval hash The generated hash value.
2336 */
2337static uint32_t PatternChopHashFunc(HashListTable *ht, void *data, uint16_t datalen)
2338{
2339 const DetectPatternTracker *p = (DetectPatternTracker *)data;
2340 uint32_t hash = p->sm_list + ContentFlagsForHash(p->cd);
2341 uint16_t content_len = p->cd->content_len;
2342 const uint8_t *content = p->cd->content;
2344 content += p->cd->fp_chop_offset;
2345 content_len = p->cd->fp_chop_len;
2346 }
2347 hash += StringHashDjb2(content, content_len);
2348 return hash % ht->array_size;
2349}
2350
2351/** \internal
2352 * \brief The hash function for Pattern. Ignores chop.
2353 *
2354 * \param ht Pointer to the hash table.
2355 * \param data Pointer to the Pattern.
2356 * \param datalen Not used in our case.
2357 *
2358 * \retval hash The generated hash value.
2359 */
2360static uint32_t PatternNoChopHashFunc(HashListTable *ht, void *data, uint16_t datalen)
2361{
2362 const DetectPatternTracker *p = (DetectPatternTracker *)data;
2363 uint32_t hash = p->sm_list + ContentFlagsForHash(p->cd);
2364 hash += StringHashDjb2(p->cd->content, p->cd->content_len);
2365 return hash % ht->array_size;
2366}
2367
2368/**
2369 * \brief The Compare function for Pattern. Compares patterns after chop is applied.
2370 *
2371 * \param data1 Pointer to the first Pattern.
2372 * \param len1 Not used.
2373 * \param data2 Pointer to the second Pattern.
2374 * \param len2 Not used.
2375 *
2376 * \retval 1 If the 2 Patterns sent as args match.
2377 * \retval 0 If the 2 Patterns sent as args do not match.
2378 */
2379static char PatternChopCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
2380{
2381 const DetectPatternTracker *p1 = (DetectPatternTracker *)data1;
2382 const DetectPatternTracker *p2 = (DetectPatternTracker *)data2;
2383
2384 if (p1->sm_list != p2->sm_list)
2385 return 0;
2386
2387 if (ContentFlagsForHash(p1->cd) != ContentFlagsForHash(p2->cd))
2388 return 0;
2389
2390 uint16_t p1_content_len = p1->cd->content_len;
2391 uint8_t *p1_content = p1->cd->content;
2393 p1_content += p1->cd->fp_chop_offset;
2394 p1_content_len = p1->cd->fp_chop_len;
2395 }
2396 uint16_t p2_content_len = p2->cd->content_len;
2397 uint8_t *p2_content = p2->cd->content;
2399 p2_content += p2->cd->fp_chop_offset;
2400 p2_content_len = p2->cd->fp_chop_len;
2401 }
2402
2403 if (p1_content_len != p2_content_len)
2404 return 0;
2405
2406 if (memcmp(p1_content, p2_content, p1_content_len) != 0) {
2407 return 0;
2408 }
2409
2410 return 1;
2411}
2412
2413/**
2414 * \brief The Compare function for Pattern. Ignores chop settings
2415 *
2416 * \param data1 Pointer to the first Pattern.
2417 * \param len1 Not used.
2418 * \param data2 Pointer to the second Pattern.
2419 * \param len2 Not used.
2420 *
2421 * \retval 1 If the 2 Patterns sent as args match.
2422 * \retval 0 If the 2 Patterns sent as args do not match.
2423 */
2424static char PatternNoChopCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
2425{
2426 const DetectPatternTracker *p1 = (DetectPatternTracker *)data1;
2427 const DetectPatternTracker *p2 = (DetectPatternTracker *)data2;
2428
2429 if (p1->sm_list != p2->sm_list)
2430 return 0;
2431
2432 if (ContentFlagsForHash(p1->cd) != ContentFlagsForHash(p2->cd))
2433 return 0;
2434
2435 if (p1->cd->content_len != p2->cd->content_len)
2436 return 0;
2437
2438 if (memcmp(p1->cd->content, p2->cd->content, p1->cd->content_len) != 0) {
2439 return 0;
2440 }
2441
2442 return 1;
2443}
2444
2445static void PatternFreeFunc(void *ptr)
2446{
2447 SCFree(ptr);
2448}
2449
2450/**
2451 * \brief Figure out the FP and their respective content ids for all the
2452 * sigs in the engine.
2453 *
2454 * \param de_ctx Detection engine context.
2455 *
2456 * \retval 0 On success.
2457 * \retval -1 On failure.
2458 */
2460{
2461 uint32_t cnt = 0;
2462 for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2463 if (s->init_data->mpm_sm != NULL) {
2464 cnt++;
2465 }
2466 }
2467 /* no mpm rules */
2468 if (cnt == 0)
2469 return 0;
2470
2471 HashListTable *ht =
2472 HashListTableInit(4096, PatternChopHashFunc, PatternChopCompareFunc, PatternFreeFunc);
2473 BUG_ON(ht == NULL);
2474 PatIntId max_id = 0;
2475
2476 for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2477 if (s->init_data->mpm_sm == NULL)
2478 continue;
2479
2480 const int sm_list = s->init_data->mpm_sm_list;
2481 BUG_ON(sm_list == -1);
2482
2484
2485 DetectPatternTracker lookup = { .cd = cd, .sm_list = sm_list, .cnt = 0, .mpm = 0 };
2486 DetectPatternTracker *res = HashListTableLookup(ht, &lookup, 0);
2487 if (res) {
2488 res->cnt++;
2489 res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
2490
2491 cd->id = res->cd->id;
2492 SCLogDebug("%u: res id %u cnt %u", s->id, res->cd->id, res->cnt);
2493 } else {
2494 DetectPatternTracker *add = SCCalloc(1, sizeof(*add));
2495 BUG_ON(add == NULL);
2496 add->cd = cd;
2497 add->sm_list = sm_list;
2498 add->cnt = 1;
2499 add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
2500 HashListTableAdd(ht, (void *)add, 0);
2501
2502 cd->id = max_id++;
2503 SCLogDebug("%u: add id %u cnt %u", s->id, add->cd->id, add->cnt);
2504 }
2505 }
2506
2508
2509 return 0;
2510}
2511
2512/** \brief add all patterns on our stats hash
2513 * Used to fill the hash later used by DumpPatterns()
2514 * \note sets up the hash table on first call
2515 */
2517{
2518 if (de_ctx->pattern_hash_table == NULL) {
2520 4096, PatternNoChopHashFunc, PatternNoChopCompareFunc, PatternFreeFunc);
2522 }
2525 do {
2526 switch (smd->type) {
2527 case DETECT_CONTENT: {
2528 const DetectContentData *cd = (const DetectContentData *)smd->ctx;
2529 DetectPatternTracker lookup = {
2530 .cd = cd, .sm_list = DETECT_SM_LIST_PMATCH, .cnt = 0, .mpm = 0
2531 };
2534 if (res) {
2535 res->cnt++;
2536 res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
2537 } else {
2538 DetectPatternTracker *add = SCCalloc(1, sizeof(*add));
2539 BUG_ON(add == NULL);
2540 add->cd = cd;
2542 add->cnt = 1;
2543 add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
2544 HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
2545 }
2546 break;
2547 }
2548 }
2549 if (smd->is_last)
2550 break;
2551 smd++;
2552 } while (1);
2553 }
2554
2556 for (; app != NULL; app = app->next) {
2557 SigMatchData *smd = app->smd;
2558 while (smd) {
2559 switch (smd->type) {
2560 case DETECT_CONTENT: {
2561 const DetectContentData *cd = (const DetectContentData *)smd->ctx;
2562
2563 DetectPatternTracker lookup = {
2564 .cd = cd, .sm_list = app->sm_list, .cnt = 0, .mpm = 0
2565 };
2568 if (res) {
2569 res->cnt++;
2570 res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
2571 } else {
2572 DetectPatternTracker *add = SCCalloc(1, sizeof(*add));
2573 BUG_ON(add == NULL);
2574 add->cd = cd;
2575 add->sm_list = app->sm_list;
2576 add->cnt = 1;
2577 add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
2578 HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
2579 }
2580 break;
2581 }
2582 }
2583 if (smd->is_last)
2584 break;
2585 smd++;
2586 }
2587 }
2589 for (; pkt != NULL; pkt = pkt->next) {
2590 SigMatchData *smd = pkt->smd;
2591 do {
2592 if (smd == NULL) {
2594 smd = s->sm_arrays[pkt->sm_list];
2595 }
2596 switch (smd->type) {
2597 case DETECT_CONTENT: {
2598 const DetectContentData *cd = (const DetectContentData *)smd->ctx;
2599
2600 DetectPatternTracker lookup = {
2601 .cd = cd, .sm_list = pkt->sm_list, .cnt = 0, .mpm = 0
2602 };
2605 if (res) {
2606 res->cnt++;
2607 res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
2608 } else {
2609 DetectPatternTracker *add = SCCalloc(1, sizeof(*add));
2610 BUG_ON(add == NULL);
2611 add->cd = cd;
2612 add->sm_list = pkt->sm_list;
2613 add->cnt = 1;
2614 add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
2615 HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
2616 }
2617 break;
2618 }
2619 }
2620 if (smd->is_last)
2621 break;
2622 smd++;
2623 } while (1);
2624 }
2626 for (; frame != NULL; frame = frame->next) {
2627 SigMatchData *smd = frame->smd;
2628 do {
2629 if (smd == NULL) {
2631 smd = s->sm_arrays[frame->sm_list];
2632 }
2633 switch (smd->type) {
2634 case DETECT_CONTENT: {
2635 const DetectContentData *cd = (const DetectContentData *)smd->ctx;
2636
2637 DetectPatternTracker lookup = {
2638 .cd = cd, .sm_list = frame->sm_list, .cnt = 0, .mpm = 0
2639 };
2642 if (res) {
2643 res->cnt++;
2644 res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
2645 } else {
2646 DetectPatternTracker *add = SCCalloc(1, sizeof(*add));
2647 BUG_ON(add == NULL);
2648 add->cd = cd;
2649 add->sm_list = frame->sm_list;
2650 add->cnt = 1;
2651 add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
2652 HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
2653 }
2654 break;
2655 }
2656 }
2657 if (smd->is_last)
2658 break;
2659 smd++;
2660 } while (1);
2661 }
2662}
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
uint16_t AppProto
@ ALPROTO_HTTP2
@ ALPROTO_UNKNOWN
@ ALPROTO_DOH2
@ ALPROTO_DNS
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition conf.c:497
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint8_t flags
Definition decode-gre.h:0
uint16_t type
#define DETECT_CONTENT_FAST_PATTERN_CHOP
#define DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c)
#define DETECT_CONTENT_FAST_PATTERN
#define DETECT_CONTENT_DEPTH_VAR
#define DETECT_CONTENT_ENDS_WITH
#define DETECT_CONTENT_OFFSET_VAR
#define DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_MPM
#define DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_IS_SINGLE(c)
#define DETECT_CONTENT_NOCASE
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 DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx)
bool DetectBufferToClient(const DetectEngineCtx *de_ctx, int buf_id, AppProto alproto)
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
int DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for builtin buffers that are in "single or "shared" mode.
void EngineAnalysisAddAllRulePatterns(DetectEngineCtx *de_ctx, const Signature *s)
add all patterns on our stats hash Used to fill the hash later used by DumpPatterns()
int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx)
Figure out the FP and their respective content ids for all the sigs in the engine.
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 DetectFrameMpmRegister(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)
register a MPM engine
void DetectMpmInitializeFrameMpms(DetectEngineCtx *de_ctx)
int MpmStoreInit(DetectEngineCtx *de_ctx)
Initializes the MpmStore mpm hash table to be used by the detection engine context.
int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
Prepare the pattern matcher ctx in a sig group head.
int SignatureHasStreamContent(const Signature *s)
check if a signature has patterns that are to be inspected against the stream payload (as opposed to ...
void DetectAppLayerMpmMultiRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionMultiBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
void DetectPktMpmRegister(const char *name, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id), InspectionBufferGetPktDataPtr GetData)
register a MPM engine
int DetectMpmPrepareFrameMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
int g_skip_prefilter
#define SGH_PROTO(sgh, p)
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 PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher)
void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx)
uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
Predict a strength value for patterns.
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.
MpmStore * MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf)
Get MpmStore for a built-in buffer type.
void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
#define SGH_DIRECTION_TC(sgh)
int SignatureHasPacketContent(const Signature *s)
check if a signature has patterns that are to be inspected against a packets payload (as opposed to t...
#define SGH_DIRECTION_TS(sgh)
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
int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
const char * builtin_mpms[]
int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
void DetectAppLayerMpmRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register an app layer keyword for mpm
void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
void DetectAppLayerMpmRegisterSingle(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionSingleBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
int(* PrefilterRegisterFunc)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx)
int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx)
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
void DetectBufferTypeSupportsMpm(const char *name)
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
int DetectEngineBufferTypeRegister(DetectEngineCtx *de_ctx, const char *name)
void DetectBufferTypeSupportsFrames(const char *name)
void DetectEngineBufferTypeSupportsMpm(DetectEngineCtx *de_ctx, const char *name)
void DetectEngineBufferTypeSupportsTransformations(DetectEngineCtx *de_ctx, const char *name)
void DetectEngineBufferTypeSupportsFrames(DetectEngineCtx *de_ctx, const char *name)
int DetectBufferTypeGetByName(const char *name)
void DetectBufferTypeSupportsTransformations(const char *name)
#define DetectEngineGetMaxSigId(de_ctx)
void SupportFastPatternForSigMatchList(int list_id, int priority)
Lets one add a sm list id to be searched for potential fp supported keywords later.
int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, const int list_id)
Checks if a particular buffer is in the list of lists that need to be searched for a keyword that has...
void DetectEngineRegisterFastPatternForId(DetectEngineCtx *de_ctx, int list_id, int priority)
uint32_t id
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
SigTableElmt * sigmatch_table
#define SIG_GROUP_HEAD_HAVERAWSTREAM
Definition detect.h:1488
#define DE_QUIET
Definition detect.h:330
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
#define SIG_FLAG_TOCLIENT
Definition detect.h:272
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
#define SIG_FLAG_TOSERVER
Definition detect.h:271
MpmBuiltinBuffers
Definition detect.h:1497
@ MPMB_TCP_STREAM_TS
Definition detect.h:1500
@ MPMB_UDP_TC
Definition detect.h:1503
@ MPMB_TCP_STREAM_TC
Definition detect.h:1501
@ MPMB_UDP_TS
Definition detect.h:1502
@ MPMB_OTHERIP
Definition detect.h:1504
@ MPMB_TCP_PKT_TS
Definition detect.h:1498
@ MPMB_MAX
Definition detect.h:1505
@ MPMB_TCP_PKT_TC
Definition detect.h:1499
@ DETECT_SM_LIST_PMATCH
Definition detect.h:119
@ DETECT_SM_LIST_DYNAMIC_START
Definition detect.h:138
DetectBufferMpmType
Definition detect.h:753
@ DETECT_BUFFER_MPM_TYPE_FRAME
Definition detect.h:756
@ DETECT_BUFFER_MPM_TYPE_APP
Definition detect.h:755
@ DETECT_BUFFER_MPM_TYPE_SIZE
Definition detect.h:758
@ DETECT_BUFFER_MPM_TYPE_PKT
Definition detect.h:754
#define SIG_FLAG_TXBOTHDIR
Definition detect.h:250
#define SIG_FLAG_REQUIRE_STREAM
Definition detect.h:255
DetectEngineCtx * de_ctx
struct Thresholds ctx
one time registration of keywords at start up
Definition detect.h:762
InspectionMultiBufferGetDataPtr GetMultiData
Definition detect.h:783
InspectionBufferGetDataPtr GetData
Definition detect.h:781
struct DetectBufferMpmRegistry_::@98::@102 frame_v1
const char * name
Definition detect.h:763
struct DetectBufferMpmRegistry_::@98::@101 pkt_v1
enum DetectBufferMpmType type
Definition detect.h:770
DetectEngineTransforms transforms
Definition detect.h:775
struct DetectBufferMpmRegistry_::@98::@100 app_v2
struct DetectBufferMpmRegistry_ * next
Definition detect.h:804
InspectionSingleBufferGetDataPtr GetDataSingle
Definition detect.h:782
int(* PrefilterRegisterWithListId)(struct DetectEngineCtx_ *de_ctx, struct SigGroupHead_ *sgh, MpmCtx *mpm_ctx, const struct DetectBufferMpmRegistry_ *mpm_reg, int list_id)
Definition detect.h:773
struct DetectEngineAppInspectionEngine_ * next
Definition detect.h:441
main detection engine ctx
Definition detect.h:932
int32_t sgh_mpm_context_proto_other_packet
Definition detect.h:1006
DetectBufferMpmRegistry * pkt_mpms_list
Definition detect.h:1089
DetectBufferMpmRegistry * app_mpms_list
Definition detect.h:1084
uint8_t sgh_mpm_ctx_cnf
Definition detect.h:1033
uint32_t buffer_type_id
Definition detect.h:1081
uint8_t mpm_matcher
Definition detect.h:935
uint32_t frame_mpms_list_cnt
Definition detect.h:1093
int32_t sgh_mpm_context_stream
Definition detect.h:1007
uint32_t pkt_mpms_list_cnt
Definition detect.h:1090
uint8_t flags
Definition detect.h:934
Signature ** sig_array
Definition detect.h:950
HashListTable * pattern_hash_table
Definition detect.h:965
Signature * sig_list
Definition detect.h:941
SCFPSupportSMList * fp_support_smlist_list
Definition detect.h:1106
int32_t sgh_mpm_context_proto_tcp_packet
Definition detect.h:1004
int32_t sgh_mpm_context_proto_udp_packet
Definition detect.h:1005
DetectBufferMpmRegistry * frame_mpms_list
Definition detect.h:1092
MpmConfig * mpm_cfg
Definition detect.h:936
DetectEngineAppInspectionEngine * app_inspect_engines
Definition detect.h:1087
uint32_t app_mpms_list_cnt
Definition detect.h:1083
HashListTable * mpm_hash_table
Definition detect.h:964
struct DetectEngineFrameInspectionEngine * next
Definition detect.h:521
struct DetectEnginePktInspectionEngine * next
Definition detect.h:494
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition detect.h:392
const struct DetectContentData_ * cd
Definition detect.h:809
uint8_t proto[256/8]
uint32_t array_size
const char * cache_dir_path
Definition util-mpm.h:90
uint32_t pattern_cnt
Definition util-mpm.h:102
uint8_t mpm_type
Definition util-mpm.h:95
uint8_t flags
Definition util-mpm.h:97
uint16_t maxlen
Definition util-mpm.h:105
uint16_t minlen
Definition util-mpm.h:104
uint32_t sid_array_size
Definition detect.h:1510
int32_t sgh_mpm_context
Definition detect.h:1515
enum MpmBuiltinBuffers buffer
Definition detect.h:1513
uint8_t * sid_array
Definition detect.h:1509
int sm_list
Definition detect.h:1514
int direction
Definition detect.h:1512
MpmCtx * mpm_ctx
Definition detect.h:1517
AppProto alproto
Definition detect.h:1516
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition util-mpm.h:175
uint8_t feature_flags
Definition util-mpm.h:184
void(* DestroyCtx)(struct MpmCtx_ *)
Definition util-mpm.h:154
struct SCFPSupportSMList_ * next
Definition detect.h:842
uint32_t sids_array_size
uint8_t * sids_array
enum DetectBufferMpmType type
Signature ** match_array
Definition detect.h:1625
MpmCtx ** frame_mpms
Definition detect.h:1613
Container for matching data for a signature group.
Definition detect.h:1629
SigGroupHeadInitData * init
Definition detect.h:1646
uint16_t flags
Definition detect.h:1630
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
struct SigMatch_ * next
Definition detect.h:360
SigMatchCtx * ctx
Definition detect.h:359
const char * name
Definition detect.h:1459
SigMatch * mpm_sm
Definition detect.h:623
uint32_t max_content_list_id
Definition detect.h:653
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
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
SigIntId iid
Definition detect.h:680
AppProto alproto
Definition detect.h:673
DetectEngineAppInspectionEngine * app_inspect
Definition detect.h:725
DetectProto proto
Definition detect.h:687
uint32_t id
Definition detect.h:713
struct Signature_ * next
Definition detect.h:750
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition detect.h:731
#define BUG_ON(x)
#define PatIntId
size_t strlcat(char *, const char *src, size_t siz)
#define MAX(x, y)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * name
uint32_t cnt
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define SCLogPerf(...)
Definition util-debug.h:234
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
uint32_t StringHashDjb2(const uint8_t *data, uint32_t datalen)
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
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 SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCMemcmp(a, b, c)
void ShortenString(const char *input, char *output, size_t output_size, char c)
Definition util-misc.c:207
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition util-mpm.c:47
uint8_t mpm_default_matcher
Definition util-mpm.c:48
MpmCtx * MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction)
Definition util-mpm.c:131
int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition util-mpm.c:249
int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name, const int sm_list, const AppProto alproto)
Register a new Mpm Context.
Definition util-mpm.c:59
void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher)
Definition util-mpm.c:202
void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx)
Definition util-mpm.c:156
int MpmAddPatternCI(MpmCtx *mpm_ctx, const uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition util-mpm.c:258
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition util-mpm.c:195
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition util-mpm.c:209
#define MPMCTX_FLAGS_GLOBAL
Definition util-mpm.h:85
#define MPM_PATTERN_CTX_OWNS_ID
Definition util-mpm.h:143
#define MPM_FEATURE_FLAG_ENDSWITH
Definition util-mpm.h:148
@ MPM_TABLE_SIZE
Definition util-mpm.h:40
#define MPM_PATTERN_FLAG_ENDSWITH
Definition util-mpm.h:144
#define MPM_CTX_FACTORY_UNIQUE_CONTEXT
Definition util-mpm.h:118
#define MPMCTX_FLAGS_CACHE_TO_DISK
Definition util-mpm.h:87
#define DEBUG_VALIDATE_BUG_ON(exp)