suricata
detect.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 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Basic detection engine
24  */
25 
26 #include "suricata-common.h"
27 #include "suricata.h"
28 
29 #include "decode.h"
30 #include "packet.h"
31 #include "flow.h"
32 #include "stream-tcp.h"
33 #include "app-layer.h"
34 #include "app-layer-parser.h"
35 #include "app-layer-frames.h"
36 
37 #include "detect.h"
38 #include "detect-dsize.h"
39 #include "detect-engine.h"
40 #include "detect-engine-build.h"
41 #include "detect-engine-frame.h"
42 #include "detect-engine-profile.h"
43 
44 #include "detect-engine-alert.h"
45 #include "detect-engine-siggroup.h"
46 #include "detect-engine-address.h"
47 #include "detect-engine-proto.h"
48 #include "detect-engine-port.h"
49 #include "detect-engine-mpm.h"
50 #include "detect-engine-iponly.h"
53 #include "detect-engine-state.h"
54 #include "detect-engine-analyzer.h"
55 
56 #include "detect-engine-payload.h"
57 #include "detect-engine-event.h"
58 
59 #include "detect-filestore.h"
60 #include "detect-flowvar.h"
61 #include "detect-replace.h"
62 
63 #include "util-validate.h"
64 #include "util-detect.h"
65 #include "util-profiling.h"
66 
67 #include "action-globals.h"
68 
69 typedef struct DetectRunScratchpad {
71  const uint8_t flow_flags; /* flow/state flags: STREAM_* */
72  const bool app_decoder_events;
73  const SigGroupHead *sgh;
75 
76 /* prototypes */
77 static DetectRunScratchpad DetectRunSetup(const DetectEngineCtx *de_ctx,
78  DetectEngineThreadCtx *det_ctx, Packet * const p, Flow * const pflow);
79 static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx,
80  DetectEngineThreadCtx *det_ctx, Flow * const pflow, Packet * const p);
81 static inline void DetectRunGetRuleGroup(const DetectEngineCtx *de_ctx,
82  Packet * const p, Flow * const pflow, DetectRunScratchpad *scratch);
83 static inline void DetectRunPrefilterPkt(ThreadVars *tv,
85  DetectRunScratchpad *scratch);
86 static inline uint8_t DetectRulePacketRules(ThreadVars *const tv, DetectEngineCtx *const de_ctx,
87  DetectEngineThreadCtx *const det_ctx, Packet *const p, Flow *const pflow,
88  const DetectRunScratchpad *scratch);
89 static void DetectRunTx(ThreadVars *tv, DetectEngineCtx *de_ctx,
90  DetectEngineThreadCtx *det_ctx, Packet *p,
91  Flow *f, DetectRunScratchpad *scratch);
92 static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
93  Packet *p, Flow *f, DetectRunScratchpad *scratch);
94 static inline void DetectRunPostRules(ThreadVars *tv, DetectEngineCtx *de_ctx,
95  DetectEngineThreadCtx *det_ctx, Packet * const p, Flow * const pflow,
96  DetectRunScratchpad *scratch);
97 static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx,
98  Packet *p, Flow * const pflow);
99 static inline void DetectRunAppendDefaultAccept(DetectEngineThreadCtx *det_ctx, Packet *p);
100 
101 /** \internal
102  */
103 static void DetectRun(ThreadVars *th_v,
105  Packet *p)
106 {
107  SCEnter();
108  SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
109  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
110  : "noflow",
111  PktSrcToString(p->pkt_src));
112 
113  /* Load the Packet's flow early, even though it might not be needed.
114  * Mark as a constant pointer, although the flow itself can change. */
115  Flow * const pflow = p->flow;
116 
117  DetectRunScratchpad scratch = DetectRunSetup(de_ctx, det_ctx, p, pflow);
118 
119  /* run the IPonly engine */
120  DetectRunInspectIPOnly(th_v, de_ctx, det_ctx, pflow, p);
121 
122  /* get our rule group */
123  DetectRunGetRuleGroup(de_ctx, p, pflow, &scratch);
124  /* if we didn't get a sig group head, we
125  * have nothing to do.... */
126  if (scratch.sgh == NULL) {
127  SCLogDebug("no sgh for this packet, nothing to match against");
128  goto end;
129  }
130 
131  /* run the prefilters for packets */
132  DetectRunPrefilterPkt(th_v, de_ctx, det_ctx, p, &scratch);
133 
135  /* inspect the rules against the packet */
136  const uint8_t pkt_policy = DetectRulePacketRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
138 
139  /* Only FW rules will already have set the action, IDS rules go through PacketAlertFinalize
140  *
141  * If rules told us to drop or accept:packet/accept:flow, we skip app_filter and app_td.
142  *
143  * accept:hook won't have set the pkt_policy, so we simply continue.
144  *
145  * TODO what about app state progression, cleanup and such? */
146  if (pkt_policy & (ACTION_DROP | ACTION_ACCEPT)) {
147  goto end;
148  }
149 
150  /* run tx/state inspection. Don't call for ICMP error msgs. */
151  if (pflow && pflow->alstate && likely(pflow->proto == p->proto)) {
152  if (p->proto == IPPROTO_TCP) {
153  if ((p->flags & PKT_STREAM_EST) == 0) {
154  SCLogDebug("packet %" PRIu64 ": skip tcp non-established", p->pcap_cnt);
155  DetectRunAppendDefaultAccept(det_ctx, p);
156  goto end;
157  }
158  const TcpSession *ssn = p->flow->protoctx;
159  bool setting_nopayload = p->flow->alparser &&
163  // we may be right after disabling app-layer (ssh)
164  if (ssn &&
165  ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0 || setting_nopayload)) {
166  // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_TX);
167  DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch);
168  // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_TX);
169  }
170  // no update to transactions
171  if (!PKT_IS_PSEUDOPKT(p) && p->app_update_direction == 0 &&
172  ((PKT_IS_TOSERVER(p) && (p->flow->flags & FLOW_TS_APP_UPDATED) == 0) ||
173  (PKT_IS_TOCLIENT(p) && (p->flow->flags & FLOW_TC_APP_UPDATED) == 0))) {
174  SCLogDebug("packet %" PRIu64 ": no app-layer update", p->pcap_cnt);
175  DetectRunAppendDefaultAccept(det_ctx, p);
176  goto end;
177  }
178  } else if (p->proto == IPPROTO_UDP) {
179  DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch);
180  }
181 
183  DetectRunTx(th_v, de_ctx, det_ctx, p, pflow, &scratch);
185  /* see if we need to increment the inspect_id and reset the de_state */
188  pflow, pflow->alparser, pflow->alstate, scratch.flow_flags, (scratch.sgh == NULL));
190  } else {
191  SCLogDebug("packet %" PRIu64 ": no flow / app-layer", p->pcap_cnt);
192  DetectRunAppendDefaultAccept(det_ctx, p);
193  }
194 
195 end:
196  DetectRunPostRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
197 
198  DetectRunCleanup(det_ctx, p, pflow);
199  SCReturn;
200 }
201 
202 static void DetectRunPostMatch(ThreadVars *tv,
203  DetectEngineThreadCtx *det_ctx, Packet *p,
204  const Signature *s)
205 {
206  /* run the packet match functions */
208  if (smd != NULL) {
210 
211  SCLogDebug("running match functions, sm %p", smd);
212 
213  while (1) {
215  (void)sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx);
216  KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
217  if (smd->is_last)
218  break;
219  smd++;
220  }
221  }
222 }
223 
224 /**
225  * \brief Get the SigGroupHead for a packet.
226  *
227  * \param de_ctx detection engine context
228  * \param p packet
229  *
230  * \retval sgh the SigGroupHead or NULL if non applies to the packet
231  */
233  const Packet *p)
234 {
235  SCEnter();
236  SigGroupHead *sgh = NULL;
237 
238  /* if the packet proto is 0 (not set), we're inspecting it against
239  * the decoder events sgh we have. */
240  if (p->proto == 0 && p->events.cnt > 0) {
241  SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead");
242  } else if (p->proto == 0) {
243  if (!(PacketIsIPv4(p) || PacketIsIPv6(p))) {
244  /* not IP, so nothing to do */
245  SCReturnPtr(NULL, "SigGroupHead");
246  }
247  }
248 
249  /* select the flow_gh */
250  const int dir = (p->flowflags & FLOW_PKT_TOCLIENT) == 0;
251 
252  int proto = PacketGetIPProto(p);
253  if (proto == IPPROTO_TCP) {
254  DetectPort *list = de_ctx->flow_gh[dir].tcp;
255  SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", de_ctx->flow_gh[1].tcp,
256  de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[dir].tcp);
257  const uint16_t port = dir ? p->dp : p->sp;
258  SCLogDebug("tcp port %u -> %u:%u", port, p->sp, p->dp);
259  DetectPort *sghport = DetectPortLookupGroup(list, port);
260  if (sghport != NULL)
261  sgh = sghport->sh;
262  SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", list, port,
263  dir ? "toserver" : "toclient", sghport, sgh);
264  } else if (proto == IPPROTO_UDP) {
265  DetectPort *list = de_ctx->flow_gh[dir].udp;
266  uint16_t port = dir ? p->dp : p->sp;
267  DetectPort *sghport = DetectPortLookupGroup(list, port);
268  if (sghport != NULL)
269  sgh = sghport->sh;
270  SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", list, port,
271  dir ? "toserver" : "toclient", sghport, sgh);
272  } else {
273  sgh = de_ctx->flow_gh[dir].sgh[proto];
274  }
275 
276  SCReturnPtr(sgh, "SigGroupHead");
277 }
278 
279 static inline void DetectPrefilterCopyDeDup(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
280 {
281  SigIntId *pf_ptr = det_ctx->pmq.rule_id_array;
282  uint32_t final_cnt = det_ctx->pmq.rule_id_array_cnt;
283  Signature **sig_array = de_ctx->sig_array;
284  Signature **match_array = det_ctx->match_array;
285  SigIntId previous_id = (SigIntId)-1;
286  while (final_cnt-- > 0) {
287  SigIntId id = *pf_ptr++;
288  Signature *s = sig_array[id];
289 
290  /* As the prefilter list can contain duplicates, check for that here. */
291  if (likely(id != previous_id)) {
292  *match_array++ = s;
293  previous_id = id;
294  }
295  }
296 
297  det_ctx->match_array_cnt = match_array - det_ctx->match_array;
299  PMQ_RESET(&det_ctx->pmq);
300 }
301 
302 /** \internal
303  * \brief update flow's file tracking flags based on the detection engine
304  * A set of flags is prepared that is sent to the File API. The
305  File API may reject one or more based on the global force settings.
306  */
307 static inline void
308 DetectPostInspectFileFlagsUpdate(Flow *f, const SigGroupHead *sgh, uint8_t direction)
309 {
310  uint16_t flow_file_flags = FLOWFILE_INIT;
311 
312  if (sgh == NULL) {
313  SCLogDebug("requesting disabling all file features for flow");
314  flow_file_flags = FLOWFILE_NONE;
315  } else {
316  if (sgh->filestore_cnt == 0) {
317  SCLogDebug("requesting disabling filestore for flow");
318  flow_file_flags |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC);
319  }
320 #ifdef HAVE_MAGIC
321  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC)) {
322  SCLogDebug("requesting disabling magic for flow");
323  flow_file_flags |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC);
324  }
325 #endif
326  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5)) {
327  SCLogDebug("requesting disabling md5 for flow");
328  flow_file_flags |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC);
329  }
330  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA1)) {
331  SCLogDebug("requesting disabling sha1 for flow");
332  flow_file_flags |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC);
333  }
334  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA256)) {
335  SCLogDebug("requesting disabling sha256 for flow");
336  flow_file_flags |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC);
337  }
338  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) {
339  SCLogDebug("requesting disabling filesize for flow");
340  flow_file_flags |= (FLOWFILE_NO_SIZE_TS|FLOWFILE_NO_SIZE_TC);
341  }
342  }
343  if (flow_file_flags != 0) {
344  FileUpdateFlowFileFlags(f, flow_file_flags, direction);
345  }
346 }
347 
348 static inline void
349 DetectRunPostGetFirstRuleGroup(const Packet *p, Flow *pflow, const SigGroupHead *sgh)
350 {
351  if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) {
352  /* first time we see this toserver sgh, store it */
353  pflow->sgh_toserver = sgh;
354  pflow->flags |= FLOW_SGH_TOSERVER;
355 
356  if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) {
357  if (pflow->protoctx != NULL) {
358  TcpSession *ssn = pflow->protoctx;
359  SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.client");
361  }
362  }
363 
364  DetectPostInspectFileFlagsUpdate(pflow,
365  pflow->sgh_toserver, STREAM_TOSERVER);
366 
367  } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) {
368  pflow->sgh_toclient = sgh;
369  pflow->flags |= FLOW_SGH_TOCLIENT;
370 
371  if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) {
372  if (pflow->protoctx != NULL) {
373  TcpSession *ssn = pflow->protoctx;
374  SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.server");
376  }
377  }
378 
379  DetectPostInspectFileFlagsUpdate(pflow,
380  pflow->sgh_toclient, STREAM_TOCLIENT);
381  }
382 }
383 
384 static inline void DetectRunGetRuleGroup(
385  const DetectEngineCtx *de_ctx,
386  Packet * const p, Flow * const pflow,
387  DetectRunScratchpad *scratch)
388 {
389  const SigGroupHead *sgh = NULL;
390 
391  if (pflow) {
392  bool use_flow_sgh = false;
393  /* Get the stored sgh from the flow (if any). Make sure we're not using
394  * the sgh for icmp error packets part of the same stream. */
395  if (PacketGetIPProto(p) == pflow->proto) { /* filter out icmp */
397  if ((p->flowflags & FLOW_PKT_TOSERVER) && (pflow->flags & FLOW_SGH_TOSERVER)) {
398  sgh = pflow->sgh_toserver;
399  SCLogDebug("sgh = pflow->sgh_toserver; => %p", sgh);
400  use_flow_sgh = true;
401  } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && (pflow->flags & FLOW_SGH_TOCLIENT)) {
402  sgh = pflow->sgh_toclient;
403  SCLogDebug("sgh = pflow->sgh_toclient; => %p", sgh);
404  use_flow_sgh = true;
405  }
407  }
408 
409  if (!(use_flow_sgh)) {
413 
414  /* HACK: prevent the wrong sgh (or NULL) from being stored in the
415  * flow's sgh pointers */
416  if (PacketIsICMPv4(p) && ICMPV4_DEST_UNREACH_IS_VALID(p)) {
417  ; /* no-op */
418  } else {
419  /* store the found sgh (or NULL) in the flow to save us
420  * from looking it up again for the next packet.
421  * Also run other tasks */
422  DetectRunPostGetFirstRuleGroup(p, pflow, sgh);
423  }
424  }
425  } else { /* p->flags & PKT_HAS_FLOW */
426  /* no flow */
427 
431  }
432 
433  scratch->sgh = sgh;
434 }
435 
436 static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx,
437  DetectEngineThreadCtx *det_ctx,
438  Flow * const pflow, Packet * const p)
439 {
440  if (pflow) {
442  SCLogDebug("testing against \"ip-only\" signatures");
443 
445  IPOnlyMatchPacket(tv, de_ctx, det_ctx, &de_ctx->io_ctx, p);
447  }
448  } else { /* p->flags & PKT_HAS_FLOW */
449  /* no flow */
450 
451  /* Even without flow we should match the packet src/dst */
453  IPOnlyMatchPacket(tv, de_ctx, det_ctx, &de_ctx->io_ctx, p);
455  }
456 }
457 
458 /** \internal
459  * \brief inspect the rule header: protocol, ports, etc
460  * \retval bool false if no match, true if match */
461 static inline bool DetectRunInspectRuleHeader(const Packet *p, const Flow *f, const Signature *s,
462  const uint32_t sflags, const uint8_t s_proto_flags)
463 {
464  /* check if this signature has a requirement for flowvars of some type
465  * and if so, if we actually have any in the flow. If not, the sig
466  * can't match and we skip it. */
467  if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) {
468  DEBUG_VALIDATE_BUG_ON(f == NULL);
469 
470  /* no flowvars? skip this sig */
471  const bool fv = f->flowvar != NULL;
472  if (!fv) {
473  SCLogDebug("skipping sig as the flow has no flowvars and sig "
474  "has SIG_FLAG_REQUIRE_FLOWVAR flag set.");
475  return false;
476  }
477  }
478 
479  if ((s_proto_flags & DETECT_PROTO_IPV4) && !PacketIsIPv4(p)) {
480  SCLogDebug("ip version didn't match");
481  return false;
482  }
483  if ((s_proto_flags & DETECT_PROTO_IPV6) && !PacketIsIPv6(p)) {
484  SCLogDebug("ip version didn't match");
485  return false;
486  }
487 
488  if (DetectProtoContainsProto(&s->proto, PacketGetIPProto(p)) == 0) {
489  SCLogDebug("proto didn't match");
490  return false;
491  }
492 
493  /* check the source & dst port in the sig */
494  if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) {
495  if (!(sflags & SIG_FLAG_DP_ANY)) {
496  if (p->flags & PKT_IS_FRAGMENT)
497  return false;
498  const DetectPort *dport = DetectPortLookupGroup(s->dp, p->dp);
499  if (dport == NULL) {
500  SCLogDebug("dport didn't match.");
501  return false;
502  }
503  }
504  if (!(sflags & SIG_FLAG_SP_ANY)) {
505  if (p->flags & PKT_IS_FRAGMENT)
506  return false;
507  const DetectPort *sport = DetectPortLookupGroup(s->sp, p->sp);
508  if (sport == NULL) {
509  SCLogDebug("sport didn't match.");
510  return false;
511  }
512  }
513  } else if ((sflags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) {
514  SCLogDebug("port-less protocol and sig needs ports");
515  return false;
516  }
517 
518  /* check the destination address */
519  if (!(sflags & SIG_FLAG_DST_ANY)) {
520  if (PacketIsIPv4(p)) {
522  return false;
523  } else if (PacketIsIPv6(p)) {
525  return false;
526  }
527  }
528  /* check the source address */
529  if (!(sflags & SIG_FLAG_SRC_ANY)) {
530  if (PacketIsIPv4(p)) {
532  return false;
533  } else if (PacketIsIPv6(p)) {
535  return false;
536  }
537  }
538 
539  return true;
540 }
541 
542 /** \internal
543  * \brief run packet/stream prefilter engines
544  */
545 static inline void DetectRunPrefilterPkt(
546  ThreadVars *tv,
548  DetectEngineThreadCtx *det_ctx,
549  Packet *p,
550  DetectRunScratchpad *scratch
551 )
552 {
553  /* create our prefilter mask */
554  PacketCreateMask(p, &p->sig_mask, scratch->alproto, scratch->app_decoder_events);
555  /* run the prefilter engines */
556  Prefilter(det_ctx, scratch->sgh, p, scratch->flow_flags, p->sig_mask);
557  /* create match list if we have non-pf and/or pf */
558  if (det_ctx->pmq.rule_id_array_cnt) {
559 #ifdef PROFILING
560  if (tv) {
561  StatsAddUI64(tv, det_ctx->counter_mpm_list, (uint64_t)det_ctx->pmq.rule_id_array_cnt);
562  }
563 #endif
565  DetectPrefilterCopyDeDup(de_ctx, det_ctx);
567  }
568 }
569 
570 /** \internal
571  * \brief check if the tx whose id is given is the only one
572  * live transaction for the flow in the given direction
573  *
574  * \param f flow
575  * \param txid transaction id
576  * \param dir direction
577  *
578  * \retval bool true if we are sure this tx is the only one live in said direction
579  */
580 static bool IsOnlyTxInDirection(Flow *f, uint64_t txid, uint8_t dir)
581 {
582  uint64_t tx_cnt = AppLayerParserGetTxCnt(f, f->alstate);
583  if (tx_cnt == txid + 1) {
584  // only live tx
585  return true;
586  }
587  if (tx_cnt == txid + 2) {
588  // 2 live txs, one after us
589  void *tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, txid + 1);
590  if (tx) {
592  // test if the other tx is unidirectional in the other way
593  if (txd && ((dir == STREAM_TOSERVER && (txd->flags & APP_LAYER_TX_SKIP_INSPECT_TS)) ||
594  (dir == STREAM_TOCLIENT &&
595  (txd->flags & APP_LAYER_TX_SKIP_INSPECT_TC)))) {
596  return true;
597  }
598  }
599  }
600  return false;
601 }
602 
603 static int SortHelper(const void *a, const void *b)
604 {
605  const Signature *sa = *(const Signature **)a;
606  const Signature *sb = *(const Signature **)b;
607  if (sa->num == sb->num)
608  return 0;
609  return sa->num > sb->num ? 1 : -1;
610 }
611 
612 static inline uint8_t DetectRulePacketRules(ThreadVars *const tv, DetectEngineCtx *const de_ctx,
613  DetectEngineThreadCtx *const det_ctx, Packet *const p, Flow *const pflow,
614  const DetectRunScratchpad *scratch)
615 {
616  uint8_t action = 0;
617  bool fw_verdict = false;
618  const bool have_fw_rules = (de_ctx->flags & DE_HAS_FIREWALL) != 0;
619  const Signature *next_s = NULL;
620 
621  /* inspect the sigs against the packet */
622  /* Prefetch the next signature. */
623  SigIntId match_cnt = det_ctx->match_array_cnt;
624 #ifdef PROFILING
625  if (tv) {
627  (uint64_t)match_cnt);
628  }
629 #endif
630  Signature **match_array = det_ctx->match_array;
631 
632  SGH_PROFILING_RECORD(det_ctx, scratch->sgh);
633 #ifdef PROFILING
634  if (match_cnt >= de_ctx->profile_match_logging_threshold)
635  RulesDumpMatchArray(det_ctx, scratch->sgh, p);
636 #endif
637 
638  bool skip_fw = false;
639  uint32_t sflags, next_sflags = 0;
640  if (match_cnt) {
641  next_s = *match_array++;
642  next_sflags = next_s->flags;
643  }
644  while (match_cnt--) {
646  bool break_out_of_packet_filter = false;
647  uint8_t alert_flags = 0;
648 #ifdef PROFILE_RULES
649  bool smatch = false; /* signature match */
650 #endif
651  const Signature *s = next_s;
652  sflags = next_sflags;
653  if (match_cnt) {
654  next_s = *match_array++;
655  next_sflags = next_s->flags;
656  }
657  const uint8_t s_proto_flags = s->proto.flags;
658 
659  SCLogDebug("packet %" PRIu64 ": inspecting signature id %" PRIu32 "", p->pcap_cnt, s->id);
660 
661  /* if we accept:hook'd the `packet_filter` hook, we skip the rest of the firewall rules. */
662  if (s->flags & SIG_FLAG_FIREWALL) {
663  if (skip_fw) {
664  SCLogDebug("skipping firewall rule %u", s->id);
665  goto next;
666  }
667  } else if (have_fw_rules) {
668  /* fw mode, we skip anything after the fw rules if:
669  * - flow pass is set
670  * - packet pass (e.g. exception policy) */
671  if (p->flags & PKT_NOPACKET_INSPECTION ||
672  (pflow != NULL && pflow->flags & (FLOW_ACTION_PASS))) {
673  SCLogDebug("skipping firewall rule %u", s->id);
674  break_out_of_packet_filter = true;
675  goto next;
676  }
677  }
678 
679  if (s->app_inspect != NULL) {
680  goto next; // handle sig in DetectRunTx
681  }
682  if (s->frame_inspect != NULL) {
683  goto next; // handle sig in DetectRunFrame
684  }
685 
686  /* skip pkt sigs for flow end packets */
687  if ((p->flags & PKT_PSEUDO_STREAM_END) != 0 && s->type == SIG_TYPE_PKT)
688  goto next;
689 
690  /* don't run mask check for stateful rules.
691  * There we depend on prefilter */
692  if ((s->mask & p->sig_mask) != s->mask) {
693  SCLogDebug("mask mismatch %x & %x != %x", s->mask, p->sig_mask, s->mask);
694  goto next;
695  }
696 
697  if (SigDsizePrefilter(p, s, sflags))
698  goto next;
699 
700  /* if the sig has alproto and the session as well they should match */
701  if (likely(sflags & SIG_FLAG_APPLAYER)) {
702  if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, scratch->alproto)) {
703  SCLogDebug("alproto mismatch");
704  goto next;
705  }
706  }
707 
708  if (!DetectRunInspectRuleHeader(p, pflow, s, sflags, s_proto_flags)) {
709  goto next;
710  }
711 
712  if (!DetectEnginePktInspectionRun(tv, det_ctx, s, pflow, p, &alert_flags)) {
713  goto next;
714  }
715 
716 #ifdef PROFILE_RULES
717  smatch = true;
718 #endif
719  DetectRunPostMatch(tv, det_ctx, p, s);
720 
721  uint64_t txid = PACKET_ALERT_NOTX;
722  if (pflow && pflow->alstate) {
723  uint8_t dir = (p->flowflags & FLOW_PKT_TOCLIENT) ? STREAM_TOCLIENT : STREAM_TOSERVER;
725  if ((s->alproto != ALPROTO_UNKNOWN && pflow->proto == IPPROTO_UDP) ||
726  (de_ctx->guess_applayer && IsOnlyTxInDirection(pflow, txid, dir))) {
727  // if there is a UDP specific app-layer signature,
728  // or only one live transaction
729  // try to use the good tx for the packet direction
730  void *tx_ptr =
731  AppLayerParserGetTx(pflow->proto, pflow->alproto, pflow->alstate, txid);
732  AppLayerTxData *txd =
733  tx_ptr ? AppLayerParserGetTxData(pflow->proto, pflow->alproto, tx_ptr)
734  : NULL;
735  if (txd && txd->guessed_applayer_logged < de_ctx->guess_applayer_log_limit) {
736  alert_flags |= PACKET_ALERT_FLAG_TX;
737  if (pflow->proto != IPPROTO_UDP) {
738  alert_flags |= PACKET_ALERT_FLAG_TX_GUESSED;
739  }
740  txd->guessed_applayer_logged++;
741  }
742  }
743  }
744  AlertQueueAppend(det_ctx, s, p, txid, alert_flags);
745 
746  if (det_ctx->post_rule_work_queue.len > 0) {
747  /* run post match prefilter engines on work queue */
748  PrefilterPostRuleMatch(det_ctx, scratch->sgh, p, pflow);
749 
750  if (det_ctx->pmq.rule_id_array_cnt > 0) {
751  /* undo "prefetch" */
752  if (next_s)
753  match_array--;
754  /* create temporary rule pointer array starting
755  * at where we are in the current match array */
756  const Signature *replace[de_ctx->sig_array_len]; // TODO heap?
757  SCLogDebug("sig_array_len %u det_ctx->pmq.rule_id_array_cnt %u",
759  const Signature **r = replace;
760  for (uint32_t x = 0; x < match_cnt; x++) {
761  *r++ = match_array[x];
762  SCLogDebug("appended %u", match_array[x]->id);
763  }
764  /* append the prefilter results, then sort it */
765  for (uint32_t x = 0; x < det_ctx->pmq.rule_id_array_cnt; x++) {
766  SCLogDebug("adding iid %u", det_ctx->pmq.rule_id_array[x]);
767  Signature *ts = de_ctx->sig_array[det_ctx->pmq.rule_id_array[x]];
768  SCLogDebug("adding id %u", ts->id);
769  if (ts->app_inspect == NULL) {
770  *r++ = ts;
771  match_cnt++;
772  }
773  }
774  if (match_cnt > 1) {
775  qsort(replace, match_cnt, sizeof(Signature *), SortHelper);
776  }
777  /* rewrite match_array to include the new additions, and deduplicate
778  * while at it. */
779  Signature **m = match_array;
780  Signature *last_sig = NULL;
781  uint32_t skipped = 0;
782  for (uint32_t x = 0; x < match_cnt; x++) {
783  /* de-duplicate */
784  if (last_sig == *m) {
785  skipped++;
786  continue;
787  }
788  last_sig = *m;
789  *m++ = (Signature *)replace[x];
790  }
791  match_cnt -= skipped;
792  /* prefetch next */
793  next_s = *match_array++;
794  next_sflags = next_s->flags;
795  SCLogDebug("%u rules added", det_ctx->pmq.rule_id_array_cnt);
796  det_ctx->post_rule_work_queue.len = 0;
797  PMQ_RESET(&det_ctx->pmq);
798  }
799  }
800 
801  /* firewall logic in the packet:filter table:
802  * 1. firewall rules preceed the packet:td rules in the list
803  * 2. if no rule issues an accept, we drop
804  * 3. drop is immediate
805  * 4. accept:
806  * - hook: skip rest of fw rules, inspect packet:td rules
807  * - packet: immediate accept, no packet:td or app:* inspect
808  * - flow: as packet, but applied to all future packets in the
809  * flow as well
810  */
811  if (s->flags & SIG_FLAG_FIREWALL) {
812  if (s->action & (ACTION_ACCEPT)) {
813  fw_verdict = true;
814 
815  enum ActionScope as = s->action_scope;
816  if (as == ACTION_SCOPE_HOOK) {
817  /* accept:hook: jump to first TD. Implemented as:
818  * skip until the first TD rule.
819  * Don't update action as we're just continuing to the next hook. */
820  skip_fw = true;
821 
822  } else if (as == ACTION_SCOPE_PACKET) {
823  /* accept:packet: break loop, return accept */
824  action |= s->action;
825  break_out_of_packet_filter = true;
826 
827  } else if (as == ACTION_SCOPE_FLOW) {
828  /* accept:flow: break loop, return accept */
829  action |= s->action;
830  break_out_of_packet_filter = true;
831 
832  /* set immediately, as we're in hook "packet_filter" */
833  if (pflow) {
834  pflow->flags |= FLOW_ACTION_ACCEPT;
835  }
836  }
837  } else if (s->action & ACTION_DROP) {
838  /* apply a drop immediately here */
839  fw_verdict = true;
840  action |= s->action;
841  break_out_of_packet_filter = true;
842  }
843  }
844 next:
845  DetectVarProcessList(det_ctx, pflow, p);
846  DetectReplaceFree(det_ctx);
847  RULE_PROFILING_END(det_ctx, s, smatch, p);
848 
849  /* fw accept:packet or accept:flow means we're done here */
850  if (break_out_of_packet_filter)
851  break;
852 
853  continue;
854  }
855 
856  /* if no rule told us to accept, and no rule explicitly dropped, we invoke the default drop
857  * policy
858  */
859  if (have_fw_rules) {
860  if (!fw_verdict) {
863  action |= ACTION_DROP;
864  } else {
865  /* apply fw action */
866  p->action |= action;
867  }
868  }
869  return action;
870 }
871 
872 static DetectRunScratchpad DetectRunSetup(
873  const DetectEngineCtx *de_ctx,
874  DetectEngineThreadCtx *det_ctx,
875  Packet * const p, Flow * const pflow)
876 {
877  AppProto alproto = ALPROTO_UNKNOWN;
878  uint8_t flow_flags = 0; /* flow/state flags */
879  bool app_decoder_events = false;
880 
882 
883 #ifdef UNITTESTS
884  p->alerts.cnt = 0;
885  p->alerts.discarded = 0;
886  p->alerts.suppressed = 0;
887 #endif
888  det_ctx->filestore_cnt = 0;
889  det_ctx->base64_decoded_len = 0;
890  det_ctx->raw_stream_progress = 0;
891  det_ctx->match_array_cnt = 0;
892 
893  det_ctx->alert_queue_size = 0;
894  p->alerts.drop.action = 0;
895 
896 #ifdef DEBUG
897  if (p->flags & PKT_STREAM_ADD) {
898  det_ctx->pkt_stream_add_cnt++;
899  }
900 #endif
901 
902  /* grab the protocol state we will detect on */
903  if (p->flags & PKT_HAS_FLOW) {
904  DEBUG_VALIDATE_BUG_ON(pflow == NULL);
905 
906  if (p->flowflags & FLOW_PKT_TOSERVER) {
907  flow_flags = STREAM_TOSERVER;
908  SCLogDebug("flag STREAM_TOSERVER set");
909  } else if (p->flowflags & FLOW_PKT_TOCLIENT) {
910  flow_flags = STREAM_TOCLIENT;
911  SCLogDebug("flag STREAM_TOCLIENT set");
912  }
913  SCLogDebug("p->flowflags 0x%02x", p->flowflags);
914 
915  if (p->flags & PKT_STREAM_EOF) {
916  flow_flags |= STREAM_EOF;
917  SCLogDebug("STREAM_EOF set");
918  }
919 
920  /* store tenant_id in the flow so that we can use it
921  * for creating pseudo packets */
922  if (p->tenant_id > 0 && pflow->tenant_id == 0) {
923  pflow->tenant_id = p->tenant_id;
924  }
925 
926  /* live ruleswap check for flow updates */
927  if (pflow->de_ctx_version == 0) {
928  /* first time this flow is inspected, set id */
929  pflow->de_ctx_version = de_ctx->version;
930  } else if (pflow->de_ctx_version != de_ctx->version) {
931  /* first time we inspect flow with this de_ctx, reset */
932  pflow->flags &= ~FLOW_SGH_TOSERVER;
933  pflow->flags &= ~FLOW_SGH_TOCLIENT;
934  pflow->sgh_toserver = NULL;
935  pflow->sgh_toclient = NULL;
936 
937  pflow->de_ctx_version = de_ctx->version;
938  GenericVarFree(pflow->flowvar);
939  pflow->flowvar = NULL;
940 
942  }
943 
944  /* Retrieve the app layer state and protocol and the tcp reassembled
945  * stream chunks. */
946  if ((p->proto == IPPROTO_TCP && (p->flags & PKT_STREAM_EST)) ||
947  (p->proto == IPPROTO_UDP) ||
949  {
950  /* update flow flags with knowledge on disruptions */
951  flow_flags = FlowGetDisruptionFlags(pflow, flow_flags);
952  alproto = FlowGetAppProtocol(pflow);
953  if (p->proto == IPPROTO_TCP && pflow->protoctx &&
956  }
957  SCLogDebug("alproto %u", alproto);
958  } else {
959  SCLogDebug("packet doesn't have established flag set (proto %d)", p->proto);
960  }
961 
962  app_decoder_events = AppLayerParserHasDecoderEvents(pflow->alparser);
963  }
964 
965  DetectRunScratchpad pad = { alproto, flow_flags, app_decoder_events, NULL };
967  return pad;
968 }
969 
970 static inline void DetectRunPostRules(
971  ThreadVars *tv,
973  DetectEngineThreadCtx *det_ctx,
974  Packet * const p,
975  Flow * const pflow,
976  DetectRunScratchpad *scratch)
977 {
978  /* so now let's iterate the alerts and remove the ones after a pass rule
979  * matched (if any). This is done inside PacketAlertFinalize() */
980  /* PR: installed "tag" keywords are handled after the threshold inspection */
981 
983  PacketAlertFinalize(de_ctx, det_ctx, p);
984  if (p->alerts.cnt > 0) {
985  StatsAddUI64(tv, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt);
986  }
987  if (p->alerts.discarded > 0) {
988  StatsAddUI64(tv, det_ctx->counter_alerts_overflow, (uint64_t)p->alerts.discarded);
989  }
990  if (p->alerts.suppressed > 0) {
991  StatsAddUI64(tv, det_ctx->counter_alerts_suppressed, (uint64_t)p->alerts.suppressed);
992  }
994 
995  /* firewall: "fail" closed if we don't have an ACCEPT. This can happen
996  * if there was no rule group. */
997  // TODO review packet src types here
998  if (de_ctx->flags & DE_HAS_FIREWALL && !(p->action & ACTION_ACCEPT) &&
999  p->pkt_src == PKT_SRC_WIRE) {
1000  SCLogDebug("packet %" PRIu64 ": droppit as no ACCEPT set %02x (pkt %s)", p->pcap_cnt,
1001  p->action, PktSrcToString(p->pkt_src));
1003  }
1004 }
1005 
1006 static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx,
1007  Packet *p, Flow * const pflow)
1008 {
1010  InspectionBufferClean(det_ctx);
1011 
1012  if (pflow != NULL) {
1013  /* update inspected tracker for raw reassembly */
1014  if (p->proto == IPPROTO_TCP && pflow->protoctx != NULL &&
1017  det_ctx->raw_stream_progress);
1018  }
1019  }
1021  SCReturn;
1022 }
1023 
1025 {
1027  det_ctx->tx_candidates = SCCalloc(size, sizeof(RuleMatchCandidateTx));
1028  if (det_ctx->tx_candidates == NULL) {
1029  FatalError("failed to allocate %" PRIu64 " bytes",
1030  (uint64_t)(size * sizeof(RuleMatchCandidateTx)));
1031  }
1032  det_ctx->tx_candidates_size = size;
1033  SCLogDebug("array initialized to %u elements (%"PRIu64" bytes)",
1034  size, (uint64_t)(size * sizeof(RuleMatchCandidateTx)));
1035 }
1036 
1038 {
1039  SCFree(det_ctx->tx_candidates);
1040  det_ctx->tx_candidates_size = 0;
1041 }
1042 
1043 /* if size >= cur_space */
1044 static inline bool RuleMatchCandidateTxArrayHasSpace(const DetectEngineThreadCtx *det_ctx,
1045  const uint32_t need)
1046 {
1047  if (det_ctx->tx_candidates_size >= need)
1048  return 1;
1049  return 0;
1050 }
1051 
1052 /* realloc */
1053 static int RuleMatchCandidateTxArrayExpand(DetectEngineThreadCtx *det_ctx, const uint32_t needed)
1054 {
1055  const uint32_t old_size = det_ctx->tx_candidates_size;
1056  uint32_t new_size = needed;
1057  void *ptmp = SCRealloc(det_ctx->tx_candidates, (new_size * sizeof(RuleMatchCandidateTx)));
1058  if (ptmp == NULL) {
1059  FatalError("failed to expand to %" PRIu64 " bytes",
1060  (uint64_t)(new_size * sizeof(RuleMatchCandidateTx)));
1061  // TODO can this be handled more gracefully?
1062  }
1063  det_ctx->tx_candidates = ptmp;
1064  det_ctx->tx_candidates_size = new_size;
1065  SCLogDebug("array expanded from %u to %u elements (%"PRIu64" bytes -> %"PRIu64" bytes)",
1066  old_size, new_size, (uint64_t)(old_size * sizeof(RuleMatchCandidateTx)),
1067  (uint64_t)(new_size * sizeof(RuleMatchCandidateTx))); (void)old_size;
1068  return 1;
1069 }
1070 
1071 /** \internal
1072  * \brief sort helper for sorting match candidates by id: ascending
1073  *
1074  * The id field is set from Signature::num, so we sort the candidates to match the signature
1075  * sort order (ascending), where candidates that have flags go first.
1076  */
1077 static int
1078 DetectRunTxSortHelper(const void *a, const void *b)
1079 {
1080  const RuleMatchCandidateTx *s0 = a;
1081  const RuleMatchCandidateTx *s1 = b;
1082  if (s1->id == s0->id) {
1083  if (s1->flags && !s0->flags)
1084  return 1;
1085  else if (!s1->flags && s0->flags)
1086  return -1;
1087  return 0;
1088  } else
1089  return s0->id > s1->id ? 1 : -1;
1090 }
1091 
1092 #if 0
1093 #define TRACE_SID_TXS(sid,txs,...) \
1094  do { \
1095  char _trace_buf[2048]; \
1096  snprintf(_trace_buf, sizeof(_trace_buf), __VA_ARGS__); \
1097  SCLogNotice("%p/%"PRIu64"/%u: %s", txs->tx_ptr, txs->tx_id, sid, _trace_buf); \
1098  } while(0)
1099 #else
1100 #define TRACE_SID_TXS(sid,txs,...)
1101 #endif
1102 
1103 // Get inner transaction for engine
1104 void *DetectGetInnerTx(void *tx_ptr, AppProto alproto, AppProto engine_alproto, uint8_t flow_flags)
1105 {
1106  if (unlikely(alproto == ALPROTO_DOH2)) {
1107  if (engine_alproto == ALPROTO_DNS) {
1108  // need to get the dns tx pointer
1109  tx_ptr = SCDoH2GetDnsTx(tx_ptr, flow_flags);
1110  } else if (engine_alproto != ALPROTO_HTTP2 && engine_alproto != ALPROTO_UNKNOWN) {
1111  // incompatible engine->alproto with flow alproto
1112  tx_ptr = NULL;
1113  }
1114  } else if (engine_alproto != alproto && engine_alproto != ALPROTO_UNKNOWN) {
1115  // incompatible engine->alproto with flow alproto
1116  tx_ptr = NULL;
1117  }
1118  return tx_ptr;
1119 }
1120 
1121 /** \internal
1122  * \brief inspect a rule against a transaction
1123  *
1124  * Inspect a rule. New detection or continued stateful
1125  * detection.
1126  *
1127  * \param stored_flags pointer to stored flags or NULL.
1128  * If stored_flags is set it means we're continuing
1129  * inspection from an earlier run.
1130  *
1131  * \retval bool true sig matched, false didn't match
1132  */
1133 static bool DetectRunTxInspectRule(ThreadVars *tv,
1135  DetectEngineThreadCtx *det_ctx,
1136  Packet *p,
1137  Flow *f,
1138  const uint8_t in_flow_flags, // direction, EOF, etc
1139  void *alstate,
1140  DetectTransaction *tx,
1141  const Signature *s,
1142  uint32_t *stored_flags,
1143  RuleMatchCandidateTx *can,
1144  DetectRunScratchpad *scratch)
1145 {
1146  const uint8_t flow_flags = in_flow_flags;
1147  const int direction = (flow_flags & STREAM_TOSERVER) ? 0 : 1;
1148  uint32_t inspect_flags = stored_flags ? *stored_flags : 0;
1149  int total_matches = 0;
1150  uint16_t file_no_match = 0;
1151  bool retval = false;
1152  bool mpm_before_progress = false; // is mpm engine before progress?
1153  bool mpm_in_progress = false; // is mpm engine in a buffer we will revisit?
1154 
1155  TRACE_SID_TXS(s->id, tx, "starting %s", direction ? "toclient" : "toserver");
1156 
1157  /* for a new inspection we inspect pkt header and packet matches */
1158  if (likely(stored_flags == NULL)) {
1159  TRACE_SID_TXS(s->id, tx, "first inspect, run packet matches");
1160  if (!DetectRunInspectRuleHeader(p, f, s, s->flags, s->proto.flags)) {
1161  TRACE_SID_TXS(s->id, tx, "DetectRunInspectRuleHeader() no match");
1162  return false;
1163  }
1164  if (!DetectEnginePktInspectionRun(tv, det_ctx, s, f, p, NULL)) {
1165  TRACE_SID_TXS(s->id, tx, "DetectEnginePktInspectionRun no match");
1166  return false;
1167  }
1168  /* stream mpm and negated mpm sigs can end up here with wrong proto */
1169  if (!(AppProtoEquals(s->alproto, f->alproto) || s->alproto == ALPROTO_UNKNOWN)) {
1170  TRACE_SID_TXS(s->id, tx, "alproto mismatch");
1171  return false;
1172  }
1173  }
1174 
1175  const DetectEngineAppInspectionEngine *engine = s->app_inspect;
1176  do {
1177  TRACE_SID_TXS(s->id, tx, "engine %p inspect_flags %x", engine, inspect_flags);
1178  // also if it is not the same direction, but
1179  // this is a transactional signature, and we are toclient
1180  if (!(inspect_flags & BIT_U32(engine->id)) &&
1181  (direction == engine->dir || ((s->flags & SIG_FLAG_TXBOTHDIR) && direction == 1))) {
1182 
1183  void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, f->alproto, engine->alproto, flow_flags);
1184  if (tx_ptr == NULL) {
1185  if (engine->alproto != ALPROTO_UNKNOWN) {
1186  /* special case: file_data on 'alert tcp' will have engines
1187  * in the list that are not for us. */
1188  engine = engine->next;
1189  continue;
1190  } else {
1191  tx_ptr = tx->tx_ptr;
1192  }
1193  }
1194 
1195  /* engines are sorted per progress, except that the one with
1196  * mpm/prefilter enabled is first */
1197  if (tx->tx_progress < engine->progress) {
1198  SCLogDebug("tx progress %d < engine progress %d",
1199  tx->tx_progress, engine->progress);
1200  break;
1201  }
1202  if (engine->mpm) {
1203  if (tx->tx_progress > engine->progress) {
1204  TRACE_SID_TXS(s->id, tx,
1205  "engine->mpm: t->tx_progress %u > engine->progress %u, so set "
1206  "mpm_before_progress",
1207  tx->tx_progress, engine->progress);
1208  mpm_before_progress = true;
1209  } else if (tx->tx_progress == engine->progress) {
1210  TRACE_SID_TXS(s->id, tx,
1211  "engine->mpm: t->tx_progress %u == engine->progress %u, so set "
1212  "mpm_in_progress",
1213  tx->tx_progress, engine->progress);
1214  mpm_in_progress = true;
1215  }
1216  }
1217 
1218  uint8_t engine_flags = flow_flags;
1219  if (direction != engine->dir) {
1220  engine_flags = flow_flags ^ (STREAM_TOCLIENT | STREAM_TOSERVER);
1221  }
1222  /* run callback: but bypass stream callback if we can */
1223  uint8_t match;
1224  if (unlikely(engine->stream && can->stream_stored)) {
1225  match = can->stream_result;
1226  TRACE_SID_TXS(s->id, tx, "stream skipped, stored result %d used instead", match);
1227  } else if (engine->v2.Callback == NULL) {
1228  /* TODO is this the cleanest way to support a non-app sig on a app hook? */
1229 
1230  if (tx->tx_progress > engine->progress) {
1231  mpm_before_progress = true; // TODO needs a new name now
1232  }
1233 
1234  /* we don't have to store a "hook" match, also don't want to keep any state to make
1235  * sure the hook gets invoked again until tx progress progresses. */
1236  if (tx->tx_progress <= engine->progress)
1238 
1239  /* if progress > engine progress, track state to avoid additional matches */
1241  } else {
1242  KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list);
1243  DEBUG_VALIDATE_BUG_ON(engine->v2.Callback == NULL);
1244  match = engine->v2.Callback(
1245  de_ctx, det_ctx, engine, s, f, engine_flags, alstate, tx_ptr, tx->tx_id);
1246  TRACE_SID_TXS(s->id, tx, "engine %p match %d", engine, match);
1247  if (engine->stream) {
1248  can->stream_stored = true;
1249  can->stream_result = match;
1250  TRACE_SID_TXS(s->id, tx, "stream ran, store result %d for next tx (if any)", match);
1251  }
1252  }
1253  if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
1254  inspect_flags |= BIT_U32(engine->id);
1255  engine = engine->next;
1256  total_matches++;
1257  continue;
1258  } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
1259  /* if the file engine matched, but indicated more
1260  * files are still in progress, we don't set inspect
1261  * flags as these would end inspection for this tx */
1262  engine = engine->next;
1263  total_matches++;
1264  continue;
1265  } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) {
1266  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1267  inspect_flags |= BIT_U32(engine->id);
1268  } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES) {
1269  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1270  inspect_flags |= BIT_U32(engine->id);
1271  file_no_match = 1;
1272  }
1273  /* implied DETECT_ENGINE_INSPECT_SIG_NO_MATCH */
1274  if (engine->mpm && mpm_before_progress) {
1275  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1276  inspect_flags |= BIT_U32(engine->id);
1277  }
1278  break;
1279  } else if (!(inspect_flags & BIT_U32(engine->id)) && s->flags & SIG_FLAG_TXBOTHDIR &&
1280  direction != engine->dir) {
1281  // for transactional rules, the engines on the opposite direction
1282  // are ordered by progress on the different side
1283  // so we have a two mixed-up lists, and we skip the elements
1284  if (direction == 0 && engine->next == NULL) {
1285  // do not match yet on request only
1286  break;
1287  }
1288  engine = engine->next;
1289  continue;
1290  }
1291 
1292  engine = engine->next;
1293  } while (engine != NULL);
1294  TRACE_SID_TXS(s->id, tx, "inspect_flags %x, total_matches %u, engine %p",
1295  inspect_flags, total_matches, engine);
1296 
1297  if (engine == NULL && total_matches) {
1298  inspect_flags |= DE_STATE_FLAG_FULL_INSPECT;
1299  TRACE_SID_TXS(s->id, tx, "MATCH");
1300  retval = true;
1301  }
1302 
1303  if (stored_flags) {
1304  *stored_flags = inspect_flags;
1305  TRACE_SID_TXS(s->id, tx, "continue inspect flags %08x", inspect_flags);
1306  } else {
1307  // store... or? If tx is done we might not want to come back to this tx
1308 
1309  // also... if mpmid tracking is enabled, we won't do a sig again for this tx...
1310  TRACE_SID_TXS(s->id, tx, "start inspect flags %08x", inspect_flags);
1311  if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
1312  if (file_no_match) {
1313  /* if we have a mismatch on a file sig, we need to keep state.
1314  * We may get another file on the same tx (for http and smtp
1315  * at least), so for a new file we need to re-eval the sig.
1316  * Thoughts / TODO:
1317  * - not for some protos that have 1 file per tx (e.g. nfs)
1318  * - maybe we only need this for file sigs that mix with
1319  * other matches? E.g. 'POST + filename', is different than
1320  * just 'filename'.
1321  */
1322  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1323  inspect_flags, flow_flags, file_no_match);
1324  }
1325  } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) && mpm_before_progress) {
1326  TRACE_SID_TXS(s->id, tx, "no need to store match sig, "
1327  "mpm won't trigger for it anymore");
1328 
1329  if (inspect_flags & DE_STATE_FLAG_FILE_INSPECT) {
1330  TRACE_SID_TXS(s->id, tx, "except that for new files, "
1331  "we may have to revisit anyway");
1332  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1333  inspect_flags, flow_flags, file_no_match);
1334  }
1335  } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) == 0 && mpm_in_progress) {
1336  TRACE_SID_TXS(s->id, tx, "no need to store no-match sig, "
1337  "mpm will revisit it");
1338  } else if (inspect_flags != 0 || file_no_match != 0) {
1339  TRACE_SID_TXS(s->id, tx, "storing state: flags %08x", inspect_flags);
1340  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1341  inspect_flags, flow_flags, file_no_match);
1342  }
1343  }
1344 
1345  return retval;
1346 }
1347 
1348 #define NO_TX \
1349  { \
1350  NULL, 0, NULL, NULL, 0, 0, 0, 0, \
1351  }
1352 
1353 /** \internal
1354  * \brief get a DetectTransaction object
1355  * \retval struct filled with relevant info or all nulls/0s
1356  */
1357 static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alproto,
1358  const uint64_t tx_id, void *tx_ptr, const int tx_end_state, const uint8_t flow_flags)
1359 {
1360  AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx_ptr);
1361  if (unlikely(txd == NULL)) {
1362  DetectTransaction no_tx = NO_TX;
1363  return no_tx;
1364  }
1365  const int tx_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx_ptr, flow_flags);
1366  bool updated = (flow_flags & STREAM_TOSERVER) ? txd->updated_ts : txd->updated_tc;
1367  if (!updated && tx_progress < tx_end_state && ((flow_flags & STREAM_EOF) == 0)) {
1368  DetectTransaction no_tx = NO_TX;
1369  return no_tx;
1370  }
1371  const uint8_t inspected_flag =
1372  (flow_flags & STREAM_TOSERVER) ? APP_LAYER_TX_INSPECTED_TS : APP_LAYER_TX_INSPECTED_TC;
1373  if (unlikely(txd->flags & inspected_flag)) {
1374  SCLogDebug("%" PRIu64 " tx already fully inspected for %s. Flags %02x", tx_id,
1375  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
1376  DetectTransaction no_tx = NO_TX;
1377  return no_tx;
1378  }
1379  const uint8_t skip_flag = (flow_flags & STREAM_TOSERVER) ? APP_LAYER_TX_SKIP_INSPECT_TS
1381  if (unlikely(txd->flags & skip_flag)) {
1382  SCLogDebug("%" PRIu64 " tx should not be inspected in direction %s. Flags %02x", tx_id,
1383  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
1384  DetectTransaction no_tx = NO_TX;
1385  return no_tx;
1386  }
1387 
1388  const uint8_t detect_progress =
1389  (flow_flags & STREAM_TOSERVER) ? txd->detect_progress_ts : txd->detect_progress_tc;
1390 
1391  const int dir_int = (flow_flags & STREAM_TOSERVER) ? 0 : 1;
1392  DetectEngineState *tx_de_state = txd->de_state;
1393  DetectEngineStateDirection *tx_dir_state =
1394  tx_de_state ? &tx_de_state->dir_state[dir_int] : NULL;
1395  DetectTransaction tx = {
1396  .tx_ptr = tx_ptr,
1397  .tx_id = tx_id,
1398  .tx_data_ptr = (struct AppLayerTxData *)txd,
1399  .de_state = tx_dir_state,
1400  .detect_progress = detect_progress,
1401  .detect_progress_orig = detect_progress,
1402  .tx_progress = tx_progress,
1403  .tx_end_state = tx_end_state,
1404  };
1405  return tx;
1406 }
1407 
1408 static inline void StoreDetectProgress(
1409  DetectTransaction *tx, const uint8_t flow_flags, const uint8_t progress)
1410 {
1412  if (likely(txd != NULL)) {
1413  if (flow_flags & STREAM_TOSERVER) {
1414  txd->detect_progress_ts = progress;
1415  } else {
1416  txd->detect_progress_tc = progress;
1417  }
1418  }
1419 }
1420 
1421 // Merge 'state' rules from the regular prefilter
1422 // updates array_idx on the way
1423 static inline void RuleMatchCandidateMergeStateRules(
1424  DetectEngineThreadCtx *det_ctx, uint32_t *array_idx)
1425 {
1426  // Now, we will merge 2 sorted lists :
1427  // the one in det_ctx->tx_candidates
1428  // and the one in det_ctx->match_array
1429  // For match_array, we take only the relevant elements where s->app_inspect != NULL
1430 
1431  // Basically, we iterate at the same time over the 2 lists
1432  // comparing and taking an element from either.
1433 
1434  // Trick is to do so in place in det_ctx->tx_candidates,
1435  // so as to minimize the number of moves in det_ctx->tx_candidates.
1436  // For this, the algorithm traverses the lists in reverse order.
1437  // Otherwise, if the first element of match_array was to be put before
1438  // all tx_candidates, we would need to shift all tx_candidates
1439 
1440  // Retain the number of elements sorted in tx_candidates before merge
1441  uint32_t j = *array_idx;
1442  // First loop only counting the number of elements to add
1443  for (uint32_t i = 0; i < det_ctx->match_array_cnt; i++) {
1444  const Signature *s = det_ctx->match_array[i];
1445  if (s->app_inspect != NULL) {
1446  (*array_idx)++;
1447  }
1448  }
1449  // Future number of elements in tx_candidates after merge
1450  uint32_t k = *array_idx;
1451 
1452  if (k == j) {
1453  // no new element from match_array to merge in tx_candidates
1454  return;
1455  }
1456 
1457  // variable i is for all elements of match_array (even not relevant ones)
1458  // variable j is for elements of tx_candidates before merge
1459  // variable k is for elements of tx_candidates after merge
1460  for (uint32_t i = det_ctx->match_array_cnt; i > 0;) {
1461  const Signature *s = det_ctx->match_array[i - 1];
1462  if (s->app_inspect == NULL) {
1463  // no relevant element, get the next one from match_array
1464  i--;
1465  continue;
1466  }
1467  // we have one element from match_array to merge in tx_candidates
1468  k--;
1469  if (j > 0) {
1470  // j > 0 means there is still at least one element in tx_candidates to merge
1471  const RuleMatchCandidateTx *s0 = &det_ctx->tx_candidates[j - 1];
1472  if (s->num <= s0->id) {
1473  // get next element from previous tx_candidates
1474  j--;
1475  // take the element from tx_candidates before merge
1476  det_ctx->tx_candidates[k].s = det_ctx->tx_candidates[j].s;
1477  det_ctx->tx_candidates[k].id = det_ctx->tx_candidates[j].id;
1478  det_ctx->tx_candidates[k].flags = det_ctx->tx_candidates[j].flags;
1479  det_ctx->tx_candidates[k].stream_reset = det_ctx->tx_candidates[j].stream_reset;
1480  continue;
1481  }
1482  } // otherwise
1483  // get next element from match_array
1484  i--;
1485  // take the element from match_array
1486  det_ctx->tx_candidates[k].s = s;
1487  det_ctx->tx_candidates[k].id = s->num;
1488  det_ctx->tx_candidates[k].flags = NULL;
1489  det_ctx->tx_candidates[k].stream_reset = 0;
1490  }
1491  // Even if k > 0 or j > 0, the loop is over. (Note that j == k now)
1492  // The remaining elements in tx_candidates up to k were already sorted
1493  // and come before any other element later in the list
1494 }
1495 
1496 /**
1497  * \internal
1498  * \brief Check and update firewall rules state.
1499  *
1500  * \param skip_fw_hook bool to indicate firewall rules skips
1501  * For state `skip_before_progress` should be skipped.
1502  *
1503  * \param skip_before_progress progress value to skip rules before.
1504  * Only used if `skip_fw_hook` is set.
1505  *
1506  * \param last_for_progress[out] set to true if this is the last rule for a progress value
1507  *
1508  * \param fw_next_progress_missing[out] set to true if the next fw rule does not target the next
1509  * progress value, or there is no fw rule for that value.
1510  *
1511  * \retval 0 no action needed
1512  * \retval 1 rest of rules shouldn't inspected
1513  * \retval -1 skip this rule
1514  */
1515 static int DetectRunTxCheckFirewallPolicy(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f,
1516  DetectTransaction *tx, const Signature *s, const uint32_t can_idx, const uint32_t can_size,
1517  bool *skip_fw_hook, const uint8_t skip_before_progress, bool *last_for_progress,
1518  bool *fw_next_progress_missing)
1519 {
1520  if (s->flags & SIG_FLAG_FIREWALL) {
1521  /* check if the next sig is on the same progress hook. If not, we need to apply our
1522  * default policy in case the current sig doesn't apply one. If the next sig has a
1523  * progress beyond our progress + 1, it means the next progress has no rules and needs
1524  * the default policy applied. But only after we evaluate the current rule first, as
1525  * that may override it.
1526  * TODO should we do this after dedup below? */
1527 
1528  if (can_idx + 1 < can_size) {
1529  const Signature *next_s = det_ctx->tx_candidates[can_idx + 1].s;
1530  SCLogDebug(
1531  "peek: peeking at sid %u / progress %u", next_s->id, next_s->app_progress_hook);
1532  if (next_s->flags & SIG_FLAG_FIREWALL) {
1533  if (s->app_progress_hook != next_s->app_progress_hook) {
1534  SCLogDebug("peek: next sid progress %u != current progress %u, so current "
1535  "is last for progress",
1536  next_s->app_progress_hook, s->app_progress_hook);
1537  *last_for_progress = true;
1538 
1539  if (next_s->app_progress_hook - s->app_progress_hook > 1) {
1540  SCLogDebug("peek: missing progress, so we'll drop that unless we get a "
1541  "sweeping accept first");
1542  *fw_next_progress_missing = true;
1543  }
1544  }
1545  } else {
1546  SCLogDebug("peek: next sid not a fw rule, so current is last for progress");
1547  *last_for_progress = true;
1548  }
1549  } else {
1550  SCLogDebug("peek: no peek beyond last rule");
1551  if (s->app_progress_hook < tx->tx_progress) {
1552  SCLogDebug("peek: there are no rules to allow the state after this rule");
1553  *fw_next_progress_missing = true;
1554  }
1555  }
1556 
1557  if ((*skip_fw_hook) == true) {
1558  if (s->app_progress_hook <= skip_before_progress) {
1559  return -1;
1560  }
1561  *skip_fw_hook = false;
1562  }
1563  } else {
1564  /* fw mode, we skip anything after the fw rules if:
1565  * - flow pass is set
1566  * - packet pass (e.g. exception policy) */
1567  if (p->flags & PKT_NOPACKET_INSPECTION || (f->flags & (FLOW_ACTION_PASS))) {
1568  SCLogDebug("skipping firewall rule %u", s->id);
1569  return 1;
1570  }
1571  }
1572  return 0;
1573 }
1574 
1575 // TODO move into det_ctx?
1577 static inline void DetectRunAppendDefaultAccept(DetectEngineThreadCtx *det_ctx, Packet *p)
1578 {
1579  if (det_ctx->de_ctx->flags & DE_HAS_FIREWALL) {
1580  memset(&default_accept, 0, sizeof(default_accept));
1583  default_accept.num = UINT32_MAX;
1587  }
1588 }
1589 
1590 /** \internal
1591  * \brief see if the accept rule needs to apply to the packet
1592  */
1593 static inline bool ApplyAcceptToPacket(
1594  const uint64_t total_txs, const DetectTransaction *tx, const Signature *s)
1595 {
1596  if ((s->flags & SIG_FLAG_FIREWALL) == 0) {
1597  return false;
1598  }
1599  if ((s->action & ACTION_ACCEPT) == 0) {
1600  return false;
1601  }
1602 
1603  /* for accept:tx we need:
1604  * - packet will only be accepted if this is set on the last tx
1605  */
1606  if (s->action_scope == ACTION_SCOPE_TX) {
1607  if (total_txs == tx->tx_id + 1) {
1608  return true;
1609  }
1610  }
1611  /* for accept:hook we need a bit more checking:
1612  * - packet will only be accepted if this is set on the last tx
1613  * - the hook accepted should be the last progress available. */
1614  if (s->action_scope == ACTION_SCOPE_HOOK) {
1615  if ((total_txs == tx->tx_id + 1) && /* last tx */
1616  (s->app_progress_hook == tx->tx_progress)) {
1617  return true;
1618  }
1619  }
1620  return false;
1621 }
1622 
1623 static void DetectRunTx(ThreadVars *tv,
1625  DetectEngineThreadCtx *det_ctx,
1626  Packet *p,
1627  Flow *f,
1628  DetectRunScratchpad *scratch)
1629 {
1630  const uint8_t flow_flags = scratch->flow_flags;
1631  const SigGroupHead * const sgh = scratch->sgh;
1632  void * const alstate = f->alstate;
1633  const uint8_t ipproto = f->proto;
1634  const AppProto alproto = f->alproto;
1635 
1636  const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
1637  uint64_t tx_id_min = AppLayerParserGetTransactionInspectId(f->alparser, flow_flags);
1638  const int tx_end_state = AppLayerParserGetStateProgressCompletionStatus(alproto, flow_flags);
1639 
1640  AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
1641  AppLayerGetTxIterState state = { 0 };
1642 
1643  uint32_t fw_verdicted = 0;
1644  uint32_t tx_inspected = 0;
1645  const bool have_fw_rules = (de_ctx->flags & DE_HAS_FIREWALL) != 0;
1646 
1647  SCLogDebug("packet %" PRIu64, p->pcap_cnt);
1648 
1649  while (1) {
1650  AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id_min, total_txs, &state);
1651  if (ires.tx_ptr == NULL)
1652  break;
1653 
1654  DetectTransaction tx =
1655  GetDetectTx(ipproto, alproto, ires.tx_id, ires.tx_ptr, tx_end_state, flow_flags);
1656  if (tx.tx_ptr == NULL) {
1657  SCLogDebug("%p/%"PRIu64" no transaction to inspect",
1658  tx.tx_ptr, tx_id_min);
1659 
1660  tx_id_min++; // next (if any) run look for +1
1661  goto next;
1662  }
1663  tx_id_min = tx.tx_id + 1; // next look for cur + 1
1664  tx_inspected++;
1665 
1666  SCLogDebug("%p/%" PRIu64 " txd flags %02x", tx.tx_ptr, tx_id_min, tx.tx_data_ptr->flags);
1667 
1668  bool do_sort = false; // do we need to sort the tx candidate list?
1669  uint32_t array_idx = 0;
1670  uint32_t total_rules = det_ctx->match_array_cnt;
1671  total_rules += (tx.de_state ? tx.de_state->cnt : 0);
1672 
1673  /* run prefilter engines and merge results into a candidates array */
1674  if (sgh->tx_engines) {
1676  DetectRunPrefilterTx(det_ctx, sgh, p, ipproto, flow_flags, alproto,
1677  alstate, &tx);
1679  SCLogDebug("%p/%"PRIu64" rules added from prefilter: %u candidates",
1680  tx.tx_ptr, tx.tx_id, det_ctx->pmq.rule_id_array_cnt);
1681 
1682  total_rules += det_ctx->pmq.rule_id_array_cnt;
1683  if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, total_rules))) {
1684  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
1685  }
1686 
1687  for (uint32_t i = 0; i < det_ctx->pmq.rule_id_array_cnt; i++) {
1688  const Signature *s = de_ctx->sig_array[det_ctx->pmq.rule_id_array[i]];
1689  const SigIntId id = s->num;
1690  det_ctx->tx_candidates[array_idx].s = s;
1691  det_ctx->tx_candidates[array_idx].id = id;
1692  det_ctx->tx_candidates[array_idx].flags = NULL;
1693  det_ctx->tx_candidates[array_idx].stream_reset = 0;
1694  array_idx++;
1695  }
1696  PMQ_RESET(&det_ctx->pmq);
1697  } else {
1698  if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, total_rules))) {
1699  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
1700  }
1701  }
1702 
1703  /* merge 'state' rules from the regular prefilter */
1704 #ifdef PROFILING
1705  uint32_t x = array_idx;
1706 #endif
1707  RuleMatchCandidateMergeStateRules(det_ctx, &array_idx);
1708 
1709  /* merge stored state into results */
1710  if (tx.de_state != NULL) {
1711  const uint32_t old = array_idx;
1712 
1713  /* if tx.de_state->flags has 'new file' set and sig below has
1714  * 'file inspected' flag, reset the file part of the state */
1715  const bool have_new_file = (tx.de_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_NEW);
1716  if (have_new_file) {
1717  SCLogDebug("%p/%"PRIu64" destate: need to consider new file",
1718  tx.tx_ptr, tx.tx_id);
1720  }
1721 
1722  SigIntId state_cnt = 0;
1723  DeStateStore *tx_store = tx.de_state->head;
1724  for (; tx_store != NULL; tx_store = tx_store->next) {
1725  SCLogDebug("tx_store %p", tx_store);
1726 
1727  SigIntId store_cnt = 0;
1728  for (store_cnt = 0;
1729  store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx.de_state->cnt;
1730  store_cnt++, state_cnt++)
1731  {
1732  DeStateStoreItem *item = &tx_store->store[store_cnt];
1733  SCLogDebug("rule id %u, inspect_flags %u", item->sid, item->flags);
1734  if (have_new_file && (item->flags & DE_STATE_FLAG_FILE_INSPECT)) {
1735  /* remove part of the state. File inspect engine will now
1736  * be able to run again */
1738  SCLogDebug("rule id %u, post file reset inspect_flags %u", item->sid, item->flags);
1739  }
1740  det_ctx->tx_candidates[array_idx].s = de_ctx->sig_array[item->sid];
1741  det_ctx->tx_candidates[array_idx].id = item->sid;
1742  det_ctx->tx_candidates[array_idx].flags = &item->flags;
1743  det_ctx->tx_candidates[array_idx].stream_reset = 0;
1744  array_idx++;
1745  }
1746  }
1747  do_sort |= (old && old != array_idx); // sort if continue list adds sids
1748  SCLogDebug("%p/%" PRIu64 " rules added from 'continue' list: %u", tx.tx_ptr, tx.tx_id,
1749  array_idx - old);
1750  }
1751  if (do_sort) {
1752  qsort(det_ctx->tx_candidates, array_idx, sizeof(RuleMatchCandidateTx),
1753  DetectRunTxSortHelper);
1754  }
1755 
1756 #ifdef PROFILING
1757  if (array_idx >= de_ctx->profile_match_logging_threshold)
1758  RulesDumpTxMatchArray(det_ctx, scratch->sgh, p, tx.tx_id, array_idx, x);
1759 #endif
1760  det_ctx->tx_id = tx.tx_id;
1761  det_ctx->tx_id_set = true;
1762  det_ctx->p = p;
1763 
1764 #ifdef DEBUG
1765  for (uint32_t i = 0; i < array_idx; i++) {
1766  RuleMatchCandidateTx *can = &det_ctx->tx_candidates[i];
1767  const Signature *s = det_ctx->tx_candidates[i].s;
1768  SCLogDebug("%u: sid %u flags %p", i, s->id, can->flags);
1769  }
1770 #endif
1771  bool skip_fw_hook = false;
1772  uint8_t skip_before_progress = 0;
1773  bool fw_next_progress_missing = false;
1774 
1775  /* if there are no rules / rule candidates, make sure we don't
1776  * invoke the default drop */
1777  if (have_fw_rules && array_idx == 0 && (tx.tx_data_ptr->flags & APP_LAYER_TX_ACCEPT)) {
1778  fw_verdicted++;
1779 
1780  /* current tx is the last we have, append a blank accept:packet */
1781  if (total_txs == tx.tx_id + 1) {
1782  DetectRunAppendDefaultAccept(det_ctx, p);
1783  return;
1784  }
1785  goto next;
1786  }
1787 
1788  bool tx_fw_verdict = false;
1789  /* run rules: inspect the match candidates */
1790  for (uint32_t i = 0; i < array_idx; i++) {
1791  RuleMatchCandidateTx *can = &det_ctx->tx_candidates[i];
1792  const Signature *s = det_ctx->tx_candidates[i].s;
1793  uint32_t *inspect_flags = det_ctx->tx_candidates[i].flags;
1794  bool break_out_of_app_filter = false;
1795 
1796  SCLogDebug("%" PRIu64 ": sid:%u: %s tx %u/%u/%u sig %u", p->pcap_cnt, s->id,
1797  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", tx.tx_progress,
1799 
1800  /* deduplicate: rules_array is sorted, but not deduplicated:
1801  * both mpm and stored state could give us the same sid.
1802  * As they are back to back in that case we can check for it
1803  * here. We select the stored state one as that comes first
1804  * in the array. */
1805  while ((i + 1) < array_idx &&
1806  det_ctx->tx_candidates[i].s == det_ctx->tx_candidates[i + 1].s) {
1807  SCLogDebug("%p/%" PRIu64 " inspecting SKIP NEXT: sid %u (%u), flags %08x",
1808  tx.tx_ptr, tx.tx_id, s->id, s->num, inspect_flags ? *inspect_flags : 0);
1809  i++;
1810  }
1811 
1812  /* skip fw rules if we're in accept:tx mode */
1813  if (have_fw_rules && (tx.tx_data_ptr->flags & APP_LAYER_TX_ACCEPT)) {
1814  /* append a blank accept:packet action for the APP_LAYER_TX_ACCEPT,
1815  * if this is the last tx */
1816  if (!tx_fw_verdict) {
1817  const bool accept_tx_applies_to_packet = total_txs == tx.tx_id + 1;
1818  if (accept_tx_applies_to_packet) {
1819  SCLogDebug("accept:(tx|hook): should be applied to the packet");
1820  DetectRunAppendDefaultAccept(det_ctx, p);
1821  }
1822  }
1823  tx_fw_verdict = true;
1824 
1825  if (s->flags & SIG_FLAG_FIREWALL) {
1826  SCLogDebug("APP_LAYER_TX_ACCEPT, so skip rule");
1827  continue;
1828  }
1829 
1830  /* threat detect rules will be inspected */
1831  }
1832 
1833  SCLogDebug("%p/%"PRIu64" inspecting: sid %u (%u), flags %08x",
1834  tx.tx_ptr, tx.tx_id, s->id, s->num, inspect_flags ? *inspect_flags : 0);
1835 
1836  if (inspect_flags) {
1838  SCLogDebug("%p/%"PRIu64" inspecting: sid %u (%u), flags %08x ALREADY COMPLETE",
1839  tx.tx_ptr, tx.tx_id, s->id, s->num, *inspect_flags);
1840  continue;
1841  }
1842  }
1843 
1844  if (inspect_flags) {
1845  /* continue previous inspection */
1846  SCLogDebug("%p/%" PRIu64 " Continuing sid %u", tx.tx_ptr, tx.tx_id, s->id);
1847  } else {
1848  /* start new inspection */
1849  SCLogDebug("%p/%"PRIu64" Start sid %u", tx.tx_ptr, tx.tx_id, s->id);
1850  }
1851 
1852  bool last_for_progress = false;
1853  if (have_fw_rules) {
1854  int fw_r = DetectRunTxCheckFirewallPolicy(det_ctx, p, f, &tx, s, i, array_idx,
1855  &skip_fw_hook, skip_before_progress, &last_for_progress,
1856  &fw_next_progress_missing);
1857  if (fw_r == -1)
1858  continue;
1859  if (fw_r == 1)
1860  break;
1861  }
1862 
1863  /* call individual rule inspection */
1865  const int r = DetectRunTxInspectRule(tv, de_ctx, det_ctx, p, f, flow_flags,
1866  alstate, &tx, s, inspect_flags, can, scratch);
1867  if (r == 1) {
1868  /* match */
1869  DetectRunPostMatch(tv, det_ctx, p, s);
1870 
1871  /* see if we need to apply tx/hook accept to the packet. This can be needed when
1872  * we've completed the inspection so far for an incomplete tx, and an accept:tx or
1873  * accept:hook is the last match.*/
1874  const bool fw_accept_to_packet = ApplyAcceptToPacket(total_txs, &tx, s);
1875 
1876  uint8_t alert_flags = (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_TX);
1877  if (fw_accept_to_packet) {
1878  SCLogDebug("accept:(tx|hook): should be applied to the packet");
1880  }
1881 
1882  SCLogDebug("%p/%"PRIu64" sig %u (%u) matched", tx.tx_ptr, tx.tx_id, s->id, s->num);
1883  AlertQueueAppend(det_ctx, s, p, tx.tx_id, alert_flags);
1884 
1885  if ((s->flags & SIG_FLAG_FIREWALL) && (s->action & ACTION_ACCEPT)) {
1886  tx_fw_verdict = true;
1887 
1888  const enum ActionScope as = s->action_scope;
1889  /* accept:hook: jump to first rule of next state.
1890  * Implemented as skip until the first rule of next state. */
1891  if (as == ACTION_SCOPE_HOOK) {
1892  skip_fw_hook = true;
1893  skip_before_progress = s->app_progress_hook;
1894 
1895  /* if there is no fw rule for the next progress value,
1896  * we invoke the default drop policy. */
1897  if (fw_next_progress_missing) {
1898  SCLogDebug("%" PRIu64 ": %s default drop for progress", p->pcap_cnt,
1899  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient");
1901  p->flow->flags |= FLOW_ACTION_DROP;
1902  break_out_of_app_filter = true;
1903  }
1904  } else if (as == ACTION_SCOPE_TX) {
1905  tx.tx_data_ptr->flags |= APP_LAYER_TX_ACCEPT;
1906  skip_fw_hook = true;
1907  skip_before_progress = (uint8_t)tx_end_state + 1; // skip all hooks
1908  SCLogDebug("accept:tx applied, skip_fw_hook, skip_before_progress %u",
1909  skip_before_progress);
1910  } else if (as == ACTION_SCOPE_PACKET) {
1911  break_out_of_app_filter = true;
1912  } else if (as == ACTION_SCOPE_FLOW) {
1913  break_out_of_app_filter = true;
1914  }
1915  }
1916  } else if (last_for_progress) {
1917  SCLogDebug("sid %u: not a match: %s rule, last_for_progress %s", s->id,
1918  (s->flags & SIG_FLAG_FIREWALL) ? "firewall" : "regular",
1919  BOOL2STR(last_for_progress));
1920  if (s->flags & SIG_FLAG_FIREWALL) {
1921  SCLogDebug("%" PRIu64 ": %s default drop for progress", p->pcap_cnt,
1922  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient");
1923  /* if this rule was the last for our progress state, and it didn't match,
1924  * we have to invoke the default drop policy. */
1926  p->flow->flags |= FLOW_ACTION_DROP;
1927  break_out_of_app_filter = true;
1928  tx_fw_verdict = true;
1929  }
1930  }
1931  DetectVarProcessList(det_ctx, p->flow, p);
1932  RULE_PROFILING_END(det_ctx, s, r, p);
1933 
1934  if (det_ctx->post_rule_work_queue.len > 0) {
1935  SCLogDebug("%p/%" PRIu64 " post_rule_work_queue len %u", tx.tx_ptr, tx.tx_id,
1936  det_ctx->post_rule_work_queue.len);
1937  /* run post match prefilter engines on work queue */
1938  PrefilterPostRuleMatch(det_ctx, scratch->sgh, p, f);
1939 
1940  uint32_t prev_array_idx = array_idx;
1941  for (uint32_t j = 0; j < det_ctx->pmq.rule_id_array_cnt; j++) {
1942  const Signature *ts = de_ctx->sig_array[det_ctx->pmq.rule_id_array[j]];
1943  if (ts->app_inspect != NULL) {
1944  const SigIntId id = ts->num;
1945  det_ctx->tx_candidates[array_idx].s = ts;
1946  det_ctx->tx_candidates[array_idx].id = id;
1947  det_ctx->tx_candidates[array_idx].flags = NULL;
1948  det_ctx->tx_candidates[array_idx].stream_reset = 0;
1949  array_idx++;
1950 
1951  SCLogDebug("%p/%" PRIu64 " rule %u (%u) added from 'post match' prefilter",
1952  tx.tx_ptr, tx.tx_id, ts->id, id);
1953  }
1954  }
1955  SCLogDebug("%p/%" PRIu64 " rules added from 'post match' prefilter: %u", tx.tx_ptr,
1956  tx.tx_id, array_idx - prev_array_idx);
1957  if (prev_array_idx != array_idx) {
1958  /* sort, but only part of array we're still going to process */
1959  qsort(det_ctx->tx_candidates + i, array_idx - i, sizeof(RuleMatchCandidateTx),
1960  DetectRunTxSortHelper);
1961  }
1962  det_ctx->post_rule_work_queue.len = 0;
1963  PMQ_RESET(&det_ctx->pmq);
1964  }
1965 
1966  if (break_out_of_app_filter)
1967  break;
1968  }
1969  if (tx_fw_verdict)
1970  fw_verdicted++;
1971 
1972  det_ctx->tx_id = 0;
1973  det_ctx->tx_id_set = false;
1974  det_ctx->p = NULL;
1975 
1976  /* see if we have any updated state to store in the tx */
1977 
1978  /* this side of the tx is done */
1979  if (tx.tx_progress >= tx.tx_end_state) {
1980  SCLogDebug("%" PRIu64 ": %s tx done", p->pcap_cnt,
1981  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient");
1982  const uint8_t inspected_flag = (flow_flags & STREAM_TOSERVER)
1985  tx.tx_data_ptr->flags |= inspected_flag;
1986  SCLogDebug("%p/%" PRIu64 " tx is done for direction %s. Progress %02x", tx.tx_ptr,
1987  tx.tx_id, flow_flags & STREAM_TOSERVER ? "toserver" : "toclient",
1988  tx.detect_progress);
1989  }
1990 
1991  if (tx.detect_progress != tx.detect_progress_orig) {
1992  SCLogDebug("%" PRIu64 ": %s tx state change %u -> %u", p->pcap_cnt,
1993  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", tx.detect_progress_orig,
1994  tx.detect_progress);
1995  SCLogDebug("%p/%" PRIu64 " Storing new progress %02x (was %02x)", tx.tx_ptr, tx.tx_id,
1997 
1998  StoreDetectProgress(&tx, flow_flags, tx.detect_progress);
1999  }
2000 
2001  InspectionBufferClean(det_ctx);
2002 
2003  next:
2004  if (!ires.has_next)
2005  break;
2006  }
2007 
2008  /* apply default policy if there were txs to inspect, we have fw rules and non of the rules
2009  * applied a policy. */
2010  SCLogDebug("packet %" PRIu64 ": tx_inspected %u fw_verdicted %u", p->pcap_cnt, tx_inspected,
2011  fw_verdicted);
2012  if (tx_inspected && have_fw_rules && tx_inspected != fw_verdicted) {
2013  SCLogDebug("%" PRIu64 ": %s default drop", p->pcap_cnt,
2014  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient");
2016  p->flow->flags |= FLOW_ACTION_DROP;
2017  return;
2018  }
2019  /* if all tables have been bypassed, we accept:packet */
2020  if (tx_inspected == 0 && fw_verdicted == 0 && have_fw_rules) {
2021  DetectRunAppendDefaultAccept(det_ctx, p);
2022  }
2023 }
2024 
2025 static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2026  Packet *p, Flow *f, DetectRunScratchpad *scratch)
2027 {
2028  const SigGroupHead *const sgh = scratch->sgh;
2029  const AppProto alproto = f->alproto;
2030 
2031  /* for TCP, limit inspection to pseudo packets or real packet that did
2032  * an app-layer update. */
2033  if (p->proto == IPPROTO_TCP && !PKT_IS_PSEUDOPKT(p) &&
2034  ((PKT_IS_TOSERVER(p) && (f->flags & FLOW_TS_APP_UPDATED) == 0) ||
2035  (PKT_IS_TOCLIENT(p) && (f->flags & FLOW_TC_APP_UPDATED) == 0))) {
2036  SCLogDebug("pcap_cnt %" PRIu64 ": %s: skip frame inspection for TCP w/o APP UPDATE",
2037  p->pcap_cnt, PKT_IS_TOSERVER(p) ? "toserver" : "toclient");
2038  return;
2039  }
2040  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
2041  if (frames_container == NULL) {
2042  return;
2043  }
2044  Frames *frames;
2045  if (PKT_IS_TOSERVER(p)) {
2046  frames = &frames_container->toserver;
2047  } else {
2048  frames = &frames_container->toclient;
2049  }
2050 
2051  for (uint32_t idx = 0; idx < frames->cnt; idx++) {
2052  SCLogDebug("frame %u", idx);
2053  Frame *frame = FrameGetByIndex(frames, idx);
2054  if (frame == NULL) {
2055  continue;
2056  }
2057 
2058  det_ctx->frame_inspect_progress = 0;
2059  uint32_t array_idx = 0;
2060  uint32_t total_rules = det_ctx->match_array_cnt;
2061 
2062  /* run prefilter engines and merge results into a candidates array */
2063  if (sgh->frame_engines) {
2064  // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX);
2065  DetectRunPrefilterFrame(det_ctx, sgh, p, frames, frame, alproto);
2066  // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX);
2067  SCLogDebug("%p/%" PRIi64 " rules added from prefilter: %u candidates", frame, frame->id,
2068  det_ctx->pmq.rule_id_array_cnt);
2069 
2070  total_rules += det_ctx->pmq.rule_id_array_cnt;
2071 
2072  if (!(RuleMatchCandidateTxArrayHasSpace(
2073  det_ctx, total_rules))) { // TODO is it safe to overload?
2074  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
2075  }
2076 
2077  for (uint32_t i = 0; i < det_ctx->pmq.rule_id_array_cnt; i++) {
2078  const Signature *s = de_ctx->sig_array[det_ctx->pmq.rule_id_array[i]];
2079  const SigIntId id = s->num;
2080  det_ctx->tx_candidates[array_idx].s = s;
2081  det_ctx->tx_candidates[array_idx].id = id;
2082  det_ctx->tx_candidates[array_idx].flags = NULL;
2083  det_ctx->tx_candidates[array_idx].stream_reset = 0;
2084  array_idx++;
2085  }
2086  PMQ_RESET(&det_ctx->pmq);
2087  }
2088  /* merge 'state' rules from the regular prefilter */
2089  uint32_t x = array_idx;
2090  for (uint32_t i = 0; i < det_ctx->match_array_cnt; i++) {
2091  const Signature *s = det_ctx->match_array[i];
2092  if (s->frame_inspect != NULL) {
2093  const SigIntId id = s->num;
2094  det_ctx->tx_candidates[array_idx].s = s;
2095  det_ctx->tx_candidates[array_idx].id = id;
2096  det_ctx->tx_candidates[array_idx].flags = NULL;
2097  det_ctx->tx_candidates[array_idx].stream_reset = 0;
2098  array_idx++;
2099 
2100  SCLogDebug("%p/%" PRIi64 " rule %u (%u) added from 'match' list", frame, frame->id,
2101  s->id, id);
2102  }
2103  }
2104  SCLogDebug("%p/%" PRIi64 " rules added from 'match' list: %u", frame, frame->id,
2105  array_idx - x);
2106  (void)x;
2107 
2108  /* run rules: inspect the match candidates */
2109  for (uint32_t i = 0; i < array_idx; i++) {
2110  const Signature *s = det_ctx->tx_candidates[i].s;
2111 
2112  /* deduplicate: rules_array is sorted, but not deduplicated.
2113  * As they are back to back in that case we can check for it
2114  * here. We select the stored state one as that comes first
2115  * in the array. */
2116  while ((i + 1) < array_idx &&
2117  det_ctx->tx_candidates[i].s == det_ctx->tx_candidates[i + 1].s) {
2118  i++;
2119  }
2120  SCLogDebug("%p/%" PRIi64 " inspecting: sid %u (%u)", frame, frame->id, s->id, s->num);
2121 
2122  /* start new inspection */
2123  SCLogDebug("%p/%" PRIi64 " Start sid %u", frame, frame->id, s->id);
2124 
2125  /* call individual rule inspection */
2127  bool r = DetectRunInspectRuleHeader(p, f, s, s->flags, s->proto.flags);
2128  if (r) {
2129  r = DetectRunFrameInspectRule(tv, det_ctx, s, f, p, frames, frame);
2130  if (r) {
2131  /* match */
2132  DetectRunPostMatch(tv, det_ctx, p, s);
2133 
2134  uint8_t alert_flags = (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_FRAME);
2135  det_ctx->frame_id = frame->id;
2136  SCLogDebug(
2137  "%p/%" PRIi64 " sig %u (%u) matched", frame, frame->id, s->id, s->num);
2138  if (frame->flags & FRAME_FLAG_TX_ID_SET) {
2139  alert_flags |= PACKET_ALERT_FLAG_TX;
2140  }
2141  AlertQueueAppend(det_ctx, s, p, frame->tx_id, alert_flags);
2142  }
2143  }
2144  DetectVarProcessList(det_ctx, p->flow, p);
2145  RULE_PROFILING_END(det_ctx, s, r, p);
2146  }
2147 
2148  /* update Frame::inspect_progress here instead of in the code above. The reason is that a
2149  * frame might be used more than once in buffers with transforms. */
2150  if (frame->inspect_progress < det_ctx->frame_inspect_progress) {
2151  frame->inspect_progress = det_ctx->frame_inspect_progress;
2152  SCLogDebug("frame->inspect_progress: %" PRIu64 " -> updated", frame->inspect_progress);
2153  } else {
2154  SCLogDebug(
2155  "frame->inspect_progress: %" PRIu64 " -> not updated", frame->inspect_progress);
2156  }
2157 
2158  SCLogDebug("%p/%" PRIi64 " rules inspected, running cleanup", frame, frame->id);
2159  InspectionBufferClean(det_ctx);
2160  }
2161 }
2162 
2163 static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id)
2164 {
2165  /* technically we need to pass a DetectEngineThreadCtx struct with the
2166  * tenant_id member. But as that member is the first in the struct, we
2167  * can use the id directly. */
2168  return HashTableLookup(h, &id, 0);
2169 }
2170 
2171 static void DetectFlow(ThreadVars *tv,
2173  Packet *p)
2174 {
2175  Flow *const f = p->flow;
2176 
2177  /* we check the flow drop here, and not the packet drop. This is
2178  * to allow stream engine "invalid" drop packets to still be
2179  * evaluated by the stream event rules. */
2180  if (f->flags & FLOW_ACTION_DROP) {
2182  SCReturn;
2183  }
2184 
2185  /* in firewall mode, we still need to run the fw rulesets even for exception policy pass */
2186  bool skip = false;
2187  if (de_ctx->flags & DE_HAS_FIREWALL) {
2188  skip = (f->flags & (FLOW_ACTION_ACCEPT));
2189 
2190  } else {
2191  skip = (p->flags & PKT_NOPACKET_INSPECTION || f->flags & (FLOW_ACTION_PASS));
2192  }
2193  if (skip) {
2194  /* enfore prior accept:flow */
2195  if (f->flags & FLOW_ACTION_ACCEPT) {
2196  p->action |= ACTION_ACCEPT;
2197  }
2198  /* hack: if we are in pass the entire flow mode, we need to still
2199  * update the inspect_id forward. So test for the condition here,
2200  * and call the update code if necessary. */
2201  const int pass = (f->flags & (FLOW_ACTION_PASS | FLOW_ACTION_ACCEPT));
2202  if (pass) {
2203  uint8_t flags = STREAM_FLAGS_FOR_PACKET(p);
2205  if (f->alstate) {
2207  }
2208  }
2209  SCLogDebug("p->pcap %"PRIu64": no detection on packet, "
2210  "PKT_NOPACKET_INSPECTION is set", p->pcap_cnt);
2211  return;
2212  }
2213 
2214  /* see if the packet matches one or more of the sigs */
2215  DetectRun(tv, de_ctx, det_ctx, p);
2216 }
2217 
2218 
2219 static void DetectNoFlow(ThreadVars *tv,
2221  Packet *p)
2222 {
2223  /* No need to perform any detection on this packet, if the given flag is set.*/
2225  return;
2226  }
2227 
2228  /* see if the packet matches one or more of the sigs */
2229  DetectRun(tv, de_ctx, det_ctx, p);
2230 }
2231 
2232 /** \brief Detection engine thread wrapper.
2233  * \param tv thread vars
2234  * \param p packet to inspect
2235  * \param data thread specific data
2236  * \param pq packet queue
2237  * \retval TM_ECODE_FAILED error
2238  * \retval TM_ECODE_OK ok
2239  */
2240 TmEcode Detect(ThreadVars *tv, Packet *p, void *data)
2241 {
2243 
2244  DetectEngineCtx *de_ctx = NULL;
2245  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
2246  if (det_ctx == NULL) {
2247  printf("ERROR: Detect has no thread ctx\n");
2248  goto error;
2249  }
2250 
2251  if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) {
2252  (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1);
2253  SCLogDebug("Detect Engine using new det_ctx - %p",
2254  det_ctx);
2255  }
2256 
2257  /* if in MT mode _and_ we have tenants registered, use
2258  * MT logic. */
2259  if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL)
2260  {
2261  uint32_t tenant_id = p->tenant_id;
2262  if (tenant_id == 0)
2263  tenant_id = det_ctx->TenantGetId(det_ctx, p);
2264  if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) {
2265  p->tenant_id = tenant_id;
2266  det_ctx = GetTenantById(det_ctx->mt_det_ctxs_hash, tenant_id);
2267  if (det_ctx == NULL)
2268  return TM_ECODE_OK;
2269  de_ctx = det_ctx->de_ctx;
2270  if (de_ctx == NULL)
2271  return TM_ECODE_OK;
2272 
2273  if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) {
2274  (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1);
2275  SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id);
2276  }
2277  } else {
2278  /* use default if no tenants are registered for this packet */
2279  de_ctx = det_ctx->de_ctx;
2280  }
2281  } else {
2282  de_ctx = det_ctx->de_ctx;
2283  }
2284 
2285  if (p->flow) {
2286  DetectFlow(tv, de_ctx, det_ctx, p);
2287  } else {
2288  DetectNoFlow(tv, de_ctx, det_ctx, p);
2289  }
2290 
2291 #ifdef PROFILE_RULES
2292  /* aggregate statistics */
2293  struct timeval ts;
2294  gettimeofday(&ts, NULL);
2295  if (ts.tv_sec != det_ctx->rule_perf_last_sync) {
2296  SCProfilingRuleThreatAggregate(det_ctx);
2297  det_ctx->rule_perf_last_sync = ts.tv_sec;
2298  }
2299 #endif
2300 
2301  return TM_ECODE_OK;
2302 error:
2303  return TM_ECODE_FAILED;
2304 }
2305 
2306 /** \brief disable file features we don't need
2307  * Called if we have no detection engine.
2308  */
2310 {
2311  DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOSERVER);
2312  DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOCLIENT);
2313 }
2314 
2315 #ifdef UNITTESTS
2316 /**
2317  * \brief wrapper for old tests
2318  */
2321 {
2322  if (p->flow) {
2323  DetectFlow(tv, de_ctx, det_ctx, p);
2324  } else {
2325  DetectNoFlow(tv, de_ctx, det_ctx, p);
2326  }
2327 }
2328 #endif
2329 
2330 /*
2331  * TESTS
2332  */
2333 
2334 #ifdef UNITTESTS
2335 #include "tests/detect.c"
2336 #endif
PKT_IS_TOCLIENT
#define PKT_IS_TOCLIENT(p)
Definition: decode.h:239
default_accept
thread_local Signature default_accept
Definition: detect.c:1576
DetectEngineAppInspectionEngine_::stream
bool stream
Definition: detect.h:441
PacketCheckAction
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition: packet.c:49
FLOWFILE_NO_MD5_TS
#define FLOWFILE_NO_MD5_TS
Definition: flow.h:137
RulesDumpTxMatchArray
void RulesDumpTxMatchArray(const DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, const Packet *p, const uint64_t tx_id, const uint32_t rule_cnt, const uint32_t pkt_prefilter_cnt)
Definition: detect-engine-profile.c:34
SIG_GROUP_HEAD_HAVEFILEMD5
#define SIG_GROUP_HEAD_HAVEFILEMD5
Definition: detect.h:1433
FLOWFILE_NO_MD5_TC
#define FLOWFILE_NO_MD5_TC
Definition: flow.h:138
SigGroupHead_::tx_engines
PrefilterEngine * tx_engines
Definition: detect.h:1582
DetectEngineAppInspectionEngine_
Definition: detect.h:436
Packet_::proto
uint8_t proto
Definition: decode.h:506
DetectTransaction_::tx_data_ptr
struct AppLayerTxData * tx_data_ptr
Definition: detect-engine-prefilter.h:34
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:440
DE_STATE_CHUNK_SIZE
#define DE_STATE_CHUNK_SIZE
Definition: detect-engine-state.h:52
RuleMatchCandidateTx::stream_stored
bool stream_stored
Definition: detect.h:1166
FLOWFILE_NO_SIZE_TS
#define FLOWFILE_NO_SIZE_TS
Definition: flow.h:149
Frame::inspect_progress
uint64_t inspect_progress
Definition: app-layer-frames.h:55
DetectEngineThreadCtx_::alert_queue_size
uint16_t alert_queue_size
Definition: detect.h:1278
PROF_DETECT_GETSGH
@ PROF_DETECT_GETSGH
Definition: suricata-common.h:450
ts
uint64_t ts
Definition: source-erf-file.c:55
FLOWFILE_NO_SIZE_TC
#define FLOWFILE_NO_SIZE_TC
Definition: flow.h:150
detect-engine.h
DE_HAS_FIREWALL
#define DE_HAS_FIREWALL
Definition: detect.h:330
detect-engine-proto.h
DetectEngineThreadCtx_::match_array_cnt
SigIntId match_array_cnt
Definition: detect.h:1289
Frame::tx_id
uint64_t tx_id
Definition: app-layer-frames.h:54
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:88
detect-dsize.h
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:712
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:155
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1242
PACKET_ALERT_FLAG_TX
#define PACKET_ALERT_FLAG_TX
Definition: decode.h:259
DetectEngineCtx_::decoder_event_sgh
struct SigGroupHead_ * decoder_event_sgh
Definition: detect.h:1005
FlowGetPacketDirection
int FlowGetPacketDirection(const Flow *f, const Packet *p)
determine the direction of the packet compared to the flow
Definition: flow.c:278
DetectEngineCtx_::flow_gh
DetectEngineLookupFlow flow_gh[FLOW_STATES]
Definition: detect.h:947
DE_STATE_FLAG_SIG_CANT_MATCH
#define DE_STATE_FLAG_SIG_CANT_MATCH
Definition: detect-engine-state.h:56
DetectEngineThreadCtx_::counter_match_list
uint16_t counter_match_list
Definition: detect.h:1247
ALPROTO_DNS
@ ALPROTO_DNS
Definition: app-layer-protos.h:47
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:460
DETECT_PROTO_IPV6
#define DETECT_PROTO_IPV6
Definition: detect-engine-proto.h:32
detect-engine-siggroup.h
SigGroupHead_::flags
uint16_t flags
Definition: detect.h:1571
APP_LAYER_TX_SKIP_INSPECT_TC
#define APP_LAYER_TX_SKIP_INSPECT_TC
Definition: app-layer-parser.h:54
PostRuleMatchWorkQueue::len
uint32_t len
Definition: detect.h:1190
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1297
DetectEngineState_
Definition: detect-engine-state.h:92
Signature_::num
SigIntId num
Definition: detect.h:681
stream-tcp.h
PrefilterRuleStore_::rule_id_array_cnt
uint32_t rule_id_array_cnt
Definition: util-prefilter.h:40
detect-engine-event.h
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1570
SIG_GROUP_HEAD_HAVEFILESIZE
#define SIG_GROUP_HEAD_HAVEFILESIZE
Definition: detect.h:1434
DetectEngineCtx_::guess_applayer
bool guess_applayer
Definition: detect.h:967
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
detect.c
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
Signature_::app_progress_hook
uint8_t app_progress_hook
Definition: detect.h:706
KEYWORD_PROFILING_SET_LIST
#define KEYWORD_PROFILING_SET_LIST(ctx, list)
Definition: util-profiling.h:46
DetectAddressMatchIPv4
int DetectAddressMatchIPv4(const DetectMatchAddressIPv4 *addrs, uint16_t addrs_cnt, const Address *a)
Match a packets address against a signatures addrs array.
Definition: detect-engine-address.c:1589
DetectEngineAppInspectionEngine_::Callback
InspectEngineFuncPtr Callback
Definition: detect.h:453
Signature_::alproto
AppProto alproto
Definition: detect.h:674
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
FLOW_SGH_TOCLIENT
#define FLOW_SGH_TOCLIENT
Definition: flow.h:75
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:609
AppLayerParserSetTransactionInspectId
void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate, void *alstate, const uint8_t flags, bool tag_txs_as_inspected)
Definition: app-layer-parser.c:753
DetectEngineStateDirection_::cnt
SigIntId cnt
Definition: detect-engine-state.h:86
AppLayerGetTxIterator
AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, const AppProto alproto)
Definition: app-layer-parser.c:706
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:367
Flow_::proto
uint8_t proto
Definition: flow.h:378
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:85
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:273
AppLayerParserGetStateProgress
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
Definition: app-layer-parser.c:1096
DetectEngineThreadCtx_::tx_id
uint64_t tx_id
Definition: detect.h:1269
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:368
action-globals.h
FLOWFILE_NO_MAGIC_TS
#define FLOWFILE_NO_MAGIC_TS
Definition: flow.h:130
FramesContainer::toserver
Frames toserver
Definition: app-layer-frames.h:74
Packet_::flags
uint32_t flags
Definition: decode.h:527
Packet_::action
uint8_t action
Definition: decode.h:592
ICMPV4_DEST_UNREACH_IS_VALID
#define ICMPV4_DEST_UNREACH_IS_VALID(p)
Definition: decode-icmpv4.h:253
Frame
Definition: app-layer-frames.h:45
Flow_
Flow data structure.
Definition: flow.h:356
DetectTransaction_::tx_end_state
const int tx_end_state
Definition: detect-engine-prefilter.h:44
PROF_DETECT_ALERT
@ PROF_DETECT_ALERT
Definition: suricata-common.h:461
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1298
SIG_GROUP_HEAD_HAVEFILESHA1
#define SIG_GROUP_HEAD_HAVEFILESHA1
Definition: detect.h:1435
FLOW_TC_APP_UPDATED
#define FLOW_TC_APP_UPDATED
Definition: flow.h:120
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:920
AppLayerParserGetStateProgressCompletionStatus
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:1125
DetectRunScratchpad
struct DetectRunScratchpad DetectRunScratchpad
PROF_DETECT_PF_TX
@ PROF_DETECT_PF_TX
Definition: suricata-common.h:456
Frames::cnt
uint16_t cnt
Definition: app-layer-frames.h:61
Frame::id
int64_t id
Definition: app-layer-frames.h:53
DetectEngineThreadCtx_::p
Packet * p
Definition: detect.h:1273
DetectEngineAppInspectionEngine_::v2
struct DetectEngineAppInspectionEngine_::@79 v2
DetectEngineState_::dir_state
DetectEngineStateDirection dir_state[2]
Definition: detect-engine-state.h:93
FrameGetByIndex
Frame * FrameGetByIndex(Frames *frames, const uint32_t idx)
Definition: app-layer-frames.c:144
RuleMatchCandidateTx::id
SigIntId id
Definition: detect.h:1162
PROF_DETECT_CLEANUP
@ PROF_DETECT_CLEANUP
Definition: suricata-common.h:463
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:241
ACTION_SCOPE_FLOW
@ ACTION_SCOPE_FLOW
Definition: action-globals.h:45
NO_TX
#define NO_TX
Definition: detect.c:1348
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:233
HashTable_
Definition: util-hash.h:35
SIG_FLAG_TXBOTHDIR
#define SIG_FLAG_TXBOTHDIR
Definition: detect.h:249
Packet_::sig_mask
SignatureMask sig_mask
Definition: decode.h:521
Frames
Definition: app-layer-frames.h:60
FramesContainer
Definition: app-layer-frames.h:73
PacketAlerts_::drop
PacketAlert drop
Definition: decode.h:279
DetectRunScratchpad
Definition: detect.c:69
SIG_GROUP_HEAD_HAVERAWSTREAM
#define SIG_GROUP_HEAD_HAVERAWSTREAM
Definition: detect.h:1429
FLOW_ACTION_DROP
#define FLOW_ACTION_DROP
Definition: flow.h:70
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:107
FLOWFILE_NONE
#define FLOWFILE_NONE
Definition: flow.h:168
detect-engine-frame.h
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2319
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:732
proto
uint8_t proto
Definition: decode-template.h:0
m
SCMutex m
Definition: flow-hash.h:6
DetectPort_::sh
struct SigGroupHead_ * sh
Definition: detect.h:230
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1231
PACKET_PROFILING_DETECT_END
#define PACKET_PROFILING_DETECT_END(p, id)
Definition: util-profiling.h:221
Detect
TmEcode Detect(ThreadVars *tv, Packet *p, void *data)
Detection engine thread wrapper.
Definition: detect.c:2240
detect-engine-payload.h
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:515
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:240
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
DetectRunFrameInspectRule
bool DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p, const Frames *frames, const Frame *frame)
Definition: detect-engine-frame.c:228
Flow_::protoctx
void * protoctx
Definition: flow.h:441
SigMatchData_
Data needed for Match()
Definition: detect.h:365
DeStateStoreItem_::sid
SigIntId sid
Definition: detect-engine-state.h:74
RuleMatchCandidateTx::s
const Signature * s
Definition: detect.h:1172
KEYWORD_PROFILING_START
#define KEYWORD_PROFILING_START
Definition: util-profiling.h:50
SigMatchData_::type
uint16_t type
Definition: detect.h:366
DetectEngineCtx_::version
uint32_t version
Definition: detect.h:1001
DisableDetectFlowFileFlags
void DisableDetectFlowFileFlags(Flow *f)
disable file features we don't need Called if we have no detection engine.
Definition: detect.c:2309
AppLayerParserGetTransactionInspectId
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
Definition: app-layer-parser.c:731
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:603
DetectTransaction_::tx_progress
const int tx_progress
Definition: detect-engine-prefilter.h:43
detect-engine-prefilter.h
DetectRunPrefilterFrame
void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const Frames *frames, const Frame *frame, const AppProto alproto)
Definition: detect-engine-frame.c:73
Packet_::events
PacketEngineEvents events
Definition: decode.h:613
Signature_::frame_inspect
DetectEngineFrameInspectionEngine * frame_inspect
Definition: detect.h:728
PROF_DETECT_PF_SORT2
@ PROF_DETECT_PF_SORT2
Definition: suricata-common.h:459
pad
uint16_t pad
Definition: source-erf-file.c:61
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
PacketCreateMask
void PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, bool app_decoder_events)
Definition: detect-engine-build.c:419
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:248
KEYWORD_PROFILING_END
#define KEYWORD_PROFILING_END(ctx, type, m)
Definition: util-profiling.h:64
detect-flowvar.h
DetectEngineThreadCtx_::mt_det_ctxs_hash
HashTable * mt_det_ctxs_hash
Definition: detect.h:1209
PacketAlert_::action
uint8_t action
Definition: decode.h:245
TcpSession_::flags
uint32_t flags
Definition: stream-tcp-private.h:294
DetectEnginePktInspectionRun
bool DetectEnginePktInspectionRun(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p, uint8_t *alert_flags)
Definition: detect-engine.c:2067
SIG_FLAG_FIREWALL
#define SIG_FLAG_FIREWALL
Definition: detect.h:245
Flow_::sgh_toserver
const struct SigGroupHead_ * sgh_toserver
Definition: flow.h:486
PROF_DETECT_TX_UPDATE
@ PROF_DETECT_TX_UPDATE
Definition: suricata-common.h:462
DetectEngineAppInspectionEngine_::id
uint8_t id
Definition: detect.h:439
DetectEngineThreadCtx_::counter_alerts_suppressed
uint16_t counter_alerts_suppressed
Definition: detect.h:1242
DetectRunStoreStateTx
void DetectRunStoreStateTx(const SigGroupHead *sgh, Flow *f, void *tx, uint64_t tx_id, const Signature *s, uint32_t inspect_flags, uint8_t flow_flags, const uint16_t file_no_match)
Definition: detect-engine-state.c:214
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:444
FLOWFILE_INIT
#define FLOWFILE_INIT
Definition: flow.h:127
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:478
FLOW_ACTION_PASS
#define FLOW_ACTION_PASS
Definition: flow.h:117
DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES
#define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES
Definition: detect-engine-state.h:43
FLOWFILE_NO_SHA1_TC
#define FLOWFILE_NO_SHA1_TC
Definition: flow.h:142
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:126
FramesContainer::toclient
Frames toclient
Definition: app-layer-frames.h:75
DetectEngineThreadCtx_::tx_candidates
RuleMatchCandidateTx * tx_candidates
Definition: detect.h:1291
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:71
PKT_DROP_REASON_DEFAULT_APP_POLICY
@ PKT_DROP_REASON_DEFAULT_APP_POLICY
Definition: decode.h:384
Signature_::addr_src_match4
DetectMatchAddressIPv4 * addr_src_match4
Definition: detect.h:709
decode.h
DetectEngineThreadCtx_::counter_alerts_overflow
uint16_t counter_alerts_overflow
Definition: detect.h:1240
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:52
TOSERVER
#define TOSERVER
Definition: flow.h:45
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:238
PACKET_ALERT_FLAG_APPLY_ACTION_TO_PACKET
#define PACKET_ALERT_FLAG_APPLY_ACTION_TO_PACKET
Definition: decode.h:267
Prefilter
void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags, const SignatureMask mask)
Definition: detect-engine-prefilter.c:216
DetectTransaction_::detect_progress_orig
const uint8_t detect_progress_orig
Definition: detect-engine-prefilter.h:41
DetectEngineThreadCtx_
Definition: detect.h:1197
DEBUG_VALIDATE_PACKET
#define DEBUG_VALIDATE_PACKET(p)
Definition: util-validate.h:101
DeStateStoreItem_::flags
uint32_t flags
Definition: detect-engine-state.h:73
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1237
DetectTransaction_::detect_progress
uint8_t detect_progress
Definition: detect-engine-prefilter.h:39
FLOWFILE_NO_STORE_TS
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:134
BIT_U32
#define BIT_U32(n)
Definition: suricata-common.h:409
DetectEngineThreadCtx_::tx_candidates_size
uint32_t tx_candidates_size
Definition: detect.h:1292
FRAME_FLAG_TX_ID_SET
#define FRAME_FLAG_TX_ID_SET
Definition: app-layer-frames.h:38
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1244
PKT_IS_FRAGMENT
#define PKT_IS_FRAGMENT
Definition: decode.h:1266
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:527
STREAM_FLAGS_FOR_PACKET
#define STREAM_FLAGS_FOR_PACKET(p)
Definition: stream.h:30
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
PMQ_RESET
#define PMQ_RESET(pmq)
Definition: util-prefilter.h:46
detect-engine-mpm.h
DetectEngineLookupFlow_::sgh
struct SigGroupHead_ * sgh[256]
Definition: detect.h:864
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:183
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DeStateStore_::next
struct DeStateStore_ * next
Definition: detect-engine-state.h:79
Packet_::sp
Port sp
Definition: decode.h:491
FLOWFILE_NO_SHA256_TS
#define FLOWFILE_NO_SHA256_TS
Definition: flow.h:145
DETECT_ENGINE_INSPECT_SIG_MATCH
#define DETECT_ENGINE_INSPECT_SIG_MATCH
Definition: detect-engine-state.h:38
PKT_DETECT_HAS_STREAMDATA
#define PKT_DETECT_HAS_STREAMDATA
Definition: decode.h:1281
FLOW_PKT_TOCLIENT_FIRST
#define FLOW_PKT_TOCLIENT_FIRST
Definition: flow.h:237
StreamReassembleRawHasDataReady
bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p)
does the stream engine have data to inspect?
Definition: stream-tcp-reassemble.c:1512
detect-engine-port.h
PktSrcToString
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition: decode.c:826
PACKET_ALERT_FLAG_TX_GUESSED
#define PACKET_ALERT_FLAG_TX_GUESSED
Definition: decode.h:265
DetectPort_
Port structure for detection engine.
Definition: detect.h:219
PacketAlerts_::discarded
uint16_t discarded
Definition: decode.h:274
app-layer-parser.h
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:726
util-detect.h
detect-engine-profile.h
Flow_::sgh_toclient
const struct SigGroupHead_ * sgh_toclient
Definition: flow.h:483
DetectEngineThreadCtx_::base64_decoded_len
int base64_decoded_len
Definition: detect.h:1276
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:266
RuleMatchCandidateTx::stream_result
uint8_t stream_result
Definition: detect.h:1167
Signature_::action
uint8_t action
Definition: detect.h:684
util-profiling.h
DetectTransaction_::tx_id
const uint64_t tx_id
Definition: detect-engine-prefilter.h:33
DetectEngineLookupFlow_::udp
DetectPort * udp
Definition: detect.h:863
DetectEngineThreadCtx_::raw_stream_progress
uint64_t raw_stream_progress
Definition: detect.h:1218
FileUpdateFlowFileFlags
void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction)
set a flow's file flags
Definition: util-file.c:1120
SCReturn
#define SCReturn
Definition: util-debug.h:273
Signature_::flags
uint32_t flags
Definition: detect.h:670
AlertQueueAppend
void AlertQueueAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, uint8_t alert_flags)
Append signature to local packet alert queue for later preprocessing.
Definition: detect-engine-alert.c:297
RuleMatchCandidateTxArrayFree
void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx)
Definition: detect.c:1037
AppLayerGetTxIterState
Definition: app-layer-parser.h:121
Packet_
Definition: decode.h:484
detect-engine-build.h
AppLayerFramesGetContainer
FramesContainer * AppLayerFramesGetContainer(Flow *f)
Definition: app-layer-parser.c:182
ACTION_SCOPE_TX
@ ACTION_SCOPE_TX
Definition: action-globals.h:47
DetectEngineThreadCtx_::frame_id
int64_t frame_id
Definition: detect.h:1270
detect-engine-alert.h
DetectEngineThreadCtx_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1235
PROF_DETECT_IPONLY
@ PROF_DETECT_IPONLY
Definition: suricata-common.h:451
RULE_PROFILING_END
#define RULE_PROFILING_END(a, b, c, p)
Definition: util-profiling.h:422
TmEcode
TmEcode
Definition: tm-threads-common.h:80
RULE_PROFILING_START
#define RULE_PROFILING_START(p)
Definition: util-profiling.h:421
ALPROTO_DOH2
@ ALPROTO_DOH2
Definition: app-layer-protos.h:66
PKT_STREAM_EOF
#define PKT_STREAM_EOF
Definition: decode.h:1241
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:287
DetectTransaction_::de_state
DetectEngineStateDirection * de_state
Definition: detect-engine-prefilter.h:35
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
detect-filestore.h
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1370
detect-replace.h
RulesDumpMatchArray
void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, const Packet *p)
Definition: detect-engine-profile.c:78
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:696
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:234
SigGroupHead_::frame_engines
PrefilterEngine * frame_engines
Definition: detect.h:1583
PACKET_ALERT_NOTX
#define PACKET_ALERT_NOTX
Definition: detect.h:54
Signature_::sp
DetectPort * sp
Definition: detect.h:720
APP_LAYER_PARSER_NO_INSPECTION
#define APP_LAYER_PARSER_NO_INSPECTION
Definition: app-layer-parser.h:35
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1118
DetectRunScratchpad::sgh
const SigGroupHead * sgh
Definition: detect.c:73
DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
#define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
Definition: detect-engine-state.h:39
DETECT_ENGINE_STATE_FLAG_FILE_NEW
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
Definition: detect-engine-state.h:70
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:489
PKT_DROP_REASON_DEFAULT_PACKET_POLICY
@ PKT_DROP_REASON_DEFAULT_PACKET_POLICY
Definition: decode.h:383
RuleMatchCandidateTx::flags
uint32_t * flags
Definition: detect.h:1163
Frame::flags
uint8_t flags
Definition: app-layer-frames.h:47
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:437
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
detect-engine-analyzer.h
FLOWFILE_NO_SHA256_TC
#define FLOWFILE_NO_SHA256_TC
Definition: flow.h:146
DetectEngineStateDirection_::head
DeStateStore * head
Definition: detect-engine-state.h:83
DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES
#define DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES
Definition: detect-engine-state.h:49
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:37
AppLayerTxData
struct AppLayerTxData AppLayerTxData
Definition: detect.h:1466
DETECT_PROTO_IPV4
#define DETECT_PROTO_IPV4
Definition: detect-engine-proto.h:31
app-layer-frames.h
DetectAddressMatchIPv6
int DetectAddressMatchIPv6(const DetectMatchAddressIPv6 *addrs, uint16_t addrs_cnt, const Address *a)
Match a packets address against a signatures addrs array.
Definition: detect-engine-address.c:1622
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:648
Packet_::flow
struct Flow_ * flow
Definition: decode.h:529
DetectEngineStateResetTxs
void DetectEngineStateResetTxs(Flow *f)
Reset de state for active tx' To be used on detect engine reload.
Definition: detect-engine-state.c:265
FLOWFILE_NO_MAGIC_TC
#define FLOWFILE_NO_MAGIC_TC
Definition: flow.h:131
flags
uint8_t flags
Definition: decode-gre.h:0
Signature_::proto
DetectProto proto
Definition: detect.h:688
suricata-common.h
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:242
ActionScope
ActionScope
Definition: action-globals.h:42
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:691
packet.h
DeStateStore_
Definition: detect-engine-state.h:77
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
DetectTransaction_
Definition: detect-engine-prefilter.h:31
Packet_::app_update_direction
uint8_t app_update_direction
Definition: decode.h:518
PROF_DETECT_SETUP
@ PROF_DETECT_SETUP
Definition: suricata-common.h:449
DetectEngineStateDirection_
Definition: detect-engine-state.h:82
DetectEngineThreadCtx_::frame_inspect_progress
uint64_t frame_inspect_progress
Definition: detect.h:1271
DetectEngineCtx_::profile_match_logging_threshold
uint32_t profile_match_logging_threshold
Definition: detect.h:1037
FLOW_TS_APP_UPDATED
#define FLOW_TS_APP_UPDATED
Definition: flow.h:119
AppLayerParserGetTxData
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:1192
FatalError
#define FatalError(...)
Definition: util-debug.h:502
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:297
FLOWFILE_NO_STORE_TC
#define FLOWFILE_NO_STORE_TC
Definition: flow.h:135
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:446
FLOW_ACTION_ACCEPT
#define FLOW_ACTION_ACCEPT
Definition: flow.h:62
util-validate.h
DetectTransaction_::tx_ptr
void * tx_ptr
Definition: detect-engine-prefilter.h:32
Signature_::addr_src_match6_cnt
uint16_t addr_src_match6_cnt
Definition: detect.h:697
StreamReassembleRawUpdateProgress
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
update stream engine after detection
Definition: stream-tcp-reassemble.c:1558
StatsAddUI64
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:146
FLOWFILE_NO_SHA1_TS
#define FLOWFILE_NO_SHA1_TS
Definition: flow.h:141
PROF_DETECT_RULES
@ PROF_DETECT_RULES
Definition: suricata-common.h:452
APP_LAYER_TX_INSPECTED_TS
#define APP_LAYER_TX_INSPECTED_TS
Definition: app-layer-parser.h:56
DetectRunScratchpad::app_decoder_events
const bool app_decoder_events
Definition: detect.c:72
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:296
Signature_::dp
DetectPort * dp
Definition: detect.h:720
PacketAlerts_::suppressed
uint16_t suppressed
Definition: decode.h:275
PACKET_PROFILING_DETECT_START
#define PACKET_PROFILING_DETECT_START(p, id)
Definition: util-profiling.h:214
PACKET_ALERT_FLAG_FRAME
#define PACKET_ALERT_FLAG_FRAME
Definition: decode.h:263
FLOW_SGH_TOSERVER
#define FLOW_SGH_TOSERVER
Definition: flow.h:73
APP_LAYER_TX_ACCEPT
#define APP_LAYER_TX_ACCEPT
Definition: app-layer-parser.h:59
DetectEngineThreadCtx_::counter_alerts
uint16_t counter_alerts
Definition: detect.h:1238
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Packet_::pkt_src
uint8_t pkt_src
Definition: decode.h:594
SGH_PROFILING_RECORD
#define SGH_PROFILING_RECORD(det_ctx, sgh)
Definition: util-profiling.h:252
PacketAlertFinalize
void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
Check the threshold of the sigs that match, set actions, break on pass action This function iterate t...
Definition: detect-engine-alert.c:506
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:711
Flow_::alstate
void * alstate
Definition: flow.h:479
Signature_::id
uint32_t id
Definition: detect.h:714
DeStateStore_::store
DeStateStoreItem store[DE_STATE_CHUNK_SIZE]
Definition: detect-engine-state.h:78
DetectEngineCtx_::guess_applayer_log_limit
uint8_t guess_applayer_log_limit
Definition: detect.h:964
Flow_::flags
uint32_t flags
Definition: flow.h:421
RuleMatchCandidateTx::stream_reset
uint32_t stream_reset
Definition: detect.h:1169
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
Signature_
Signature container.
Definition: detect.h:669
InspectionBufferClean
void InspectionBufferClean(DetectEngineThreadCtx *det_ctx)
Definition: detect-engine.c:1550
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
TRACE_SID_TXS
#define TRACE_SID_TXS(sid, txs,...)
Definition: detect.c:1100
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:235
DetectEngineThreadCtx_::tx_id_set
bool tx_id_set
Definition: detect.h:1267
PacketDrop
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
Definition: packet.c:33
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:201
DetectRunScratchpad::flow_flags
const uint8_t flow_flags
Definition: detect.c:71
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1313
suricata.h
IPOnlyMatchPacket
void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineIPOnlyCtx *io_ctx, Packet *p)
Match a packet against the IP Only detection engine contexts.
Definition: detect-engine-iponly.c:998
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:938
Packet_::dst
Address dst
Definition: decode.h:489
PROF_DETECT_TX
@ PROF_DETECT_TX
Definition: suricata-common.h:453
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:438
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1226
PrefilterPostRuleMatch
void PrefilterPostRuleMatch(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f)
invoke post-rule match "prefilter" engines
Definition: detect-engine-prefilter.c:193
DetectGetInnerTx
void * DetectGetInnerTx(void *tx_ptr, AppProto alproto, AppProto engine_alproto, uint8_t flow_flags)
Definition: detect.c:1104
DetectRunScratchpad::alproto
const AppProto alproto
Definition: detect.c:70
DE_STATE_FLAG_FULL_INSPECT
#define DE_STATE_FLAG_FULL_INSPECT
Definition: detect-engine-state.h:55
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:238
DetectEngineThreadCtx_::mt_det_ctxs_cnt
uint32_t mt_det_ctxs_cnt
Definition: detect.h:1207
AppLayerGetTxIteratorFunc
AppLayerGetTxIterTuple(* AppLayerGetTxIteratorFunc)(const uint8_t ipproto, const AppProto alproto, void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
tx iterator prototype
Definition: app-layer-parser.h:130
likely
#define likely(expr)
Definition: util-optimize.h:32
IPPROTO_SCTP
#define IPPROTO_SCTP
Definition: decode.h:1207
DE_STATE_FLAG_FILE_INSPECT
#define DE_STATE_FLAG_FILE_INSPECT
Definition: detect-engine-state.h:60
id
uint32_t id
Definition: detect-flowbits.c:933
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:922
DetectEngineCtx_::io_ctx
DetectEngineIPOnlyCtx io_ctx
Definition: detect.h:958
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:708
FlowGetDisruptionFlags
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags)
get 'disruption' flags: GAP/DEPTH/PASS
Definition: flow.c:1137
TcpSession_
Definition: stream-tcp-private.h:283
flow.h
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:695
SigIntId
#define SigIntId
Definition: suricata-common.h:324
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1838
DeStateStoreItem_
Definition: detect-engine-state.h:72
GenericVarFree
void GenericVarFree(GenericVar *gv)
Definition: util-var.c:48
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:694
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
Packet_::dp
Port dp
Definition: decode.h:499
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::sig_array_len
uint32_t sig_array_len
Definition: detect.h:939
SIG_GROUP_HEAD_HAVEFILESHA256
#define SIG_GROUP_HEAD_HAVEFILESHA256
Definition: detect.h:1436
Signature_::type
enum SignatureType type
Definition: detect.h:672
SigGroupHead_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1576
AppLayerParserGetTxCnt
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
Definition: app-layer-parser.c:1111
PACKET_ALERT_FLAG_STATE_MATCH
#define PACKET_ALERT_FLAG_STATE_MATCH
Definition: decode.h:255
AppLayerParserHasDecoderEvents
bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate)
Definition: app-layer-parser.c:1522
FLOW_PKT_TOSERVER_FIRST
#define FLOW_PKT_TOSERVER_FIRST
Definition: flow.h:236
DetectEngineLookupFlow_::tcp
DetectPort * tcp
Definition: detect.h:862
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
detect-engine-address.h
Flow_::tenant_id
uint32_t tenant_id
Definition: flow.h:416
Packet_::src
Address src
Definition: decode.h:488
DetectEngineThreadCtx_::counter_mpm_list
uint16_t counter_mpm_list
Definition: detect.h:1244
SigMatchSignaturesGetSgh
const SigGroupHead * SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p)
Get the SigGroupHead for a packet.
Definition: detect.c:232
DetectRunPrefilterTx
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
Definition: detect-engine-prefilter.c:95
RuleMatchCandidateTxArrayInit
void RuleMatchCandidateTxArrayInit(DetectEngineThreadCtx *det_ctx, uint32_t size)
Definition: detect.c:1024
APP_LAYER_TX_INSPECTED_TC
#define APP_LAYER_TX_INSPECTED_TC
Definition: app-layer-parser.h:57
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:243
DetectPortLookupGroup
DetectPort * DetectPortLookupGroup(DetectPort *dp, uint16_t port)
Function that find the group matching port in a group head.
Definition: detect-engine-port.c:613
DetectEngineThreadCtx_::post_rule_work_queue
PostRuleMatchWorkQueue post_rule_work_queue
Definition: detect.h:1296
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1239
detect-engine-threshold.h
APP_LAYER_TX_SKIP_INSPECT_TS
#define APP_LAYER_TX_SKIP_INSPECT_TS
Definition: app-layer-parser.h:53
Signature_::mask
SignatureMask mask
Definition: detect.h:680
app-layer.h
RuleMatchCandidateTx
Definition: detect.h:1161
DetectEngineThreadCtx_::TenantGetId
uint32_t(* TenantGetId)(const void *, const Packet *p)
Definition: detect.h:1214
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:38
PacketEngineEvents_::cnt
uint8_t cnt
Definition: decode.h:292
Flow_::de_ctx_version
uint32_t de_ctx_version
Definition: flow.h:464
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:135
DetectEngineThreadCtx_::match_array
Signature ** match_array
Definition: detect.h:1284