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