suricata
detect-engine-mpm.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2014 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23  *
24  * Multi pattern matcher
25  */
26 
27 #include "suricata.h"
28 #include "suricata-common.h"
29 
30 #include "app-layer-protos.h"
31 
32 #include "decode.h"
33 #include "detect.h"
34 #include "detect-engine.h"
35 #include "detect-engine-siggroup.h"
36 #include "detect-engine-mpm.h"
37 #include "detect-engine-iponly.h"
38 #include "detect-parse.h"
40 #include "util-mpm.h"
41 #include "util-memcmp.h"
42 #include "util-memcpy.h"
43 #include "conf.h"
44 #include "detect-fast-pattern.h"
45 
46 #include "detect-tcphdr.h"
47 #include "detect-udphdr.h"
48 
49 #include "flow.h"
50 #include "flow-var.h"
51 #include "detect-flow.h"
52 
53 #include "detect-content.h"
54 
55 #include "detect-engine-payload.h"
56 #include "detect-engine-dns.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 
66 const char *builtin_mpms[] = {
67  "toserver TCP packet",
68  "toclient TCP packet",
69  "toserver TCP stream",
70  "toclient TCP stream",
71  "toserver UDP packet",
72  "toclient UDP packet",
73  "other IP packet",
74 
75  NULL };
76 
77 /* Registry for mpm keywords
78  *
79  * Keywords are registered at engine start up
80  */
81 
82 static DetectBufferMpmRegistery *g_mpm_list[DETECT_BUFFER_MPM_TYPE_SIZE] = { NULL, NULL };
83 static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0 };
84 
85 /** \brief register a MPM engine
86  *
87  * \note to be used at start up / registration only. Errors are fatal.
88  */
89 void DetectAppLayerMpmRegister2(const char *name,
90  int direction, int priority,
91  int (*PrefilterRegister)(DetectEngineCtx *de_ctx,
92  SigGroupHead *sgh, MpmCtx *mpm_ctx,
93  const DetectBufferMpmRegistery *mpm_reg, int list_id),
95  AppProto alproto, int tx_min_progress)
96 {
97  SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority,
98  PrefilterRegister, GetData, alproto, tx_min_progress);
99 
100  if (PrefilterRegister == PrefilterGenericMpmRegister && GetData == NULL) {
101  // must register GetData with PrefilterGenericMpmRegister
102  abort();
103  }
104 
107  int sm_list = DetectBufferTypeGetByName(name);
108  if (sm_list == -1) {
110  "MPM engine registration for %s failed", name);
111  }
112 
113  DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
114  BUG_ON(am == NULL);
115  am->name = name;
116  snprintf(am->pname, sizeof(am->pname), "%s", am->name);
117  am->direction = direction;
118  am->sm_list = sm_list;
119  am->priority = priority;
121 
122  am->PrefilterRegisterWithListId = PrefilterRegister;
123  am->app_v2.GetData = GetData;
124  am->app_v2.alproto = alproto;
125  am->app_v2.tx_min_progress = tx_min_progress;
126 
127  if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] == NULL) {
128  g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] = am;
129  } else {
131  while (t->next != NULL) {
132  t = t->next;
133  }
134 
135  t->next = am;
136  am->id = t->id + 1;
137  }
138  g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP]++;
139 
140  SupportFastPatternForSigMatchList(sm_list, priority);
141 }
142 
143 /** \brief copy a mpm engine from parent_id, add in transforms */
145  const int id, const int parent_id,
146  DetectEngineTransforms *transforms)
147 {
148  SCLogDebug("registering %d/%d", id, parent_id);
149 
151  while (t) {
152  if (t->sm_list == parent_id) {
153  DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
154  BUG_ON(am == NULL);
155  am->name = t->name;
156  am->direction = t->direction;
157  am->sm_list = id; // use new id
160  am->app_v2.GetData = t->app_v2.GetData;
161  am->app_v2.alproto = t->app_v2.alproto;
162  am->app_v2.tx_min_progress = t->app_v2.tx_min_progress;
163  am->priority = t->priority;
165  am->next = t->next;
166  if (transforms) {
167  memcpy(&am->transforms, transforms, sizeof(*transforms));
168 
169  /* create comma separated string of the names of the
170  * transforms and then shorten it if necessary. Finally
171  * use it to construct the 'profile' name for the engine */
172  char xforms[1024] = "";
173  for (int i = 0; i < transforms->cnt; i++) {
174  char ttstr[64];
175  (void)snprintf(ttstr,sizeof(ttstr), "%s,",
176  sigmatch_table[transforms->transforms[i]].name);
177  strlcat(xforms, ttstr, sizeof(xforms));
178  }
179  xforms[strlen(xforms)-1] = '\0';
180 
181  size_t space = sizeof(am->pname) - strlen(am->name) - 3;
182  char toprint[space + 1];
183  memset(toprint, 0x00, space + 1);
184  if (space < strlen(xforms)) {
185  ShortenString(xforms, toprint, space, '~');
186  } else {
187  strlcpy(toprint, xforms,sizeof(toprint));
188  }
189  (void)snprintf(am->pname, sizeof(am->pname), "%s#%d (%s)",
190  am->name, id, toprint);
191  } else {
192  (void)snprintf(am->pname, sizeof(am->pname), "%s#%d",
193  am->name, id);
194  }
195  am->id = de_ctx->app_mpms_list_cnt++;
196 
198  t->next = am;
199  SCLogDebug("copied mpm registration for %s id %u "
200  "with parent %u and GetData %p",
201  t->name, id, parent_id, am->app_v2.GetData);
202  t = am;
203  }
204  t = t->next;
205  }
206 }
207 
209 {
210  const DetectBufferMpmRegistery *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP];
211  while (list != NULL) {
212  DetectBufferMpmRegistery *n = SCCalloc(1, sizeof(*n));
213  BUG_ON(n == NULL);
214 
215  *n = *list;
216  n->next = NULL;
217 
218  if (de_ctx->app_mpms_list == NULL) {
219  de_ctx->app_mpms_list = n;
220  } else {
222  while (t->next != NULL) {
223  t = t->next;
224  }
225  t->next = n;
226  }
227 
228  /* default to whatever the global setting is */
229  int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
230 
231  /* see if we use a unique or shared mpm ctx for this type */
232  int confshared = 0;
233  char confstring[256] = "detect.mpm.";
234  strlcat(confstring, n->name, sizeof(confstring));
235  strlcat(confstring, ".shared", sizeof(confstring));
236  if (ConfGetBool(confstring, &confshared) == 1)
237  shared = confshared;
238 
239  if (shared == 0) {
240  if (!(de_ctx->flags & DE_QUIET)) {
241  SCLogPerf("using unique mpm ctx' for %s", n->name);
242  }
244  } else {
245  if (!(de_ctx->flags & DE_QUIET)) {
246  SCLogPerf("using shared mpm ctx' for %s", n->name);
247  }
249  }
250 
251  list = list->next;
252  }
253  de_ctx->app_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP];
254  SCLogDebug("mpm: de_ctx app_mpms_list %p %u",
255  de_ctx->app_mpms_list, de_ctx->app_mpms_list_cnt);
256 }
257 
258 /**
259  * \brief initialize mpm contexts for applayer buffers that are in
260  * "single or "shared" mode.
261  */
263 {
264  int r = 0;
265  const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
266  while (am != NULL) {
267  int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0;
268 
270  {
271  MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir);
272  if (mpm_ctx != NULL) {
273  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
274  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
275  }
276  }
277  }
278  am = am->next;
279  }
280  return r;
281 }
282 
283 /** \brief register a MPM engine
284  *
285  * \note to be used at start up / registration only. Errors are fatal.
286  */
287 void DetectPktMpmRegister(const char *name,
288  int priority,
289  int (*PrefilterRegister)(DetectEngineCtx *de_ctx,
290  SigGroupHead *sgh, MpmCtx *mpm_ctx,
291  const DetectBufferMpmRegistery *mpm_reg, int list_id),
293 {
294  SCLogDebug("registering %s/%d/%p/%p", name, priority,
295  PrefilterRegister, GetData);
296 
297  if (PrefilterRegister == PrefilterGenericMpmPktRegister && GetData == NULL) {
298  // must register GetData with PrefilterGenericMpmRegister
299  abort();
300  }
301 
304  int sm_list = DetectBufferTypeGetByName(name);
305  if (sm_list == -1) {
307  "MPM engine registration for %s failed", name);
308  }
309 
310  DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
311  BUG_ON(am == NULL);
312  am->name = name;
313  snprintf(am->pname, sizeof(am->pname), "%s", am->name);
314  am->sm_list = sm_list;
315  am->priority = priority;
317 
318  am->PrefilterRegisterWithListId = PrefilterRegister;
319  am->pkt_v1.GetData = GetData;
320 
321  if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] == NULL) {
322  g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] = am;
323  } else {
325  while (t->next != NULL) {
326  t = t->next;
327  }
328  t->next = am;
329  am->id = t->id + 1;
330  }
331  g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT]++;
332 
333  SupportFastPatternForSigMatchList(sm_list, priority);
334  SCLogDebug("%s/%d done", name, sm_list);
335 }
336 
337 /** \brief copy a mpm engine from parent_id, add in transforms */
339  const int id, const int parent_id,
340  DetectEngineTransforms *transforms)
341 {
342  SCLogDebug("registering %d/%d", id, parent_id);
343 
345  while (t) {
346  if (t->sm_list == parent_id) {
347  DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
348  BUG_ON(am == NULL);
349  am->name = t->name;
350  snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id);
351  am->sm_list = id; // use new id
354  am->pkt_v1.GetData = t->pkt_v1.GetData;
355  am->priority = t->priority;
357  am->next = t->next;
358  if (transforms) {
359  memcpy(&am->transforms, transforms, sizeof(*transforms));
360  }
361  am->id = de_ctx->pkt_mpms_list_cnt++;
362 
364  t->next = am;
365  SCLogDebug("copied mpm registration for %s id %u "
366  "with parent %u and GetData %p",
367  t->name, id, parent_id, am->pkt_v1.GetData);
368  t = am;
369  }
370  t = t->next;
371  }
372 }
373 
375 {
376  const DetectBufferMpmRegistery *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT];
377  while (list != NULL) {
378  DetectBufferMpmRegistery *n = SCCalloc(1, sizeof(*n));
379  BUG_ON(n == NULL);
380 
381  *n = *list;
382  n->next = NULL;
383 
384  if (de_ctx->pkt_mpms_list == NULL) {
385  de_ctx->pkt_mpms_list = n;
386  } else {
388  while (t->next != NULL) {
389  t = t->next;
390  }
391 
392  t->next = n;
393  }
394 
395  /* default to whatever the global setting is */
396  int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
397 
398  /* see if we use a unique or shared mpm ctx for this type */
399  int confshared = 0;
400  char confstring[256] = "detect.mpm.";
401  strlcat(confstring, n->name, sizeof(confstring));
402  strlcat(confstring, ".shared", sizeof(confstring));
403  if (ConfGetBool(confstring, &confshared) == 1)
404  shared = confshared;
405 
406  if (shared == 0) {
407  if (!(de_ctx->flags & DE_QUIET)) {
408  SCLogPerf("using unique mpm ctx' for %s", n->name);
409  }
411  } else {
412  if (!(de_ctx->flags & DE_QUIET)) {
413  SCLogPerf("using shared mpm ctx' for %s", n->name);
414  }
416  }
417 
418  list = list->next;
419  }
420  de_ctx->pkt_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT];
421  SCLogDebug("mpm: de_ctx pkt_mpms_list %p %u",
422  de_ctx->pkt_mpms_list, de_ctx->pkt_mpms_list_cnt);
423 }
424 
425 /**
426  * \brief initialize mpm contexts for applayer buffers that are in
427  * "single or "shared" mode.
428  */
430 {
431  SCLogDebug("preparing pkt mpm");
432  int r = 0;
433  const DetectBufferMpmRegistery *am = de_ctx->pkt_mpms_list;
434  while (am != NULL) {
435  SCLogDebug("%s", am->name);
437  {
438  MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, 0);
439  if (mpm_ctx != NULL) {
440  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
441  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
442  SCLogDebug("%s: %d", am->name, r);
443  }
444  }
445  }
446  am = am->next;
447  }
448  return r;
449 }
450 
451 static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name)
452 {
453  /* default to whatever the global setting is */
454  int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
455 
456  /* see if we use a unique or shared mpm ctx for this type */
457  int confshared = 0;
458  char confstring[256] = "detect.mpm.";
459  strlcat(confstring, name, sizeof(confstring));
460  strlcat(confstring, ".shared", sizeof(confstring));
461  if (ConfGetBool(confstring, &confshared) == 1)
462  shared = confshared;
463 
464  int32_t ctx;
465  if (shared == 0) {
467  SCLogPerf("using unique mpm ctx' for %s", name);
468  } else {
469  ctx = MpmFactoryRegisterMpmCtxProfile(de_ctx, name);
470  SCLogPerf("using shared mpm ctx' for %s", name);
471  }
472  return ctx;
473 }
474 
476 {
477  de_ctx->sgh_mpm_context_proto_tcp_packet = SetupBuiltinMpm(de_ctx, "tcp-packet");
478  de_ctx->sgh_mpm_context_stream = SetupBuiltinMpm(de_ctx, "tcp-stream");
479 
480  de_ctx->sgh_mpm_context_proto_udp_packet = SetupBuiltinMpm(de_ctx, "udp-packet");
481  de_ctx->sgh_mpm_context_proto_other_packet = SetupBuiltinMpm(de_ctx, "other-ip");
482 }
483 
484 /**
485  * \brief initialize mpm contexts for builtin buffers that are in
486  * "single or "shared" mode.
487  */
489 {
490  int r = 0;
491  MpmCtx *mpm_ctx = NULL;
492 
495  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
496  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
497  }
499  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
500  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
501  }
502  }
503 
506  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
507  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
508  }
510  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
511  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
512  }
513  }
514 
517  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
518  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
519  }
520  }
521 
523  mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0);
524  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
525  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
526  }
527  mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1);
528  if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
529  r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
530  }
531  }
532 
533  return r;
534 }
535 
536 /**
537  * \brief check if a signature has patterns that are to be inspected
538  * against a packets payload (as opposed to the stream payload)
539  *
540  * \param s signature
541  *
542  * \retval 1 true
543  * \retval 0 false
544  */
546 {
547  SCEnter();
548 
549  if (s == NULL) {
550  SCReturnInt(0);
551  }
552 
553  if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
554  SCReturnInt(1);
555  }
556 
557  if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) ||
558  (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL))
559  {
560  SCLogDebug("no mpm");
561  SCReturnInt(0);
562  }
563 
564  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
565  SCReturnInt(0);
566  }
567 
568  SCReturnInt(1);
569 }
570 
571 /**
572  * \brief check if a signature has patterns that are to be inspected
573  * against the stream payload (as opposed to the individual packets
574  * payload(s))
575  *
576  * \param s signature
577  *
578  * \retval 1 true
579  * \retval 0 false
580  */
582 {
583  SCEnter();
584 
585  if (s == NULL) {
586  SCReturnInt(0);
587  }
588 
589  if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
590  SCReturnInt(0);
591  }
592 
593  if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) ||
594  (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL))
595  {
596  SCLogDebug("no mpm");
597  SCReturnInt(0);
598  }
599 
600  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
601  SCReturnInt(0);
602  }
603 
604  SCReturnInt(1);
605 }
606 
607 
608 /**
609  * \brief Function to return the multi pattern matcher algorithm to be
610  * used by the engine, based on the mpm-algo setting in yaml
611  * Use the default mpm if none is specified in the yaml file.
612  *
613  * \retval mpm algo value
614  */
616 {
617  const char *mpm_algo;
618  uint16_t mpm_algo_val = mpm_default_matcher;
619 
620  /* Get the mpm algo defined in config file by the user */
621  if ((ConfGet("mpm-algo", &mpm_algo)) == 1) {
622  uint16_t u;
623 
624  if (mpm_algo != NULL) {
625 #if __BYTE_ORDER == __BIG_ENDIAN
626  if (strcmp(mpm_algo, "ac-ks") == 0) {
628  "not work on big endian systems at this time.");
629  exit(EXIT_FAILURE);
630  }
631 #endif
632  if (strcmp("auto", mpm_algo) == 0) {
633  goto done;
634  }
635  for (u = 0; u < MPM_TABLE_SIZE; u++) {
636  if (mpm_table[u].name == NULL)
637  continue;
638 
639  if (strcmp(mpm_table[u].name, mpm_algo) == 0) {
640  mpm_algo_val = u;
641  goto done;
642  }
643  }
644  }
645 
646  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid mpm algo supplied "
647  "in the yaml conf file: \"%s\"", mpm_algo);
648  exit(EXIT_FAILURE);
649  }
650 
651  done:
652  return mpm_algo_val;
653 }
654 
655 /** \brief cleans up the mpm instance after a match */
657 {
658  PmqReset(&det_ctx->pmq);
659 }
660 
661 void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher)
662 {
663  SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher);
664  mpm_table[mpm_matcher].DestroyCtx(mpm_ctx);
665 }
666 
667 void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
668 {
669  SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher);
670  //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx);
671 }
672 void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
673 {
674  SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher);
675  if (mpm_table[mpm_matcher].DestroyThreadCtx != NULL)
676  mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx);
677 }
678 void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
679 {
680  SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher);
681  MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher);
682 }
683 
684 /** \brief Predict a strength value for patterns
685  *
686  * Patterns with high character diversity score higher.
687  * Alpha chars score not so high
688  * Other printable + a few common codes a little higher
689  * Everything else highest.
690  * Longer patterns score better than short patters.
691  *
692  * \param pat pattern
693  * \param patlen length of the pattern
694  *
695  * \retval s pattern score
696  */
697 uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
698 {
699  uint8_t a[256];
700  memset(&a, 0 ,sizeof(a));
701 
702  uint32_t s = 0;
703  uint16_t u = 0;
704  for (u = 0; u < patlen; u++) {
705  if (a[pat[u]] == 0) {
706  if (isalpha(pat[u]))
707  s += 3;
708  else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF)
709  s += 4;
710  else
711  s += 6;
712 
713  a[pat[u]] = 1;
714  } else {
715  s++;
716  }
717  }
718 
719  return s;
720 }
721 
722 static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx,
723  const DetectContentData *cd,
724  const Signature *s, uint8_t flags,
725  int chop)
726 {
727  uint16_t pat_offset = cd->offset;
728  uint16_t pat_depth = cd->depth;
729 
730  /* recompute offset/depth to cope with chop */
731  if (chop && (pat_depth || pat_offset)) {
732  pat_offset += cd->fp_chop_offset;
733  if (pat_depth) {
734  pat_depth -= cd->content_len;
735  pat_depth += cd->fp_chop_offset + cd->fp_chop_len;
736  }
737  }
738 
739  /* We have to effectively "wild card" values that will be coming from
740  * byte_extract variables
741  */
743  pat_depth = pat_offset = 0;
744  }
745 
746  if (cd->flags & DETECT_CONTENT_NOCASE) {
747  if (chop) {
748  MpmAddPatternCI(mpm_ctx,
749  cd->content + cd->fp_chop_offset, cd->fp_chop_len,
750  pat_offset, pat_depth,
751  cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
752  } else {
753  MpmAddPatternCI(mpm_ctx,
754  cd->content, cd->content_len,
755  pat_offset, pat_depth,
756  cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
757  }
758  } else {
759  if (chop) {
760  MpmAddPatternCS(mpm_ctx,
761  cd->content + cd->fp_chop_offset, cd->fp_chop_len,
762  pat_offset, pat_depth,
763  cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
764  } else {
765  MpmAddPatternCS(mpm_ctx,
766  cd->content, cd->content_len,
767  pat_offset, pat_depth,
768  cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
769  }
770  }
771 
772  return;
773 }
774 
775 #define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1)
776 #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER)
777 #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT)
778 
779 static void SetMpm(Signature *s, SigMatch *mpm_sm)
780 {
781  if (s == NULL || mpm_sm == NULL)
782  return;
783 
784  DetectContentData *cd = (DetectContentData *)mpm_sm->ctx;
786  if (DETECT_CONTENT_IS_SINGLE(cd) &&
787  !(cd->flags & DETECT_CONTENT_NEGATED) &&
788  !(cd->flags & DETECT_CONTENT_REPLACE) &&
789  cd->content_len == cd->fp_chop_len)
790  {
792  }
793  } else {
794  if (DETECT_CONTENT_IS_SINGLE(cd) &&
795  !(cd->flags & DETECT_CONTENT_NEGATED) &&
796  !(cd->flags & DETECT_CONTENT_REPLACE))
797  {
799  }
800  }
801  cd->flags |= DETECT_CONTENT_MPM;
802  s->init_data->mpm_sm = mpm_sm;
803  return;
804 }
805 
806 static SigMatch *GetMpmForList(const Signature *s, const int list, SigMatch *mpm_sm,
807  uint16_t max_len, bool skip_negated_content)
808 {
809  for (SigMatch *sm = s->init_data->smlists[list]; sm != NULL; sm = sm->next) {
810  if (sm->type != DETECT_CONTENT)
811  continue;
812 
813  const DetectContentData *cd = (DetectContentData *)sm->ctx;
814  /* skip_negated_content is only set if there's absolutely no
815  * non-negated content present in the sig */
816  if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
817  continue;
818  if (cd->content_len != max_len)
819  continue;
820 
821  if (mpm_sm == NULL) {
822  mpm_sm = sm;
823  } else {
824  DetectContentData *data1 = (DetectContentData *)sm->ctx;
825  DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
826  uint32_t ls = PatternStrength(data1->content, data1->content_len);
827  uint32_t ss = PatternStrength(data2->content, data2->content_len);
828  if (ls > ss) {
829  mpm_sm = sm;
830  } else if (ls == ss) {
831  /* if 2 patterns are of equal strength, we pick the longest */
832  if (data1->content_len > data2->content_len)
833  mpm_sm = sm;
834  } else {
835  SCLogDebug("sticking with mpm_sm");
836  }
837  }
838  }
839  return mpm_sm;
840 }
841 
843 {
844  if (s->init_data->mpm_sm != NULL)
845  return;
846 
847  SigMatch *mpm_sm = NULL, *sm = NULL;
848  const int nlists = s->init_data->smlists_array_size;
849  int nn_sm_list[nlists];
850  int n_sm_list[nlists];
851  memset(nn_sm_list, 0, nlists * sizeof(int));
852  memset(n_sm_list, 0, nlists * sizeof(int));
853  int count_nn_sm_list = 0;
854  int count_n_sm_list = 0;
855 
856  /* inspect rule to see if we have the fast_pattern reg to
857  * force using a sig, otherwise keep stats about the patterns */
858  for (int list_id = 0; list_id < nlists; list_id++) {
859  if (s->init_data->smlists[list_id] == NULL)
860  continue;
861 
862  if (!FastPatternSupportEnabledForSigMatchList(de_ctx, list_id))
863  continue;
864 
865  for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
866  if (sm->type != DETECT_CONTENT)
867  continue;
868 
869  const DetectContentData *cd = (DetectContentData *)sm->ctx;
870  /* fast_pattern set in rule, so using this pattern */
871  if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
872  SetMpm(s, sm);
873  return;
874  }
875 
876  if (cd->flags & DETECT_CONTENT_NEGATED) {
877  n_sm_list[list_id] = 1;
878  count_n_sm_list++;
879  } else {
880  nn_sm_list[list_id] = 1;
881  count_nn_sm_list++;
882  }
883  }
884  }
885 
886  /* prefer normal not-negated over negated */
887  int *curr_sm_list = NULL;
888  int skip_negated_content = 1;
889  if (count_nn_sm_list > 0) {
890  curr_sm_list = nn_sm_list;
891  } else if (count_n_sm_list > 0) {
892  curr_sm_list = n_sm_list;
893  skip_negated_content = 0;
894  } else {
895  return;
896  }
897 
898  int final_sm_list[nlists];
899  memset(&final_sm_list, 0, (nlists * sizeof(int)));
900 
901  int count_final_sm_list = 0;
902  int priority;
903 
905  while (tmp != NULL) {
906  for (priority = tmp->priority;
907  tmp != NULL && priority == tmp->priority;
908  tmp = tmp->next)
909  {
910  if (tmp->list_id >= nlists)
911  continue;
912  if (curr_sm_list[tmp->list_id] == 0)
913  continue;
914  final_sm_list[count_final_sm_list++] = tmp->list_id;
915  }
916  if (count_final_sm_list != 0)
917  break;
918  }
919 
920  BUG_ON(count_final_sm_list == 0);
921 
922  uint16_t max_len = 0;
923  for (int i = 0; i < count_final_sm_list; i++) {
924  if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
925  continue;
926 
927  for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) {
928  if (sm->type != DETECT_CONTENT)
929  continue;
930 
931  const DetectContentData *cd = (DetectContentData *)sm->ctx;
932  /* skip_negated_content is only set if there's absolutely no
933  * non-negated content present in the sig */
934  if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
935  continue;
936  if (max_len < cd->content_len)
937  max_len = cd->content_len;
938  }
939  }
940 
941  for (int i = 0; i < count_final_sm_list; i++) {
942  if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
943  continue;
944 
945  mpm_sm = GetMpmForList(s, final_sm_list[i], mpm_sm, max_len, skip_negated_content);
946  }
947 
948  /* assign to signature */
949  SetMpm(s, mpm_sm);
950  return;
951 }
952 
953 /** \internal
954  * \brief The hash function for MpmStore
955  *
956  * \param ht Pointer to the hash table.
957  * \param data Pointer to the MpmStore.
958  * \param datalen Not used in our case.
959  *
960  * \retval hash The generated hash value.
961  */
962 static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
963 {
964  const MpmStore *ms = (MpmStore *)data;
965  uint32_t hash = 0;
966  uint32_t b = 0;
967 
968  for (b = 0; b < ms->sid_array_size; b++)
969  hash += ms->sid_array[b];
970 
971  return hash % ht->array_size;
972 }
973 
974 /**
975  * \brief The Compare function for MpmStore
976  *
977  * \param data1 Pointer to the first MpmStore.
978  * \param len1 Not used.
979  * \param data2 Pointer to the second MpmStore.
980  * \param len2 Not used.
981  *
982  * \retval 1 If the 2 MpmStores sent as args match.
983  * \retval 0 If the 2 MpmStores sent as args do not match.
984  */
985 static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2,
986  uint16_t len2)
987 {
988  const MpmStore *ms1 = (MpmStore *)data1;
989  const MpmStore *ms2 = (MpmStore *)data2;
990 
991  if (ms1->sid_array_size != ms2->sid_array_size)
992  return 0;
993 
994  if (ms1->buffer != ms2->buffer)
995  return 0;
996 
997  if (ms1->direction != ms2->direction)
998  return 0;
999 
1000  if (ms1->sm_list != ms2->sm_list)
1001  return 0;
1002 
1003  if (SCMemcmp(ms1->sid_array, ms2->sid_array,
1004  ms1->sid_array_size) != 0)
1005  {
1006  return 0;
1007  }
1008 
1009  return 1;
1010 }
1011 
1012 static void MpmStoreFreeFunc(void *ptr)
1013 {
1014  MpmStore *ms = ptr;
1015  if (ms != NULL) {
1016  if (ms->mpm_ctx != NULL && !(ms->mpm_ctx->flags & MPMCTX_FLAGS_GLOBAL))
1017  {
1018  SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx);
1020  SCFree(ms->mpm_ctx);
1021  }
1022  ms->mpm_ctx = NULL;
1023 
1024  SCFree(ms->sid_array);
1025  SCFree(ms);
1026  }
1027 }
1028 
1029 /**
1030  * \brief Initializes the MpmStore mpm hash table to be used by the detection
1031  * engine context.
1032  *
1033  * \param de_ctx Pointer to the detection engine context.
1034  *
1035  * \retval 0 On success.
1036  * \retval -1 On failure.
1037  */
1039 {
1040  de_ctx->mpm_hash_table = HashListTableInit(4096,
1041  MpmStoreHashFunc,
1042  MpmStoreCompareFunc,
1043  MpmStoreFreeFunc);
1044  if (de_ctx->mpm_hash_table == NULL)
1045  goto error;
1046 
1047  return 0;
1048 
1049 error:
1050  return -1;
1051 }
1052 
1053 /**
1054  * \brief Adds a MpmStore to the detection engine context MpmStore
1055  *
1056  * \param de_ctx Pointer to the detection engine context.
1057  * \param sgh Pointer to the MpmStore.
1058  *
1059  * \retval ret 0 on Successfully adding the argument sgh; -1 on failure.
1060  */
1061 static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s)
1062 {
1063  int ret = HashListTableAdd(de_ctx->mpm_hash_table, (void *)s, 0);
1064  return ret;
1065 }
1066 
1067 /**
1068  * \brief Used to lookup a MpmStore from the MpmStore
1069  *
1070  * \param de_ctx Pointer to the detection engine context.
1071  * \param sgh Pointer to the MpmStore.
1072  *
1073  * \retval rsgh On success a pointer to the MpmStore if the MpmStore is
1074  * found in the hash table; NULL on failure.
1075  */
1076 static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s)
1077 {
1079  (void *)s, 0);
1080  return rs;
1081 }
1082 
1083 static const DetectBufferMpmRegistery *GetByMpmStore(const DetectEngineCtx *de_ctx,
1084  const MpmStore *ms)
1085 {
1086  const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
1087  while (am != NULL) {
1088  if (ms->sm_list == am->sm_list &&
1089  ms->direction == am->direction) {
1090  return am;
1091  }
1092  am = am->next;
1093  }
1094  am = de_ctx->pkt_mpms_list;
1095  while (am != NULL) {
1096  if (ms->sm_list == am->sm_list) {
1097  return am;
1098  }
1099  am = am->next;
1100  }
1101  return NULL;
1102 }
1103 
1105 {
1106  HashListTableBucket *htb = NULL;
1107 
1108  uint32_t stats[MPMB_MAX] = {0};
1109  int app_mpms_cnt = de_ctx->buffer_type_map_elements;
1110  uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build
1111  memset(&appstats, 0x00, sizeof(appstats));
1112  int pkt_mpms_cnt = de_ctx->buffer_type_map_elements;
1113  uint32_t pktstats[pkt_mpms_cnt + 1]; // +1 to silence scan-build
1114  memset(&pktstats, 0x00, sizeof(pktstats));
1115 
1116  for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table);
1117  htb != NULL;
1118  htb = HashListTableGetListNext(htb))
1119  {
1120  const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb);
1121  if (ms == NULL) {
1122  continue;
1123  }
1124  if (ms->buffer < MPMB_MAX)
1125  stats[ms->buffer]++;
1126  else if (ms->sm_list != DETECT_SM_LIST_PMATCH) {
1127  const DetectBufferMpmRegistery *am = GetByMpmStore(de_ctx, ms);
1128  if (am != NULL) {
1129  switch (am->type) {
1131  SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p",
1132  am->name,
1133  ms->mpm_ctx->pattern_cnt,
1134  ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
1135  ms->mpm_ctx);
1136  pktstats[am->sm_list]++;
1137  break;
1139  SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p",
1140  am->name,
1141  am->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient",
1142  ms->mpm_ctx->pattern_cnt,
1143  ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
1144  ms->mpm_ctx);
1145  appstats[am->sm_list]++;
1146  break;
1148  break;
1149  }
1150  }
1151  }
1152  }
1153 
1154  if (!(de_ctx->flags & DE_QUIET)) {
1155  for (int x = 0; x < MPMB_MAX; x++) {
1156  SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]);
1157  }
1158  const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
1159  while (am != NULL) {
1160  if (appstats[am->sm_list] > 0) {
1161  const char *name = am->name;
1162  const char *direction = am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient";
1163  SCLogPerf("AppLayer MPM \"%s %s (%s)\": %u", direction, name,
1164  AppProtoToString(am->app_v2.alproto), appstats[am->sm_list]);
1165  }
1166  am = am->next;
1167  }
1168  const DetectBufferMpmRegistery *pm = de_ctx->pkt_mpms_list;
1169  while (pm != NULL) {
1170  if (pktstats[pm->sm_list] > 0) {
1171  const char *name = pm->name;
1172  SCLogPerf("Pkt MPM \"%s\": %u", name, pktstats[pm->sm_list]);
1173  }
1174  pm = pm->next;
1175  }
1176  }
1177 }
1178 
1179 /**
1180  * \brief Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by
1181  * MpmStoreInit() function.
1182  *
1183  * \param de_ctx Pointer to the detection engine context.
1184  */
1186 {
1187  if (de_ctx->mpm_hash_table == NULL)
1188  return;
1189 
1191  de_ctx->mpm_hash_table = NULL;
1192  return;
1193 }
1194 
1195 static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
1196 {
1197  const Signature *s = NULL;
1198  uint32_t sig;
1199  int dir = 0;
1200 
1201  if (ms->buffer != MPMB_MAX) {
1203 
1204  switch (ms->buffer) {
1205  /* TS is 1 */
1206  case MPMB_TCP_PKT_TS:
1207  case MPMB_TCP_STREAM_TS:
1208  case MPMB_UDP_TS:
1209  dir = 1;
1210  break;
1211 
1212  /* TC is 0 */
1213  default:
1214  case MPMB_UDP_TC:
1215  case MPMB_TCP_STREAM_TC:
1216  case MPMB_TCP_PKT_TC:
1217  case MPMB_OTHERIP: /**< use 0 for other */
1218  dir = 0;
1219  break;
1220  }
1221  } else {
1223 
1224  if (ms->direction == SIG_FLAG_TOSERVER)
1225  dir = 1;
1226  else
1227  dir = 0;
1228  }
1229 
1230  ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir);
1231  if (ms->mpm_ctx == NULL)
1232  return;
1233 
1234  MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher);
1235 
1236  /* add the patterns */
1237  for (sig = 0; sig < (ms->sid_array_size * 8); sig++) {
1238  if (ms->sid_array[sig / 8] & (1 << (sig % 8))) {
1239  s = de_ctx->sig_array[sig];
1240  if (s == NULL)
1241  continue;
1242  if ((s->flags & ms->direction) == 0)
1243  continue;
1244  if (s->init_data->mpm_sm == NULL)
1245  continue;
1246  int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1247  if (list < 0)
1248  continue;
1249  if (list != ms->sm_list)
1250  continue;
1251 
1252  SCLogDebug("adding %u", s->id);
1253 
1255 
1256  int skip = 0;
1257  /* negated logic: if mpm match can't be used to be sure about this
1258  * pattern, we have to inspect the rule fully regardless of mpm
1259  * match. So in this case there is no point of adding it at all.
1260  * The non-mpm list entry for the sig will make sure the sig is
1261  * inspected. */
1262  if ((cd->flags & DETECT_CONTENT_NEGATED) &&
1264  {
1265  skip = 1;
1266  SCLogDebug("not adding negated mpm as it's not 'single'");
1267  }
1268 
1269  if (!skip) {
1270  PopulateMpmHelperAddPattern(ms->mpm_ctx,
1271  cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP));
1272  }
1273  }
1274  }
1275 
1276  if (ms->mpm_ctx->pattern_cnt == 0) {
1277  MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx);
1278  ms->mpm_ctx = NULL;
1279  } else {
1281  if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) {
1283  }
1284  }
1285  }
1286 }
1287 
1288 
1289 /** \brief Get MpmStore for a built-in buffer type
1290  *
1291  */
1293  enum MpmBuiltinBuffers buf)
1294 {
1295  const Signature *s = NULL;
1296  uint32_t sig;
1297  uint32_t cnt = 0;
1298  int direction = 0;
1299  uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1300  uint8_t sids_array[max_sid];
1301  memset(sids_array, 0x00, max_sid);
1302  int sgh_mpm_context = 0;
1303  int sm_list = DETECT_SM_LIST_PMATCH;
1304 
1305  switch (buf) {
1306  case MPMB_TCP_PKT_TS:
1307  case MPMB_TCP_PKT_TC:
1308  sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet;
1309  break;
1310  case MPMB_TCP_STREAM_TS:
1311  case MPMB_TCP_STREAM_TC:
1312  sgh_mpm_context = de_ctx->sgh_mpm_context_stream;
1313  break;
1314  case MPMB_UDP_TS:
1315  case MPMB_UDP_TC:
1316  sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet;
1317  break;
1318  case MPMB_OTHERIP:
1319  sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet;
1320  break;
1321  default:
1322  break;
1323  }
1324 
1325  switch(buf) {
1326  case MPMB_TCP_PKT_TS:
1327  case MPMB_TCP_STREAM_TS:
1328  case MPMB_UDP_TS:
1329  direction = SIG_FLAG_TOSERVER;
1330  break;
1331 
1332  case MPMB_TCP_PKT_TC:
1333  case MPMB_TCP_STREAM_TC:
1334  case MPMB_UDP_TC:
1335  direction = SIG_FLAG_TOCLIENT;
1336  break;
1337 
1338  case MPMB_OTHERIP:
1339  direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER);
1340  break;
1341 
1342  case MPMB_MAX:
1343  BUG_ON(1);
1344  break;
1345  }
1346 
1347  for (sig = 0; sig < sgh->sig_cnt; sig++) {
1348  s = sgh->match_array[sig];
1349  if (s == NULL)
1350  continue;
1351 
1352  if (s->init_data->mpm_sm == NULL)
1353  continue;
1354 
1355  int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1356  if (list < 0)
1357  continue;
1358 
1359  if (list != DETECT_SM_LIST_PMATCH)
1360  continue;
1361 
1362  switch (buf) {
1363  case MPMB_TCP_PKT_TS:
1364  case MPMB_TCP_PKT_TC:
1365  if (SignatureHasPacketContent(s) == 1)
1366  {
1367  sids_array[s->num / 8] |= 1 << (s->num % 8);
1368  cnt++;
1369  }
1370  break;
1371  case MPMB_TCP_STREAM_TS:
1372  case MPMB_TCP_STREAM_TC:
1373  if (SignatureHasStreamContent(s) == 1)
1374  {
1375  sids_array[s->num / 8] |= 1 << (s->num % 8);
1376  cnt++;
1377  }
1378  break;
1379  case MPMB_UDP_TS:
1380  case MPMB_UDP_TC:
1381  sids_array[s->num / 8] |= 1 << (s->num % 8);
1382  cnt++;
1383  break;
1384  case MPMB_OTHERIP:
1385  sids_array[s->num / 8] |= 1 << (s->num % 8);
1386  cnt++;
1387  break;
1388  default:
1389  break;
1390  }
1391  }
1392 
1393  if (cnt == 0)
1394  return NULL;
1395 
1396  MpmStore lookup = { sids_array, max_sid, direction, buf, sm_list, 0, NULL};
1397 
1398  MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1399  if (result == NULL) {
1400  MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1401  if (copy == NULL)
1402  return NULL;
1403  uint8_t *sids = SCCalloc(1, max_sid);
1404  if (sids == NULL) {
1405  SCFree(copy);
1406  return NULL;
1407  }
1408 
1409  memcpy(sids, sids_array, max_sid);
1410  copy->sid_array = sids;
1411  copy->sid_array_size = max_sid;
1412  copy->buffer = buf;
1413  copy->direction = direction;
1414  copy->sm_list = sm_list;
1415  copy->sgh_mpm_context = sgh_mpm_context;
1416 
1417  MpmStoreSetup(de_ctx, copy);
1418  MpmStoreAdd(de_ctx, copy);
1419  return copy;
1420  } else {
1421  return result;
1422  }
1423 }
1424 
1425 static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx,
1426  SigGroupHead *sgh, const DetectBufferMpmRegistery *am)
1427 {
1428  const Signature *s = NULL;
1429  uint32_t sig;
1430  uint32_t cnt = 0;
1431  uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1432  uint8_t sids_array[max_sid];
1433  memset(sids_array, 0x00, max_sid);
1434 
1435  SCLogDebug("handling %s direction %s for list %d", am->name,
1436  am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1437  am->sm_list);
1438 
1439  for (sig = 0; sig < sgh->sig_cnt; sig++) {
1440  s = sgh->match_array[sig];
1441  if (s == NULL)
1442  continue;
1443 
1444  if (s->init_data->mpm_sm == NULL)
1445  continue;
1446 
1447  int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1448  if (list < 0)
1449  continue;
1450 
1451  if ((s->flags & am->direction) == 0)
1452  continue;
1453 
1454  if (list != am->sm_list)
1455  continue;
1456 
1457  sids_array[s->num / 8] |= 1 << (s->num % 8);
1458  cnt++;
1459  }
1460 
1461  if (cnt == 0)
1462  return NULL;
1463 
1464  MpmStore lookup = { sids_array, max_sid, am->direction,
1465  MPMB_MAX, am->sm_list, 0, NULL};
1466  SCLogDebug("am->direction %d am->sm_list %d",
1467  am->direction, am->sm_list);
1468 
1469  MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1470  if (result == NULL) {
1471  SCLogDebug("new unique mpm for %s %s: %u patterns",
1472  am->name,
1473  am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1474  cnt);
1475 
1476  MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1477  if (copy == NULL)
1478  return NULL;
1479  uint8_t *sids = SCCalloc(1, max_sid);
1480  if (sids == NULL) {
1481  SCFree(copy);
1482  return NULL;
1483  }
1484 
1485  memcpy(sids, sids_array, max_sid);
1486  copy->sid_array = sids;
1487  copy->sid_array_size = max_sid;
1488  copy->buffer = MPMB_MAX;
1489  copy->direction = am->direction;
1490  copy->sm_list = am->sm_list;
1491  copy->sgh_mpm_context = am->sgh_mpm_context;
1492 
1493  MpmStoreSetup(de_ctx, copy);
1494  MpmStoreAdd(de_ctx, copy);
1495  return copy;
1496  } else {
1497  SCLogDebug("using existing mpm %p", result);
1498  return result;
1499  }
1500  return NULL;
1501 }
1502 
1503 static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx,
1504  SigGroupHead *sgh, const DetectBufferMpmRegistery *am)
1505 {
1506  const Signature *s = NULL;
1507  uint32_t sig;
1508  uint32_t cnt = 0;
1509  uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1510  uint8_t sids_array[max_sid];
1511  memset(sids_array, 0x00, max_sid);
1512 
1513  SCLogDebug("handling %s for list %d", am->name,
1514  am->sm_list);
1515 
1516  for (sig = 0; sig < sgh->sig_cnt; sig++) {
1517  s = sgh->match_array[sig];
1518  if (s == NULL)
1519  continue;
1520 
1521  if (s->init_data->mpm_sm == NULL)
1522  continue;
1523 
1524  int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1525  if (list < 0)
1526  continue;
1527 
1528  if (list != am->sm_list)
1529  continue;
1530 
1531  sids_array[s->num / 8] |= 1 << (s->num % 8);
1532  cnt++;
1533  }
1534 
1535  if (cnt == 0)
1536  return NULL;
1537 
1538  MpmStore lookup = { sids_array, max_sid, SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT,
1539  MPMB_MAX, am->sm_list, 0, NULL};
1540  SCLogDebug("am->sm_list %d", am->sm_list);
1541 
1542  MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1543  if (result == NULL) {
1544  SCLogDebug("new unique mpm for %s: %u patterns",
1545  am->name, cnt);
1546 
1547  MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1548  if (copy == NULL)
1549  return NULL;
1550  uint8_t *sids = SCCalloc(1, max_sid);
1551  if (sids == NULL) {
1552  SCFree(copy);
1553  return NULL;
1554  }
1555 
1556  memcpy(sids, sids_array, max_sid);
1557  copy->sid_array = sids;
1558  copy->sid_array_size = max_sid;
1559  copy->buffer = MPMB_MAX;
1561  copy->sm_list = am->sm_list;
1562  copy->sgh_mpm_context = am->sgh_mpm_context;
1563 
1564  MpmStoreSetup(de_ctx, copy);
1565  MpmStoreAdd(de_ctx, copy);
1566  return copy;
1567  } else {
1568  SCLogDebug("using existing mpm %p", result);
1569  return result;
1570  }
1571  return NULL;
1572 }
1573 
1574 static void SetRawReassemblyFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1575 {
1576  const Signature *s = NULL;
1577  uint32_t sig;
1578 
1579  for (sig = 0; sig < sgh->sig_cnt; sig++) {
1580  s = sgh->match_array[sig];
1581  if (s == NULL)
1582  continue;
1583 
1584  if (SignatureHasStreamContent(s) == 1) {
1586  SCLogDebug("rule group %p has SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1587  return;
1588  }
1589  }
1590  SCLogDebug("rule group %p does NOT have SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1591 }
1592 
1593 static void PrepareAppMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
1594 {
1595  if (de_ctx->app_mpms_list_cnt == 0)
1596  return;
1597 
1598  sh->init->app_mpms = SCCalloc(de_ctx->app_mpms_list_cnt, sizeof(MpmCtx *));
1599  BUG_ON(sh->init->app_mpms == NULL);
1600 
1602  while (a != NULL) {
1603  if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) ||
1605  {
1606  MpmStore *mpm_store = MpmStorePrepareBufferAppLayer(de_ctx, sh, a);
1607  if (mpm_store != NULL) {
1608  sh->init->app_mpms[a->id] = mpm_store->mpm_ctx;
1609 
1610  SCLogDebug("a %p a->name %s a->PrefilterRegisterWithListId %p "
1611  "mpm_store->mpm_ctx %p", a, a->name,
1612  a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
1613 
1614  /* if we have just certain types of negated patterns,
1615  * mpm_ctx can be NULL */
1616  if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
1618  sh, mpm_store->mpm_ctx,
1619  a, a->sm_list) != 0);
1620  SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
1621  }
1622  }
1623  }
1624  a = a->next;
1625  }
1626 }
1627 
1628 static void PreparePktMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
1629 {
1630  if (de_ctx->pkt_mpms_list_cnt == 0)
1631  return;
1632 
1633  sh->init->pkt_mpms = SCCalloc(de_ctx->pkt_mpms_list_cnt, sizeof(MpmCtx *));
1634  BUG_ON(sh->init->pkt_mpms == NULL);
1635 
1637  while (a != NULL) {
1638  MpmStore *mpm_store = MpmStorePrepareBufferPkt(de_ctx, sh, a);
1639  if (mpm_store != NULL) {
1640  sh->init->pkt_mpms[a->id] = mpm_store->mpm_ctx;
1641 
1642  SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p "
1643  "mpm_store->mpm_ctx %p", a, a->name,
1644  a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
1645 
1646  /* if we have just certain types of negated patterns,
1647  * mpm_ctx can be NULL */
1648  if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
1650  sh, mpm_store->mpm_ctx,
1651  a, a->sm_list) != 0);
1652  SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
1653  }
1654  }
1655  a = a->next;
1656  }
1657 }
1658 
1659 /** \brief Prepare the pattern matcher ctx in a sig group head.
1660  *
1661  */
1663 {
1664  MpmStore *mpm_store = NULL;
1665  if (SGH_PROTO(sh, IPPROTO_TCP)) {
1666  if (SGH_DIRECTION_TS(sh)) {
1667  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS);
1668  if (mpm_store != NULL) {
1669  PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1670  }
1671 
1672  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS);
1673  if (mpm_store != NULL) {
1674  PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
1675  }
1676 
1677  SetRawReassemblyFlag(de_ctx, sh);
1678  }
1679  if (SGH_DIRECTION_TC(sh)) {
1680  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC);
1681  if (mpm_store != NULL) {
1682  PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1683  }
1684 
1685  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC);
1686  if (mpm_store != NULL) {
1687  PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
1688  }
1689 
1690  SetRawReassemblyFlag(de_ctx, sh);
1691  }
1692  } else if (SGH_PROTO(sh, IPPROTO_UDP)) {
1693  if (SGH_DIRECTION_TS(sh)) {
1694  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS);
1695  if (mpm_store != NULL) {
1696  PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1697  }
1698  }
1699  if (SGH_DIRECTION_TC(sh)) {
1700  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC);
1701  if (mpm_store != NULL) {
1702  PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1703  }
1704  }
1705  } else {
1706  mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP);
1707  if (mpm_store != NULL) {
1708  PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1709  }
1710  }
1711 
1712  PrepareAppMpms(de_ctx, sh);
1713  PreparePktMpms(de_ctx, sh);
1714  return 0;
1715 }
1716 
1717 typedef struct DetectFPAndItsId_ {
1719  uint16_t content_len;
1720  uint32_t flags;
1721  int sm_list;
1722 
1723  uint8_t *content;
1725 
1726 /**
1727  * \brief Figured out the FP and their respective content ids for all the
1728  * sigs in the engine.
1729  *
1730  * \param de_ctx Detection engine context.
1731  *
1732  * \retval 0 On success.
1733  * \retval -1 On failure.
1734  */
1736 {
1737  uint32_t struct_total_size = 0;
1738  uint32_t content_total_size = 0;
1739  Signature *s = NULL;
1740 
1741  /* Count the amount of memory needed to store all the structures
1742  * and the content of those structures. This will over estimate the
1743  * true size, since duplicates are removed below, but counted here.
1744  */
1745  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
1746  if (s->flags & SIG_FLAG_PREFILTER)
1747  continue;
1748 
1749  RetrieveFPForSig(de_ctx, s);
1750  if (s->init_data->mpm_sm != NULL) {
1752  struct_total_size += sizeof(DetectFPAndItsId);
1753  content_total_size += cd->content_len;
1754 
1755  s->flags |= SIG_FLAG_PREFILTER;
1756  }
1757  }
1758  /* no rules */
1759  if (struct_total_size + content_total_size == 0)
1760  return 0;
1761 
1762  /* array hash buffer - I've run out of ideas to name it */
1763  uint8_t *ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size));
1764  if (unlikely(ahb == NULL))
1765  return -1;
1766 
1767  uint8_t *content = NULL;
1768  uint16_t content_len = 0;
1769  PatIntId max_id = 0;
1770  DetectFPAndItsId *struct_offset = (DetectFPAndItsId *)ahb;
1771  uint8_t *content_offset = ahb + struct_total_size;
1772 
1773  for (s = de_ctx->sig_list; s != NULL; s = s->next) {
1774  if (s->init_data->mpm_sm != NULL) {
1776  BUG_ON(sm_list == -1);
1777 
1779  DetectFPAndItsId *dup = (DetectFPAndItsId *)ahb;
1781  content = cd->content + cd->fp_chop_offset;
1782  content_len = cd->fp_chop_len;
1783  } else {
1784  content = cd->content;
1785  content_len = cd->content_len;
1786  }
1787  uint32_t flags = cd->flags & DETECT_CONTENT_NOCASE;
1788  /* Check for content already found on the same list */
1789  for (; dup != struct_offset; dup++) {
1790  if (dup->content_len != content_len)
1791  continue;
1792  if (dup->sm_list != sm_list)
1793  continue;
1794  if (dup->flags != flags)
1795  continue;
1796  /* Check for pattern matching a duplicate. Use case insensitive matching
1797  * for case insensitive patterns. */
1798  if (flags & DETECT_CONTENT_NOCASE) {
1799  if (SCMemcmpLowercase(dup->content, content, content_len) != 0)
1800  continue;
1801  } else {
1802  /* Case sensitive matching */
1803  if (SCMemcmp(dup->content, content, content_len) != 0)
1804  continue;
1805  }
1806  /* Found a match with a previous pattern. */
1807  break;
1808  }
1809  if (dup != struct_offset) {
1810  /* Exited for-loop before the end, so found an existing match.
1811  * Use its ID. */
1812  cd->id = dup->id;
1813  continue;
1814  }
1815 
1816  /* Not found, so new content. Give it a new ID and add it
1817  * to the array. Copy the content at the end of the
1818  * content array.
1819  */
1820  struct_offset->id = max_id++;
1821  cd->id = struct_offset->id;
1822  struct_offset->content_len = content_len;
1823  struct_offset->sm_list = sm_list;
1824  struct_offset->content = content_offset;
1825  struct_offset->flags = flags;
1826 
1827  content_offset += content_len;
1828 
1829  if (flags & DETECT_CONTENT_NOCASE) {
1830  /* Need to store case-insensitive patterns as lower case
1831  * because SCMemcmpLowercase() above assumes that all
1832  * patterns are stored lower case so that it doesn't
1833  * need to re-lower its first argument.
1834  */
1835  memcpy_tolower(struct_offset->content, content, content_len);
1836  } else {
1837  memcpy(struct_offset->content, content, content_len);
1838  }
1839 
1840  struct_offset++;
1841  } /* if (s->mpm_sm != NULL) */
1842  } /* for */
1843 
1844  de_ctx->max_fp_id = max_id;
1845 
1846  SCFree(ahb);
1847 
1848  return 0;
1849 }
void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx)
Definition: util-mpm.c:215
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
#define PatIntId
uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
Predict a strength value for patterns.
DetectProto proto
Definition: detect.h:539
SigIntId sig_cnt
Definition: detect.h:1341
SignatureInitData * init_data
Definition: detect.h:591
uint16_t flags
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:369
#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c)
#define SCLogDebug(...)
Definition: util-debug.h:335
const char * builtin_mpms[]
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
uint8_t flags
Definition: util-mpm.h:92
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:302
Signature ** sig_array
Definition: detect.h:776
uint16_t minlen
Definition: util-mpm.h:99
#define SIG_FLAG_PREFILTER
Definition: detect.h:243
int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx)
Figured out the FP and their respective content ids for all the sigs in the engine.
void PacketPatternCleanup(DetectEngineThreadCtx *det_ctx)
cleans up the mpm instance after a match
int32_t sgh_mpm_context
Definition: detect.h:1255
InspectionBuffer *(* InspectionBufferGetPktDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Packet *p, const int list_id)
Definition: detect.h:449
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
#define BUG_ON(x)
uint32_t pattern_cnt
Definition: util-mpm.h:97
uint32_t flags
Definition: detect.h:523
uint32_t id
Definition: detect.h:555
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
Signature ** match_array
Definition: detect.h:1361
#define DETECT_CONTENT_FAST_PATTERN
uint32_t sid_array_size
Definition: detect.h:1250
#define unlikely(expr)
Definition: util-optimize.h:35
void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
DetectEngineTransforms transforms
Definition: detect.h:618
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
int transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:370
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:517
uint16_t PatternMatchDefaultMatcher(void)
Function to return the multi pattern matcher algorithm to be used by the engine, based on the mpm-alg...
struct DetectBufferMpmRegistery_::@95::@97 app_v2
Signature * sig_list
Definition: detect.h:767
int32_t sgh_mpm_context_proto_tcp_packet
Definition: detect.h:846
uint8_t * sid_array
Definition: detect.h:1249
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:224
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:256
uint8_t proto[256/8]
void DetectPktMpmRegister(const char *name, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistery *mpm_reg, int list_id), InspectionBufferGetPktDataPtr GetData)
register a MPM engine
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:146
struct DetectFPAndItsId_ DetectFPAndItsId
Container for matching data for a signature group.
Definition: detect.h:1336
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
#define SGH_PROTO(sgh, p)
void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx)
DetectBufferMpmRegistery * pkt_mpms_list
Definition: detect.h:931
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:223
void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
const char * name
Definition: detect.h:1200
uint16_t AppProto
Signature container.
Definition: detect.h:522
int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
int32_t sgh_mpm_context_proto_other_packet
Definition: detect.h:848
HashListTable * mpm_hash_table
Definition: detect.h:802
int sm_list
Definition: detect.h:1254
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name)
Register a new Mpm Context.
Definition: util-mpm.c:55
#define DETECT_CONTENT_IS_SINGLE(c)
#define SGH_DIRECTION_TS(sgh)
SigIntId num
Definition: detect.h:532
void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms)
copy a mpm engine from parent_id, add in transforms
struct SigMatch_ * next
Definition: detect.h:322
main detection engine ctx
Definition: detect.h:761
uint32_t max_fp_id
Definition: detect.h:828
#define MPMCTX_FLAGS_GLOBAL
Definition: util-mpm.h:85
MpmBuiltinBuffers
Definition: detect.h:1237
SCFPSupportSMList * sm_fp_support_smlist_list
#define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
uint32_t pkt_mpms_list_cnt
Definition: detect.h:932
#define DE_QUIET
Definition: detect.h:292
MpmCtx ** pkt_mpms
Definition: detect.h:1325
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:161
#define DetectEngineGetMaxSigId(de_ctx)
Definition: detect-engine.h:81
int DetectBufferTypeGetByName(const char *name)
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#define SIG_FLAG_TOCLIENT
Definition: detect.h:237
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
int32_t sgh_mpm_context_stream
Definition: detect.h:849
void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher)
uint8_t flags
Definition: detect.h:762
int direction
Definition: detect.h:1252
MpmCtx ** app_mpms
Definition: detect.h:1324
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
struct SCFPSupportSMList_ * next
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
uint8_t mpm_type
Definition: util-mpm.h:90
uint16_t mpm_matcher
Definition: detect.h:810
one time registration of keywords at start up
Definition: detect.h:605
#define SIG_FLAG_TOSERVER
Definition: detect.h:236
int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx)
#define SCEnter(...)
Definition: util-debug.h:337
PrefilterRuleStore pmq
Definition: detect.h:1102
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:575
enum DetectBufferMpmType type
Definition: detect.h:612
uint32_t buffer_type_map_elements
Definition: detect.h:918
int SignatureHasPacketContent(const Signature *s)
check if a signature has patterns that are to be inspected against a packets payload (as opposed to t...
void ShortenString(const char *input, char *output, size_t output_size, char c)
Definition: util-misc.c:220
void MpmStoreFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by MpmStoreInit() function...
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
struct DetectBufferMpmRegistery_::@95::@98 pkt_v1
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:145
uint32_t flags
Definition: detect.h:1337
#define MPM_PATTERN_CTX_OWNS_ID
Definition: util-mpm.h:139
struct Signature_ * next
Definition: detect.h:594
#define SCReturnInt(x)
Definition: util-debug.h:341
int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
int32_t sgh_mpm_context_proto_udp_packet
Definition: detect.h:847
#define SIG_GROUP_HEAD_HAVERAWSTREAM
Definition: detect.h:1228
void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
struct SigMatch_ ** smlists
Definition: detect.h:516
void DetectBufferTypeSupportsMpm(const char *name)
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistery *mpm_reg, int list_id)
uint32_t smlists_array_size
Definition: detect.h:514
#define DETECT_CONTENT_MPM
SigMatchCtx * ctx
Definition: detect.h:321
#define SCMalloc(a)
Definition: util-mem.h:222
#define MPM_CTX_FACTORY_UNIQUE_CONTEXT
Definition: util-mpm.h:113
int mpm_default_matcher
Definition: util-mpm.h:170
#define DETECT_CONTENT_OFFSET_BE
uint16_t maxlen
Definition: util-mpm.h:100
void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:261
#define DETECT_CONTENT_NEGATED
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:169
#define SCFree(a)
Definition: util-mem.h:322
#define DETECT_CONTENT_REPLACE
void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx)
void DetectBufferTypeSupportsTransformations(const char *name)
void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms)
copy a mpm engine from parent_id, add in transforms
MpmCtx * mpm_ctx
Definition: detect.h:1257
int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, const int list_id)
Checks if a particular list(Signature->sm_lists[]) is in the list of lists that need to be searched f...
int DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for builtin buffers that are in "single or "shared" mode. ...
void SupportFastPatternForSigMatchList(int list_id, int priority)
Lets one add a sm list id to be searched for potential fp supported keywords later.
int MpmStoreInit(DetectEngineCtx *de_ctx)
Initializes the MpmStore mpm hash table to be used by the detection engine context.
void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx)
#define SCLogPerf(...)
Definition: util-debug.h:261
MpmCtx * MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction)
Definition: util-mpm.c:192
#define FatalError(x,...)
Definition: util-debug.h:559
int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx)
int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistery *mpm_reg, int list_id)
DetectBufferMpmRegistery * app_mpms_list
Definition: detect.h:928
uint32_t array_size
Definition: util-hashlist.h:41
int SignatureHasStreamContent(const Signature *s)
check if a signature has patterns that are to be inspected against the stream payload (as opposed to ...
uint8_t sgh_mpm_context
Definition: detect.h:823
int MpmAddPatternCI(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:311
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
#define DETECT_CONTENT_FAST_PATTERN_CHOP
#define DETECT_CONTENT_NOCASE
enum MpmBuiltinBuffers buffer
Definition: detect.h:1253
void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
int(* PrefilterRegisterWithListId)(struct DetectEngineCtx_ *de_ctx, struct SigGroupHead_ *sgh, MpmCtx *mpm_ctx, const struct DetectBufferMpmRegistery_ *mpm_reg, int list_id)
Definition: detect.h:615
uint32_t app_mpms_list_cnt
Definition: detect.h:929
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:619
#define DETECT_CONTENT_DEPTH_BE
InspectionBuffer *(* InspectionBufferGetDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id)
Definition: detect.h:375
#define SGH_DIRECTION_TC(sgh)
struct DetectBufferMpmRegistery_ * next
Definition: detect.h:637
SigMatch * mpm_sm
Definition: detect.h:493
int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
Prepare the pattern matcher ctx in a sig group head.
const char * name
Definition: detect.h:606
MpmStore * MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf)
Get MpmStore for a built-in buffer type.
a single match condition for a signature
Definition: detect.h:318
void PmqReset(PrefilterRuleStore *)
Reset a Pmq for reusage. Meant to be called after a single search.
SigGroupHeadInitData * init
Definition: detect.h:1364