suricata
detect-engine-build.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2023 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 #include "suricata-common.h"
19 #include "detect.h"
20 #include "detect-engine.h"
21 #include "detect-parse.h"
22 #include "detect-content.h"
23 
24 #include "detect-engine-build.h"
25 #include "detect-engine-address.h"
26 #include "detect-engine-analyzer.h"
27 #include "detect-engine-iponly.h"
28 #include "detect-engine-mpm.h"
29 #include "detect-engine-siggroup.h"
30 #include "detect-engine-port.h"
32 #include "detect-engine-proto.h"
34 
35 #include "detect-dsize.h"
36 #include "detect-tcp-flags.h"
37 #include "detect-flow.h"
38 #include "detect-config.h"
39 #include "detect-flowbits.h"
40 
42 #include "util-profiling.h"
43 #include "util-validate.h"
44 #include "util-var-name.h"
45 #include "util-conf.h"
46 
47 /* Magic numbers to make the rules of a certain order fall in the same group */
48 #define DETECT_PGSCORE_RULE_PORT_WHITELISTED 111 /* Rule port group contains a whitelisted port */
49 #define DETECT_PGSCORE_RULE_MPM_FAST_PATTERN 99 /* Rule contains an MPM fast pattern */
50 #define DETECT_PGSCORE_RULE_MPM_NEGATED 77 /* Rule contains a negated MPM */
51 #define DETECT_PGSCORE_RULE_NO_MPM 55 /* Rule does not contain MPM */
52 #define DETECT_PGSCORE_RULE_SYN_ONLY 33 /* Rule needs SYN check */
53 
55 {
56  if (de_ctx == NULL)
57  return;
58 
59  for (Signature *s = de_ctx->sig_list; s != NULL;) {
60  Signature *ns = s->next;
61  SigFree(de_ctx, s);
62  s = ns;
63  }
64  de_ctx->sig_list = NULL;
65 
67  de_ctx->sig_list = NULL;
68 }
69 
70 /** \brief Find a specific signature by sid and gid
71  * \param de_ctx detection engine ctx
72  * \param sid the signature id
73  * \param gid the signature group id
74  *
75  * \retval s sig found
76  * \retval NULL sig not found
77  */
79 {
80  if (de_ctx == NULL)
81  return NULL;
82 
83  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
84  if (s->id == sid && s->gid == gid)
85  return s;
86  }
87 
88  return NULL;
89 }
90 
91 /**
92  * \brief Check if a signature contains the filestore keyword.
93  *
94  * \param s signature
95  *
96  * \retval 0 no
97  * \retval 1 yes
98  */
100 {
101  if (s == NULL)
102  return 0;
103 
104  if (s->flags & SIG_FLAG_FILESTORE)
105  return 1;
106 
107  return 0;
108 }
109 
110 /**
111  * \brief Check if a signature contains the filemagic keyword.
112  *
113  * \param s signature
114  *
115  * \retval 0 no
116  * \retval 1 yes
117  */
119 {
120  if (s == NULL)
121  return 0;
122 
124  return 1;
125 
126  return 0;
127 }
128 
129 /**
130  * \brief Check if a signature contains the filemd5 keyword.
131  *
132  * \param s signature
133  *
134  * \retval 0 no
135  * \retval 1 yes
136  */
138 {
139  if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_MD5))
140  return 1;
141 
142  return 0;
143 }
144 
145 /**
146  * \brief Check if a signature contains the filesha1 keyword.
147  *
148  * \param s signature
149  *
150  * \retval 0 no
151  * \retval 1 yes
152  */
154 {
155  if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA1))
156  return 1;
157 
158  return 0;
159 }
160 
161 /**
162  * \brief Check if a signature contains the filesha256 keyword.
163  *
164  * \param s signature
165  *
166  * \retval 0 no
167  * \retval 1 yes
168  */
170 {
171  if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA256))
172  return 1;
173 
174  return 0;
175 }
176 
177 /**
178  * \brief Check if a signature contains the filesize keyword.
179  *
180  * \param s signature
181  *
182  * \retval 0 no
183  * \retval 1 yes
184  */
186 {
187  if (s == NULL)
188  return 0;
189 
191  return 1;
192 
193  return 0;
194 }
195 
196 static bool SignatureInspectsBuffers(const Signature *s)
197 {
198  return (s->init_data->buffer_index > 0);
199 }
200 
201 /** \brief Test is a initialized signature is IP only
202  * \param de_ctx detection engine ctx
203  * \param s the signature
204  * \retval 1 sig is ip only
205  * \retval 2 sig is like ip only
206  * \retval 0 sig is not ip only
207  */
209 {
210  if (s->alproto != ALPROTO_UNKNOWN)
211  return 0;
212 
213  if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
214  return 0;
215 
216  // may happen for 'config' keyword, postmatch
217  if (s->flags & SIG_FLAG_APPLAYER)
218  return 0;
219 
220  /* if flow dir is set we can't process it in ip-only */
221  if (!(((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) ||
224  return 0;
225 
226  /* for now assume that all registered buffer types are incompatible */
227  if (SignatureInspectsBuffers(s)) {
228  SCReturnInt(0);
229  }
230 
231  /* TMATCH list can be ignored, it contains TAGs and
232  * tags are compatible to IP-only. */
233 
235  for (; sm != NULL; sm = sm->next) {
237  return 0;
238  /* we have enabled flowbits to be compatible with ip only sigs, as long
239  * as the sig only has a "set" flowbits */
240  if (sm->type == DETECT_FLOWBITS &&
241  (((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET)) {
242  return 0;
243  }
244  }
246  for ( ; sm != NULL; sm = sm->next) {
248  return 0;
249  /* we have enabled flowbits to be compatible with ip only sigs, as long
250  * as the sig only has a "set" flowbits */
251  if (sm->type == DETECT_FLOWBITS &&
252  (((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) {
253  return 0;
254  }
255  }
256 
258  /* Rule is IP only, but contains negated addresses. */
259  return 2;
260  }
261  if (!(de_ctx->flags & DE_QUIET)) {
262  SCLogDebug("IP-ONLY (%" PRIu32 "): source %s, dest %s", s->id,
263  s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET",
264  s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET");
265  }
266  return 1;
267 }
268 
269 /** \internal
270  * \brief Test is a initialized signature is inspecting protocol detection only
271  * \param de_ctx detection engine ctx
272  * \param s the signature
273  * \retval 1 sig is dp only
274  * \retval 0 sig is not dp only
275  */
276 static int SignatureIsPDOnly(const DetectEngineCtx *de_ctx, const Signature *s)
277 {
278  if (s->alproto != ALPROTO_UNKNOWN)
279  return 0;
280 
281  if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
282  return 0;
283 
284  /* for now assume that all registered buffer types are incompatible */
285  if (SignatureInspectsBuffers(s)) {
286  SCReturnInt(0);
287  }
288 
289  /* TMATCH list can be ignored, it contains TAGs and
290  * tags are compatible to DP-only. */
291 
292  /* match list matches may be compatible to DP only. We follow the same
293  * logic as IP-only so we can use that flag */
294 
296  if (sm == NULL)
297  return 0;
298 
299  int pd = 0;
300  for ( ; sm != NULL; sm = sm->next) {
301  if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) {
302  pd = 1;
303  } else {
304  /* flowbits are supported for dp only sigs, as long
305  * as the sig only has a "set" flowbits */
306  if (sm->type == DETECT_FLOWBITS) {
307  if ((((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) {
308  SCLogDebug("%u: not PD-only: flowbit settings other than 'set'", s->id);
309  return 0;
310  }
311  } else if (sm->type == DETECT_FLOW) {
313  SCLogDebug("%u: not PD-only: flow settings other than toserver/toclient", s->id);
314  return 0;
315  }
316  } else if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) {
317  SCLogDebug("%u: not PD-only: %s not PD/IP-only compat", s->id, sigmatch_table[sm->type].name);
318  return 0;
319  }
320  }
321  }
322 
323  if (pd) {
324  SCLogDebug("PD-ONLY (%" PRIu32 ")", s->id);
325  }
326  return pd;
327 }
328 
329 /**
330  * \internal
331  * \brief Check if the initialized signature is inspecting the packet payload
332  * \param de_ctx detection engine ctx
333  * \param s the signature
334  * \retval 1 sig is inspecting the payload
335  * \retval 0 sig is not inspecting the payload
336  */
337 static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, const Signature *s)
338 {
339 
340  if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) {
341  return 1;
342  }
343  return 0;
344 }
345 
346 /**
347  * \internal
348  * \brief check if a signature is decoder event matching only
349  * \param de_ctx detection engine
350  * \param s the signature to test
351  * \retval 0 not a DEOnly sig
352  * \retval 1 DEOnly sig
353  */
354 static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s)
355 {
356  if (s->alproto != ALPROTO_UNKNOWN) {
357  SCReturnInt(0);
358  }
359 
360  if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
361  {
362  SCReturnInt(0);
363  }
364 
365  /* for now assume that all registered buffer types are incompatible */
366  if (SignatureInspectsBuffers(s)) {
367  SCReturnInt(0);
368  }
369 
370  /* check for conflicting keywords */
372  for ( ;sm != NULL; sm = sm->next) {
374  SCReturnInt(0);
375  }
376 
377  /* need at least one decode event keyword to be considered decode event. */
379  for ( ;sm != NULL; sm = sm->next) {
380  if (sm->type == DETECT_DECODE_EVENT)
381  goto deonly;
382  if (sm->type == DETECT_ENGINE_EVENT)
383  goto deonly;
384  if (sm->type == DETECT_STREAM_EVENT)
385  goto deonly;
386  }
387 
388  SCReturnInt(0);
389 
390 deonly:
391  if (!(de_ctx->flags & DE_QUIET)) {
392  SCLogDebug("DE-ONLY (%" PRIu32 "): source %s, dest %s", s->id,
393  s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET",
394  s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET");
395  }
396 
397  SCReturnInt(1);
398 }
399 
400 #define MASK_TCP_INITDEINIT_FLAGS (TH_SYN|TH_RST|TH_FIN)
401 #define MASK_TCP_UNUSUAL_FLAGS (TH_URG|TH_ECN|TH_CWR)
402 
403 /* Create mask for this packet + it's flow if it has one
404  */
405 void
407  bool app_decoder_events)
408 {
409  if (!(p->flags & PKT_NOPAYLOAD_INSPECTION) && p->payload_len > 0) {
410  SCLogDebug("packet has payload");
411  (*mask) |= SIG_MASK_REQUIRE_PAYLOAD;
412  } else if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
413  SCLogDebug("stream data available");
414  (*mask) |= SIG_MASK_REQUIRE_PAYLOAD;
415  } else {
416  SCLogDebug("packet has no payload");
417  (*mask) |= SIG_MASK_REQUIRE_NO_PAYLOAD;
418  }
419 
420  if (p->events.cnt > 0 || app_decoder_events != 0 || p->app_layer_events != NULL) {
421  SCLogDebug("packet/flow has events set");
423  }
424 
425  if (!(PKT_IS_PSEUDOPKT(p)) && PKT_IS_TCP(p)) {
426  if ((p->tcph->th_flags & MASK_TCP_INITDEINIT_FLAGS) != 0) {
428  }
429  if ((p->tcph->th_flags & MASK_TCP_UNUSUAL_FLAGS) != 0) {
431  }
432  }
433 
434  if (p->flags & PKT_HAS_FLOW) {
435  SCLogDebug("packet has flow");
436  (*mask) |= SIG_MASK_REQUIRE_FLOW;
437  }
438 }
439 
440 static int SignatureCreateMask(Signature *s)
441 {
442  SCEnter();
443 
444  if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) {
446  SCLogDebug("sig requires payload");
447  }
448 
449  SigMatch *sm;
450  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
451  switch(sm->type) {
452  case DETECT_FLOWBITS:
453  {
454  /* figure out what flowbit action */
456  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
457  /* not a mask flag, but still set it here */
459 
460  SCLogDebug("SIG_FLAG_REQUIRE_FLOWVAR set as sig has "
461  "flowbit isset option.");
462  }
463 
464  /* flow is required for any flowbit manipulation */
466  SCLogDebug("sig requires flow to be able to manipulate "
467  "flowbit(s)");
468  break;
469  }
470  case DETECT_FLOWINT:
471  /* flow is required for any flowint manipulation */
473  SCLogDebug("sig requires flow to be able to manipulate "
474  "flowint(s)");
475  break;
476  case DETECT_FLAGS:
477  {
478  DetectFlagsData *fl = (DetectFlagsData *)sm->ctx;
479 
480  if (fl->flags & TH_SYN) {
482  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT");
483  }
484  if (fl->flags & TH_RST) {
486  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT");
487  }
488  if (fl->flags & TH_FIN) {
490  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT");
491  }
492  if (fl->flags & TH_URG) {
494  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL");
495  }
496  if (fl->flags & TH_ECN) {
498  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL");
499  }
500  if (fl->flags & TH_CWR) {
502  SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL");
503  }
504  break;
505  }
506  case DETECT_DSIZE:
507  {
508  DetectU16Data *ds = (DetectU16Data *)sm->ctx;
509  /* LT will include 0, so no payload.
510  * if GT is used in the same rule the
511  * flag will be set anyway. */
512  if (ds->mode == DETECT_UINT_RA || ds->mode == DETECT_UINT_GT ||
513  ds->mode == DETECT_UINT_NE || ds->mode == DETECT_UINT_GTE) {
514 
516  SCLogDebug("sig requires payload");
517 
518  } else if (ds->mode == DETECT_UINT_EQ) {
519  if (ds->arg1 > 0) {
521  SCLogDebug("sig requires payload");
522  } else {
524  SCLogDebug("sig requires no payload");
525  }
526  }
527  break;
528  }
531  break;
532  case DETECT_ENGINE_EVENT:
534  break;
535  }
536  }
537 
538  for (sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; sm != NULL; sm = sm->next) {
539  switch (sm->type) {
540  case DETECT_CONFIG: {
542  if (fd->scope == CONFIG_SCOPE_FLOW) {
544  }
545  break;
546  }
547  }
548  }
549 
552  SCLogDebug("sig requires flow");
553  }
554 
555  if (s->flags & SIG_FLAG_APPLAYER) {
557  SCLogDebug("sig requires flow");
558  }
559 
560  SCLogDebug("mask %02X", s->mask);
561  SCReturnInt(0);
562 }
563 
564 static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx)
565 {
567 }
568 
569 /** \brief Pure-PCRE or bytetest rule */
570 static bool RuleInspectsPayloadHasNoMpm(const Signature *s)
571 {
572  if (s->init_data->mpm_sm == NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
573  return true;
574  return false;
575 }
576 
577 static int RuleGetMpmPatternSize(const Signature *s)
578 {
579  if (s->init_data->mpm_sm == NULL)
580  return -1;
581  int mpm_list = s->init_data->mpm_sm_list;
582  if (mpm_list < 0)
583  return -1;
584  const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx;
585  if (cd == NULL)
586  return -1;
587  return (int)cd->content_len;
588 }
589 
590 static bool RuleMpmIsNegated(const Signature *s)
591 {
592  if (s->flags & SIG_FLAG_MPM_NEG)
593  return true;
594  if (s->init_data->mpm_sm == NULL)
595  return false;
596  int mpm_list = s->init_data->mpm_sm_list;
597  if (mpm_list < 0)
598  return false;
599  const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx;
600  if (cd == NULL)
601  return false;
602  return (cd->flags & DETECT_CONTENT_NEGATED) ? true : false;
603 }
604 
605 static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigGroupHead *sgh,
606  const int add_rules, const int add_mpm_stats)
607 {
608  uint32_t prefilter_cnt = 0;
609  uint32_t mpm_cnt = 0;
610  uint32_t nonmpm_cnt = 0;
611  uint32_t mpm_depth_cnt = 0;
612  uint32_t mpm_endswith_cnt = 0;
613  uint32_t negmpm_cnt = 0;
614  uint32_t any5_cnt = 0;
615  uint32_t payload_no_mpm_cnt = 0;
616  uint32_t syn_cnt = 0;
617 
618  uint32_t mpms_min = 0;
619  uint32_t mpms_max = 0;
620 
621  int max_buffer_type_id = de_ctx->buffer_type_id;
622 
623  struct {
624  uint32_t total;
625  uint32_t cnt;
626  uint32_t min;
627  uint32_t max;
628  } mpm_stats[max_buffer_type_id];
629  memset(mpm_stats, 0x00, sizeof(mpm_stats));
630 
631  uint32_t alstats[ALPROTO_MAX] = {0};
632  uint32_t mpm_sizes[max_buffer_type_id][256];
633  memset(mpm_sizes, 0, sizeof(mpm_sizes));
634  uint32_t alproto_mpm_bufs[ALPROTO_MAX][max_buffer_type_id];
635  memset(alproto_mpm_bufs, 0, sizeof(alproto_mpm_bufs));
636 
637  DEBUG_VALIDATE_BUG_ON(sgh->init == NULL);
638  if (sgh->init == NULL)
639  return NULL;
640 
641  json_t *js = json_object();
642  if (unlikely(js == NULL))
643  return NULL;
644 
645  json_object_set_new(js, "id", json_integer(sgh->id));
646 
647  json_t *js_array = json_array();
648 
649  for (uint32_t x = 0; x < sgh->init->sig_cnt; x++) {
650  const Signature *s = sgh->init->match_array[x];
651  if (s == NULL)
652  continue;
653 
654  int any = 0;
655  if (s->proto.flags & DETECT_PROTO_ANY) {
656  any++;
657  }
658  if (s->flags & SIG_FLAG_DST_ANY) {
659  any++;
660  }
661  if (s->flags & SIG_FLAG_SRC_ANY) {
662  any++;
663  }
664  if (s->flags & SIG_FLAG_DP_ANY) {
665  any++;
666  }
667  if (s->flags & SIG_FLAG_SP_ANY) {
668  any++;
669  }
670  if (any == 5) {
671  any5_cnt++;
672  }
673 
674  prefilter_cnt += (s->init_data->prefilter_sm != 0);
675  if (s->init_data->mpm_sm == NULL) {
676  nonmpm_cnt++;
677 
678  if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) {
679  SCLogDebug("SGH %p Non-MPM inspecting only packets. Rule %u", sgh, s->id);
680  }
681 
682  DetectPort *sp = s->sp;
683  DetectPort *dp = s->dp;
684 
685  if (s->flags & SIG_FLAG_TOSERVER && (dp->port == 0 && dp->port2 == 65535)) {
686  SCLogDebug("SGH %p Non-MPM toserver and to 'any'. Rule %u", sgh, s->id);
687  }
688  if (s->flags & SIG_FLAG_TOCLIENT && (sp->port == 0 && sp->port2 == 65535)) {
689  SCLogDebug("SGH %p Non-MPM toclient and to 'any'. Rule %u", sgh, s->id);
690  }
691 
693  syn_cnt++;
694  }
695 
696  } else {
697  int mpm_list = s->init_data->mpm_sm_list;
698  BUG_ON(mpm_list < 0);
699  const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx;
700  uint32_t size = cd->content_len < 256 ? cd->content_len : 255;
701 
702  mpm_sizes[mpm_list][size]++;
703  alproto_mpm_bufs[s->alproto][mpm_list]++;
704 
705  if (mpm_list == DETECT_SM_LIST_PMATCH) {
706  if (size == 1) {
707  DetectPort *sp = s->sp;
708  DetectPort *dp = s->dp;
709  if (s->flags & SIG_FLAG_TOSERVER) {
710  if (dp->port == 0 && dp->port2 == 65535) {
711  SCLogDebug("SGH %p toserver 1byte fast_pattern to ANY. Rule %u", sgh, s->id);
712  } else {
713  SCLogDebug("SGH %p toserver 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, dp->port, dp->port2, s->id);
714  }
715  }
716  if (s->flags & SIG_FLAG_TOCLIENT) {
717  if (sp->port == 0 && sp->port2 == 65535) {
718  SCLogDebug("SGH %p toclient 1byte fast_pattern to ANY. Rule %u", sgh, s->id);
719  } else {
720  SCLogDebug("SGH %p toclient 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, sp->port, sp->port2, s->id);
721  }
722  }
723  }
724  }
725 
726  uint32_t w = PatternStrength(cd->content, cd->content_len);
727  if (mpms_min == 0)
728  mpms_min = w;
729  if (w < mpms_min)
730  mpms_min = w;
731  if (w > mpms_max)
732  mpms_max = w;
733 
734  BUG_ON(mpm_list >= max_buffer_type_id);
735  mpm_stats[mpm_list].total += w;
736  mpm_stats[mpm_list].cnt++;
737  if (mpm_stats[mpm_list].min == 0 || w < mpm_stats[mpm_list].min)
738  mpm_stats[mpm_list].min = w;
739  if (w > mpm_stats[mpm_list].max)
740  mpm_stats[mpm_list].max = w;
741 
742  mpm_cnt++;
743 
744  if (w < 10) {
745  SCLogDebug("SGH %p Weak MPM Pattern on %s. Rule %u", sgh, DetectListToString(mpm_list), s->id);
746  }
747  if (w < 10 && any == 5) {
748  SCLogDebug("SGH %p Weak MPM Pattern on %s, rule is 5xAny. Rule %u", sgh, DetectListToString(mpm_list), s->id);
749  }
750 
751  if (cd->flags & DETECT_CONTENT_NEGATED) {
752  SCLogDebug("SGH %p MPM Pattern on %s, is negated. Rule %u", sgh, DetectListToString(mpm_list), s->id);
753  negmpm_cnt++;
754  }
755  if (cd->flags & DETECT_CONTENT_ENDS_WITH) {
756  mpm_endswith_cnt++;
757  }
758  if (cd->flags & DETECT_CONTENT_DEPTH) {
759  mpm_depth_cnt++;
760  }
761  }
762 
763  if (RuleInspectsPayloadHasNoMpm(s)) {
764  SCLogDebug("SGH %p No MPM. Payload inspecting. Rule %u", sgh, s->id);
765  payload_no_mpm_cnt++;
766  }
767 
768  alstats[s->alproto]++;
769 
770  if (add_rules) {
771  json_t *js_sig = json_object();
772  if (unlikely(js == NULL))
773  continue;
774  json_object_set_new(js_sig, "sig_id", json_integer(s->id));
775  json_array_append_new(js_array, js_sig);
776  }
777  }
778 
779  json_object_set_new(js, "rules", js_array);
780 
781  json_t *stats = json_object();
782  json_object_set_new(stats, "total", json_integer(sgh->init->sig_cnt));
783 
784  json_t *types = json_object();
785  json_object_set_new(types, "mpm", json_integer(mpm_cnt));
786  json_object_set_new(types, "non_mpm", json_integer(nonmpm_cnt));
787  json_object_set_new(types, "mpm_depth", json_integer(mpm_depth_cnt));
788  json_object_set_new(types, "mpm_endswith", json_integer(mpm_endswith_cnt));
789  json_object_set_new(types, "negated_mpm", json_integer(negmpm_cnt));
790  json_object_set_new(types, "payload_but_no_mpm", json_integer(payload_no_mpm_cnt));
791  json_object_set_new(types, "prefilter", json_integer(prefilter_cnt));
792  json_object_set_new(types, "syn", json_integer(syn_cnt));
793  json_object_set_new(types, "any5", json_integer(any5_cnt));
794  json_object_set_new(stats, "types", types);
795 
796  for (AppProto i = 0; i < ALPROTO_MAX; i++) {
797  if (alstats[i] > 0) {
798  json_t *app = json_object();
799  json_object_set_new(app, "total", json_integer(alstats[i]));
800 
801  for (int y = 0; y < max_buffer_type_id; y++) {
802  if (alproto_mpm_bufs[i][y] == 0)
803  continue;
804 
805  const char *name;
807  name = DetectListToHumanString(y);
808  else
810 
811  json_object_set_new(app, name, json_integer(alproto_mpm_bufs[i][y]));
812  }
813 
814  const char *proto_name = (i == ALPROTO_UNKNOWN) ? "payload" : AppProtoToString(i);
815  json_object_set_new(stats, proto_name, app);
816  }
817  }
818 
819  if (add_mpm_stats) {
820  json_t *mpm_js = json_object();
821 
822  for (int i = 0; i < max_buffer_type_id; i++) {
823  if (mpm_stats[i].cnt > 0) {
824 
825  json_t *mpm_sizes_array = json_array();
826  for (int y = 0; y < 256; y++) {
827  if (mpm_sizes[i][y] == 0)
828  continue;
829 
830  json_t *e = json_object();
831  json_object_set_new(e, "size", json_integer(y));
832  json_object_set_new(e, "count", json_integer(mpm_sizes[i][y]));
833  json_array_append_new(mpm_sizes_array, e);
834  }
835 
836  json_t *buf = json_object();
837  json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt));
838  json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt));
839  json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min));
840  json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max));
841 
842  json_object_set_new(buf, "sizes", mpm_sizes_array);
843 
844  const char *name;
846  name = DetectListToHumanString(i);
847  else
849 
850  json_object_set_new(mpm_js, name, buf);
851  }
852  }
853 
854  json_object_set_new(stats, "mpm", mpm_js);
855  }
856  json_object_set_new(js, "stats", stats);
857 
858  json_object_set_new(js, "score", json_integer(sgh->init->score));
859 
860  return js;
861 }
862 
863 static void RulesDumpGrouping(const DetectEngineCtx *de_ctx,
864  const int add_rules, const int add_mpm_stats)
865 {
866  json_t *js = json_object();
867  if (unlikely(js == NULL))
868  return;
869 
870  int p;
871  for (p = 0; p < 256; p++) {
872  if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
873  const char *name = (p == IPPROTO_TCP) ? "tcp" : "udp";
874 
875  json_t *tcp = json_object();
876 
877  json_t *ts_array = json_array();
878  DetectPort *list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[1].tcp :
879  de_ctx->flow_gh[1].udp;
880  while (list != NULL) {
881  json_t *port = json_object();
882  json_object_set_new(port, "port", json_integer(list->port));
883  json_object_set_new(port, "port2", json_integer(list->port2));
884 
885  json_t *tcp_ts =
886  RulesGroupPrintSghStats(de_ctx, list->sh, add_rules, add_mpm_stats);
887  json_object_set_new(port, "rulegroup", tcp_ts);
888  json_array_append_new(ts_array, port);
889 
890  list = list->next;
891  }
892  json_object_set_new(tcp, "toserver", ts_array);
893 
894  json_t *tc_array = json_array();
895  list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[0].tcp :
896  de_ctx->flow_gh[0].udp;
897  while (list != NULL) {
898  json_t *port = json_object();
899  json_object_set_new(port, "port", json_integer(list->port));
900  json_object_set_new(port, "port2", json_integer(list->port2));
901 
902  json_t *tcp_tc =
903  RulesGroupPrintSghStats(de_ctx, list->sh, add_rules, add_mpm_stats);
904  json_object_set_new(port, "rulegroup", tcp_tc);
905  json_array_append_new(tc_array, port);
906 
907  list = list->next;
908  }
909  json_object_set_new(tcp, "toclient", tc_array);
910 
911  json_object_set_new(js, name, tcp);
912  } else if (p == IPPROTO_ICMP || p == IPPROTO_ICMPV6) {
913  const char *name = (p == IPPROTO_ICMP) ? "icmpv4" : "icmpv6";
914  json_t *o = json_object();
915  if (de_ctx->flow_gh[1].sgh[p]) {
916  json_t *ts = json_object();
917  json_t *group_ts = RulesGroupPrintSghStats(
918  de_ctx, de_ctx->flow_gh[1].sgh[p], add_rules, add_mpm_stats);
919  json_object_set_new(ts, "rulegroup", group_ts);
920  json_object_set_new(o, "toserver", ts);
921  }
922  if (de_ctx->flow_gh[0].sgh[p]) {
923  json_t *tc = json_object();
924  json_t *group_tc = RulesGroupPrintSghStats(
925  de_ctx, de_ctx->flow_gh[0].sgh[p], add_rules, add_mpm_stats);
926  json_object_set_new(tc, "rulegroup", group_tc);
927  json_object_set_new(o, "toclient", tc);
928  }
929  json_object_set_new(js, name, o);
930  }
931  }
932 
933  const char *filename = "rule_group.json";
934  const char *log_dir = ConfigGetLogDirectory();
935  char log_path[PATH_MAX] = "";
936 
937  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
938 
939  FILE *fp = fopen(log_path, "w");
940  if (fp == NULL) {
941  return;
942  }
943 
944  char *js_s = json_dumps(js,
945  JSON_PRESERVE_ORDER|JSON_ESCAPE_SLASH);
946  if (unlikely(js_s == NULL)) {
947  fclose(fp);
948  return;
949  }
950 
951  json_object_clear(js);
952  json_decref(js);
953 
954  fprintf(fp, "%s\n", js_s);
955  free(js_s);
956  fclose(fp);
957  return;
958 }
959 
960 static int RulesGroupByProto(DetectEngineCtx *de_ctx)
961 {
962  Signature *s = de_ctx->sig_list;
963 
964  SigGroupHead *sgh_ts[256] = {NULL};
965  SigGroupHead *sgh_tc[256] = {NULL};
966 
967  for ( ; s != NULL; s = s->next) {
968  if (s->type == SIG_TYPE_IPONLY)
969  continue;
970 
971  int p;
972  for (p = 0; p < 256; p++) {
973  if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
974  continue;
975  }
976  if (!(s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) {
977  continue;
978  }
979 
980  if (s->flags & SIG_FLAG_TOCLIENT) {
981  SigGroupHeadAppendSig(de_ctx, &sgh_tc[p], s);
982  }
983  if (s->flags & SIG_FLAG_TOSERVER) {
984  SigGroupHeadAppendSig(de_ctx, &sgh_ts[p], s);
985  }
986  }
987  }
988 
989  /* lets look at deduplicating this list */
992 
993  uint32_t cnt = 0;
994  uint32_t own = 0;
995  uint32_t ref = 0;
996  int p;
997  for (p = 0; p < 256; p++) {
998  if (p == IPPROTO_TCP || p == IPPROTO_UDP)
999  continue;
1000  if (sgh_ts[p] == NULL)
1001  continue;
1002 
1003  cnt++;
1004 
1005  SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_ts[p]);
1006  if (lookup_sgh == NULL) {
1007  SCLogDebug("proto group %d sgh %p is the original", p, sgh_ts[p]);
1008 
1009  SigGroupHeadSetSigCnt(sgh_ts[p], 0);
1010  SigGroupHeadBuildMatchArray(de_ctx, sgh_ts[p], 0);
1011 
1012  SigGroupHeadHashAdd(de_ctx, sgh_ts[p]);
1013  SigGroupHeadStore(de_ctx, sgh_ts[p]);
1014  own++;
1015  } else {
1016  SCLogDebug("proto group %d sgh %p is a copy", p, sgh_ts[p]);
1017 
1018  SigGroupHeadFree(de_ctx, sgh_ts[p]);
1019  sgh_ts[p] = lookup_sgh;
1020  ref++;
1021  }
1022  }
1023  SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies",
1024  "toserver", cnt, own, ref);
1025 
1026  cnt = 0;
1027  own = 0;
1028  ref = 0;
1029  for (p = 0; p < 256; p++) {
1030  if (p == IPPROTO_TCP || p == IPPROTO_UDP)
1031  continue;
1032  if (sgh_tc[p] == NULL)
1033  continue;
1034 
1035  cnt++;
1036 
1037  SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_tc[p]);
1038  if (lookup_sgh == NULL) {
1039  SCLogDebug("proto group %d sgh %p is the original", p, sgh_tc[p]);
1040 
1041  SigGroupHeadSetSigCnt(sgh_tc[p], 0);
1042  SigGroupHeadBuildMatchArray(de_ctx, sgh_tc[p], 0);
1043 
1044  SigGroupHeadHashAdd(de_ctx, sgh_tc[p]);
1045  SigGroupHeadStore(de_ctx, sgh_tc[p]);
1046  own++;
1047 
1048  } else {
1049  SCLogDebug("proto group %d sgh %p is a copy", p, sgh_tc[p]);
1050 
1051  SigGroupHeadFree(de_ctx, sgh_tc[p]);
1052  sgh_tc[p] = lookup_sgh;
1053  ref++;
1054  }
1055  }
1056  SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies",
1057  "toclient", cnt, own, ref);
1058 
1059  for (p = 0; p < 256; p++) {
1060  if (p == IPPROTO_TCP || p == IPPROTO_UDP)
1061  continue;
1062 
1063  de_ctx->flow_gh[0].sgh[p] = sgh_tc[p];
1064  de_ctx->flow_gh[1].sgh[p] = sgh_ts[p];
1065  }
1066 
1067  return 0;
1068 }
1069 
1070 static int PortIsWhitelisted(const DetectEngineCtx *de_ctx,
1071  const DetectPort *a, int ipproto)
1072 {
1074  if (ipproto == IPPROTO_UDP)
1075  w = de_ctx->udp_whitelist;
1076 
1077  while (w) {
1078  /* Make sure the whitelist port falls in the port range of a */
1079  DEBUG_VALIDATE_BUG_ON(a->port > a->port2);
1080  if (a->port == w->port && w->port2 == a->port2) {
1081  return 1;
1082  }
1083  w = w->next;
1084  }
1085 
1086  return 0;
1087 }
1088 
1089 static int RuleSetWhitelist(Signature *s)
1090 {
1091  DetectPort *p = NULL;
1092  if (s->flags & SIG_FLAG_TOSERVER)
1093  p = s->dp;
1094  else if (s->flags & SIG_FLAG_TOCLIENT)
1095  p = s->sp;
1096  else
1097  return 0;
1098 
1099  /* for sigs that don't use 'any' as port, see if we want to
1100  * whitelist poor sigs */
1101  int wl = 0;
1102  if (!(p->port == 0 && p->port2 == 65535)) {
1103  /* pure pcre, bytetest, etc rules */
1104  if (RuleInspectsPayloadHasNoMpm(s)) {
1105  SCLogDebug("Rule %u MPM has 1 byte fast_pattern. Whitelisting SGH's.", s->id);
1107 
1108  } else if (RuleMpmIsNegated(s)) {
1109  SCLogDebug("Rule %u MPM is negated. Whitelisting SGH's.", s->id);
1111 
1112  /* one byte pattern in packet/stream payloads */
1113  } else if (s->init_data->mpm_sm != NULL &&
1115  RuleGetMpmPatternSize(s) == 1) {
1116  SCLogDebug("Rule %u No MPM. Payload inspecting. Whitelisting SGH's.", s->id);
1118 
1120  SCLogDebug("Rule %u Needs SYN, so inspected often. Whitelisting SGH's.", s->id);
1122  }
1123  }
1124 
1125  s->init_data->score = wl;
1126  return wl;
1127 }
1128 
1129 static int SortCompare(const void *a, const void *b)
1130 {
1131  const DetectPort *pa = *(const DetectPort **)a;
1132  const DetectPort *pb = *(const DetectPort **)b;
1133 
1134  if (pa->sh->init->score < pb->sh->init->score) {
1135  return 1;
1136  } else if (pa->sh->init->score > pb->sh->init->score) {
1137  return -1;
1138  }
1139 
1140  if (pa->sh->init->sig_cnt < pb->sh->init->sig_cnt) {
1141  return 1;
1142  } else if (pa->sh->init->sig_cnt > pb->sh->init->sig_cnt) {
1143  return -1;
1144  }
1145 
1146  /* Hack to make the qsort output deterministic across platforms.
1147  * This had to be done because the order of equal elements sorted
1148  * by qsort is undeterministic and showed different output on BSD,
1149  * MacOS and Windows. Sorting based on id makes it deterministic. */
1150  if (pa->sh->id < pb->sh->id)
1151  return -1;
1152 
1153  return 1;
1154 }
1155 
1156 static inline void SortGroupList(
1157  uint32_t *groups, DetectPort **list, int (*CompareFunc)(const void *, const void *))
1158 {
1159  int cnt = 0;
1160  for (DetectPort *x = *list; x != NULL; x = x->next) {
1161  DEBUG_VALIDATE_BUG_ON(x->port > x->port2);
1162  cnt++;
1163  }
1164  if (cnt <= 1)
1165  return;
1166 
1167  /* build temporary array to sort with qsort */
1168  DetectPort **array = (DetectPort **)SCCalloc(cnt, sizeof(DetectPort *));
1169  if (array == NULL)
1170  return;
1171 
1172  int idx = 0;
1173  for (DetectPort *x = *list; x != NULL;) {
1174  /* assign a temporary id to resolve otherwise equal groups */
1175  x->sh->id = idx + 1;
1176  SigGroupHeadSetSigCnt(x->sh, 0);
1177  DetectPort *next = x->next;
1178  x->next = x->prev = x->last = NULL;
1179  DEBUG_VALIDATE_BUG_ON(x->port > x->port2);
1180  array[idx++] = x;
1181  x = next;
1182  }
1183  DEBUG_VALIDATE_BUG_ON(cnt != idx);
1184 
1185  qsort(array, idx, sizeof(DetectPort *), SortCompare);
1186 
1187  /* rebuild the list based on the qsort-ed array */
1188  DetectPort *new_list = NULL, *tail = NULL;
1189  for (int i = 0; i < idx; i++) {
1190  DetectPort *p = array[i];
1191  /* unset temporary group id */
1192  p->sh->id = 0;
1193 
1194  if (new_list == NULL) {
1195  new_list = p;
1196  }
1197  if (tail != NULL) {
1198  tail->next = p;
1199  }
1200  p->prev = tail;
1201  tail = p;
1202  }
1203 
1204  *list = new_list;
1205  *groups = idx;
1206 
1207 #if DEBUG
1208  int dbgcnt = 0;
1209  SCLogDebug("SORTED LIST:");
1210  for (DetectPort *tmp = *list; tmp != NULL; tmp = tmp->next) {
1211  SCLogDebug("item:= [%u:%u]; score: %d; sig_cnt: %d", tmp->port, tmp->port2,
1212  tmp->sh->init->score, tmp->sh->init->sig_cnt);
1213  dbgcnt++;
1214  BUG_ON(dbgcnt > cnt);
1215  }
1216 #endif
1217  SCFree(array);
1218 }
1219 /** \internal
1220  * \brief Create a list of DetectPort objects sorted based on CompareFunc's
1221  * logic.
1222  *
1223  * List can limit the number of groups. In this case an extra "join" group
1224  * is created that contains the sigs belonging to that. It's *appended* to
1225  * the list, meaning that if the list is walked linearly it's found last.
1226  * The joingr is meant to be a catch all.
1227  *
1228  */
1229 static int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list,
1230  DetectPort **newhead, uint32_t unique_groups,
1231  int (*CompareFunc)(const void *, const void *))
1232 {
1233  DetectPort *tmplist = NULL, *joingr = NULL;
1234  uint32_t groups = 0;
1235 
1236  /* insert the ports into the tmplist, where it will
1237  * be sorted descending on 'cnt' and on whether a group
1238  * is whitelisted. */
1239  tmplist = port_list;
1240  SortGroupList(&groups, &tmplist, SortCompare);
1241  uint32_t left = unique_groups;
1242  if (left == 0)
1243  left = groups;
1244 
1245  /* create another list: take the port groups from above
1246  * and add them to the 2nd list until we have met our
1247  * count. The rest is added to the 'join' group. */
1248  DetectPort *tmplist2 = NULL, *tmplist2_tail = NULL;
1249  DetectPort *gr, *next_gr;
1250  for (gr = tmplist; gr != NULL;) {
1251  next_gr = gr->next;
1252 
1253  SCLogDebug("temp list gr %p %u:%u", gr, gr->port, gr->port2);
1254  DetectPortPrint(gr);
1255 
1256  /* if we've set up all the unique groups, add the rest to the
1257  * catch-all joingr */
1258  if (left == 0) {
1259  if (joingr == NULL) {
1260  DetectPortParse(de_ctx, &joingr, "0:65535");
1261  if (joingr == NULL) {
1262  goto error;
1263  }
1264  SCLogDebug("joingr => %u-%u", joingr->port, joingr->port2);
1265  joingr->next = NULL;
1266  }
1267  SigGroupHeadCopySigs(de_ctx, gr->sh, &joingr->sh);
1268 
1269  /* when a group's sigs are added to the joingr, we can free it */
1270  gr->next = NULL;
1271  DetectPortFree(de_ctx, gr);
1272  /* append */
1273  } else {
1274  gr->next = NULL;
1275 
1276  if (tmplist2 == NULL) {
1277  tmplist2 = gr;
1278  tmplist2_tail = gr;
1279  } else {
1280  tmplist2_tail->next = gr;
1281  tmplist2_tail = gr;
1282  }
1283  }
1284 
1285  if (left > 0)
1286  left--;
1287 
1288  gr = next_gr;
1289  }
1290 
1291  /* if present, append the joingr that covers the rest */
1292  if (joingr != NULL) {
1293  SCLogDebug("appending joingr %p %u:%u", joingr, joingr->port, joingr->port2);
1294 
1295  if (tmplist2 == NULL) {
1296  tmplist2 = joingr;
1297  // tmplist2_tail = joingr;
1298  } else {
1299  tmplist2_tail->next = joingr;
1300  // tmplist2_tail = joingr;
1301  }
1302  } else {
1303  SCLogDebug("no joingr");
1304  }
1305 
1306  /* pass back our new list to the caller */
1307  *newhead = tmplist2;
1308  DetectPortPrintList(*newhead);
1309 
1310  return 0;
1311 error:
1312  return -1;
1313 }
1314 
1315 #define UNDEFINED_PORT 0
1316 #define RANGE_PORT 1
1317 #define SINGLE_PORT 2
1319 typedef struct UniquePortPoint_ {
1320  uint16_t port; /* value of the port */
1321  bool single; /* is the port single or part of a range */
1323 
1324 /**
1325  * \brief Function to set unique port points. Consider all the ports
1326  * flattened out on one line, set the points that correspond
1327  * to a valid port. Also store whether the port point stored
1328  * was a single port or part of a range.
1329  *
1330  * \param p Port object to be set
1331  * \param unique_list List of unique port points to be updated
1332  * \param size_list Current size of the list
1333  *
1334  * \return Updated size of the list
1335  */
1336 static inline uint32_t SetUniquePortPoints(
1337  const DetectPort *p, uint8_t *unique_list, uint32_t size_list)
1338 {
1339  if (unique_list[p->port] == UNDEFINED_PORT) {
1340  if (p->port == p->port2) {
1341  unique_list[p->port] = SINGLE_PORT;
1342  } else {
1343  unique_list[p->port] = RANGE_PORT;
1344  }
1345  size_list++;
1346  } else if (((unique_list[p->port] == SINGLE_PORT) && (p->port != p->port2)) ||
1347  ((unique_list[p->port] == RANGE_PORT) && (p->port == p->port2))) {
1348  if ((p->port != UINT16_MAX) && (unique_list[p->port + 1] == UNDEFINED_PORT)) {
1349  unique_list[p->port + 1] = RANGE_PORT;
1350  size_list++;
1351  }
1352  }
1353 
1354  /* Treat right boundary as single point to avoid creating unneeded
1355  * ranges later on */
1356  if (unique_list[p->port2] == UNDEFINED_PORT) {
1357  size_list++;
1358  }
1359  unique_list[p->port2] = SINGLE_PORT;
1360  return size_list;
1361 }
1362 
1363 /**
1364  * \brief Function to set the *final* unique port points and save them
1365  * for later use. The points are already sorted because of the way
1366  * they have been retrieved and saved earlier for use at this point.
1367  *
1368  * \param unique_list List of the unique port points to be used
1369  * \param size_unique_arr Number of unique port points
1370  * \param final_arr List of the final unique port points to be created
1371  */
1372 static inline void SetFinalUniquePortPoints(
1373  const uint8_t *unique_list, const uint32_t size_unique_arr, UniquePortPoint *final_arr)
1374 {
1375  for (uint32_t i = 0, j = 0; i < (UINT16_MAX + 1); i++) {
1376  DEBUG_VALIDATE_BUG_ON(j > size_unique_arr);
1377  if (unique_list[i] == RANGE_PORT) {
1378  final_arr[j].port = (uint16_t)i;
1379  final_arr[j++].single = false;
1380  } else if (unique_list[i] == SINGLE_PORT) {
1381  final_arr[j].port = (uint16_t)i;
1382  final_arr[j++].single = true;
1383  }
1384  }
1385 }
1386 
1387 /**
1388  * \brief Function to create the list of ports with the smallest ranges
1389  * by resolving overlaps and end point conditions. These contain the
1390  * correct SGHs as well after going over the interval tree to find
1391  * any range overlaps.
1392  *
1393  * \param de_ctx Detection Engine Context
1394  * \param unique_list Final list of unique port points
1395  * \param size_list Size of the unique_list
1396  * \param it Pointer to the interval tree
1397  * \param list Pointer to the list where final ports will be stored
1398  *
1399  * \return 0 on success, -1 otherwise
1400  */
1401 static inline int CreatePortList(DetectEngineCtx *de_ctx, const uint8_t *unique_list,
1402  const uint32_t size_list, SCPortIntervalTree *it, DetectPort **list)
1403 {
1404  /* Only do the operations if there is at least one unique port */
1405  if (size_list == 0)
1406  return 0;
1407  UniquePortPoint *final_unique_points =
1408  (UniquePortPoint *)SCCalloc(size_list, sizeof(UniquePortPoint));
1409  if (final_unique_points == NULL)
1410  return -1;
1411  SetFinalUniquePortPoints(unique_list, size_list, final_unique_points);
1412  /* Handle edge case when there is just one unique port */
1413  if (size_list == 1) {
1415  de_ctx, final_unique_points[0].port, final_unique_points[0].port, &it->tree, list);
1416  } else {
1417  UniquePortPoint *p1 = &final_unique_points[0];
1418  UniquePortPoint *p2 = &final_unique_points[1];
1419  uint16_t port = p1 ? p1->port : 0; // just for cppcheck
1420  uint16_t port2 = p2->port;
1421  for (uint32_t i = 1; i < size_list; i++) {
1422  DEBUG_VALIDATE_BUG_ON(port > port2);
1423  if ((p1 && p1->single) && p2->single) {
1424  SCPortIntervalFindOverlappingRanges(de_ctx, port, port, &it->tree, list);
1425  SCPortIntervalFindOverlappingRanges(de_ctx, port2, port2, &it->tree, list);
1426  port = port2 + 1;
1427  } else if (p1 && p1->single) {
1428  SCPortIntervalFindOverlappingRanges(de_ctx, port, port, &it->tree, list);
1429  if ((port2 > port + 1)) {
1431  de_ctx, port + 1, port2 - 1, &it->tree, list);
1432  port = port2;
1433  } else {
1434  port = port + 1;
1435  }
1436  } else if (p2->single) {
1437  /* If port2 is boundary and less or equal to port + 1, create a range
1438  * keeping the boundary away as it is single port */
1439  if ((port2 >= port + 1)) {
1440  SCPortIntervalFindOverlappingRanges(de_ctx, port, port2 - 1, &it->tree, list);
1441  }
1442  /* Deal with port2 as it is a single port */
1443  SCPortIntervalFindOverlappingRanges(de_ctx, port2, port2, &it->tree, list);
1444  port = port2 + 1;
1445  } else {
1446  if ((port2 > port + 1)) {
1447  SCPortIntervalFindOverlappingRanges(de_ctx, port, port2 - 1, &it->tree, list);
1448  port = port2;
1449  } else {
1450  SCPortIntervalFindOverlappingRanges(de_ctx, port, port2, &it->tree, list);
1451  port = port2 + 1;
1452  }
1453  }
1454  /* if the current port matches the p2->port, assign it to p1 so that
1455  * there is a UniquePortPoint object to check other info like whether
1456  * the port with this value is single */
1457  if (port == p2->port) {
1458  p1 = p2;
1459  } else {
1460  p1 = NULL;
1461  }
1462  if (i + 1 < size_list) {
1463  p2 = &final_unique_points[i + 1];
1464  port2 = p2->port;
1465  }
1466  }
1467  }
1468  /* final_unique_points array is no longer needed */
1469  SCFree(final_unique_points);
1470  return 0;
1471 }
1472 
1473 static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, uint32_t direction)
1474 {
1475  /* step 1: create a hash of 'DetectPort' objects based on all the
1476  * rules. Each object will have a SGH with the sigs added
1477  * that belong to the SGH. */
1479 
1480  uint32_t size_unique_port_arr = 0;
1481  const Signature *s = de_ctx->sig_list;
1482  DetectPort *list = NULL;
1483 
1484  uint8_t *unique_port_points = (uint8_t *)SCCalloc(UINT16_MAX + 1, sizeof(uint8_t));
1485  if (unique_port_points == NULL)
1486  return NULL;
1487 
1488  while (s) {
1489  /* IP Only rules are handled separately */
1490  if (s->type == SIG_TYPE_IPONLY)
1491  goto next;
1492  /* Protocol does not match the Signature protocol and is neither IP or pkthdr */
1493  if (!(s->proto.proto[ipproto / 8] & (1<<(ipproto % 8)) || (s->proto.flags & DETECT_PROTO_ANY)))
1494  goto next;
1495  /* Direction does not match Signature direction */
1496  if (direction == SIG_FLAG_TOSERVER) {
1497  if (!(s->flags & SIG_FLAG_TOSERVER))
1498  goto next;
1499  } else if (direction == SIG_FLAG_TOCLIENT) {
1500  if (!(s->flags & SIG_FLAG_TOCLIENT))
1501  goto next;
1502  }
1503 
1504  /* see if we want to exclude directionless sigs that really care only for
1505  * to_server syn scans/floods */
1509  (!(s->dp->port == 0 && s->dp->port2 == 65535))) {
1510  SCLogWarning("rule %u: SYN-only to port(s) %u:%u "
1511  "w/o direction specified, disabling for toclient direction",
1512  s->id, s->dp->port, s->dp->port2);
1513  goto next;
1514  }
1515 
1516  DetectPort *p = NULL;
1517  if (direction == SIG_FLAG_TOSERVER)
1518  p = s->dp;
1519  else if (direction == SIG_FLAG_TOCLIENT)
1520  p = s->sp;
1521  else
1522  BUG_ON(1);
1523 
1524  int wl = s->init_data->score;
1525  while (p) {
1526  int pwl = PortIsWhitelisted(de_ctx, p, ipproto) ? DETECT_PGSCORE_RULE_PORT_WHITELISTED
1527  : 0;
1528  pwl = MAX(wl,pwl);
1529 
1530  DetectPort *lookup = DetectPortHashLookup(de_ctx, p);
1531  if (lookup) {
1532  SigGroupHeadAppendSig(de_ctx, &lookup->sh, s);
1533  lookup->sh->init->score = MAX(lookup->sh->init->score, pwl);
1534  } else {
1536  BUG_ON(tmp2 == NULL);
1537  SigGroupHeadAppendSig(de_ctx, &tmp2->sh, s);
1538  tmp2->sh->init->score = pwl;
1539  DetectPortHashAdd(de_ctx, tmp2);
1540  size_unique_port_arr =
1541  SetUniquePortPoints(tmp2, unique_port_points, size_unique_port_arr);
1542  }
1543 
1544  p = p->next;
1545  }
1546  next:
1547  s = s->next;
1548  }
1549 
1550  /* step 2: create a list of the smallest port ranges with
1551  * appropriate SGHs */
1552 
1553  /* Create an interval tree of all the given ports to make the search
1554  * for overlaps later on easier */
1556  if (it == NULL)
1557  goto error;
1558 
1559  HashListTableBucket *htb = NULL;
1560  for (htb = HashListTableGetListHead(de_ctx->dport_hash_table); htb != NULL;
1561  htb = HashListTableGetListNext(htb)) {
1563  if (SCPortIntervalInsert(de_ctx, it, p) != SC_OK) {
1564  SCLogDebug("Port was not inserted in the tree");
1565  goto error;
1566  }
1567  }
1568 
1569  /* Create a sorted list of ports in ascending order after resolving overlaps
1570  * and corresponding SGHs */
1571  if (CreatePortList(de_ctx, unique_port_points, size_unique_port_arr, it, &list) < 0)
1572  goto error;
1573 
1574  /* unique_port_points array is no longer needed */
1575  SCFree(unique_port_points);
1576 
1577  /* Port hashes are no longer needed */
1579 
1580  SCLogDebug("rules analyzed");
1581 
1582  /* step 3: group the list and shrink it if necessary */
1583  DetectPort *newlist = NULL;
1584  uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups :
1586  CreateGroupedPortList(de_ctx, list, &newlist, groupmax, SortCompare);
1587  list = newlist;
1588 
1589  /* step 4: deduplicate the SGH's */
1592 
1593  uint32_t cnt = 0;
1594  uint32_t own = 0;
1595  uint32_t ref = 0;
1596  DetectPort *iter;
1597  for (iter = list ; iter != NULL; iter = iter->next) {
1598  BUG_ON (iter->sh == NULL);
1599  DEBUG_VALIDATE_BUG_ON(own + ref != cnt);
1600  cnt++;
1601 
1602  SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, iter->sh);
1603  if (lookup_sgh == NULL) {
1604  SCLogDebug("port group %p sgh %p is the original", iter, iter->sh);
1605 
1606  SigGroupHeadSetSigCnt(iter->sh, 0);
1608  SigGroupHeadSetProtoAndDirection(iter->sh, ipproto, direction);
1609  SigGroupHeadHashAdd(de_ctx, iter->sh);
1610  SigGroupHeadStore(de_ctx, iter->sh);
1611  iter->flags |= PORT_SIGGROUPHEAD_COPY;
1612  own++;
1613  } else {
1614  SCLogDebug("port group %p sgh %p is a copy", iter, iter->sh);
1615 
1616  SigGroupHeadFree(de_ctx, iter->sh);
1617  iter->sh = lookup_sgh;
1618  iter->flags |= PORT_SIGGROUPHEAD_COPY;
1619  ref++;
1620  }
1621  }
1622 #if 0
1623  for (iter = list ; iter != NULL; iter = iter->next) {
1624  SCLogInfo("PORT %u-%u %p (sgh=%s, whitelisted=%s/%d)",
1625  iter->port, iter->port2, iter->sh,
1626  iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own",
1627  iter->sh->init->whitelist ? "true" : "false",
1628  iter->sh->init->whitelist);
1629  }
1630 #endif
1631  SCLogPerf("%s %s: %u port groups, %u unique SGH's, %u copies",
1632  ipproto == 6 ? "TCP" : "UDP",
1633  direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1634  cnt, own, ref);
1636  return list;
1637 
1638 error:
1639  if (unique_port_points != NULL)
1640  SCFree(unique_port_points);
1641  if (it != NULL)
1643 
1644  return NULL;
1645 }
1646 
1648 {
1649  BUG_ON(s->type != SIG_TYPE_NOT_SET);
1650  int iponly = 0;
1651 
1652  /* see if the sig is dp only */
1653  if (SignatureIsPDOnly(de_ctx, s) == 1) {
1654  s->type = SIG_TYPE_PDONLY;
1655 
1656  /* see if the sig is ip only */
1657  } else if ((iponly = SignatureIsIPOnly(de_ctx, s)) > 0) {
1658  if (iponly == 1) {
1659  s->type = SIG_TYPE_IPONLY;
1660  } else if (iponly == 2) {
1662  }
1663  } else if (SignatureIsDEOnly(de_ctx, s) == 1) {
1664  s->type = SIG_TYPE_DEONLY;
1665 
1666  } else {
1667  const bool has_match = s->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL;
1668  const bool has_pmatch = s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL;
1669  bool has_buffer_frame_engine = false;
1670  bool has_buffer_packet_engine = false;
1671  bool has_buffer_app_engine = false;
1672 
1673  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1674  const uint32_t id = s->init_data->buffers[x].id;
1675 
1677  has_buffer_packet_engine = true;
1679  has_buffer_frame_engine = true;
1680  } else {
1681  has_buffer_app_engine = true;
1682  }
1683  }
1684 
1685  if (has_buffer_packet_engine) {
1686  s->type = SIG_TYPE_PKT;
1687  } else if (has_buffer_frame_engine || has_buffer_app_engine) {
1688  s->type = SIG_TYPE_APP_TX;
1689  } else if (has_pmatch) {
1692  s->type = SIG_TYPE_PKT;
1693  } else if ((s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM)) ==
1695  s->type = SIG_TYPE_STREAM;
1696  } else {
1698  }
1699  } else if (has_match) {
1700  s->type = SIG_TYPE_PKT;
1701 
1702  /* app-layer but no inspect engines */
1703  } else if (s->flags & SIG_FLAG_APPLAYER) {
1704  s->type = SIG_TYPE_APPLAYER;
1705  } else {
1706  s->type = SIG_TYPE_PKT;
1707  }
1708  }
1709 }
1710 
1711 extern int g_skip_prefilter;
1712 /**
1713  * \brief Preprocess signature, classify ip-only, etc, build sig array
1714  *
1715  * \param de_ctx Pointer to the Detection Engine Context
1716  *
1717  * \retval 0 on success
1718  * \retval -1 on failure
1719  */
1721 {
1722  uint32_t cnt_iponly = 0;
1723  uint32_t cnt_payload = 0;
1724  uint32_t cnt_applayer = 0;
1725  uint32_t cnt_deonly = 0;
1726 
1727  if (!(de_ctx->flags & DE_QUIET)) {
1728  SCLogDebug("building signature grouping structure, stage 1: "
1729  "preprocessing rules...");
1730  }
1731 
1734  if (de_ctx->sig_array == NULL)
1735  goto error;
1736 
1737  /* now for every rule add the source group */
1738  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
1739  de_ctx->sig_array[s->num] = s;
1740 
1741  SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", s->id, s->num, s, de_ctx->sig_array[s->num]);
1742 
1743  if (s->type == SIG_TYPE_PDONLY) {
1744  SCLogDebug("Signature %"PRIu32" is considered \"PD only\"", s->id);
1745  } else if (s->type == SIG_TYPE_IPONLY) {
1746  SCLogDebug("Signature %"PRIu32" is considered \"IP only\"", s->id);
1747  cnt_iponly++;
1748  } else if (SignatureIsInspectingPayload(de_ctx, s) == 1) {
1749  SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", s->id);
1750  cnt_payload++;
1751  } else if (s->type == SIG_TYPE_DEONLY) {
1752  SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", s->id);
1753  cnt_deonly++;
1754  } else if (s->flags & SIG_FLAG_APPLAYER) {
1755  SCLogDebug("Signature %"PRIu32" is considered \"Applayer inspecting\"", s->id);
1756  cnt_applayer++;
1757  }
1758 
1759 #ifdef DEBUG
1760  if (SCLogDebugEnabled()) {
1761  uint16_t colen = 0;
1762  char copresent = 0;
1763  SigMatch *sm;
1764  DetectContentData *co;
1765  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
1766  if (sm->type != DETECT_CONTENT)
1767  continue;
1768 
1769  copresent = 1;
1770  co = (DetectContentData *)sm->ctx;
1771  if (co->content_len > colen)
1772  colen = co->content_len;
1773  }
1774 
1775  if (copresent && colen == 1) {
1776  SCLogDebug("signature %8u content maxlen 1", s->id);
1777  for (int proto = 0; proto < 256; proto++) {
1778  if (s->proto.proto[(proto/8)] & (1<<(proto%8)))
1779  SCLogDebug("=> proto %" PRId32 "", proto);
1780  }
1781  }
1782  }
1783 #endif /* DEBUG */
1784 
1785  if (RuleMpmIsNegated(s)) {
1786  s->flags |= SIG_FLAG_MPM_NEG;
1787  }
1788 
1789  SignatureCreateMask(s);
1792 
1793  RuleSetWhitelist(s);
1794 
1795  /* if keyword engines are enabled in the config, handle them here */
1797  !(s->flags & SIG_FLAG_PREFILTER)) {
1798  int prefilter_list = DETECT_TBLSIZE;
1799 
1800  // TODO buffers?
1801 
1802  /* get the keyword supporting prefilter with the lowest type */
1803  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
1804  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
1805  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
1806  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
1807  prefilter_list = MIN(prefilter_list, sm->type);
1808  }
1809  }
1810  }
1811  }
1812 
1813  /* apply that keyword as prefilter */
1814  if (prefilter_list != DETECT_TBLSIZE) {
1815  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
1816  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
1817  if (sm->type == prefilter_list) {
1818  s->init_data->prefilter_sm = sm;
1819  s->flags |= SIG_FLAG_PREFILTER;
1820  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id, sigmatch_table[sm->type].name);
1821  break;
1822  }
1823  }
1824  }
1825  }
1826  }
1827 
1828  /* run buffer type callbacks if any */
1829  for (int x = 0; x < DETECT_SM_LIST_MAX; x++) {
1830  if (s->init_data->smlists[x])
1832  }
1833  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
1835  }
1836 
1837  de_ctx->sig_cnt++;
1838  }
1839 
1840  if (!(de_ctx->flags & DE_QUIET)) {
1841  if (strlen(de_ctx->config_prefix) > 0)
1842  SCLogInfo("tenant id %d: %" PRIu32 " signatures processed. %" PRIu32 " are IP-only "
1843  "rules, %" PRIu32 " are inspecting packet payload, %" PRIu32
1844  " inspect application layer, %" PRIu32 " are decoder event only",
1845  de_ctx->tenant_id, de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer,
1846  cnt_deonly);
1847  else
1848  SCLogInfo("%" PRIu32 " signatures processed. %" PRIu32 " are IP-only "
1849  "rules, %" PRIu32 " are inspecting packet payload, %" PRIu32
1850  " inspect application layer, %" PRIu32 " are decoder event only",
1851  de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, cnt_deonly);
1852 
1853  SCLogConfig("building signature grouping structure, stage 1: "
1854  "preprocessing rules... complete");
1855  }
1856 
1857  if (DetectFlowbitsAnalyze(de_ctx) != 0)
1858  goto error;
1859 
1860  return 0;
1861 
1862 error:
1863  return -1;
1864 }
1865 
1866 /**
1867  * \internal
1868  * \brief add a decoder event signature to the detection engine ctx
1869  */
1870 static void DetectEngineAddDecoderEventSig(DetectEngineCtx *de_ctx, Signature *s)
1871 {
1872  SCLogDebug("adding signature %"PRIu32" to the decoder event sgh", s->id);
1874 }
1875 
1876 /**
1877  * \brief Fill the global src group head, with the sigs included
1878  *
1879  * \param de_ctx Pointer to the Detection Engine Context whose Signatures have
1880  * to be processed
1881  *
1882  * \retval 0 On success
1883  * \retval -1 On failure
1884  */
1886 {
1887  SCLogDebug("building signature grouping structure, stage 2: "
1888  "building source address lists...");
1889 
1891 
1892  de_ctx->flow_gh[1].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOSERVER);
1893  de_ctx->flow_gh[0].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOCLIENT);
1894  de_ctx->flow_gh[1].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOSERVER);
1895  de_ctx->flow_gh[0].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOCLIENT);
1896 
1897  /* Setup the other IP Protocols (so not TCP/UDP) */
1898  RulesGroupByProto(de_ctx);
1899 
1900  /* now for every rule add the source group to our temp lists */
1901  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
1902  SCLogDebug("s->id %"PRIu32, s->id);
1903  if (s->type == SIG_TYPE_IPONLY) {
1905  } else if (s->type == SIG_TYPE_DEONLY) {
1906  DetectEngineAddDecoderEventSig(de_ctx, s);
1907  }
1908  }
1909 
1912  return 0;
1913 }
1914 
1915 static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx)
1916 {
1917  if (de_ctx->decoder_event_sgh == NULL)
1918  return;
1919 
1920  uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx);
1923 }
1924 
1926 {
1927  /* prepare the decoder event sgh */
1928  DetectEngineBuildDecoderEventSgh(de_ctx);
1929  return 0;
1930 }
1931 
1933 {
1934  BUG_ON(de_ctx == NULL);
1935 
1936  SCLogDebug("cleaning up signature grouping structure...");
1937 
1940  de_ctx->decoder_event_sgh = NULL;
1941 
1942  for (int f = 0; f < FLOW_STATES; f++) {
1943  for (int p = 0; p < 256; p++) {
1944  de_ctx->flow_gh[f].sgh[p] = NULL;
1945  }
1946 
1947  /* free lookup lists */
1949  de_ctx->flow_gh[f].tcp = NULL;
1951  de_ctx->flow_gh[f].udp = NULL;
1952  }
1953 
1954  for (uint32_t idx = 0; idx < de_ctx->sgh_array_cnt; idx++) {
1955  SigGroupHead *sgh = de_ctx->sgh_array[idx];
1956  if (sgh == NULL)
1957  continue;
1958 
1959  SCLogDebug("sgh %p", sgh);
1960  SigGroupHeadFree(de_ctx, sgh);
1961  }
1963  de_ctx->sgh_array = NULL;
1964  de_ctx->sgh_array_cnt = 0;
1965  de_ctx->sgh_array_size = 0;
1966 
1968 
1969  SCLogDebug("cleaning up signature grouping structure... complete");
1970  return 0;
1971 }
1972 
1973 #if 0
1974 static void DbgPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1975 {
1976  if (sgh == NULL) {
1977  printf("\n");
1978  return;
1979  }
1980 
1981  uint32_t sig;
1982  for (sig = 0; sig < sgh->sig_cnt; sig++) {
1983  printf("%" PRIu32 " ", sgh->match_array[sig]->id);
1984  }
1985  printf("\n");
1986 }
1987 
1988 static void DbgPrintSigs2(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1989 {
1990  if (sgh == NULL || sgh->init == NULL) {
1991  printf("\n");
1992  return;
1993  }
1994 
1995  uint32_t sig;
1996  for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) {
1997  if (sgh->init->sig_array[(sig/8)] & (1<<(sig%8))) {
1998  printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id);
1999  }
2000  }
2001  printf("\n");
2002 }
2003 #endif
2004 
2005 /** \brief finalize preparing sgh's */
2007 {
2008  SCEnter();
2009 
2010  //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt);
2011 
2012  uint32_t cnt = 0;
2013  for (uint32_t idx = 0; idx < de_ctx->sgh_array_cnt; idx++) {
2014  SigGroupHead *sgh = de_ctx->sgh_array[idx];
2015  if (sgh == NULL)
2016  continue;
2017 
2018  SCLogDebug("sgh %p", sgh);
2019 
2021  SCLogDebug("filestore count %u", sgh->filestore_cnt);
2022 
2024 
2026 
2027  sgh->id = idx;
2028  cnt++;
2029  }
2030  SCLogPerf("Unique rule groups: %u", cnt);
2031 
2033 
2034  if (de_ctx->decoder_event_sgh != NULL) {
2035  /* no need to set filestore count here as that would make a
2036  * signature not decode event only. */
2037  }
2038 
2039  int dump_grouping = 0;
2040  (void)ConfGetBool("detect.profiling.grouping.dump-to-disk", &dump_grouping);
2041 
2042  if (dump_grouping) {
2043  int add_rules = 0;
2044  (void)ConfGetBool("detect.profiling.grouping.include-rules", &add_rules);
2045  int add_mpm_stats = 0;
2046  (void)ConfGetBool("detect.profiling.grouping.include-mpm-stats", &add_mpm_stats);
2047 
2048  RulesDumpGrouping(de_ctx, add_rules, add_mpm_stats);
2049  }
2050 
2051  for (uint32_t idx = 0; idx < de_ctx->sgh_array_cnt; idx++) {
2052  SigGroupHead *sgh = de_ctx->sgh_array[idx];
2053  if (sgh == NULL)
2054  continue;
2056  sgh->init = NULL;
2057  }
2058  /* cleanup the hashes now since we won't need them
2059  * after the initialization phase. */
2061 
2062 #ifdef PROFILING
2064 #endif
2065  SCReturnInt(0);
2066 }
2067 
2068 extern bool rule_engine_analysis_set;
2069 /** \internal
2070  * \brief perform final per signature setup tasks
2071  *
2072  * - Create SigMatchData arrays from the init only SigMatch lists
2073  * - Setup per signature inspect engines
2074  * - remove signature init data.
2075  */
2076 static int SigMatchPrepare(DetectEngineCtx *de_ctx)
2077 {
2078  SCEnter();
2079 
2080  Signature *s = de_ctx->sig_list;
2081  for (; s != NULL; s = s->next) {
2082  /* set up inspect engines */
2084 
2085  /* built-ins */
2086  for (int type = 0; type < DETECT_SM_LIST_MAX; type++) {
2087  /* skip PMATCH if it is used in a stream 'app engine' instead */
2089  continue;
2090  SigMatch *sm = s->init_data->smlists[type];
2092  }
2093  /* set up the pkt inspection engines */
2095 
2099  }
2100  /* free lists. Ctx' are xferred to sm_arrays so won't get freed */
2101  for (uint32_t i = 0; i < DETECT_SM_LIST_MAX; i++) {
2102  SigMatch *sm = s->init_data->smlists[i];
2103  while (sm != NULL) {
2104  SigMatch *nsm = sm->next;
2105  SigMatchFree(de_ctx, sm);
2106  sm = nsm;
2107  }
2108  }
2109  for (uint32_t i = 0; i < (uint32_t)s->init_data->transforms.cnt; i++) {
2110  if (s->init_data->transforms.transforms[i].options) {
2111  int transform = s->init_data->transforms.transforms[i].transform;
2112  sigmatch_table[transform].Free(
2114  s->init_data->transforms.transforms[i].options = NULL;
2115  }
2116  }
2117  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2118  SigMatch *sm = s->init_data->buffers[x].head;
2119  while (sm != NULL) {
2120  SigMatch *nsm = sm->next;
2121  SigMatchFree(de_ctx, sm);
2122  sm = nsm;
2123  }
2124  }
2125  if (s->init_data->cidr_dst != NULL)
2127 
2128  if (s->init_data->cidr_src != NULL)
2130 
2131  SCFree(s->init_data->buffers);
2132  SCFree(s->init_data);
2133  s->init_data = NULL;
2134  }
2135 
2137  SCReturnInt(0);
2138 }
2139 
2140 /**
2141  * \brief Convert the signature list into the runtime match structure.
2142  *
2143  * \param de_ctx Pointer to the Detection Engine Context whose Signatures have
2144  * to be processed
2145  *
2146  * \retval 0 On Success.
2147  * \retval -1 On failure.
2148  */
2150 {
2151  Signature *s = de_ctx->sig_list;
2152 
2153  /* Assign the unique order id of signatures after sorting,
2154  * so the IP Only engine process them in order too. Also
2155  * reset the old signums and assign new signums. We would
2156  * have experienced Sig reordering by now, hence the new
2157  * signums. */
2158  de_ctx->signum = 0;
2159  while (s != NULL) {
2160  s->num = de_ctx->signum++;
2161 
2162  s = s->next;
2163  }
2164 
2166  return -1;
2167 
2168  SigInitStandardMpmFactoryContexts(de_ctx);
2169 
2170  if (SigPrepareStage1(de_ctx) != 0) {
2171  FatalError("initializing the detection engine failed");
2172  }
2173 
2174  if (SigPrepareStage2(de_ctx) != 0) {
2175  FatalError("initializing the detection engine failed");
2176  }
2177 
2178  if (SigPrepareStage3(de_ctx) != 0) {
2179  FatalError("initializing the detection engine failed");
2180  }
2181  if (SigPrepareStage4(de_ctx) != 0) {
2182  FatalError("initializing the detection engine failed");
2183  }
2184 
2189  if (r != 0) {
2190  FatalError("initializing the detection engine failed");
2191  }
2192 
2193  if (SigMatchPrepare(de_ctx) != 0) {
2194  FatalError("initializing the detection engine failed");
2195  }
2196 
2197 #ifdef PROFILING
2200  de_ctx->profile_match_logging_threshold = UINT_MAX; // disabled
2201 
2202  intmax_t v = 0;
2203  if (ConfGetInt("detect.profiling.inspect-logging-threshold", &v) == 1)
2204  de_ctx->profile_match_logging_threshold = (uint32_t)v;
2205 #endif
2206 #ifdef PROFILE_RULES
2208 #endif
2209 
2211 
2214  }
2215  return 0;
2216 }
2217 
2219 {
2221 
2222  return 0;
2223 }
detect-tcp-flags.h
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:56
SIG_TYPE_STREAM
@ SIG_TYPE_STREAM
Definition: detect.h:72
DETECT_FLOW_FLAG_TOCLIENT
#define DETECT_FLOW_FLAG_TOCLIENT
Definition: detect-flow.h:28
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:530
detect-content.h
ts
uint64_t ts
Definition: source-erf-file.c:55
util-port-interval-tree.h
detect-engine.h
DetectEngineResetMaxSigId
void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:2922
DetectEngineBufferTypeSupportsPacketGetById
bool DetectEngineBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1239
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:116
MASK_TCP_UNUSUAL_FLAGS
#define MASK_TCP_UNUSUAL_FLAGS
Definition: detect-engine-build.c:401
DetectFlagsSignatureNeedsSynOnlyPackets
int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s)
Definition: detect-tcp-flags.c:532
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:581
detect-engine-proto.h
detect-dsize.h
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1022
UniquePortPoint_
Definition: detect-engine-build.c:1319
SIG_TYPE_APP_TX
@ SIG_TYPE_APP_TX
Definition: detect.h:75
SigMatchFree
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:347
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1286
DetectEngineCtx_::decoder_event_sgh
struct SigGroupHead_ * decoder_event_sgh
Definition: detect.h:922
DetectPortHashInit
int DetectPortHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the DetectPort hash.
Definition: detect-engine-port.c:1370
DetectEngineCtx_::flow_gh
DetectEngineLookupFlow flow_gh[FLOW_STATES]
Definition: detect.h:869
FILE_SIG_NEED_SHA1
#define FILE_SIG_NEED_SHA1
Definition: detect.h:319
SigPrepareStage4
int SigPrepareStage4(DetectEngineCtx *de_ctx)
finalize preparing sgh's
Definition: detect-engine-build.c:2006
detect-engine-siggroup.h
DetectFlowData_
Definition: detect-flow.h:37
SigTableElmt_::name
const char * name
Definition: detect.h:1296
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1075
Signature_::num
SigIntId num
Definition: detect.h:608
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1276
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:483
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1448
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:171
SIG_FLAG_INIT_FLOW
#define SIG_FLAG_INIT_FLOW
Definition: detect.h:287
SigFree
void SigFree(DetectEngineCtx *, Signature *)
Definition: detect-parse.c:1644
DumpPatterns
void DumpPatterns(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:1290
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SigGroupHeadBuildNonPrefilterArray
int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
build an array of rule id's for sigs with no prefilter Also updated de_ctx::non_pf_store_cnt_max to t...
Definition: detect-engine-siggroup.c:632
DetectFlagsData_::flags
uint8_t flags
Definition: detect-tcp-flags.h:38
SigGroupHeadInitData_::sig_array
uint8_t * sig_array
Definition: detect.h:1423
DetectPortFree
void DetectPortFree(const DetectEngineCtx *de_ctx, DetectPort *dp)
Free a DetectPort and its members.
Definition: detect-engine-port.c:80
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:62
DetectEngineCtx_::max_uniq_toclient_groups
uint16_t max_uniq_toclient_groups
Definition: detect.h:895
MpmStoreReportStats
void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
Definition: detect-engine-mpm.c:1408
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:562
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:544
DETECT_FLOW
@ DETECT_FLOW
Definition: detect-engine-register.h:54
Signature_::alproto
AppProto alproto
Definition: detect.h:601
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
DETECT_UINT_NE
#define DETECT_UINT_NE
Definition: detect-engine-uint.h:36
IPOnlyDeinit
void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
Deinitialize the IP Only detection engine context.
Definition: detect-engine-iponly.c:948
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DetectPort_::port
uint16_t port
Definition: detect.h:218
ThresholdHashAllocate
void ThresholdHashAllocate(DetectEngineCtx *de_ctx)
Allocate threshold context hash tables.
Definition: detect-engine-threshold.c:659
PORT_SIGGROUPHEAD_COPY
#define PORT_SIGGROUPHEAD_COPY
Definition: detect.h:214
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:81
DETECT_DECODE_EVENT
@ DETECT_DECODE_EVENT
Definition: detect-engine-register.h:104
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:135
Packet_::flags
uint32_t flags
Definition: decode.h:474
UNDEFINED_PORT
#define UNDEFINED_PORT
Definition: detect-engine-build.c:1315
PatternStrength
uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
Predict a strength value for patterns.
Definition: detect-engine-mpm.c:905
TH_RST
#define TH_RST
Definition: decode-tcp.h:36
DETECT_TBLSIZE
@ DETECT_TBLSIZE
Definition: detect-engine-register.h:358
DetectFlowbitsAnalyze
int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
Definition: detect-flowbits.c:419
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:2394
DETECT_AL_APP_LAYER_EVENT
@ DETECT_AL_APP_LAYER_EVENT
Definition: detect-engine-register.h:187
TH_FIN
#define TH_FIN
Definition: decode-tcp.h:34
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:75
SigTableElmt_::flags
uint16_t flags
Definition: detect.h:1290
SCProfilingSghInitCounters
void SCProfilingSghInitCounters(DetectEngineCtx *de_ctx)
Register the keyword profiling counters.
Definition: util-profiling-rulegroups.c:366
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:839
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:27
SIG_TYPE_PKT_STREAM
@ SIG_TYPE_PKT_STREAM
Definition: detect.h:71
DetectFlagsSignatureNeedsSynPackets
int DetectFlagsSignatureNeedsSynPackets(const Signature *s)
Definition: detect-tcp-flags.c:513
TransformData_::options
void * options
Definition: detect.h:406
DetectFlowbitsData_::cmd
uint8_t cmd
Definition: detect-flowbits.h:37
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:287
SigGroupHeadSetProtoAndDirection
void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, uint8_t ipproto, int dir)
Definition: detect-engine-siggroup.c:502
SIGMATCH_DEONLY_COMPAT
#define SIGMATCH_DEONLY_COMPAT
Definition: detect.h:1480
DETECT_UINT_EQ
#define DETECT_UINT_EQ
Definition: detect-engine-uint.h:35
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1102
DetectMpmInitializeBuiltinMpms
void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx)
Definition: detect-engine-mpm.c:701
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:239
util-var-name.h
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:250
MIN
#define MIN(x, y)
Definition: suricata-common.h:391
rule_engine_analysis_set
bool rule_engine_analysis_set
Definition: detect-engine-loader.c:55
DE_QUIET
#define DE_QUIET
Definition: detect.h:324
DetectPort_::next
struct DetectPort_ * next
Definition: detect.h:231
DetectEngineCtx_::dport_hash_table
HashListTable * dport_hash_table
Definition: detect.h:977
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:649
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:975
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:548
JSON_ESCAPE_SLASH
#define JSON_ESCAPE_SLASH
Definition: suricata-common.h:277
proto
uint8_t proto
Definition: decode-template.h:0
DetectPort_::sh
struct SigGroupHead_ * sh
Definition: detect.h:228
DetectContentData_
Definition: detect-content.h:93
DETECT_FLOWBITS_CMD_ISSET
#define DETECT_FLOWBITS_CMD_ISSET
Definition: detect-flowbits.h:32
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1011
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:54
DetectPortPrintList
void DetectPortPrintList(DetectPort *head)
Helper function used to print the list of ports present in this DetectPort list.
Definition: detect-engine-port.c:100
DETECT_UINT_GT
#define DETECT_UINT_GT
Definition: detect-engine-uint.h:32
SigPrepareStage1
int SigPrepareStage1(DetectEngineCtx *de_ctx)
Preprocess signature, classify ip-only, etc, build sig array.
Definition: detect-engine-build.c:1720
DETECT_PGSCORE_RULE_SYN_ONLY
#define DETECT_PGSCORE_RULE_SYN_ONLY
Definition: detect-engine-build.c:52
DETECT_PGSCORE_RULE_PORT_WHITELISTED
#define DETECT_PGSCORE_RULE_PORT_WHITELISTED
Definition: detect-engine-build.c:48
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:267
MAX
#define MAX(x, y)
Definition: suricata-common.h:395
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:238
SigGroupHeadSetupFiles
void SigGroupHeadSetupFiles(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Set the need hash flag in the sgh.
Definition: detect-engine-siggroup.c:589
ALPROTO_MAX
@ ALPROTO_MAX
Definition: app-layer-protos.h:76
SIG_TYPE_APPLAYER
@ SIG_TYPE_APPLAYER
Definition: detect.h:74
SignatureIsFilesizeInspecting
int SignatureIsFilesizeInspecting(const Signature *s)
Check if a signature contains the filesize keyword.
Definition: detect-engine-build.c:185
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:587
DetectPort_::port2
uint16_t port2
Definition: detect.h:219
detect-engine-prefilter.h
Packet_::app_layer_events
AppLayerDecoderEvents * app_layer_events
Definition: decode.h:613
Packet_::events
PacketEngineEvents events
Definition: decode.h:611
FLOW_STATES
#define FLOW_STATES
Definition: detect.h:836
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:2456
DetectPort_::flags
uint8_t flags
Definition: detect.h:221
DetectPortPrint
void DetectPortPrint(DetectPort *dp)
Helper function that print the DetectPort info.
Definition: detect-engine-port.c:590
PacketCreateMask
void PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, bool app_decoder_events)
Definition: detect-engine-build.c:406
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:245
SigGroupHeadHashInit
int SigGroupHeadHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the SigGroupHeads.
Definition: detect-engine-siggroup.c:257
DetectEngineCtx_::udp_whitelist
DetectPort * udp_whitelist
Definition: detect.h:980
FILE_SIG_NEED_MD5
#define FILE_SIG_NEED_MD5
Definition: detect.h:318
DETECT_PREFILTER_AUTO
@ DETECT_PREFILTER_AUTO
Definition: detect.h:821
DetectEngineCtx_::sgh_array_size
uint32_t sgh_array_size
Definition: detect.h:907
SCPortIntervalInsert
int SCPortIntervalInsert(DetectEngineCtx *, SCPortIntervalTree *, const DetectPort *)
Function to insert a node in the interval tree.
Definition: util-port-interval-tree.c:109
SignatureIsFileSha256Inspecting
int SignatureIsFileSha256Inspecting(const Signature *s)
Check if a signature contains the filesha256 keyword.
Definition: detect-engine-build.c:169
Signature_::next
struct Signature_ * next
Definition: detect.h:668
PKT_IS_TCP
#define PKT_IS_TCP(p)
Definition: decode.h:248
DetectFlowbitsData_
Definition: detect-flowbits.h:35
DetectEngineMultiTenantEnabled
int DetectEngineMultiTenantEnabled(void)
Definition: detect-engine.c:3722
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:55
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:124
SigGroupHeadInitData_::score
int score
Definition: detect.h:1428
DetectPortCopySingle
DetectPort * DetectPortCopySingle(DetectEngineCtx *de_ctx, DetectPort *src)
Function that return a copy of DetectPort src sigs.
Definition: detect-engine-port.c:550
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:266
DetectPortParse
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
Definition: detect-engine-port.c:1182
SigAddressCleanupStage1
int SigAddressCleanupStage1(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:1932
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:70
TCPHdr_::th_flags
uint8_t th_flags
Definition: decode-tcp.h:148
SigGroupHeadBuildMatchArray
int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx)
Create an array with all the internal ids of the sigs that this sig group head will check for.
Definition: detect-engine-siggroup.c:551
SigGroupHeadInitData_::sig_cnt
SigIntId sig_cnt
Definition: detect.h:1441
DETECT_CONTENT_ENDS_WITH
#define DETECT_CONTENT_ENDS_WITH
Definition: detect-content.h:42
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DETECT_FLOWINT
@ DETECT_FLOWINT
Definition: detect-engine-register.h:87
IPOnlyInit
void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
Setup the IP Only detection engine context.
Definition: detect-engine-iponly.c:909
SIG_MASK_REQUIRE_ENGINE_EVENT
#define SIG_MASK_REQUIRE_ENGINE_EVENT
Definition: detect.h:306
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:64
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:560
SigFindSignatureBySidGid
Signature * SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint32_t gid)
Find a specific signature by sid and gid.
Definition: detect-engine-build.c:78
DetectConfigData_::scope
enum ConfigScope scope
Definition: detect-config.h:32
DetectEngineGetMaxSigId
#define DetectEngineGetMaxSigId(de_ctx)
Definition: detect-engine.h:105
DETECT_FLOW_FLAG_TOSERVER
#define DETECT_FLOW_FLAG_TOSERVER
Definition: detect-flow.h:27
FILE_SIG_NEED_MAGIC
#define FILE_SIG_NEED_MAGIC
Definition: detect.h:316
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:558
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:301
SignatureInitData_::cidr_dst
IPOnlyCIDRItem * cidr_dst
Definition: detect.h:555
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect-engine-mpm.h
DetectEngineLookupFlow_::sgh
struct SigGroupHead_ * sgh[256]
Definition: detect.h:777
detect.h
SIG_MASK_REQUIRE_FLAGS_INITDEINIT
#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT
Definition: detect.h:302
SCProfilingPrefilterInitCounters
void SCProfilingPrefilterInitCounters(DetectEngineCtx *de_ctx)
Register the prefilter profiling counters.
Definition: util-profiling-prefilter.c:297
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:1883
PKT_DETECT_HAS_STREAMDATA
#define PKT_DETECT_HAS_STREAMDATA
Definition: decode.h:1061
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:354
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
detect-engine-port.h
DETECT_ENGINE_EVENT
@ DETECT_ENGINE_EVENT
Definition: detect-engine-register.h:210
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:114
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
DetectContentPropagateLimits
void DetectContentPropagateLimits(Signature *s)
Definition: detect-content.c:716
DetectPort_
Port structure for detection engine.
Definition: detect.h:217
SigGroupHead_::init
SigGroupHeadInitData * init
Definition: detect.h:1471
DetectEngineCtx_::sig_cnt
uint32_t sig_cnt
Definition: detect.h:848
DETECT_PGSCORE_RULE_NO_MPM
#define DETECT_PGSCORE_RULE_NO_MPM
Definition: detect-engine-build.c:51
UniquePortPoint_::single
bool single
Definition: detect-engine-build.c:1321
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:555
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:353
DetectProto_::proto
uint8_t proto[256/8]
Definition: detect-engine-proto.h:37
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
IPOnlyPrepare
void IPOnlyPrepare(DetectEngineCtx *de_ctx)
Build the radix trees from the lists of parsed addresses in CIDR format the result should be 4 radix ...
Definition: detect-engine-iponly.c:1133
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2218
DETECT_PGSCORE_RULE_MPM_FAST_PATTERN
#define DETECT_PGSCORE_RULE_MPM_FAST_PATTERN
Definition: detect-engine-build.c:49
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:262
util-profiling.h
FILE_SIG_NEED_SHA256
#define FILE_SIG_NEED_SHA256
Definition: detect.h:320
DetectEngineLookupFlow_::udp
DetectPort * udp
Definition: detect.h:776
Signature_::flags
uint32_t flags
Definition: detect.h:597
SCPortIntervalTreeInit
SCPortIntervalTree * SCPortIntervalTreeInit(void)
Function to initialize the interval tree.
Definition: util-port-interval-tree.c:58
Packet_
Definition: decode.h:437
detect-engine-build.h
type
uint16_t type
Definition: decode-vlan.c:107
DETECT_UINT_GTE
#define DETECT_UINT_GTE
Definition: detect-engine-uint.h:33
IPOnlyPrint
void IPOnlyPrint(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
Print stats of the IP Only engine.
Definition: detect-engine-iponly.c:937
DetectConfigData_
Definition: detect-config.h:29
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DETECT_AL_APP_LAYER_PROTOCOL
@ DETECT_AL_APP_LAYER_PROTOCOL
Definition: detect-engine-register.h:35
DetectEngineCtx_::max_uniq_toserver_groups
uint16_t max_uniq_toserver_groups
Definition: detect.h:896
IPOnlyAddSignature
void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, Signature *s)
Add a signature to the lists of Addresses in CIDR format (sorted) this step is necessary to build the...
Definition: detect-engine-iponly.c:1556
SC_OK
@ SC_OK
Definition: util-error.h:27
DETECT_CONFIG
@ DETECT_CONFIG
Definition: detect-engine-register.h:213
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:665
TH_ECN
#define TH_ECN
Definition: decode-tcp.h:41
DetectEngineCtx_::sgh_array_cnt
uint32_t sgh_array_cnt
Definition: detect.h:906
SigGroupHeadAppendSig
int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, const Signature *s)
Add a Signature to a SigGroupHead.
Definition: detect-engine-siggroup.c:334
DetectEngineCtx_::sgh_array
struct SigGroupHead_ ** sgh_array
Definition: detect.h:905
UniquePortPoint_::port
uint16_t port
Definition: detect-engine-build.c:1320
SignatureInitData_::dst_contains_negation
bool dst_contains_negation
Definition: detect.h:545
SigGroupHeadFree
void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Free a SigGroupHead and its members.
Definition: detect-engine-siggroup.c:162
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:410
SIG_TYPE_DEONLY
@ SIG_TYPE_DEONLY
Definition: detect.h:69
detect-flowbits.h
SIG_MASK_REQUIRE_PAYLOAD
#define SIG_MASK_REQUIRE_PAYLOAD
Definition: detect.h:300
TH_URG
#define TH_URG
Definition: decode-tcp.h:39
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
DETECT_DSIZE
@ DETECT_DSIZE
Definition: detect-engine-register.h:52
Signature_::sp
DetectPort * sp
Definition: detect.h:637
SIG_TYPE_NOT_SET
@ SIG_TYPE_NOT_SET
Definition: detect.h:63
SignatureIsFileSha1Inspecting
int SignatureIsFileSha1Inspecting(const Signature *s)
Check if a signature contains the filesha1 keyword.
Definition: detect-engine-build.c:153
IPOnlyCIDRListFree
void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
This function free a IPOnlyCIDRItem list.
Definition: detect-engine-iponly.c:481
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2149
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:962
SIG_FLAG_MPM_NEG
#define SIG_FLAG_MPM_NEG
Definition: detect.h:252
SCPortIntervalTree_::tree
struct PI tree
Definition: detect-engine-port.h:45
detect-engine-analyzer.h
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:291
DetectEngineBufferTypeSupportsFramesGetById
bool DetectEngineBufferTypeSupportsFramesGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1257
SCPortIntervalTreeFree
void SCPortIntervalTreeFree(DetectEngineCtx *, SCPortIntervalTree *)
Function to free an entire interval tree.
Definition: util-port-interval-tree.c:92
EngineAnalysisRules2
void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
Definition: detect-engine-analyzer.c:942
SigGroupHeadSetSigCnt
void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx)
Updates the SigGroupHead->sig_cnt with the total count of all the Signatures present in this SigGroup...
Definition: detect-engine-siggroup.c:461
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:38
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
util-conf.h
DetectMpmPrepareFrameMpms
int DetectMpmPrepareFrameMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
Definition: detect-engine-mpm.c:488
SINGLE_PORT
#define SINGLE_PORT
Definition: detect-engine-build.c:1317
DetectEnginePktInspectionSetup
int DetectEnginePktInspectionSetup(Signature *s)
Definition: detect-engine.c:1985
tail
Host * tail
Definition: host.h:2
TH_SYN
#define TH_SYN
Definition: decode-tcp.h:35
Signature_::proto
DetectProto proto
Definition: detect.h:615
suricata-common.h
SIG_MASK_REQUIRE_NO_PAYLOAD
#define SIG_MASK_REQUIRE_NO_PAYLOAD
Definition: detect.h:304
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:240
SigGroupHeadStore
void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Definition: detect-engine-siggroup.c:108
SigMatch_::type
uint16_t type
Definition: detect.h:351
Packet_::tcph
TCPHdr * tcph
Definition: decode.h:567
SigGroupHeadInitData_::match_array
Signature ** match_array
Definition: detect.h:1444
Signature_::file_flags
uint8_t file_flags
Definition: detect.h:612
SigPrepareStage3
int SigPrepareStage3(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:1925
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:127
DetectPort_::prev
struct DetectPort_ * prev
Definition: detect.h:230
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:230
DetectContentData_::content
uint8_t * content
Definition: detect-content.h:94
MASK_TCP_INITDEINIT_FLAGS
#define MASK_TCP_INITDEINIT_FLAGS
Definition: detect-engine-build.c:400
DetectListToString
const char * DetectListToString(int list)
Definition: detect-parse.c:189
DetectEngineCtx_::profile_match_logging_threshold
uint32_t profile_match_logging_threshold
Definition: detect.h:960
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:847
DetectMpmPreparePktMpms
int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
Definition: detect-engine-mpm.c:655
SigGroupHeadHashFree
void SigGroupHeadHashFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by SigGroupHeadHashInit() function.
Definition: detect-engine-siggroup.c:312
DetectEngineCtx_::tcp_whitelist
DetectPort * tcp_whitelist
Definition: detect.h:979
SIG_MASK_REQUIRE_FLAGS_UNUSUAL
#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL
Definition: detect.h:303
TransformData_::transform
int transform
Definition: detect.h:405
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:90
SigGroupHeadHashAdd
int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Adds a SigGroupHead to the detection engine context SigGroupHead hash table.
Definition: detect-engine-siggroup.c:279
util-validate.h
detect-flow.h
SCPortIntervalTree_
Definition: detect-engine-port.h:44
SigPrepareStage2
int SigPrepareStage2(DetectEngineCtx *de_ctx)
Fill the global src group head, with the sigs included.
Definition: detect-engine-build.c:1885
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:586
ConfigGetLogDirectory
const char * ConfigGetLogDirectory(void)
Definition: util-conf.c:38
HtpBodyChunk_::next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:179
SigGroupHeadHashLookup
SigGroupHead * SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Used to lookup a SigGroupHead hash from the detection engine context SigGroupHead hash table.
Definition: detect-engine-siggroup.c:296
Signature_::dp
DetectPort * dp
Definition: detect.h:637
DETECT_STREAM_EVENT
@ DETECT_STREAM_EVENT
Definition: detect-engine-register.h:211
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1050
SignatureIsFilestoring
int SignatureIsFilestoring(const Signature *s)
Check if a signature contains the filestore keyword.
Definition: detect-engine-build.c:99
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SignatureIsIPOnly
int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s)
Test is a initialized signature is IP only.
Definition: detect-engine-build.c:208
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1283
DetectMpmPrepareBuiltinMpms
int DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for builtin buffers that are in "single or "shared" mode.
Definition: detect-engine-mpm.c:714
Signature_::id
uint32_t id
Definition: detect.h:631
HashListTableBucket_
Definition: util-hashlist.h:28
detect-engine-iponly.h
SignatureInitData_::score
int score
Definition: detect.h:573
detect-parse.h
SignatureInitDataBuffer_::id
uint32_t id
Definition: detect.h:523
Signature_
Signature container.
Definition: detect.h:596
SigMatch_
a single match condition for a signature
Definition: detect.h:350
TH_CWR
#define TH_CWR
Definition: decode-tcp.h:43
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:132
SigGroupHeadInitDataFree
void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
Definition: detect-engine-siggroup.c:60
SignatureMask
#define SignatureMask
Definition: detect.h:309
SignatureIsFileMd5Inspecting
int SignatureIsFileMd5Inspecting(const Signature *s)
Check if a signature contains the filemd5 keyword.
Definition: detect-engine-build.c:137
DETECT_PGSCORE_RULE_MPM_NEGATED
#define DETECT_PGSCORE_RULE_MPM_NEGATED
Definition: detect-engine-build.c:50
DetectFlagsData_
Definition: detect-tcp-flags.h:37
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1647
RANGE_PORT
#define RANGE_PORT
Definition: detect-engine-build.c:1316
SCProfilingKeywordInitCounters
void SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx)
Register the keyword profiling counters.
Definition: util-profiling-keywords.c:362
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:411
DetectPortHashAdd
int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp)
Adds a DetectPort to the detection engine context DetectPort hash table.
Definition: detect-engine-port.c:1390
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:856
CONFIG_SCOPE_FLOW
@ CONFIG_SCOPE_FLOW
Definition: util-config.h:48
DetectContentData_::content_len
uint16_t content_len
Definition: detect-content.h:95
DetectEngineCtx_::buffer_type_id
uint32_t buffer_type_id
Definition: detect.h:992
PrefilterSetupRuleGroup
void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Definition: detect-engine-prefilter.c:413
SigParseApplyDsizeToContent
void SigParseApplyDsizeToContent(Signature *s)
Apply dsize as depth to content matches in the rule.
Definition: detect-dsize.c:333
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:841
UniquePortPoint
struct UniquePortPoint_ UniquePortPoint
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:568
SCProfilingRuleInitCounters
void SCProfilingRuleInitCounters(DetectEngineCtx *)
DetectEngineCtx_::io_ctx
DetectEngineIPOnlyCtx io_ctx
Definition: detect.h:880
DetectU16Data
DetectUintData_u16 DetectU16Data
Definition: detect-engine-uint.h:42
DetectPortHashFree
void DetectPortHashFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by DetectPortInit() function.
Definition: detect-engine-port.c:1421
DetectPortHashLookup
DetectPort * DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp)
Used to lookup a DetectPort hash from the detection engine context DetectPort hash table.
Definition: detect-engine-port.c:1406
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::sig_array_len
uint32_t sig_array_len
Definition: detect.h:857
detect-config.h
DETECT_FLAGS
@ DETECT_FLAGS
Definition: detect-engine-register.h:42
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
Signature_::type
enum SignatureType type
Definition: detect.h:599
SignatureIsFilemagicInspecting
int SignatureIsFilemagicInspecting(const Signature *s)
Check if a signature contains the filemagic keyword.
Definition: detect-engine-build.c:118
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:859
DetectEngineCtx_::tenant_id
uint32_t tenant_id
Definition: detect.h:845
SigGroupHead_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1454
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:587
DetectMpmPrepareAppMpms
int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx)
initialize mpm contexts for applayer buffers that are in "single or "shared" mode.
Definition: detect-engine-mpm.c:261
SIGMATCH_IPONLY_COMPAT
#define SIGMATCH_IPONLY_COMPAT
Definition: detect.h:1478
DetectEngineLookupFlow_::tcp
DetectPort * tcp
Definition: detect.h:775
DetectPortCleanupList
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
Definition: detect-engine-port.c:124
SIG_TYPE_PDONLY
@ SIG_TYPE_PDONLY
Definition: detect.h:68
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:771
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:103
DetectEngineAppInspectionEngine2Signature
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine.c:706
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:273
detect-engine-address.h
SigGroupHead_::id
uint32_t id
Definition: detect.h:1456
VarNameStoreActivate
int VarNameStoreActivate(void)
Definition: util-var-name.c:214
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:264
DETECT_UINT_RA
#define DETECT_UINT_RA
Definition: detect-engine-uint.h:34
FILE_SIG_NEED_SIZE
#define FILE_SIG_NEED_SIZE
Definition: detect.h:321
SCPortIntervalFindOverlappingRanges
void SCPortIntervalFindOverlappingRanges(DetectEngineCtx *, const uint16_t, const uint16_t, const struct PI *, DetectPort **)
Callee function to find all overlapping port ranges as asked by the detection engine during Stage 2 o...
Definition: util-port-interval-tree.c:316
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:241
DETECT_FLOWBITS_CMD_SET
#define DETECT_FLOWBITS_CMD_SET
Definition: detect-flowbits.h:28
detect-engine-threshold.h
SigGroupHeadCopySigs
int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst)
Copies the bitarray holding the sids from the source SigGroupHead to the destination SigGroupHead.
Definition: detect-engine-siggroup.c:405
Signature_::mask
SignatureMask mask
Definition: detect.h:607
SIG_TYPE_LIKE_IPONLY
@ SIG_TYPE_LIKE_IPONLY
Definition: detect.h:65
PacketEngineEvents_::cnt
uint8_t cnt
Definition: decode.h:309
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:249