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