suricata
detect-engine-prefilter.c
Go to the documentation of this file.
1/* Copyright (C) 2016-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/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Prefilter engine
24 *
25 * Prefilter engines have as purpose to check for a critical common part of
26 * a set of rules. If the condition is present in the traffic, the rules
27 * will have to be inspected individually. Otherwise, the rules can be
28 * skipped.
29 *
30 * The best example of this is the MPM. From each rule take a pattern and
31 * add it to the MPM state machine. Inspect that in one step and only
32 * individually inspect the rules that had a match in MPM.
33 *
34 * This prefilter API is designed to abstract this logic so that it becomes
35 * easier to add other types of prefilters.
36 *
37 * The prefilter engines are structured as a simple list of engines. Each
38 * engine checks for a condition using it's callback function and private
39 * data. It then adds the rule match candidates to the PrefilterRuleStore
40 * structure.
41 *
42 * After the engines have run the resulting list of match candidates is
43 * sorted by the rule id's so that the individual inspection happens in
44 * the correct order.
45 */
46
47#include "suricata-common.h"
48#include "suricata.h"
49
50#include "detect-engine.h"
52#include "detect-engine-mpm.h"
53#include "detect-engine-frame.h"
54#include "detect-engine-uint.h"
55
56#include "app-layer-parser.h"
57#include "app-layer-htp.h"
58
59#include "util-profiling.h"
60#include "util-validate.h"
61#include "util-hash-string.h"
62
63static int PrefilterStoreGetId(DetectEngineCtx *de_ctx,
64 const char *name, void (*FreeFunc)(void *));
65static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx,
66 const uint32_t id);
67
68static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n)
69{
70 if (n < 2)
71 return;
72 SigIntId p = sids[n / 2];
73 SigIntId *l = sids;
74 SigIntId *r = sids + n - 1;
75 while (l <= r) {
76 if (*l < p)
77 l++;
78 else if (*r > p)
79 r--;
80 else {
81 SigIntId t = *l;
82 *l = *r;
83 *r = t;
84 l++;
85 r--;
86 }
87 }
88 QuickSortSigIntId(sids, (uint32_t)(r - sids) + 1);
89 QuickSortSigIntId(l, (uint32_t)(sids + n - l));
90}
91
92/**
93 * \brief run prefilter engines on a transaction
94 */
96 const SigGroupHead *sgh,
97 Packet *p,
98 const uint8_t ipproto,
99 const uint8_t flow_flags,
100 const AppProto alproto,
101 void *alstate,
103{
104 /* reset rule store */
105 det_ctx->pmq.rule_id_array_cnt = 0;
106
107 SCLogDebug("packet %" PRIu64 " tx %p progress %d tx->detect_progress %02x", p->pcap_cnt,
108 tx->tx_ptr, tx->tx_progress, tx->detect_progress);
109
110 PrefilterEngine *engine = sgh->tx_engines;
111 do {
112 // based on flow alproto, and engine, we get right tx_ptr
113 void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, alproto, engine->alproto, flow_flags);
114 if (tx_ptr == NULL) {
115 // incompatible engine->alproto with flow alproto
116 goto next;
117 }
118
119 if (engine->ctx.tx_min_progress != -1) {
120#ifdef DEBUG
121 const char *pname = AppLayerParserGetStateNameById(ipproto, engine->alproto,
122 engine->ctx.tx_min_progress, flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
123 SCLogDebug("engine %p min_progress %d %s:%s", engine, engine->ctx.tx_min_progress,
124 AppProtoToString(engine->alproto), pname);
125#endif
126 /* if engine needs tx state to be higher, break out. */
127 if (engine->ctx.tx_min_progress > tx->tx_progress)
128 break;
129 if (tx->tx_progress > engine->ctx.tx_min_progress) {
130 SCLogDebug("tx->tx_progress %u > engine->ctx.tx_min_progress %d", tx->tx_progress,
131 engine->ctx.tx_min_progress);
132
133 /* if state value is at or beyond engine state, we can skip it. It means we ran at
134 * least once already. */
135 if (tx->detect_progress > engine->ctx.tx_min_progress) {
136 SCLogDebug("tx already marked progress as beyond engine: %u > %u",
137 tx->detect_progress, engine->ctx.tx_min_progress);
138 goto next;
139 } else {
140 SCLogDebug("tx->tx_progress %u > engine->ctx.tx_min_progress %d: "
141 "tx->detect_progress %u",
143 }
144 }
145#ifdef DEBUG
146 uint32_t old = det_ctx->pmq.rule_id_array_cnt;
147#endif
149 engine->cb.PrefilterTx(det_ctx, engine->pectx, p, p->flow, tx_ptr, tx->tx_id,
150 tx->tx_data_ptr, flow_flags);
151 PREFILTER_PROFILING_END(det_ctx, engine->gid);
152 SCLogDebug("engine %p min_progress %d %s:%s: results %u", engine,
153 engine->ctx.tx_min_progress, AppProtoToString(engine->alproto), pname,
154 det_ctx->pmq.rule_id_array_cnt - old);
155
156 if (tx->tx_progress > engine->ctx.tx_min_progress && engine->is_last_for_progress) {
157 /* track with an offset of one, so that tx->progress 0 complete is tracked
158 * as 1, progress 1 as 2, etc. This is to allow 0 to mean: nothing tracked, even
159 * though a parser may use 0 as a valid value. */
160 tx->detect_progress = engine->ctx.tx_min_progress + 1;
161 SCLogDebug("tx->tx_progress %d engine->ctx.tx_min_progress %d "
162 "engine->is_last_for_progress %d => tx->detect_progress updated to %02x",
164 tx->detect_progress);
165 }
166 } else {
168 engine->cb.PrefilterTx(det_ctx, engine->pectx, p, p->flow, tx_ptr, tx->tx_id,
169 tx->tx_data_ptr, flow_flags);
170 PREFILTER_PROFILING_END(det_ctx, engine->gid);
171 }
172 next:
173 if (engine->is_last)
174 break;
175 engine++;
176 } while (1);
177
178 /* Sort the rule list to lets look at pmq.
179 * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */
180 if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) {
182 QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
184 }
185}
186
187/** \brief invoke post-rule match "prefilter" engines
188 *
189 * Invoke prefilter engines that depend on a rule match to run.
190 * e.g. the flowbits:set prefilter that adds sids that depend on
191 * a flowbit "set" to the match array.
192 */
194 DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f)
195{
196 SCLogDebug("post-rule-match engines %p", sgh->post_rule_match_engines);
197 if (sgh->post_rule_match_engines) {
199 do {
200 SCLogDebug("running post-rule-match engine");
202 engine->cb.PrefilterPostRule(det_ctx, engine->pectx, p, f);
203 PREFILTER_PROFILING_END(det_ctx, engine->gid);
204
205 if (engine->is_last)
206 break;
207 engine++;
208 } while (1);
209
210 if (det_ctx->pmq.rule_id_array_cnt > 1) {
211 QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
212 }
213 }
214}
215
217 const uint8_t flags, const SignatureMask mask)
218{
219 SCEnter();
220#if 0
221 /* TODO review this check */
222 SCLogDebug("sgh %p frame_engines %p", sgh, sgh->frame_engines);
223 if (p->proto == IPPROTO_TCP && sgh->frame_engines && p->flow &&
224 p->flow->alproto != ALPROTO_UNKNOWN && p->flow->alparser != NULL) {
226 PrefilterFrames(det_ctx, sgh, p, flags, p->flow->alproto);
228 }
229#endif
230 if (sgh->pkt_engines) {
232 /* run packet engines */
233 PrefilterEngine *engine = sgh->pkt_engines;
234 do {
235 /* run engine if:
236 * mask matches
237 * no hook is used OR hook matches
238 */
239 if (((engine->ctx.pkt.mask & mask) == engine->ctx.pkt.mask) &&
240 (engine->ctx.pkt.hook == 0 || (p->pkt_hooks & BIT_U16(engine->ctx.pkt.hook)))) {
242 engine->cb.Prefilter(det_ctx, p, engine->pectx);
243 PREFILTER_PROFILING_END(det_ctx, engine->gid);
244 }
245
246 if (engine->is_last)
247 break;
248 engine++;
249 } while (1);
251 }
252
253 /* run payload inspecting engines */
254 if (sgh->payload_engines &&
257 {
259 PrefilterEngine *engine = sgh->payload_engines;
260 while (1) {
262 engine->cb.Prefilter(det_ctx, p, engine->pectx);
263 PREFILTER_PROFILING_END(det_ctx, engine->gid);
264
265 if (engine->is_last)
266 break;
267 engine++;
268 }
270 }
271
272 /* Sort the rule list to lets look at pmq.
273 * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */
274 if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) {
276 QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
278 }
279 SCReturn;
280}
281
283 SignatureMask mask, enum SignatureHookPkt hook, void *pectx, void (*FreeFunc)(void *pectx),
284 const char *name)
285{
286 if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL)
287 return -1;
288
289 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
290 if (e == NULL)
291 return -1;
292 memset(e, 0x00, sizeof(*e));
293
294 // TODO right now we represent the hook in a u8 in the prefilter engine for space reasons.
295 BUG_ON(hook >= 8);
296
297 e->Prefilter = PrefilterFunc;
298 e->pectx = pectx;
299 e->Free = FreeFunc;
300 e->pkt_mask = mask;
301 e->pkt_hook = hook;
302
303 if (sgh->init->pkt_engines == NULL) {
304 sgh->init->pkt_engines = e;
305 } else {
307 while (t->next != NULL) {
308 t = t->next;
309 }
310
311 t->next = e;
312 e->id = t->id + 1;
313 }
314
315 e->name = name;
316 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
317 return 0;
318}
319
321 PrefilterPktFn PrefilterFunc, void *pectx, void (*FreeFunc)(void *pectx), const char *name)
322{
323 if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL)
324 return -1;
325
326 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
327 if (e == NULL)
328 return -1;
329 memset(e, 0x00, sizeof(*e));
330
331 e->Prefilter = PrefilterFunc;
332 e->pectx = pectx;
333 e->Free = FreeFunc;
334
335 if (sgh->init->payload_engines == NULL) {
336 sgh->init->payload_engines = e;
337 } else {
339 while (t->next != NULL) {
340 t = t->next;
341 }
342
343 t->next = e;
344 e->id = t->id + 1;
345 }
346
347 e->name = name;
348 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
349 return 0;
350}
351
353 PrefilterTxFn PrefilterTxFunc, AppProto alproto, int tx_min_progress, void *pectx,
354 void (*FreeFunc)(void *pectx), const char *name)
355{
356 if (sgh == NULL || PrefilterTxFunc == NULL || pectx == NULL)
357 return -1;
358
359 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
360 if (e == NULL)
361 return -1;
362 memset(e, 0x00, sizeof(*e));
363
364 e->PrefilterTx = PrefilterTxFunc;
365 e->pectx = pectx;
366 e->alproto = alproto;
367 // TODO change function prototype ?
368 DEBUG_VALIDATE_BUG_ON(tx_min_progress > INT8_MAX);
369 e->tx_min_progress = (uint8_t)tx_min_progress;
370 e->Free = FreeFunc;
371
372 if (sgh->init->tx_engines == NULL) {
373 sgh->init->tx_engines = e;
374 } else {
376 while (t->next != NULL) {
377 t = t->next;
378 }
379
380 t->next = e;
381 e->id = t->id + 1;
382 }
383
384 e->name = name;
385 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
386 return 0;
387}
388
390 PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx,
391 void (*FreeFunc)(void *pectx), const char *name)
392{
393 if (sgh == NULL || PrefilterFrameFunc == NULL || pectx == NULL)
394 return -1;
395
396 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
397 if (e == NULL)
398 return -1;
399 memset(e, 0x00, sizeof(*e));
400
401 e->frame_type = frame_type;
402 e->alproto = alproto;
403 e->PrefilterFrame = PrefilterFrameFunc;
404 e->pectx = pectx;
405 e->Free = FreeFunc;
406
407 if (sgh->init->frame_engines == NULL) {
408 sgh->init->frame_engines = e;
409 } else {
411 while (t->next != NULL) {
412 t = t->next;
413 }
414
415 t->next = e;
416 e->id = t->id + 1;
417 }
418
419 e->name = name;
420 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
421 return 0;
422}
423
425 void (*PrefilterPostRuleFunc)(
426 DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f),
427 void *pectx, void (*FreeFunc)(void *pectx), const char *name)
428{
429 if (sgh == NULL || PrefilterPostRuleFunc == NULL || pectx == NULL)
430 return -1;
431
432 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
433 if (e == NULL)
434 return -1;
435 memset(e, 0x00, sizeof(*e));
436 e->PrefilterPostRule = PrefilterPostRuleFunc;
437 e->pectx = pectx;
438 e->Free = FreeFunc;
439
440 if (sgh->init->post_rule_match_engines == NULL) {
442 } else {
444 while (t->next != NULL) {
445 t = t->next;
446 }
447
448 t->next = e;
449 e->id = t->id + 1;
450 }
451
452 e->name = name;
453 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
454 return 0;
455}
456
457static void PrefilterFreeEngineList(PrefilterEngineList *e)
458{
459 if (e->Free && e->pectx) {
460 e->Free(e->pectx);
461 }
462 SCFreeAligned(e);
463}
464
466{
467 PrefilterEngineList *t = list;
468
469 while (t != NULL) {
471 PrefilterFreeEngineList(t);
472 t = next;
473 }
474}
475
476static void PrefilterFreeEngines(const DetectEngineCtx *de_ctx, PrefilterEngine *list)
477{
478 PrefilterEngine *t = list;
479
480 while (1) {
481 const PrefilterStore *s = PrefilterStoreGetStore(de_ctx, t->gid);
482 if (s && s->FreeFunc && t->pectx) {
483 s->FreeFunc(t->pectx);
484 }
485
486 if (t->is_last)
487 break;
488 t++;
489 }
490 SCFreeAligned(list);
491}
492
494{
495 if (sgh->pkt_engines) {
496 PrefilterFreeEngines(de_ctx, sgh->pkt_engines);
497 sgh->pkt_engines = NULL;
498 }
499 if (sgh->payload_engines) {
500 PrefilterFreeEngines(de_ctx, sgh->payload_engines);
501 sgh->payload_engines = NULL;
502 }
503 if (sgh->tx_engines) {
504 PrefilterFreeEngines(de_ctx, sgh->tx_engines);
505 sgh->tx_engines = NULL;
506 }
507 if (sgh->frame_engines) {
508 PrefilterFreeEngines(de_ctx, sgh->frame_engines);
509 sgh->frame_engines = NULL;
510 }
511 if (sgh->post_rule_match_engines) {
512 PrefilterFreeEngines(de_ctx, sgh->post_rule_match_engines);
513 sgh->post_rule_match_engines = NULL;
514 }
515}
516
517static int PrefilterSetupRuleGroupSortHelper(const void *a, const void *b)
518{
519 const PrefilterEngine *s0 = a;
520 const PrefilterEngine *s1 = b;
521 if (s1->ctx.tx_min_progress == s0->ctx.tx_min_progress) {
522 if (s1->alproto == s0->alproto) {
523 return s0->local_id > s1->local_id ? 1 : -1;
524 } else {
525 return s0->alproto > s1->alproto ? 1 : -1;
526 }
527 } else {
528 return s0->ctx.tx_min_progress > s1->ctx.tx_min_progress ? 1 : -1;
529 }
530}
531
532/** prefilter engine data for the non-prefilter engine for the prefilter API */
534 uint32_t sid : 30;
535 uint32_t type : 2; /**< type for `value` field below: 0:alproto 1:dport 2:dsize */
536 uint16_t value;
537 /* since we have 2 more bytes available due to padding, we can add some additional
538 * filters here. */
539 union {
540 struct {
543 struct {
544 /* filter for frame type */
545 uint8_t type;
547 struct {
548 uint8_t foo; // TODO unused
550 };
551};
552
557
559 uint32_t size;
560 uint32_t array[];
561};
562
563/** \internal
564 * \brief wrapper for use in APIs */
565static void PrefilterNonPFDataFree(void *data)
566{
567 SCFree(data);
568}
569
570static void PrefilterTxNonPF(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,
571 void *tx, const uint64_t tx_id, const AppLayerTxData *tx_data, const uint8_t flags)
572{
573 const struct PrefilterNonPFDataTx *data = (const struct PrefilterNonPFDataTx *)pectx;
574 SCLogDebug("adding %u sids", data->size);
575 PrefilterAddSids(&det_ctx->pmq, data->array, data->size);
576}
577
578#ifdef NONPF_PKT_STATS
579static thread_local uint64_t prefilter_pkt_nonpf_called = 0;
580static thread_local uint64_t prefilter_pkt_nonpf_mask_fail = 0;
581static thread_local uint64_t prefilter_pkt_nonpf_alproto_fail = 0;
582static thread_local uint64_t prefilter_pkt_nonpf_dsize_fail = 0;
583static thread_local uint64_t prefilter_pkt_nonpf_dport_fail = 0;
584static thread_local uint64_t prefilter_pkt_nonpf_sids = 0;
585#define NONPF_PKT_STATS_INCR(s) (s)++
586#else
587#define NONPF_PKT_STATS_INCR(s)
588#endif
589
591{
592#ifdef NONPF_PKT_STATS
593 SCLogDebug("prefilter non-pf: called:%" PRIu64 ", mask_fail:%" PRIu64 ", alproto fail:%" PRIu64
594 ", dport fail:%" PRIu64 ", dsize fail:%" PRIu64 ", sids:%" PRIu64
595 ", avg sids:%" PRIu64,
596 prefilter_pkt_nonpf_called, prefilter_pkt_nonpf_mask_fail,
597 prefilter_pkt_nonpf_alproto_fail, prefilter_pkt_nonpf_dport_fail,
598 prefilter_pkt_nonpf_dsize_fail, prefilter_pkt_nonpf_sids,
599 prefilter_pkt_nonpf_called ? prefilter_pkt_nonpf_sids / prefilter_pkt_nonpf_called : 0);
600#endif
601}
602
603static void PrefilterPktNonPF(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
604{
605 const uint16_t alproto = p->flow ? p->flow->alproto : ALPROTO_UNKNOWN;
606 const SignatureMask mask = p->sig_mask;
607 const struct PrefilterNonPFData *data = (const struct PrefilterNonPFData *)pectx;
608 SCLogDebug("adding %u sids", data->size);
609 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_called);
610 for (uint32_t i = 0; i < data->size; i++) {
611 const struct PrefilterNonPFDataSig *ds = &data->array[i];
612 const SignatureMask rule_mask = ds->pkt.sig_mask;
613 if ((rule_mask & mask) == rule_mask) {
614 switch (ds->type) {
615 case 0:
616 if (ds->value == ALPROTO_UNKNOWN || AppProtoEquals(ds->value, alproto)) {
617 const uint32_t sid = ds->sid;
618 PrefilterAddSids(&det_ctx->pmq, &sid, 1);
619 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_sids);
620 } else {
621 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_alproto_fail);
622 }
623 break;
624 case 1:
625 if (ds->value == p->dp) {
626 const uint32_t sid = ds->sid;
627 PrefilterAddSids(&det_ctx->pmq, &sid, 1);
628 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_sids);
629 } else {
630 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_dport_fail);
631 }
632 break;
633 case 2:
634 if (ds->value == p->payload_len) {
635 const uint32_t sid = ds->sid;
636 PrefilterAddSids(&det_ctx->pmq, &sid, 1);
637 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_sids);
638 } else {
639 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_dsize_fail);
640 }
641 break;
642 }
643 } else {
644 NONPF_PKT_STATS_INCR(prefilter_pkt_nonpf_mask_fail);
645 }
646 }
647}
648
649static void PrefilterPktNonPFHookFlowStart(
650 DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
651{
653 PrefilterPktNonPF(det_ctx, p, pectx);
654 }
655}
656
657/** \internal
658 * \brief engine to select the non-prefilter rules for frames
659 * Checks the alproto and type as well.
660 * Direction needs no checking as the rule groups are per direction. */
661static void PrefilterFrameNonPF(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
662 const Frames *frames, const Frame *frame)
663{
664 DEBUG_VALIDATE_BUG_ON(p->flow == NULL);
665 const uint16_t alproto = p->flow->alproto;
666 const struct PrefilterNonPFData *data = (const struct PrefilterNonPFData *)pectx;
667 SCLogDebug("adding %u sids", data->size);
668 for (uint32_t i = 0; i < data->size; i++) {
669 const struct PrefilterNonPFDataSig *ds = &data->array[i];
670 if (ds->frame.type == frame->type &&
671 (ds->value == ALPROTO_UNKNOWN || AppProtoEquals(ds->value, alproto))) {
672 const uint32_t sid = ds->sid;
673 PrefilterAddSids(&det_ctx->pmq, &sid, 1);
674 }
675 }
676}
677
678/* helper funcs for the non prefilter names hash */
679
680static uint32_t NonPFNamesHash(HashTable *h, void *data, uint16_t _len)
681{
682 const char *str = data;
683 return StringHashDjb2((const uint8_t *)str, (uint16_t)strlen(str)) % h->array_size;
684}
685
686static char NonPFNamesCompare(void *data1, uint16_t _len1, void *data2, uint16_t len2)
687{
688 const char *s1 = data1;
689 const char *s2 = data2;
690 return StringHashCompareFunc(data1, (uint16_t)strlen(s1), data2, (uint16_t)strlen(s2));
691}
692
693static void NonPFNamesFree(void *data)
694{
695 SCFree(data);
696}
697
698/* helper funcs for assembling non-prefilter engines */
699
702 int dir; /**< 0: toserver, 1: toclient */
703 int progress; /**< progress state value to register at */
704 int sig_list; /**< special handling: normally 0, but for special cases (app-layer-state,
705 app-layer-event) use the list id to create separate engines */
706 uint32_t sigs_cnt;
708 const char *engine_name; /**< pointer to name owned by DetectEngineCtx::non_pf_engine_names */
709};
710
711static uint32_t TxNonPFHash(HashListTable *h, void *data, uint16_t _len)
712{
713 struct TxNonPFData *d = data;
714 return (d->alproto + d->progress + d->dir + d->sig_list) % h->array_size;
715}
716
717static char TxNonPFCompare(void *data1, uint16_t _len1, void *data2, uint16_t len2)
718{
719 struct TxNonPFData *d1 = data1;
720 struct TxNonPFData *d2 = data2;
721 return d1->alproto == d2->alproto && d1->progress == d2->progress && d1->dir == d2->dir &&
722 d1->sig_list == d2->sig_list;
723}
724
725static void TxNonPFFree(void *data)
726{
727 struct TxNonPFData *d = data;
728 SCFree(d->sigs);
729 SCFree(d);
730}
731
732static int TxNonPFAddSig(DetectEngineCtx *de_ctx, HashListTable *tx_engines_hash,
733 const AppProto alproto, const int dir, const int16_t progress, const int sig_list,
734 const char *name, const Signature *s)
735{
736 const uint32_t max_sids = DetectEngineGetMaxSigId(de_ctx);
737
738 struct TxNonPFData lookup = {
739 .alproto = alproto,
740 .dir = dir,
741 .progress = progress,
742 .sig_list = sig_list,
743 .sigs_cnt = 0,
744 .sigs = NULL,
745 .engine_name = NULL,
746 };
747 struct TxNonPFData *e = HashListTableLookup(tx_engines_hash, &lookup, 0);
748 if (e != NULL) {
749 bool found = false;
750 // avoid adding same sid multiple times
751 for (uint32_t y = 0; y < e->sigs_cnt; y++) {
752 if (e->sigs[y].sid == s->iid) {
753 found = true;
754 break;
755 }
756 }
757 if (!found) {
758 BUG_ON(e->sigs_cnt == max_sids);
759 e->sigs[e->sigs_cnt].sid = s->iid;
760 e->sigs[e->sigs_cnt].value = alproto;
761 e->sigs_cnt++;
762 }
763 return 0;
764 }
765
766 struct TxNonPFData *add = SCCalloc(1, sizeof(*add));
767 if (add == NULL) {
768 return -1;
769 }
770 add->dir = dir;
771 add->alproto = alproto;
772 add->progress = progress;
773 add->sig_list = sig_list;
774 add->sigs = SCCalloc(max_sids, sizeof(struct PrefilterNonPFDataSig));
775 if (add->sigs == NULL) {
776 SCFree(add);
777 return -1;
778 }
779 add->sigs_cnt = 0;
780 add->sigs[add->sigs_cnt].sid = s->iid;
781 add->sigs[add->sigs_cnt].value = alproto;
782 add->sigs_cnt++;
783
784 char engine_name[128];
785 snprintf(engine_name, sizeof(engine_name), "%s:%s:non_pf:%s", AppProtoToString(alproto), name,
786 dir == 0 ? "toserver" : "toclient");
787 char *engine_name_heap = SCStrdup(engine_name);
788 if (engine_name_heap == NULL) {
789 SCFree(add->sigs);
790 SCFree(add);
791 return -1;
792 }
793 int result = HashTableAdd(
794 de_ctx->non_pf_engine_names, engine_name_heap, (uint16_t)strlen(engine_name_heap));
795 if (result != 0) {
796 SCFree(add->sigs);
797 SCFree(add);
798 return -1;
799 }
800
801 add->engine_name = engine_name_heap;
802 SCLogDebug("engine_name_heap %s", engine_name_heap);
803
804 int ret = HashListTableAdd(tx_engines_hash, add, 0);
805 if (ret != 0) {
806 SCFree(add->sigs);
807 SCFree(add);
808 return -1;
809 }
810
811 return 0;
812}
813
814/** \internal
815 * \brief setup non-prefilter rules in special "non-prefilter" engines that are registered in the
816 * prefilter logic.
817 *
818 * \retval 0 ok
819 * \retval -1 error
820 */
821static int SetupNonPrefilter(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
822{
823 const uint32_t max_sids = DetectEngineGetMaxSigId(de_ctx);
824 SCLogDebug("max_sids %u", max_sids);
825 struct PrefilterNonPFDataSig *pkt_non_pf_array = SCCalloc(max_sids, sizeof(*pkt_non_pf_array));
826 if (pkt_non_pf_array == NULL) {
827 return -1;
828 }
829 uint32_t pkt_non_pf_array_size = 0;
830 struct PrefilterNonPFDataSig *frame_non_pf_array =
831 SCCalloc(max_sids, sizeof(*frame_non_pf_array));
832 if (frame_non_pf_array == NULL) {
833 SCFree(pkt_non_pf_array);
834 return -1;
835 }
836 uint32_t frame_non_pf_array_size = 0;
837
838 struct PrefilterNonPFDataSig *pkt_hook_flow_start_non_pf_array =
839 SCCalloc(max_sids, sizeof(*pkt_hook_flow_start_non_pf_array));
840 if (pkt_hook_flow_start_non_pf_array == NULL) {
841 SCFree(pkt_non_pf_array);
842 SCFree(frame_non_pf_array);
843 return -1;
844 }
845 uint32_t pkt_hook_flow_start_non_pf_array_size = 0;
846 SignatureMask pkt_hook_flow_start_mask = 0;
847 bool pkt_hook_flow_start_mask_init = false;
848
849 HashListTable *tx_engines_hash =
850 HashListTableInit(256, TxNonPFHash, TxNonPFCompare, TxNonPFFree);
851 if (tx_engines_hash == NULL) {
852 SCFree(pkt_non_pf_array);
853 SCFree(pkt_hook_flow_start_non_pf_array);
854 SCFree(frame_non_pf_array);
855 return -1;
856 }
857
858 if (de_ctx->non_pf_engine_names == NULL) {
860 HashTableInit(512, NonPFNamesHash, NonPFNamesCompare, NonPFNamesFree);
861 if (de_ctx->non_pf_engine_names == NULL) {
862 SCFree(pkt_non_pf_array);
863 SCFree(pkt_hook_flow_start_non_pf_array);
864 SCFree(frame_non_pf_array);
865 HashListTableFree(tx_engines_hash);
866 return -1;
867 }
868 }
869
870 SignatureMask pkt_mask = 0;
871 bool pkt_mask_init = false;
872#ifdef NONPF_PKT_STATS
873 uint32_t nonpf_pkt_alproto = 0;
874 uint32_t nonpf_pkt_dsize = 0;
875 uint32_t nonpf_pkt_dport = 0;
876#endif
877 const int app_events_list_id = DetectBufferTypeGetByName("app-layer-events");
878 SCLogDebug("app_events_list_id %d", app_events_list_id);
879 const int app_state_list_id = DetectBufferTypeGetByName("app-layer-state");
880 SCLogDebug("app_state_list_id %d", app_state_list_id);
881 for (uint32_t sig = 0; sig < sgh->init->sig_cnt; sig++) {
882 Signature *s = sgh->init->match_array[sig];
883 if (s == NULL)
884 continue;
885 SCLogDebug("checking sid %u for non-prefilter", s->id);
886 if (s->init_data->mpm_sm != NULL && (s->flags & SIG_FLAG_MPM_NEG) == 0)
887 continue;
888 if (s->init_data->prefilter_sm != NULL)
889 continue;
891 continue;
892 SCLogDebug("setting up sid %u for non-prefilter", s->id);
893
894 uint8_t frame_type = 0; /**< only a single type per rule */
895 bool tx_non_pf = false;
896 bool frame_non_pf = false;
897 bool pkt_non_pf = false;
898
901 // TODO code duplication with regular pkt case below
902
903 /* for pkt non prefilter, we have some space in the structure,
904 * so we can squeeze another filter */
905 uint8_t type;
906 uint16_t value;
907 if ((s->flags & SIG_FLAG_DSIZE) && s->dsize_mode == DETECT_UINT_EQ) {
908 SCLogDebug("dsize extra match");
909 type = 2;
910 value = s->dsize_low;
911 } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2) {
912 type = 1;
913 value = s->dp->port;
914 } else {
915 type = 0;
916 value = s->alproto;
917 }
918 pkt_hook_flow_start_non_pf_array[pkt_hook_flow_start_non_pf_array_size].sid = s->iid;
919 pkt_hook_flow_start_non_pf_array[pkt_hook_flow_start_non_pf_array_size].value = value;
920 pkt_hook_flow_start_non_pf_array[pkt_hook_flow_start_non_pf_array_size].type = type;
921 pkt_hook_flow_start_non_pf_array[pkt_hook_flow_start_non_pf_array_size].pkt.sig_mask =
922 s->mask;
923 pkt_hook_flow_start_non_pf_array_size++;
924
925 if (pkt_hook_flow_start_mask_init) {
926 pkt_hook_flow_start_mask &= s->mask;
927 } else {
928 pkt_hook_flow_start_mask = s->mask;
929 pkt_hook_flow_start_mask_init = true;
930 }
931
932 SCLogDebug("flow_start hook");
933 continue; // done for this sig
934 }
935
936 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
937 const int list_id = s->init_data->buffers[x].id;
939 if (buf == NULL)
940 continue;
941 /* for now, exclude app-layer-events, as they are not tied to a specific
942 * progress value like other keywords. */
943 SCLogDebug("list_id %d buf %p", list_id, buf);
944 if (list_id == app_events_list_id)
945 continue;
946 if (buf->packet) {
947 SCLogDebug("packet buf");
948 /* packet is handled below */
949 pkt_non_pf = true;
950 } else if (buf->frame) {
952 f != NULL; f = f->next) {
953 if (!((((s->flags & SIG_FLAG_TOSERVER) != 0 && f->dir == 0) ||
954 ((s->flags & SIG_FLAG_TOCLIENT) != 0 && f->dir == 1)) &&
955 list_id == (int)f->sm_list &&
956 AppProtoEquals(s->alproto, f->alproto)))
957 continue;
958
959 SCLogDebug("frame '%s' type %u", buf->name, f->type);
960 frame_type = f->type;
961 frame_non_pf = true;
962
963 frame_non_pf_array[frame_non_pf_array_size].sid = s->iid;
964 frame_non_pf_array[frame_non_pf_array_size].value = s->alproto;
965 frame_non_pf_array[frame_non_pf_array_size].frame.type = frame_type;
966 frame_non_pf_array_size++;
967 break;
968 }
969
970 } else {
971 SCLogDebug("x %u list_id %d", x, list_id);
973 app != NULL; app = app->next) {
974 SCLogDebug("app %p proto %s list_d %d sig dir %0x", app,
975 AppProtoToString(app->alproto), app->sm_list,
977
978 /* skip if:
979 * - not in our dir
980 * - not our list
981 * - app proto mismatch. Both sig and app can have proto or unknown */
982 if (!((((s->flags & SIG_FLAG_TOSERVER) != 0 && app->dir == 0) ||
983 ((s->flags & SIG_FLAG_TOCLIENT) != 0 && app->dir == 1)) &&
984 list_id == (int)app->sm_list &&
985 (s->alproto == ALPROTO_UNKNOWN || app->alproto == ALPROTO_UNKNOWN ||
986 AppProtoEquals(s->alproto, app->alproto))))
987 continue;
988
989 int sig_list = 0;
990 if (list_id == app_state_list_id)
991 sig_list = app_state_list_id;
992 if (TxNonPFAddSig(de_ctx, tx_engines_hash, app->alproto, app->dir,
993 app->progress, sig_list, buf->name, s) != 0) {
994 goto error;
995 }
996 tx_non_pf = true;
997 }
998 }
999 }
1000 /* handle hook only rules */
1001 if (!tx_non_pf && s->init_data->hook.type == SIGNATURE_HOOK_TYPE_APP) {
1002 const int dir = (s->flags & SIG_FLAG_TOSERVER) ? 0 : 1;
1003 const char *pname = AppLayerParserGetStateNameById(IPPROTO_TCP, // TODO
1005 dir == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT);
1006
1007 if (TxNonPFAddSig(de_ctx, tx_engines_hash, s->alproto, dir,
1009 pname, s) != 0) {
1010 goto error;
1011 }
1012 tx_non_pf = true;
1013 }
1014 /* mark as prefiltered as the sig is now part of a engine */
1015 // s->flags |= SIG_FLAG_PREFILTER;
1016 // TODO doesn't work for sigs that are in multiple sgh's
1017
1018 /* default to pkt if there was no tx or frame match */
1019 if (!(tx_non_pf || frame_non_pf)) {
1020 if (!pkt_non_pf) {
1021 SCLogDebug("not frame, not tx, so pkt");
1022 }
1023 pkt_non_pf = true;
1024 }
1025
1026 SCLogDebug("setting up sid %u for non-prefilter: %s", s->id,
1027 tx_non_pf ? "tx engine" : (frame_non_pf ? "frame engine" : "pkt engine"));
1028
1029 if (pkt_non_pf) {
1030 /* for pkt non prefilter, we have some space in the structure,
1031 * so we can squeeze another filter */
1032 uint8_t type;
1033 uint16_t value;
1034 if ((s->flags & SIG_FLAG_DSIZE) && s->dsize_mode == DETECT_UINT_EQ) {
1035 SCLogDebug("dsize extra match");
1036 type = 2;
1037 value = s->dsize_low;
1038#ifdef NONPF_PKT_STATS
1039 nonpf_pkt_dsize++;
1040#endif
1041 } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2) {
1042 type = 1;
1043 value = s->dp->port;
1044#ifdef NONPF_PKT_STATS
1045 nonpf_pkt_dport++;
1046#endif
1047 } else {
1048 type = 0;
1049 value = s->alproto;
1050#ifdef NONPF_PKT_STATS
1051 nonpf_pkt_alproto++;
1052#endif
1053 }
1054
1055 pkt_non_pf_array[pkt_non_pf_array_size].sid = s->iid;
1056 pkt_non_pf_array[pkt_non_pf_array_size].value = value;
1057 pkt_non_pf_array[pkt_non_pf_array_size].type = type;
1058 pkt_non_pf_array[pkt_non_pf_array_size].pkt.sig_mask = s->mask;
1059 pkt_non_pf_array_size++;
1060
1061 if (pkt_mask_init) {
1062 pkt_mask &= s->mask;
1063 } else {
1064 pkt_mask = s->mask;
1065 pkt_mask_init = true;
1066 }
1067 }
1068 }
1069
1070 /* for each unique sig set, add an engine */
1071 for (HashListTableBucket *b = HashListTableGetListHead(tx_engines_hash); b != NULL;
1072 b = HashListTableGetListNext(b)) {
1074 SCLogDebug("%s engine for %s hook %d has %u non-pf sigs",
1075 t->dir == 0 ? "toserver" : "toclient", AppProtoToString(t->alproto), t->progress,
1076 t->sigs_cnt);
1077
1078 if (((sgh->init->direction & SIG_FLAG_TOSERVER) && t->dir == 1) ||
1079 ((sgh->init->direction & SIG_FLAG_TOCLIENT) && t->dir == 0)) {
1080 SCLogDebug("skipped");
1081 continue;
1082 }
1083
1084 /* register special progress value to indicate we need to run it all the time */
1085 int engine_progress = t->progress;
1086 if (t->sig_list == app_state_list_id) {
1087 SCLogDebug("engine %s for state list", t->engine_name);
1088 engine_progress = -1;
1089 }
1090
1091 struct PrefilterNonPFDataTx *data =
1092 SCCalloc(1, sizeof(*data) + t->sigs_cnt * sizeof(data->array[0]));
1093 if (data == NULL)
1094 goto error;
1095 data->size = t->sigs_cnt;
1096 for (uint32_t i = 0; i < t->sigs_cnt; i++) {
1097 data->array[i] = t->sigs[i].sid;
1098 }
1099 if (PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxNonPF, t->alproto, engine_progress,
1100 (void *)data, PrefilterNonPFDataFree, t->engine_name) < 0) {
1101 SCFree(data);
1102 goto error;
1103 }
1104 }
1105 HashListTableFree(tx_engines_hash);
1106 tx_engines_hash = NULL;
1107
1108 if (pkt_non_pf_array_size) {
1109 struct PrefilterNonPFData *data =
1110 SCCalloc(1, sizeof(*data) + pkt_non_pf_array_size * sizeof(data->array[0]));
1111 if (data == NULL)
1112 goto error;
1113 data->size = pkt_non_pf_array_size;
1114 memcpy((uint8_t *)&data->array, pkt_non_pf_array,
1115 pkt_non_pf_array_size * sizeof(data->array[0]));
1116 enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
1117 if (PrefilterAppendEngine(de_ctx, sgh, PrefilterPktNonPF, pkt_mask, hook, (void *)data,
1118 PrefilterNonPFDataFree, "packet:non_pf") < 0) {
1119 SCFree(data);
1120 goto error;
1121 }
1122 }
1123 if (pkt_hook_flow_start_non_pf_array_size) {
1124 struct PrefilterNonPFData *data = SCCalloc(
1125 1, sizeof(*data) + pkt_hook_flow_start_non_pf_array_size * sizeof(data->array[0]));
1126 if (data == NULL)
1127 goto error;
1128 data->size = pkt_hook_flow_start_non_pf_array_size;
1129 memcpy((uint8_t *)&data->array, pkt_hook_flow_start_non_pf_array,
1130 pkt_hook_flow_start_non_pf_array_size * sizeof(data->array[0]));
1131 SCLogDebug("packet:flow_start:non_pf added with %u rules", data->size);
1134 PrefilterPktNonPFHookFlowStart, // TODO no longer needed to have a dedicated
1135 // callback
1136 pkt_hook_flow_start_mask, hook, (void *)data, PrefilterNonPFDataFree,
1137 "packet:flow_start:non_pf") < 0) {
1138 SCFree(data);
1139 goto error;
1140 }
1141 }
1142 if (frame_non_pf_array_size) {
1143 SCLogDebug("%u frame non-pf sigs", frame_non_pf_array_size);
1144 struct PrefilterNonPFData *data =
1145 SCCalloc(1, sizeof(*data) + frame_non_pf_array_size * sizeof(data->array[0]));
1146 if (data == NULL)
1147 goto error;
1148 data->size = frame_non_pf_array_size;
1149 memcpy((uint8_t *)&data->array, frame_non_pf_array,
1150 frame_non_pf_array_size * sizeof(data->array[0]));
1151 if (PrefilterAppendFrameEngine(de_ctx, sgh, PrefilterFrameNonPF, ALPROTO_UNKNOWN,
1152 FRAME_ANY_TYPE, (void *)data, PrefilterNonPFDataFree, "frame:non_pf") < 0) {
1153 SCFree(data);
1154 goto error;
1155 }
1156 }
1157
1158 SCFree(pkt_hook_flow_start_non_pf_array);
1159 pkt_hook_flow_start_non_pf_array = NULL;
1160 SCFree(pkt_non_pf_array);
1161 pkt_non_pf_array = NULL;
1162 SCFree(frame_non_pf_array);
1163 frame_non_pf_array = NULL;
1164 return 0;
1165
1166error:
1167 if (tx_engines_hash) {
1168 HashListTableFree(tx_engines_hash);
1169 }
1170 SCFree(pkt_hook_flow_start_non_pf_array);
1171 SCFree(pkt_non_pf_array);
1172 SCFree(frame_non_pf_array);
1173 return -1;
1174}
1175
1177{
1178 int r = PatternMatchPrepareGroup(de_ctx, sgh);
1179 if (r != 0) {
1180 FatalError("failed to set up pattern matching");
1181 }
1182
1183 /* set up engines if needed - when prefilter is set to auto we run
1184 * all engines, otherwise only those that have been forced by the
1185 * prefilter keyword. */
1187 for (int i = 0; i < DETECT_TBLSIZE; i++) {
1188 if (sigmatch_table[i].SetupPrefilter != NULL &&
1189 (setting == DETECT_PREFILTER_AUTO || de_ctx->sm_types_prefilter[i])) {
1191 }
1192 }
1193
1194 if (SetupNonPrefilter(de_ctx, sgh) != 0) {
1195 return -1;
1196 }
1197
1198 /* we have lists of engines in sgh->init now. Lets setup the
1199 * match arrays */
1201 if (sgh->init->pkt_engines != NULL) {
1202 uint32_t cnt = 0;
1203 for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
1204 cnt++;
1205 }
1207 if (sgh->pkt_engines == NULL) {
1208 return -1;
1209 }
1210 memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
1211
1212 PrefilterEngine *e = sgh->pkt_engines;
1213 for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
1214 e->local_id = el->id;
1215 e->cb.Prefilter = el->Prefilter;
1216 e->ctx.pkt.mask = el->pkt_mask;
1217 // TODO right now we represent the hook in a u8 in the prefilter engine for space
1218 // reasons.
1219 BUG_ON(el->pkt_hook >= 8);
1220 e->ctx.pkt.hook = (uint8_t)el->pkt_hook;
1221 e->pectx = el->pectx;
1222 el->pectx = NULL; // e now owns the ctx
1223 e->gid = el->gid;
1224 if (el->next == NULL) {
1225 e->is_last = true;
1226 }
1227 e++;
1228 }
1229 }
1230 if (sgh->init->payload_engines != NULL) {
1231 uint32_t cnt = 0;
1232 for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
1233 cnt++;
1234 }
1236 if (sgh->payload_engines == NULL) {
1237 return -1;
1238 }
1239 memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
1240
1242 for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
1243 e->local_id = el->id;
1244 e->cb.Prefilter = el->Prefilter;
1245 e->ctx.pkt.mask = el->pkt_mask;
1246 // TODO right now we represent the hook in a u8 in the prefilter engine for space
1247 // reasons.
1248 BUG_ON(el->pkt_hook >= 8);
1249 e->ctx.pkt.hook = (uint8_t)el->pkt_hook;
1250 e->pectx = el->pectx;
1251 el->pectx = NULL; // e now owns the ctx
1252 e->gid = el->gid;
1253 if (el->next == NULL) {
1254 e->is_last = true;
1255 }
1256 e++;
1257 }
1258 }
1259 if (sgh->init->tx_engines != NULL) {
1260 uint32_t cnt = 0;
1261 for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
1262 cnt++;
1263 }
1265 if (sgh->tx_engines == NULL) {
1266 return -1;
1267 }
1268 memset(sgh->tx_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
1269
1270 uint16_t local_id = 0;
1271 PrefilterEngine *e = sgh->tx_engines;
1272 for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
1273 e->local_id = local_id++;
1274 e->alproto = el->alproto;
1276 e->cb.PrefilterTx = el->PrefilterTx;
1277 e->pectx = el->pectx;
1278 el->pectx = NULL; // e now owns the ctx
1279 e->gid = el->gid;
1280 e++;
1281 }
1282
1283 /* sort by tx_min_progress, then alproto, then local_id */
1284 qsort(sgh->tx_engines, local_id, sizeof(PrefilterEngine),
1285 PrefilterSetupRuleGroupSortHelper);
1286 sgh->tx_engines[local_id - 1].is_last = true;
1287 sgh->tx_engines[local_id - 1].is_last_for_progress = true;
1288
1289 PrefilterEngine *engine;
1290
1291 /* per alproto to set is_last_for_progress per alproto because the inspect
1292 * loop skips over engines that are not the correct alproto */
1293 for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1294 int last_tx_progress = 0;
1295 bool last_tx_progress_set = false;
1296 PrefilterEngine *prev_engine = NULL;
1297 engine = sgh->tx_engines;
1298 do {
1299 if (engine->ctx.tx_min_progress != -1)
1300 BUG_ON(engine->ctx.tx_min_progress < last_tx_progress);
1301 if (engine->alproto == a) {
1302 if (last_tx_progress_set && engine->ctx.tx_min_progress > last_tx_progress) {
1303 if (prev_engine) {
1304 prev_engine->is_last_for_progress = true;
1305 }
1306 }
1307
1308 last_tx_progress_set = true;
1309 prev_engine = engine;
1310 } else {
1311 if (prev_engine) {
1312 prev_engine->is_last_for_progress = true;
1313 }
1314 }
1315 last_tx_progress = engine->ctx.tx_min_progress;
1316 if (engine->is_last)
1317 break;
1318 engine++;
1319 } while (1);
1320 }
1321#ifdef DEBUG
1322 SCLogDebug("sgh %p", sgh);
1323 engine = sgh->tx_engines;
1324 do {
1325 SCLogDebug("engine: gid %u alproto %s tx_min_progress %d is_last %s "
1326 "is_last_for_progress %s",
1327 engine->gid, AppProtoToString(engine->alproto), engine->ctx.tx_min_progress,
1328 engine->is_last ? "true" : "false",
1329 engine->is_last_for_progress ? "true" : "false");
1330 if (engine->is_last)
1331 break;
1332 engine++;
1333 } while (1);
1334#endif
1335 }
1336 if (sgh->init->frame_engines != NULL) {
1337 uint32_t cnt = 0;
1338 for (el = sgh->init->frame_engines; el != NULL; el = el->next) {
1339 cnt++;
1340 }
1342 if (sgh->frame_engines == NULL) {
1343 return -1;
1344 }
1345 memset(sgh->frame_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
1346
1348 for (el = sgh->init->frame_engines; el != NULL; el = el->next) {
1349 e->local_id = el->id;
1350 e->ctx.frame_type = el->frame_type;
1352 e->alproto = el->alproto;
1353 e->pectx = el->pectx;
1354 el->pectx = NULL; // e now owns the ctx
1355 e->gid = el->gid;
1356 if (el->next == NULL) {
1357 e->is_last = true;
1358 }
1359 e++;
1360 }
1361 }
1362
1363 if (sgh->init->post_rule_match_engines != NULL) {
1364 uint32_t cnt = 0;
1365 for (el = sgh->init->post_rule_match_engines; el != NULL; el = el->next) {
1366 cnt++;
1367 }
1369 if (sgh->post_rule_match_engines == NULL) {
1370 return -1;
1371 }
1372 memset(sgh->post_rule_match_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
1373
1374 uint16_t local_id = 0;
1376 for (el = sgh->init->post_rule_match_engines; el != NULL; el = el->next) {
1377 e->local_id = local_id++;
1379 e->pectx = el->pectx;
1380 el->pectx = NULL; // e now owns the ctx
1381 e->gid = el->gid;
1382 e->is_last = (el->next == NULL);
1383 e++;
1384 }
1385 SCLogDebug("sgh %p max local_id %u", sgh, local_id);
1386 }
1387
1388 return 0;
1389}
1390
1391/* hash table for assigning a unique id to each engine type. */
1392
1393static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
1394{
1395 PrefilterStore *ctx = data;
1396
1397 uint32_t hash = (uint32_t)strlen(ctx->name);
1398
1399 for (size_t u = 0; u < strlen(ctx->name); u++) {
1400 hash += ctx->name[u];
1401 }
1402
1403 hash %= ht->array_size;
1404 return hash;
1405}
1406
1407static char PrefilterStoreCompareFunc(void *data1, uint16_t len1,
1408 void *data2, uint16_t len2)
1409{
1410 PrefilterStore *ctx1 = data1;
1411 PrefilterStore *ctx2 = data2;
1412 return (strcmp(ctx1->name, ctx2->name) == 0);
1413}
1414
1415static void PrefilterStoreFreeFunc(void *ptr)
1416{
1417 SCFree(ptr);
1418}
1419
1426
1428{
1430
1432 PrefilterStoreHashFunc,
1433 PrefilterStoreCompareFunc,
1434 PrefilterStoreFreeFunc);
1436}
1437
1438static int PrefilterStoreGetId(DetectEngineCtx *de_ctx,
1439 const char *name, void (*FreeFunc)(void *))
1440{
1441 PrefilterStore ctx = { name, FreeFunc, 0 };
1442
1444
1445 SCLogDebug("looking up %s", name);
1446
1448 if (rctx != NULL) {
1449 return rctx->id;
1450 }
1451
1452 PrefilterStore *actx = SCCalloc(1, sizeof(*actx));
1453 if (actx == NULL) {
1454 return -1;
1455 }
1456
1457 actx->name = name;
1458 actx->FreeFunc = FreeFunc;
1459 actx->id = de_ctx->prefilter_id++;
1460 SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id);
1461
1462 int ret = HashListTableAdd(de_ctx->prefilter_hash_table, actx, 0);
1463 if (ret != 0) {
1464 SCFree(actx);
1465 return -1;
1466 }
1467
1468 int r = actx->id;
1469 return r;
1470}
1471
1472/** \warning slow */
1473static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx,
1474 const uint32_t id)
1475{
1476
1477 const PrefilterStore *store = NULL;
1478 if (de_ctx->prefilter_hash_table != NULL) {
1480 for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
1482 if (ctx->id == id) {
1483 store = ctx;
1484 break;
1485 }
1486 }
1487 }
1488 return store;
1489}
1490
1491#ifdef PROFILING
1492const char *PrefilterStoreGetName(const uint32_t id)
1493{
1494 return NULL;
1495}
1496#endif
1497
1498#include "util-print.h"
1499
1509
1510/** \brief Generic Mpm prefilter callback for simple InspectionSingleBufferGetDataPtr
1511 *
1512 * \param det_ctx detection engine thread ctx
1513 * \param p packet to inspect
1514 * \param f flow to inspect
1515 * \param txv tx to inspect
1516 * \param pectx inspection context
1517 */
1518static void PrefilterMpmTxSingle(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
1519 Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
1520{
1521 SCEnter();
1522
1523 const PrefilterMpmCtx *ctx = (const PrefilterMpmCtx *)pectx;
1524 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
1525 SCLogDebug("running on list %d", ctx->list_id);
1526
1528 det_ctx, ctx->transforms, f, flags, txv, ctx->list_id, ctx->GetDataSingle);
1529 if (buffer == NULL)
1530 return;
1531
1532 const uint32_t data_len = buffer->inspect_len;
1533 const uint8_t *data = buffer->inspect;
1534
1535 SCLogDebug("mpm'ing buffer:");
1536 // PrintRawDataFp(stdout, data, data_len);
1537
1538 if (data != NULL && data_len >= mpm_ctx->minlen) {
1539 (void)mpm_table[mpm_ctx->mpm_type].Search(
1540 mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
1541 PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
1542 }
1543}
1544
1545/** \brief Generic Mpm prefilter callback
1546 *
1547 * \param det_ctx detection engine thread ctx
1548 * \param p packet to inspect
1549 * \param f flow to inspect
1550 * \param txv tx to inspect
1551 * \param pectx inspection context
1552 */
1553static void PrefilterMpm(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,
1554 void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
1555{
1556 SCEnter();
1557
1558 const PrefilterMpmCtx *ctx = (const PrefilterMpmCtx *)pectx;
1559 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
1560 SCLogDebug("running on list %d", ctx->list_id);
1561
1562 InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms, f, flags, txv, ctx->list_id);
1563 if (buffer == NULL)
1564 return;
1565
1566 const uint32_t data_len = buffer->inspect_len;
1567 const uint8_t *data = buffer->inspect;
1568
1569 SCLogDebug("mpm'ing buffer:");
1570 //PrintRawDataFp(stdout, data, data_len);
1571
1572 if (data != NULL && data_len >= mpm_ctx->minlen) {
1573 (void)mpm_table[mpm_ctx->mpm_type].Search(
1574 mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
1575 PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
1576 }
1577}
1578
1579static void PrefilterGenericMpmFree(void *ptr)
1580{
1581 SCFree(ptr);
1582}
1583
1585 const DetectBufferMpmRegistry *mpm_reg, int list_id)
1586{
1587 SCEnter();
1588 PrefilterMpmCtx *pectx = SCCalloc(1, sizeof(*pectx));
1589 if (pectx == NULL)
1590 return -1;
1591 pectx->list_id = list_id;
1592 pectx->GetData = mpm_reg->app_v2.GetData;
1593 pectx->mpm_ctx = mpm_ctx;
1594 pectx->transforms = &mpm_reg->transforms;
1595
1597 mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
1598 pectx, PrefilterGenericMpmFree, mpm_reg->pname);
1599 if (r != 0) {
1600 SCFree(pectx);
1601 }
1602 return r;
1603}
1604
1606 const DetectBufferMpmRegistry *mpm_reg, int list_id)
1607{
1608 SCEnter();
1609 PrefilterMpmCtx *pectx = SCCalloc(1, sizeof(*pectx));
1610 if (pectx == NULL)
1611 return -1;
1612 pectx->list_id = list_id;
1613 pectx->GetDataSingle = mpm_reg->app_v2.GetDataSingle;
1614 pectx->mpm_ctx = mpm_ctx;
1615 pectx->transforms = &mpm_reg->transforms;
1616
1617 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmTxSingle, mpm_reg->app_v2.alproto,
1618 mpm_reg->app_v2.tx_min_progress, pectx, PrefilterGenericMpmFree, mpm_reg->pname);
1619 if (r != 0) {
1620 SCFree(pectx);
1621 }
1622 return r;
1623}
1624
1625static void PrefilterMultiGenericMpmFree(void *ptr)
1626{
1627 // PrefilterMpmListId
1628 SCFree(ptr);
1629}
1630
1631static void PrefilterMultiMpm(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,
1632 void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
1633{
1634 SCEnter();
1635
1636 const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx;
1637 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
1638 SCLogDebug("running on list %d", ctx->list_id);
1639 uint32_t local_id = 0;
1640
1641 do {
1642 // loop until we get a NULL
1644 det_ctx, ctx->transforms, f, flags, txv, ctx->list_id, local_id, ctx->GetData);
1645 if (buffer == NULL)
1646 break;
1647
1648 if (buffer->inspect_len >= mpm_ctx->minlen) {
1649 (void)mpm_table[mpm_ctx->mpm_type].Search(
1650 mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len);
1652 }
1653
1654 local_id++;
1655 } while (1);
1656}
1657
1659 const DetectBufferMpmRegistry *mpm_reg, int list_id)
1660{
1661 SCEnter();
1662 PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx));
1663 if (pectx == NULL)
1664 return -1;
1665 pectx->list_id = list_id;
1666 pectx->GetData = mpm_reg->app_v2.GetMultiData;
1667 pectx->mpm_ctx = mpm_ctx;
1668 pectx->transforms = &mpm_reg->transforms;
1669
1670 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMultiMpm, mpm_reg->app_v2.alproto,
1671 mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMultiGenericMpmFree, mpm_reg->pname);
1672 if (r != 0) {
1673 SCFree(pectx);
1674 }
1675 return r;
1676}
1677
1678/* generic mpm for pkt engines */
1679
1686
1687/** \brief Generic Mpm prefilter callback
1688 *
1689 * \param det_ctx detection engine thread ctx
1690 * \param p packet to inspect
1691 * \param f flow to inspect
1692 * \param txv tx to inspect
1693 * \param pectx inspection context
1694 */
1695static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx,
1696 Packet *p, const void *pectx)
1697{
1698 SCEnter();
1699
1700 const PrefilterMpmPktCtx *ctx = (const PrefilterMpmPktCtx *)pectx;
1701 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
1702 SCLogDebug("running on list %d", ctx->list_id);
1703
1704 InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms,
1705 p, ctx->list_id);
1706 if (buffer == NULL)
1707 return;
1708
1709 const uint32_t data_len = buffer->inspect_len;
1710 const uint8_t *data = buffer->inspect;
1711
1712 SCLogDebug("mpm'ing buffer:");
1713 //PrintRawDataFp(stdout, data, data_len);
1714
1715 if (data != NULL && data_len >= mpm_ctx->minlen) {
1716 (void)mpm_table[mpm_ctx->mpm_type].Search(
1717 mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
1718 PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
1719 }
1720}
1721
1722static void PrefilterMpmPktFree(void *ptr)
1723{
1724 SCFree(ptr);
1725}
1726
1728 const DetectBufferMpmRegistry *mpm_reg, int list_id)
1729{
1730 SCEnter();
1731 PrefilterMpmPktCtx *pectx = SCCalloc(1, sizeof(*pectx));
1732 if (pectx == NULL)
1733 return -1;
1734 pectx->list_id = list_id;
1735 pectx->GetData = mpm_reg->pkt_v1.GetData;
1736 pectx->mpm_ctx = mpm_ctx;
1737 pectx->transforms = &mpm_reg->transforms;
1738
1739 enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
1740 int r = PrefilterAppendEngine(
1741 de_ctx, sgh, PrefilterMpmPkt, 0, hook, pectx, PrefilterMpmPktFree, mpm_reg->pname);
1742 if (r != 0) {
1743 SCFree(pectx);
1744 }
1745 return r;
1746}
1747
1748#define QUEUE_STEP 16
1749
1751 DetectEngineThreadCtx *det_ctx, const Signature *s, const int type, const uint32_t value)
1752{
1753 if (det_ctx->post_rule_work_queue.q == NULL) {
1754 det_ctx->post_rule_work_queue.q =
1756 if (det_ctx->post_rule_work_queue.q == NULL) {
1758 return;
1759 }
1761 } else if (det_ctx->post_rule_work_queue.len == det_ctx->post_rule_work_queue.size) {
1762 void *ptr = SCRealloc(
1765 if (ptr == NULL) {
1767 return;
1768 }
1769 det_ctx->post_rule_work_queue.q = ptr;
1771 }
1773 det_ctx->post_rule_work_queue.q[det_ctx->post_rule_work_queue.len].value = value;
1774#ifdef DEBUG
1775 det_ctx->post_rule_work_queue.q[det_ctx->post_rule_work_queue.len].id = s->iid;
1776#endif
1777 det_ctx->post_rule_work_queue.len++;
1778 SCLogDebug("det_ctx->post_rule_work_queue.len %u", det_ctx->post_rule_work_queue.len);
1779}
#define FRAME_ANY_TYPE
struct HtpBodyChunk_ * next
const char * AppLayerParserGetStateNameById(uint8_t ipproto, AppProto alproto, const int id, const uint8_t direction)
struct AppLayerTxData AppLayerTxData
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
uint16_t AppProto
@ ALPROTO_FAILED
@ ALPROTO_UNKNOWN
uint8_t flags
Definition decode-gre.h:0
uint16_t type
#define SignatureMask
Definition decode.h:99
#define PKT_NOPAYLOAD_INSPECTION
Definition decode.h:1252
#define PKT_DETECT_HAS_STREAMDATA
Definition decode.h:1305
bool(* InspectionSingleBufferGetDataPtr)(const void *txv, const uint8_t flow_flags, const uint8_t **buf, uint32_t *buf_len)
InspectionBuffer *(* InspectionBufferGetDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id)
int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
Prepare the pattern matcher ctx in a sig group head.
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
#define NONPF_PKT_STATS_INCR(s)
int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
void PrefilterPostRuleMatch(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f)
invoke post-rule match "prefilter" engines
const char * PrefilterStoreGetName(const uint32_t id)
void PostRuleMatchWorkQueueAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, const int type, const uint32_t value)
void PrefilterPktNonPFStatsDump(void)
int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, SignatureMask mask, enum SignatureHookPkt hook, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
void PrefilterDeinit(DetectEngineCtx *de_ctx)
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterTxFn PrefilterTxFunc, AppProto alproto, int tx_min_progress, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t ipproto, const uint8_t flow_flags, const AppProto alproto, void *alstate, DetectTransaction *tx)
run prefilter engines on a transaction
int PrefilterMultiGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
#define QUEUE_STEP
void PrefilterInit(DetectEngineCtx *de_ctx)
int PrefilterAppendPostRuleEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void(*PrefilterPostRuleFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f), void *pectx, void(*FreeFunc)(void *pectx), const char *name)
int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags, const SignatureMask mask)
void PrefilterFreeEnginesList(PrefilterEngineList *list)
int PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
int PrefilterSingleMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
int DETECT_TBLSIZE
#define DETECT_UINT_EQ
InspectionBuffer * DetectGetSingleData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, InspectionSingleBufferGetDataPtr GetBuf)
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
int DetectBufferTypeGetByName(const char *name)
InspectionBuffer * DetectGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, uint32_t index, InspectionMultiBufferGetDataPtr GetBuf)
#define DetectEngineGetMaxSigId(de_ctx)
SigTableElmt * sigmatch_table
void * DetectGetInnerTx(void *tx_ptr, AppProto alproto, AppProto engine_alproto, uint8_t flow_flags)
Definition detect.c:1153
SignatureHookPkt
Definition detect.h:538
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition detect.h:539
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition detect.h:540
DetectEnginePrefilterSetting
Definition detect.h:895
@ DETECT_PREFILTER_AUTO
Definition detect.h:897
#define SIG_FLAG_TOCLIENT
Definition detect.h:272
InspectionBuffer *(* InspectionBufferGetPktDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Packet *p, const int list_id)
Definition detect.h:478
void(* PrefilterFrameFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, const struct Frames *frames, const struct Frame *frame)
Definition detect.h:1522
#define SIG_FLAG_TOSERVER
Definition detect.h:271
#define SIG_FLAG_PREFILTER
Definition detect.h:278
@ DETECT_EVENT_POST_MATCH_QUEUE_FAILED
Definition detect.h:1485
#define SIG_FLAG_MPM_NEG
Definition detect.h:257
void(* PrefilterTxFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t tx_id, const AppLayerTxData *tx_data, const uint8_t flags)
Definition detect.h:1526
void(* PrefilterPktFn)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
Definition detect.h:1521
#define SIG_FLAG_DSIZE
Definition detect.h:248
@ SIGNATURE_HOOK_TYPE_PKT
Definition detect.h:548
@ SIGNATURE_HOOK_TYPE_APP
Definition detect.h:549
#define FLOW_PKT_TOCLIENT_FIRST
Definition flow.h:237
#define FLOW_PKT_TOSERVER_FIRST
Definition flow.h:236
DetectEngineCtx * de_ctx
struct Thresholds ctx
one time registration of keywords at start up
Definition detect.h:762
InspectionMultiBufferGetDataPtr GetMultiData
Definition detect.h:783
InspectionBufferGetDataPtr GetData
Definition detect.h:781
struct DetectBufferMpmRegistry_::@98::@101 pkt_v1
DetectEngineTransforms transforms
Definition detect.h:775
struct DetectBufferMpmRegistry_::@98::@100 app_v2
InspectionSingleBufferGetDataPtr GetDataSingle
Definition detect.h:782
char name[64]
Definition detect.h:450
main detection engine ctx
Definition detect.h:932
DetectEngineFrameInspectionEngine * frame_inspect_engines
Definition detect.h:1091
HashListTable * prefilter_hash_table
Definition detect.h:1096
enum DetectEnginePrefilterSetting prefilter_setting
Definition detect.h:1064
uint32_t prefilter_id
Definition detect.h:1095
bool * sm_types_prefilter
Definition detect.h:1111
DetectEngineAppInspectionEngine * app_inspect_engines
Definition detect.h:1087
HashTable * non_pf_engine_names
Definition detect.h:1142
MpmThreadCtx mtc
Definition detect.h:1345
PostRuleMatchWorkQueue post_rule_work_queue
Definition detect.h:1347
PrefilterRuleStore pmq
Definition detect.h:1349
uint16_t port
Definition detect.h:221
uint16_t port2
Definition detect.h:222
struct DetectPort_ * next
Definition detect.h:234
struct AppLayerTxData * tx_data_ptr
Flow data structure.
Definition flow.h:356
AppProto alproto
application level protocol
Definition flow.h:450
AppLayerParserState * alparser
Definition flow.h:478
struct Flow_ * next
Definition flow.h:396
uint8_t type
Definition flow.h:363
uint32_t array_size
uint32_t array_size
Definition util-hash.h:37
uint8_t mpm_type
Definition util-mpm.h:95
uint16_t minlen
Definition util-mpm.h:104
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition util-mpm.h:178
uint8_t flowflags
Definition decode.h:532
uint64_t pcap_cnt
Definition decode.h:626
SignatureMask sig_mask
Definition decode.h:538
struct Flow_ * flow
Definition decode.h:546
uint16_t pkt_hooks
Definition decode.h:541
uint16_t payload_len
Definition decode.h:606
uint32_t flags
Definition decode.h:544
uint8_t proto
Definition decode.h:523
Port dp
Definition decode.h:516
PostRuleMatchWorkQueueItem * q
Definition detect.h:1226
PrefilterTxFn PrefilterTx
Definition detect.h:1549
enum SignatureHookPkt pkt_hook
Definition detect.h:1542
PrefilterFrameFn PrefilterFrame
Definition detect.h:1550
PrefilterPktFn Prefilter
Definition detect.h:1548
SignatureMask pkt_mask
Definition detect.h:1540
struct PrefilterEngineList_ * next
Definition detect.h:1554
void(* PrefilterPostRule)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f)
Definition detect.h:1551
const char * name
Definition detect.h:1559
void(* Free)(void *pectx)
Definition detect.h:1557
SignatureMask mask
Definition detect.h:1572
union PrefilterEngine_::@113 cb
PrefilterTxFn PrefilterTx
Definition detect.h:1590
int8_t tx_min_progress
Definition detect.h:1577
uint16_t local_id
Definition detect.h:1565
AppProto alproto
Definition detect.h:1568
bool is_last_for_progress
Definition detect.h:1582
union PrefilterEngine_::@112 ctx
uint8_t frame_type
Definition detect.h:1578
void(* PrefilterPostRule)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f)
Definition detect.h:1592
PrefilterFrameFn PrefilterFrame
Definition detect.h:1591
struct PrefilterEngine_::@112::@114 pkt
uint32_t gid
Definition detect.h:1597
PrefilterPktFn Prefilter
Definition detect.h:1589
InspectionSingleBufferGetDataPtr GetDataSingle
InspectionBufferGetDataPtr GetData
const DetectEngineTransforms * transforms
InspectionMultiBufferGetDataPtr GetData
const DetectEngineTransforms * transforms
const DetectEngineTransforms * transforms
InspectionBufferGetPktDataPtr GetData
struct PrefilterNonPFDataSig::@62::@65 frame
struct PrefilterNonPFDataSig::@62::@66 app
struct PrefilterNonPFDataSig::@62::@64 pkt
struct PrefilterNonPFDataSig array[]
Signature ** match_array
Definition detect.h:1625
PrefilterEngineList * frame_engines
Definition detect.h:1618
PrefilterEngineList * post_rule_match_engines
Definition detect.h:1619
PrefilterEngineList * pkt_engines
Definition detect.h:1615
PrefilterEngineList * tx_engines
Definition detect.h:1617
PrefilterEngineList * payload_engines
Definition detect.h:1616
Container for matching data for a signature group.
Definition detect.h:1629
PrefilterEngine * payload_engines
Definition detect.h:1640
SigGroupHeadInitData * init
Definition detect.h:1646
PrefilterEngine * frame_engines
Definition detect.h:1642
PrefilterEngine * tx_engines
Definition detect.h:1641
PrefilterEngine * post_rule_match_engines
Definition detect.h:1643
PrefilterEngine * pkt_engines
Definition detect.h:1639
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition detect.h:1444
struct SignatureHook_::@95::@97 pkt
union SignatureHook_::@95 t
enum SignatureHookPkt ph
Definition detect.h:582
struct SignatureHook_::@95::@96 app
int app_progress
Definition detect.h:579
enum SignatureHookType type
Definition detect.h:572
SigMatch * mpm_sm
Definition detect.h:623
SigMatch * prefilter_sm
Definition detect.h:625
SignatureInitDataBuffer * buffers
Definition detect.h:647
uint32_t buffer_index
Definition detect.h:648
SignatureHook hook
Definition detect.h:590
Signature container.
Definition detect.h:668
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
uint8_t dsize_mode
Definition detect.h:677
DetectPort * dp
Definition detect.h:719
SignatureMask mask
Definition detect.h:679
uint32_t id
Definition detect.h:713
uint16_t dsize_low
Definition detect.h:675
struct PrefilterNonPFDataSig * sigs
@ PROF_DETECT_PF_SORT1
@ PROF_DETECT_PF_RECORD
@ PROF_DETECT_PF_PAYLOAD
@ PROF_DETECT_PF_PKT
#define BUG_ON(x)
#define SigIntId
#define str(s)
#define CLS
#define BIT_U16(n)
const char * name
uint32_t cnt
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturn
Definition util-debug.h:279
char StringHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
uint32_t StringHashDjb2(const uint8_t *data, uint32_t datalen)
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition util-hash.c:104
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition util-hash.c:35
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashListTableFree(HashListTable *ht)
#define HashListTableGetListData(hb)
#define HashListTableGetListNext(hb)
#define SCFreeAligned(p)
Definition util-mem.h:77
#define SCFree(p)
Definition util-mem.h:61
#define SCMallocAligned(size, align)
Definition util-mem.h:68
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition util-mpm.c:47
#define likely(expr)
#define PREFILTER_PROFILING_END(ctx, profile_id)
#define PACKET_PROFILING_DETECT_START(p, id)
#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes)
#define PREFILTER_PROFILING_START(det_ctx)
#define PACKET_PROFILING_DETECT_END(p, id)
#define DEBUG_VALIDATE_BUG_ON(exp)