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