suricata
detect.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Basic detection engine
24  */
25 
26 #include "suricata-common.h"
27 #include "suricata.h"
28 
29 #include "decode.h"
30 #include "packet.h"
31 #include "flow.h"
32 #include "stream-tcp.h"
33 #include "app-layer.h"
34 #include "app-layer-parser.h"
35 #include "app-layer-frames.h"
36 
37 #include "detect.h"
38 #include "detect-parse.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",
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  if (EngineModeIsFirewall()) {
164  SCLogDebug("default accept: no PKT_STREAM_EST");
165  DetectRunAppendDefaultAccept(det_ctx, p);
166  }
167  goto end;
168  }
169  const TcpSession *ssn = p->flow->protoctx;
170  bool setting_nopayload = p->flow->alparser &&
172  p->flow->alparser, APP_LAYER_PARSER_NO_INSPECTION) &&
174  // we may be right after disabling app-layer (ssh)
175  if (ssn &&
176  ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0 || setting_nopayload)) {
177  // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_TX);
178  DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch);
179  // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_TX);
180  }
181  // no update to transactions
182  if (!PKT_IS_PSEUDOPKT(p) && p->app_update_direction == 0 &&
183  ((PKT_IS_TOSERVER(p) && (p->flow->flags & FLOW_TS_APP_UPDATED) == 0) ||
184  (PKT_IS_TOCLIENT(p) && (p->flow->flags & FLOW_TC_APP_UPDATED) == 0))) {
185  SCLogDebug("packet %" PRIu64 ": no app-layer update", PcapPacketCntGet(p));
186  if (EngineModeIsFirewall()) {
187  SCLogDebug("default accept: no app update");
188  DetectRunAppendDefaultAccept(det_ctx, p);
189  }
190  goto end;
191  }
192  } else if (p->proto == IPPROTO_UDP) {
193  DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch);
194  }
195 
197  DetectRunTx(th_v, de_ctx, det_ctx, p, pflow, &scratch);
199  /* see if we need to increment the inspect_id and reset the de_state */
202  pflow, pflow->alparser, pflow->alstate, scratch.flow_flags, (scratch.sgh == NULL));
204  } else {
205  SCLogDebug("packet %" PRIu64 ": no flow / app-layer", PcapPacketCntGet(p));
206  if (EngineModeIsFirewall()) {
207  SCLogDebug("default accept: no flow/app");
208  DetectRunAppendDefaultAccept(det_ctx, p);
209  }
210  }
211 
212 end:
213  DetectRunPostRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
214 
215  DetectRunCleanup(det_ctx, p, pflow);
216  SCReturn;
217 }
218 
219 /** \internal
220  */
221 static void DetectRunPacketHook(ThreadVars *th_v, const DetectEngineCtx *de_ctx,
222  DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p,
223  enum DetectFirewallPacketPolicies fw_pkt_policy)
224 {
225  SCEnter();
226  SCLogDebug("pcap_cnt %" PRIu64 " direction %s pkt_src %s", PcapPacketCntGet(p),
227  p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
228  : "noflow",
230 
231  /* Load the Packet's flow early, even though it might not be needed.
232  * Mark as a constant pointer, although the flow itself can change. */
233  Flow *const pflow = p->flow;
234 
235  DetectRunScratchpad scratch = DetectRunSetup(de_ctx, det_ctx, p, pflow, fw_pkt_policy);
236  scratch.sgh = sgh;
237 
238  /* if we didn't get a sig group head, we
239  * have nothing to do.... */
240  if (scratch.sgh == NULL) {
241  SCLogDebug("no sgh for this packet, nothing to match against");
242  goto end;
243  }
244 
245  /* run the prefilters for packets */
246  DetectRunPrefilterPkt(th_v, de_ctx, det_ctx, p, &scratch);
247 
248  // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); // TODO
249  /* inspect the rules against the packet */
250  const uint8_t pkt_policy = DetectRulePacketRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
251  // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_RULES);
252  if (pkt_policy & (ACTION_DROP | ACTION_ACCEPT)) {
253  goto end;
254  }
255 
256 end:
257  DetectRunPostRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
258 
259  DetectRunCleanup(det_ctx, p, pflow);
260  SCReturn;
261 }
262 
263 static void DetectRunPostMatch(ThreadVars *tv,
264  DetectEngineThreadCtx *det_ctx, Packet *p,
265  const Signature *s)
266 {
267  /* run the packet match functions */
269  if (smd != NULL) {
271 
272  SCLogDebug("running match functions, sm %p", smd);
273 
274  while (1) {
276  (void)sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx);
277  KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
278  if (smd->is_last)
279  break;
280  smd++;
281  }
282  }
283 }
284 
285 /**
286  * \brief Get the SigGroupHead for a packet.
287  *
288  * \param de_ctx detection engine context
289  * \param p packet
290  *
291  * \retval sgh the SigGroupHead or NULL if non applies to the packet
292  */
294  const Packet *p)
295 {
296  SCEnter();
297  SigGroupHead *sgh = NULL;
298 
299  /* use ethernet non-IP sgh if we're ethernet but have no (valid) IP layer on top of it. */
300  if (PacketIsEthernet(p) && p->proto == 0 && de_ctx->eth_non_ip_sgh != NULL) {
301  SCLogDebug("using eth_non_ip_sgh %p", de_ctx->eth_non_ip_sgh);
302  SCReturnPtr(de_ctx->eth_non_ip_sgh, "SigGroupHead");
303  }
304 
305  /* if the packet proto is 0 (not set), we're inspecting it against
306  * the decoder events sgh we have. */
307  if (p->proto == 0 && p->events.cnt > 0) {
308  SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead");
309  } else if (p->proto == 0) {
310  if (!(PacketIsIPv4(p) || PacketIsIPv6(p))) {
311  /* not IP, so nothing to do */
312  SCReturnPtr(NULL, "SigGroupHead");
313  }
314  }
315 
316  /* select the flow_gh */
317  const int dir = (p->flowflags & FLOW_PKT_TOCLIENT) == 0;
318 
319  int proto = PacketGetIPProto(p);
320  if (proto == IPPROTO_TCP) {
321  DetectPort *list = de_ctx->flow_gh[dir].tcp;
322  SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", de_ctx->flow_gh[1].tcp,
323  de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[dir].tcp);
324  const uint16_t port = dir ? p->dp : p->sp;
325  SCLogDebug("tcp port %u -> %u:%u", port, p->sp, p->dp);
326  DetectPort *sghport = DetectPortLookupGroup(list, port);
327  if (sghport != NULL)
328  sgh = sghport->sh;
329  SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", list, port,
330  dir ? "toserver" : "toclient", sghport, sgh);
331  } else if (proto == IPPROTO_UDP) {
332  DetectPort *list = de_ctx->flow_gh[dir].udp;
333  uint16_t port = dir ? p->dp : p->sp;
334  DetectPort *sghport = DetectPortLookupGroup(list, port);
335  if (sghport != NULL)
336  sgh = sghport->sh;
337  SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", list, port,
338  dir ? "toserver" : "toclient", sghport, sgh);
339  } else {
340  sgh = de_ctx->flow_gh[dir].sgh[proto];
341  }
342 
343  SCReturnPtr(sgh, "SigGroupHead");
344 }
345 
346 static inline void DetectPrefilterCopyDeDup(
348 {
349  SigIntId *pf_ptr = det_ctx->pmq.rule_id_array;
350  uint32_t final_cnt = det_ctx->pmq.rule_id_array_cnt;
351  Signature **sig_array = de_ctx->sig_array;
352  Signature **match_array = det_ctx->match_array;
353  SigIntId previous_id = (SigIntId)-1;
354  while (final_cnt-- > 0) {
355  SigIntId id = *pf_ptr++;
356  Signature *s = sig_array[id];
357 
358  /* As the prefilter list can contain duplicates, check for that here. */
359  if (likely(id != previous_id)) {
360  *match_array++ = s;
361  previous_id = id;
362  }
363  }
364 
365  det_ctx->match_array_cnt = (uint32_t)(match_array - det_ctx->match_array);
367  PMQ_RESET(&det_ctx->pmq);
368 }
369 
370 /** \internal
371  * \brief update flow's file tracking flags based on the detection engine
372  * A set of flags is prepared that is sent to the File API. The
373  File API may reject one or more based on the global force settings.
374  */
375 static inline void
376 DetectPostInspectFileFlagsUpdate(Flow *f, const SigGroupHead *sgh, uint8_t direction)
377 {
378  uint16_t flow_file_flags = FLOWFILE_INIT;
379 
380  if (sgh == NULL) {
381  SCLogDebug("requesting disabling all file features for flow");
382  flow_file_flags = FLOWFILE_NONE;
383  } else {
384  if (sgh->filestore_cnt == 0) {
385  SCLogDebug("requesting disabling filestore for flow");
386  flow_file_flags |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC);
387  }
388 #ifdef HAVE_MAGIC
389  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC)) {
390  SCLogDebug("requesting disabling magic for flow");
391  flow_file_flags |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC);
392  }
393 #endif
394  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5)) {
395  SCLogDebug("requesting disabling md5 for flow");
396  flow_file_flags |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC);
397  }
398  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA1)) {
399  SCLogDebug("requesting disabling sha1 for flow");
400  flow_file_flags |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC);
401  }
402  if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA256)) {
403  SCLogDebug("requesting disabling sha256 for flow");
404  flow_file_flags |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC);
405  }
406  }
407  if (flow_file_flags != 0) {
408  FileUpdateFlowFileFlags(f, flow_file_flags, direction);
409  }
410 }
411 
412 static inline void
413 DetectRunPostGetFirstRuleGroup(const Packet *p, Flow *pflow, const SigGroupHead *sgh)
414 {
415  if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) {
416  /* first time we see this toserver sgh, store it */
417  pflow->sgh_toserver = sgh;
418  pflow->flags |= FLOW_SGH_TOSERVER;
419 
420  if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) {
421  if (pflow->protoctx != NULL) {
422  TcpSession *ssn = pflow->protoctx;
423  SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.client");
425  }
426  }
427 
428  DetectPostInspectFileFlagsUpdate(pflow,
429  pflow->sgh_toserver, STREAM_TOSERVER);
430 
431  } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) {
432  pflow->sgh_toclient = sgh;
433  pflow->flags |= FLOW_SGH_TOCLIENT;
434 
435  if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) {
436  if (pflow->protoctx != NULL) {
437  TcpSession *ssn = pflow->protoctx;
438  SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.server");
440  }
441  }
442 
443  DetectPostInspectFileFlagsUpdate(pflow,
444  pflow->sgh_toclient, STREAM_TOCLIENT);
445  }
446 }
447 
448 static inline void DetectRunGetRuleGroup(
449  const DetectEngineCtx *de_ctx,
450  Packet * const p, Flow * const pflow,
451  DetectRunScratchpad *scratch)
452 {
453  const SigGroupHead *sgh = NULL;
454 
455  if (pflow) {
456  bool use_flow_sgh = false;
457  /* Get the stored sgh from the flow (if any). Make sure we're not using
458  * the sgh for icmp error packets part of the same stream. */
459  if (PacketGetIPProto(p) == pflow->proto) { /* filter out icmp */
461  if ((p->flowflags & FLOW_PKT_TOSERVER) && (pflow->flags & FLOW_SGH_TOSERVER)) {
462  sgh = pflow->sgh_toserver;
463  SCLogDebug("sgh = pflow->sgh_toserver; => %p", sgh);
464  use_flow_sgh = true;
465  } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && (pflow->flags & FLOW_SGH_TOCLIENT)) {
466  sgh = pflow->sgh_toclient;
467  SCLogDebug("sgh = pflow->sgh_toclient; => %p", sgh);
468  use_flow_sgh = true;
469  }
471  }
472 
473  if (!(use_flow_sgh)) {
477 
478  /* HACK: prevent the wrong sgh (or NULL) from being stored in the
479  * flow's sgh pointers */
480  if (PacketIsICMPv4(p) && ICMPV4_DEST_UNREACH_IS_VALID(p)) {
481  ; /* no-op */
482  } else {
483  /* store the found sgh (or NULL) in the flow to save us
484  * from looking it up again for the next packet.
485  * Also run other tasks */
486  DetectRunPostGetFirstRuleGroup(p, pflow, sgh);
487  }
488  }
489  } else { /* p->flags & PKT_HAS_FLOW */
490  /* no flow */
491 
495  }
496 
497  scratch->sgh = sgh;
498 }
499 
500 static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx,
501  DetectEngineThreadCtx *det_ctx,
502  Flow * const pflow, Packet * const p)
503 {
504  if (pflow) {
506  SCLogDebug("testing against \"ip-only\" signatures");
507 
509  IPOnlyMatchPacket(tv, de_ctx, det_ctx, &de_ctx->io_ctx, p);
511  }
512  } else { /* p->flags & PKT_HAS_FLOW */
513  /* no flow */
514 
515  /* Even without flow we should match the packet src/dst */
517  IPOnlyMatchPacket(tv, de_ctx, det_ctx, &de_ctx->io_ctx, p);
519  }
520 }
521 
522 /** \internal
523  * \brief inspect the rule header: protocol, ports, etc
524  * \retval bool false if no match, true if match */
525 static inline bool DetectRunInspectRuleHeader(
526  const Packet *p, const Flow *f, const Signature *s, const uint32_t sflags)
527 {
528  /* check if this signature has a requirement for flowvars of some type
529  * and if so, if we actually have any in the flow. If not, the sig
530  * can't match and we skip it. */
531  if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) {
532  DEBUG_VALIDATE_BUG_ON(f == NULL);
533 
534  /* no flowvars? skip this sig */
535  const bool fv = f->flowvar != NULL;
536  if (!fv) {
537  SCLogDebug("skipping sig as the flow has no flowvars and sig "
538  "has SIG_FLAG_REQUIRE_FLOWVAR flag set.");
539  return false;
540  }
541  }
542 
543  if (!(s->proto == NULL)) {
544  const uint8_t s_proto_flags = s->proto->flags;
545  /* TODO does it make sense to move these flags to s->flags? */
546  if ((s_proto_flags & DETECT_PROTO_IPV4) && !PacketIsIPv4(p)) {
547  SCLogDebug("ip version didn't match");
548  return false;
549  }
550  if ((s_proto_flags & DETECT_PROTO_IPV6) && !PacketIsIPv6(p)) {
551  SCLogDebug("ip version didn't match");
552  return false;
553  }
554  if (DetectProtoContainsProto(s->proto, PacketGetIPProto(p)) == 0) {
555  SCLogDebug("proto didn't match");
556  if (PacketIsEthernet(p) &&
557  (s_proto_flags & (DETECT_PROTO_ETHERNET | DETECT_PROTO_ARP))) {
558  SCLogDebug("checking ether/arp protocol");
559  if ((s_proto_flags & DETECT_PROTO_ARP) && !PacketIsARP(p)) {
560  return false;
561  }
562  SCLogDebug("checking eth protocol: match!");
563  } else {
564  return false;
565  }
566  }
567  }
568 
569  /* check the source & dst port in the sig */
570  if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) {
571  if (!(sflags & SIG_FLAG_DP_ANY)) {
572  if (p->flags & PKT_IS_FRAGMENT)
573  return false;
574  const DetectPort *dport = DetectPortLookupGroup(s->dp, p->dp);
575  if (dport == NULL) {
576  SCLogDebug("dport didn't match.");
577  return false;
578  }
579  }
580  if (!(sflags & SIG_FLAG_SP_ANY)) {
581  if (p->flags & PKT_IS_FRAGMENT)
582  return false;
583  const DetectPort *sport = DetectPortLookupGroup(s->sp, p->sp);
584  if (sport == NULL) {
585  SCLogDebug("sport didn't match.");
586  return false;
587  }
588  }
589  } else if ((sflags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) {
590  SCLogDebug("port-less protocol and sig needs ports");
591  return false;
592  }
593 
594  /* check the destination address */
595  if (!(sflags & SIG_FLAG_DST_ANY)) {
596  if (PacketIsIPv4(p)) {
598  return false;
599  } else if (PacketIsIPv6(p)) {
601  return false;
602  }
603  }
604  /* check the source address */
605  if (!(sflags & SIG_FLAG_SRC_ANY)) {
606  if (PacketIsIPv4(p)) {
608  return false;
609  } else if (PacketIsIPv6(p)) {
611  return false;
612  }
613  }
614 
615  return true;
616 }
617 
618 /** \internal
619  * \brief run packet/stream prefilter engines
620  */
621 static inline void DetectRunPrefilterPkt(ThreadVars *tv, const DetectEngineCtx *de_ctx,
622  DetectEngineThreadCtx *det_ctx, Packet *p, DetectRunScratchpad *scratch)
623 {
624  /* create our prefilter mask */
625  PacketCreateMask(p, &p->sig_mask, scratch->alproto, scratch->app_decoder_events);
626  /* run the prefilter engines */
627  Prefilter(det_ctx, scratch->sgh, p, scratch->flow_flags, p->sig_mask);
628  /* create match list if we have non-pf and/or pf */
629  if (det_ctx->pmq.rule_id_array_cnt) {
630 #ifdef PROFILING
631  if (tv) {
633  &tv->stats, det_ctx->counter_mpm_list, (int64_t)det_ctx->pmq.rule_id_array_cnt);
634  }
635 #endif
637  DetectPrefilterCopyDeDup(de_ctx, det_ctx);
639  }
640 }
641 
642 /** \internal
643  * \brief check if the tx whose id is given is the only one
644  * live transaction for the flow in the given direction
645  *
646  * \param f flow
647  * \param txid transaction id
648  * \param dir direction
649  *
650  * \retval bool true if we are sure this tx is the only one live in said direction
651  */
652 static bool IsOnlyTxInDirection(Flow *f, uint64_t txid, uint8_t dir)
653 {
654  uint64_t tx_cnt = AppLayerParserGetTxCnt(f, f->alstate);
655  if (tx_cnt == txid + 1) {
656  // only live tx
657  return true;
658  }
659  if (tx_cnt == txid + 2) {
660  // 2 live txs, one after us
661  void *tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, txid + 1);
662  if (tx) {
664  // test if the other tx is unidirectional in the other way
665  if ((dir == STREAM_TOSERVER && (txd->flags & APP_LAYER_TX_SKIP_INSPECT_TS)) ||
666  (dir == STREAM_TOCLIENT && (txd->flags & APP_LAYER_TX_SKIP_INSPECT_TC))) {
667  return true;
668  }
669  }
670  }
671  return false;
672 }
673 
674 static int SortHelper(const void *a, const void *b)
675 {
676  const Signature *sa = *(const Signature **)a;
677  const Signature *sb = *(const Signature **)b;
678  if (sa->iid == sb->iid)
679  return 0;
680  return sa->iid > sb->iid ? 1 : -1;
681 }
682 
683 static inline bool SkipFwRules(const Packet *p)
684 {
685  if (p->flow != NULL) {
686  return (p->flow->flags & FLOW_ACTION_ACCEPT) != 0;
687  }
688  return false;
689 }
690 
691 /**
692  * \internal
693  * \brief apply packet default policy
694  * \param[in] de_ctx detect engine, for looking up the policy
695  * \param[in] policy policy to apply
696  * \param[in] p packet to apply policy to
697  * \param[in] final see if we need to apply accept:hook to the packet
698  * \retval action action to immediately apply, accept:hook will not set this unless final is true
699  *
700  * If this is run from the post-match final check, we need to apply a
701  * packet:filter accept:hook to the packet as well.
702  */
703 static uint8_t DetectRunApplyPacketPolicy(const DetectEngineCtx *de_ctx,
704  DetectEngineThreadCtx *det_ctx, const enum DetectFirewallPacketPolicies policy, Packet *p,
705  const bool final)
706 {
708  const struct DetectFirewallPolicy *pol = &de_ctx->fw_policies->pkt[policy];
709  if (pol->action & ACTION_DROP) {
710  SCLogDebug("packet %" PRIu64 ": drop PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY",
713  if (p->flow && pol->action_scope == ACTION_SCOPE_FLOW) {
714  FlowSetDropAction(p->flow, FLOW_ACTION_BY_FIREWALL);
715  SCLogDebug("packet %" PRIu64 ": drop scope flow", PcapPacketCntGet(p));
716  }
717  } else if (pol->action & ACTION_ACCEPT) {
718  SCLogDebug("packet %" PRIu64 ": accept", PcapPacketCntGet(p));
719  if (pol->action_scope == ACTION_SCOPE_PACKET) {
720  p->action |= pol->action;
721  SCLogDebug("packet %" PRIu64 ": accept scope packet", PcapPacketCntGet(p));
722  } else if (pol->action_scope == ACTION_SCOPE_HOOK) {
723  SCLogDebug("packet %" PRIu64 ": accept scope hook", PcapPacketCntGet(p));
724  if (final) {
725  p->action |= pol->action;
726  SCLogDebug("packet %" PRIu64 ": accept scope hook upgraded to packet",
728  }
729  } else if (pol->action_scope == ACTION_SCOPE_FLOW) {
730  p->action |= pol->action;
731  SCLogDebug("packet %" PRIu64 ": accept scope flow", PcapPacketCntGet(p));
732  if (p->flow) {
734  }
735  } else {
736  /* should be unreachable */
738  }
739  } else {
740  /* should be unreachable */
742  }
744  if (s != NULL) {
746  }
747  return p->action;
748 }
749 
750 /** \internal
751  * \brief helper for appending a packet alert
752  * Tries to find (guess) a TX to add to the alert.
753  */
754 static void DetectRulePacketAppendAlert(const DetectEngineCtx *de_ctx,
755  DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, Flow *f,
756  const uint8_t alert_flags_in)
757 {
759 
760  if (f && f->alstate) {
761  const uint8_t dir = (p->flowflags & FLOW_PKT_TOCLIENT) ? STREAM_TOCLIENT : STREAM_TOSERVER;
762  const uint64_t tx_id = AppLayerParserGetTransactionInspectId(f->alparser, dir);
763  if ((s->alproto != ALPROTO_UNKNOWN && f->proto == IPPROTO_UDP) ||
764  (de_ctx->guess_applayer && IsOnlyTxInDirection(f, tx_id, dir))) {
765  // if there is a UDP specific app-layer signature,
766  // or only one live transaction
767  // try to use the good tx for the packet direction
768  void *tx_ptr = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, tx_id);
769  AppLayerTxData *txd =
770  tx_ptr ? AppLayerParserGetTxData(f->proto, f->alproto, tx_ptr) : NULL;
772  uint8_t alert_flags = alert_flags_in;
773  if (f->proto != IPPROTO_UDP) {
774  alert_flags |= PACKET_ALERT_FLAG_TX_GUESSED;
775  }
777  AlertQueueAppendAppTxFromPacket(det_ctx, s, p, tx_id, txd->tx_type, alert_flags);
778  return;
779  }
780  }
781  }
782  AlertQueueAppendPacket(det_ctx, s, p, alert_flags_in);
783 }
784 
785 static inline uint8_t DetectRulePacketRules(ThreadVars *const tv,
786  const DetectEngineCtx *const de_ctx, DetectEngineThreadCtx *const det_ctx, Packet *const p,
787  Flow *const pflow, const DetectRunScratchpad *scratch)
788 {
789  uint8_t action = 0;
790  bool fw_verdict = false;
791  const bool have_fw_rules = EngineModeIsFirewall();
792  const Signature *next_s = NULL;
793 
794  /* inspect the sigs against the packet */
795  /* Prefetch the next signature. */
796  SigIntId match_cnt = det_ctx->match_array_cnt;
797 #ifdef PROFILING
798  if (tv) {
799  StatsCounterAvgAddI64(&tv->stats, det_ctx->counter_match_list, (int64_t)match_cnt);
800  }
801 #endif
802  Signature **match_array = det_ctx->match_array;
803 
804  SGH_PROFILING_RECORD(det_ctx, scratch->sgh);
805 #ifdef PROFILING
806  if (match_cnt >= de_ctx->profile_match_logging_threshold)
807  RulesDumpMatchArray(det_ctx, scratch->sgh, p);
808 #endif
809 
810  bool skip_fw = SkipFwRules(p);
811  uint32_t sflags, next_sflags = 0;
812  if (match_cnt) {
813  next_s = *match_array++;
814  next_sflags = next_s->flags;
815  }
816  while (match_cnt--) {
818  bool break_out_of_packet_filter = false;
819  uint8_t alert_flags = 0;
820 #ifdef PROFILE_RULES
821  bool smatch = false; /* signature match */
822 #endif
823  const Signature *s = next_s;
824  sflags = next_sflags;
825  if (match_cnt) {
826  next_s = *match_array++;
827  next_sflags = next_s->flags;
828  }
829 
830  SCLogDebug("packet %" PRIu64 ": inspecting signature id %" PRIu32 "", PcapPacketCntGet(p),
831  s->id);
832 
833  /* if we accept:hook'd the `packet_filter` hook, we skip the rest of the firewall rules. */
834  if (s->flags & SIG_FLAG_FIREWALL) {
835  if (skip_fw) {
836  SCLogDebug("skipping firewall rule %u", s->id);
837  goto next;
838  }
839  } else if (have_fw_rules) {
840  /* fw mode, we skip anything after the fw rules if:
841  * - flow pass is set
842  * - packet pass (e.g. exception policy) */
844  (pflow != NULL && pflow->flags & (FLOW_ACTION_PASS))) {
845  SCLogDebug("skipping firewall rule %u", s->id);
846  break_out_of_packet_filter = true;
847  goto next;
848  }
849  }
850 
851  if (s->app_inspect != NULL) {
852  goto next; // handle sig in DetectRunTx
853  }
854  if (s->frame_inspect != NULL) {
855  goto next; // handle sig in DetectRunFrame
856  }
857 
858  /* skip pkt sigs for flow end packets */
859  if ((p->flags & PKT_PSEUDO_STREAM_END) != 0 && s->type == SIG_TYPE_PKT)
860  goto next;
861 
862  /* don't run mask check for stateful rules.
863  * There we depend on prefilter */
864  if ((s->mask & p->sig_mask) != s->mask) {
865  SCLogDebug("mask mismatch %x & %x != %x", s->mask, p->sig_mask, s->mask);
866  goto next;
867  }
868 
869  if (SigDsizePrefilter(p, s, sflags))
870  goto next;
871 
872  /* if the sig has alproto and the session as well they should match */
873  if (likely(sflags & SIG_FLAG_APPLAYER)) {
874  if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, scratch->alproto)) {
875  SCLogDebug("alproto mismatch");
876  goto next;
877  }
878  }
879 
880  if (DetectRunInspectRuleHeader(p, pflow, s, sflags) == false) {
881  goto next;
882  }
883 
884  if (!DetectEnginePktInspectionRun(tv, det_ctx, s, pflow, p, &alert_flags)) {
885  goto next;
886  }
887 
888 #ifdef PROFILE_RULES
889  smatch = true;
890 #endif
891  DetectRunPostMatch(tv, det_ctx, p, s);
892 
893  DetectRulePacketAppendAlert(de_ctx, det_ctx, s, p, pflow, alert_flags);
894 
895  if (det_ctx->post_rule_work_queue.len > 0) {
896  /* run post match prefilter engines on work queue */
897  PrefilterPostRuleMatch(det_ctx, scratch->sgh, p, pflow);
898 
899  if (det_ctx->pmq.rule_id_array_cnt > 0) {
900  /* undo "prefetch" */
901  match_array--;
902  SCLogDebug("sig_array_len %u det_ctx->pmq.rule_id_array_cnt %u",
904  const Signature **r = det_ctx->replace;
905  for (uint32_t x = 0; x < match_cnt; x++) {
906  *r++ = match_array[x];
907  SCLogDebug("appended %u", match_array[x]->id);
908  }
909  /* append the prefilter results, then sort it */
910  for (uint32_t x = 0; x < det_ctx->pmq.rule_id_array_cnt; x++) {
911  SCLogDebug("adding iid %u", det_ctx->pmq.rule_id_array[x]);
912  Signature *ts = de_ctx->sig_array[det_ctx->pmq.rule_id_array[x]];
913  SCLogDebug("adding id %u", ts->id);
914  if (ts->app_inspect == NULL) {
915  *r++ = ts;
916  match_cnt++;
917  }
918  }
919  if (match_cnt > 1) {
920  qsort(det_ctx->replace, match_cnt, sizeof(Signature *), SortHelper);
921  }
922  /* rewrite match_array to include the new additions, and deduplicate
923  * while at it. */
924  Signature **m = match_array;
925  Signature *last_sig = NULL;
926  uint32_t skipped = 0;
927  for (uint32_t x = 0; x < match_cnt; x++) {
928  /* de-duplicate */
929  if (last_sig == *m) {
930  skipped++;
931  continue;
932  }
933  last_sig = *m;
934  *m++ = (Signature *)det_ctx->replace[x];
935  }
936  match_cnt -= skipped;
937  /* prefetch next */
938  next_s = *match_array++;
939  next_sflags = next_s->flags;
940  SCLogDebug("%u rules added", det_ctx->pmq.rule_id_array_cnt);
941  det_ctx->post_rule_work_queue.len = 0;
942  PMQ_RESET(&det_ctx->pmq);
943  }
944  }
945 
946  /* firewall logic in the packet:filter table:
947  * 1. firewall rules preceed the packet:td rules in the list
948  * 2. if no rule issues an accept, we drop
949  * 3. drop is immediate
950  * 4. accept:
951  * - hook: skip rest of fw rules, inspect packet:td rules
952  * - packet: immediate accept, no packet:td or app:* inspect
953  * - flow: as packet, but applied to all future packets in the
954  * flow as well
955  */
956  if (s->flags & SIG_FLAG_FIREWALL) {
957  if (s->action & (ACTION_ACCEPT)) {
958  fw_verdict = true;
959 
960  enum ActionScope as = s->action_scope;
961  if (as == ACTION_SCOPE_HOOK) {
962  /* accept:hook: jump to first TD. Implemented as:
963  * skip until the first TD rule.
964  * Don't update action as we're just continuing to the next hook. */
965  skip_fw = true;
966 
967  } else if (as == ACTION_SCOPE_PACKET) {
968  /* accept:packet: break loop, return accept */
969  action |= s->action;
970  skip_fw = true;
971 
972  } else if (as == ACTION_SCOPE_FLOW) {
973  /* accept:flow: break loop, return accept */
974  action |= s->action;
975  skip_fw = true;
976 
977  /* set immediately, as we're in hook "packet_filter" */
978  if (pflow) {
979  pflow->flags |= FLOW_ACTION_ACCEPT;
980  }
981  }
982  } else if (s->action & ACTION_DROP) {
983  /* apply a drop immediately here */
984  fw_verdict = true;
985  action |= s->action;
986  break_out_of_packet_filter = true;
987  }
988  }
989 next:
990  DetectVarProcessList(det_ctx, pflow, p);
991  DetectReplaceFree(det_ctx);
992  RULE_PROFILING_END(det_ctx, s, smatch, p);
993 
994  /* fw drop means we're done here */
995  if (break_out_of_packet_filter)
996  break;
997 
998  continue;
999  }
1000 
1001  /* if no rule told us to accept, and no rule explicitly dropped, we invoke the default drop
1002  * policy
1003  */
1004  if (have_fw_rules) {
1005  if (skip_fw || fw_verdict) {
1006  /* apply fw action */
1007  p->action |= action;
1008  } else {
1010  /* non-final call as we may have to consider app-layer still */
1011  action |= DetectRunApplyPacketPolicy(de_ctx, det_ctx, scratch->fw_pkt_policy, p, false);
1012  }
1013  }
1014  return action;
1015 }
1016 
1017 /** \internal
1018  * \param fw_pkt_policy policy to apply to packet rules
1019  */
1020 static DetectRunScratchpad DetectRunSetup(const DetectEngineCtx *de_ctx,
1021  DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow,
1022  const enum DetectFirewallPacketPolicies fw_pkt_policy)
1023 {
1024  AppProto alproto = ALPROTO_UNKNOWN;
1025  uint8_t flow_flags = 0; /* flow/state flags */
1026  bool app_decoder_events = false;
1027 
1029 
1030 #ifdef UNITTESTS
1031  if (RunmodeIsUnittests()) {
1032  p->alerts.cnt = 0;
1033  p->alerts.discarded = 0;
1034  p->alerts.suppressed = 0;
1035  }
1036 #endif
1037  det_ctx->filestore_cnt = 0;
1038  det_ctx->base64_decoded_len = 0;
1039  det_ctx->raw_stream_progress = 0;
1040  det_ctx->match_array_cnt = 0;
1041  det_ctx->json_content_len = 0;
1042 
1043  det_ctx->alert_queue_size = 0;
1044  p->alerts.drop.action = 0;
1046 
1047 #ifdef DEBUG
1048  if (p->flags & PKT_STREAM_ADD) {
1049  det_ctx->pkt_stream_add_cnt++;
1050  }
1051 #endif
1052 
1053  /* grab the protocol state we will detect on */
1054  if (p->flags & PKT_HAS_FLOW) {
1055  DEBUG_VALIDATE_BUG_ON(pflow == NULL);
1056 
1057  if (p->flowflags & FLOW_PKT_TOSERVER) {
1058  flow_flags = STREAM_TOSERVER;
1059  SCLogDebug("flag STREAM_TOSERVER set");
1060  } else if (p->flowflags & FLOW_PKT_TOCLIENT) {
1061  flow_flags = STREAM_TOCLIENT;
1062  SCLogDebug("flag STREAM_TOCLIENT set");
1063  }
1064  SCLogDebug("p->flowflags 0x%02x", p->flowflags);
1065 
1066  if (p->flags & PKT_PSEUDO_STREAM_END) {
1067  flow_flags |= STREAM_EOF;
1068  SCLogDebug("STREAM_EOF set");
1069  }
1070 
1071  /* store tenant_id in the flow so that we can use it
1072  * for creating pseudo packets */
1073  if (p->tenant_id > 0 && pflow->tenant_id == 0) {
1074  pflow->tenant_id = p->tenant_id;
1075  }
1076 
1077  /* live ruleswap check for flow updates */
1078  if (pflow->de_ctx_version == 0) {
1079  /* first time this flow is inspected, set id */
1080  pflow->de_ctx_version = de_ctx->version;
1081  } else if (pflow->de_ctx_version != de_ctx->version) {
1082  /* first time we inspect flow with this de_ctx, reset */
1083  pflow->flags &= ~FLOW_SGH_TOSERVER;
1084  pflow->flags &= ~FLOW_SGH_TOCLIENT;
1085  pflow->sgh_toserver = NULL;
1086  pflow->sgh_toclient = NULL;
1087 
1088  pflow->de_ctx_version = de_ctx->version;
1089  SCGenericVarFree(pflow->flowvar);
1090  pflow->flowvar = NULL;
1091 
1093  }
1094 
1095  /* Retrieve the app layer state and protocol and the tcp reassembled
1096  * stream chunks. */
1097  if ((p->proto == IPPROTO_TCP && (p->flags & PKT_STREAM_EST)) ||
1098  (p->proto == IPPROTO_UDP) ||
1100  {
1101  /* update flow flags with knowledge on disruptions */
1102  flow_flags = FlowGetDisruptionFlags(pflow, flow_flags);
1103  alproto = SCFlowGetAppProtocol(pflow);
1104  if (p->proto == IPPROTO_TCP && pflow->protoctx &&
1107  }
1108  SCLogDebug("alproto %u", alproto);
1109  } else {
1110  SCLogDebug("packet doesn't have established flag set (proto %d)", p->proto);
1111  }
1112 
1113  app_decoder_events = AppLayerParserHasDecoderEvents(pflow->alparser);
1114  }
1115 
1116  DetectRunScratchpad pad = { alproto, flow_flags, app_decoder_events, fw_pkt_policy, NULL };
1118  return pad;
1119 }
1120 
1121 static inline void DetectRunPostRules(ThreadVars *tv, const DetectEngineCtx *de_ctx,
1122  DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow,
1123  DetectRunScratchpad *scratch)
1124 {
1125  /* so now let's iterate the alerts and remove the ones after a pass rule
1126  * matched (if any). This is done inside PacketAlertFinalize() */
1127  /* PR: installed "tag" keywords are handled after the threshold inspection */
1128 
1130  PacketAlertFinalize(de_ctx, det_ctx, p);
1131  if (p->alerts.cnt > 0) {
1132  StatsCounterAddI64(&tv->stats, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt);
1133  }
1134  if (p->alerts.discarded > 0) {
1136  &tv->stats, det_ctx->counter_alerts_overflow, (uint64_t)p->alerts.discarded);
1137  }
1138  if (p->alerts.firewall_discarded > 0) {
1140  (uint64_t)p->alerts.firewall_discarded);
1141  }
1142  if (p->alerts.suppressed > 0) {
1144  &tv->stats, det_ctx->counter_alerts_suppressed, (uint64_t)p->alerts.suppressed);
1145  }
1147 
1148  /* firewall: "fail" closed if we don't have an ACCEPT. This can happen
1149  * if there was no rule group. */
1150  // TODO review packet src types here
1151  if (EngineModeIsFirewall() && ((p->action & (ACTION_ACCEPT | ACTION_DROP)) == 0) &&
1152  p->pkt_src == PKT_SRC_WIRE) {
1153  SCLogDebug("packet %" PRIu64 ": default action as no verdict set %02x (pkt %s)",
1155  (void)DetectRunApplyPacketPolicy(de_ctx, det_ctx, scratch->fw_pkt_policy, p, true);
1157  }
1158 }
1159 
1160 static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx,
1161  Packet *p, Flow * const pflow)
1162 {
1164  InspectionBufferClean(det_ctx);
1165 
1166  if (pflow != NULL) {
1167  /* update inspected tracker for raw reassembly */
1168  if (p->proto == IPPROTO_TCP && pflow->protoctx != NULL &&
1171  det_ctx->raw_stream_progress);
1172  }
1173  }
1175  SCReturn;
1176 }
1177 
1179  DETECT_TX_FW_FC_OK = 0, /**< continue to next rule */
1180  DETECT_TX_FW_FC_SKIP = 1, /**< skip this rule, continue to next */
1181  DETECT_TX_FW_FC_BREAK = 2, /**< break rule loop */
1182 };
1183 
1185 {
1187  det_ctx->tx_candidates = SCCalloc(size, sizeof(RuleMatchCandidateTx));
1188  if (det_ctx->tx_candidates == NULL) {
1189  FatalError("failed to allocate %" PRIu64 " bytes",
1190  (uint64_t)(size * sizeof(RuleMatchCandidateTx)));
1191  }
1192  det_ctx->tx_candidates_size = size;
1193  SCLogDebug("array initialized to %u elements (%"PRIu64" bytes)",
1194  size, (uint64_t)(size * sizeof(RuleMatchCandidateTx)));
1195 }
1196 
1198 {
1199  SCFree(det_ctx->tx_candidates);
1200  det_ctx->tx_candidates_size = 0;
1201 }
1202 
1203 /* if size >= cur_space */
1204 static inline bool RuleMatchCandidateTxArrayHasSpace(const DetectEngineThreadCtx *det_ctx,
1205  const uint32_t need)
1206 {
1207  if (det_ctx->tx_candidates_size >= need)
1208  return 1;
1209  return 0;
1210 }
1211 
1212 /* realloc */
1213 static int RuleMatchCandidateTxArrayExpand(DetectEngineThreadCtx *det_ctx, const uint32_t needed)
1214 {
1215  const uint32_t old_size = det_ctx->tx_candidates_size;
1216  uint32_t new_size = needed;
1217  void *ptmp = SCRealloc(det_ctx->tx_candidates, (new_size * sizeof(RuleMatchCandidateTx)));
1218  if (ptmp == NULL) {
1219  FatalError("failed to expand to %" PRIu64 " bytes",
1220  (uint64_t)(new_size * sizeof(RuleMatchCandidateTx)));
1221  // TODO can this be handled more gracefully?
1222  }
1223  det_ctx->tx_candidates = ptmp;
1224  det_ctx->tx_candidates_size = new_size;
1225  SCLogDebug("array expanded from %u to %u elements (%"PRIu64" bytes -> %"PRIu64" bytes)",
1226  old_size, new_size, (uint64_t)(old_size * sizeof(RuleMatchCandidateTx)),
1227  (uint64_t)(new_size * sizeof(RuleMatchCandidateTx))); (void)old_size;
1228  return 1;
1229 }
1230 
1231 /** \internal
1232  * \brief sort helper for sorting match candidates by id: ascending
1233  *
1234  * The id field is set from Signature::num, so we sort the candidates to match the signature
1235  * sort order (ascending), where candidates that have flags go first.
1236  */
1237 static int
1238 DetectRunTxSortHelper(const void *a, const void *b)
1239 {
1240  const RuleMatchCandidateTx *s0 = a;
1241  const RuleMatchCandidateTx *s1 = b;
1242  if (s1->id == s0->id) {
1243  if (s1->flags && !s0->flags)
1244  return 1;
1245  else if (!s1->flags && s0->flags)
1246  return -1;
1247  return 0;
1248  } else
1249  return s0->id > s1->id ? 1 : -1;
1250 }
1251 
1252 #if 0
1253 #define TRACE_SID_TXS(sid,txs,...) \
1254  do { \
1255  char _trace_buf[2048]; \
1256  snprintf(_trace_buf, sizeof(_trace_buf), __VA_ARGS__); \
1257  SCLogNotice("%p/%"PRIu64"/%u: %s", txs->tx_ptr, txs->tx_id, sid, _trace_buf); \
1258  } while(0)
1259 #else
1260 #define TRACE_SID_TXS(sid,txs,...)
1261 #endif
1262 
1263 /** \internal
1264  * \brief get correct transaction pointer
1265  *
1266  * Gets an encapsulated DNS transaction in the DOH2 case.
1267  *
1268  * Returns NULL is the TX is not to be inspected by this engine.
1269  */
1270 void *DetectGetInnerTx(void *tx_ptr, AppProto alproto, AppProto engine_alproto, uint8_t flow_flags)
1271 {
1272  SCLogDebug("pre: tx_ptr %p flow::alproto %s engine::alproto %s", tx_ptr,
1273  AppProtoToString(alproto), AppProtoToString(engine_alproto));
1274  if (unlikely(alproto == ALPROTO_DOH2)) {
1275  switch (engine_alproto) {
1276  case ALPROTO_DOH2:
1277  /* need to get the dns tx pointer */
1278  tx_ptr = SCDoH2GetDnsTx(tx_ptr, flow_flags);
1279  break;
1280  case ALPROTO_HTTP2:
1281  case ALPROTO_UNKNOWN:
1282  /* tx_ptr is untouched, so use outer (HTTP/2) layer */
1283  break;
1284  default:
1285  /* any other protocol is a mismatch with DOH2 */
1286  tx_ptr = NULL;
1287  break;
1288  }
1289  } else if (engine_alproto != alproto && engine_alproto != ALPROTO_UNKNOWN) {
1290  /* incompatible engine->alproto with flow alproto */
1291  tx_ptr = NULL;
1292  }
1293  return tx_ptr;
1294 }
1295 
1296 /** \internal
1297  * \brief inspect a rule against a transaction
1298  *
1299  * Inspect a rule. New detection or continued stateful
1300  * detection.
1301  *
1302  * \param stored_flags pointer to stored flags or NULL.
1303  * If stored_flags is set it means we're continuing
1304  * inspection from an earlier run.
1305  *
1306  * \retval 1 sig matched
1307  * \retval 0 partial incomplete match
1308  * \retval -1 failed to match
1309  * \retval -2 no match yet, but not final: the MPM engine will revisit the
1310  * tx as it progresses. The caller must not apply a hook default
1311  * policy for it: that could decide the packet before the revisit
1312  * can turn it into a match.
1313  */
1314 static int DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx,
1315  DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f,
1316  const uint8_t in_flow_flags, // direction, EOF, etc
1317  void *alstate, DetectTransaction *tx, const Signature *s, uint32_t *stored_flags,
1319 {
1320  const uint8_t flow_flags = in_flow_flags;
1321  const int direction = (flow_flags & STREAM_TOSERVER) ? 0 : 1;
1322  uint32_t inspect_flags = stored_flags ? *stored_flags : 0;
1323  int total_matches = 0;
1324  uint16_t file_no_match = 0;
1325  bool mpm_before_progress = false; // is mpm engine before progress?
1326  bool mpm_in_progress = false; // is mpm engine in a buffer we will revisit?
1327 
1328  TRACE_SID_TXS(s->id, tx, "starting %s", direction ? "toclient" : "toserver");
1329 
1330  /* for a new inspection we inspect pkt header and packet matches */
1331  if (likely(stored_flags == NULL)) {
1332  TRACE_SID_TXS(s->id, tx, "first inspect, run packet matches");
1333  /* the firewall LTE coverage build already ran the same header check for
1334  * this candidate, so skip repeating it */
1335  if (!can->fw_lte_header_ok && DetectRunInspectRuleHeader(p, f, s, s->flags) == false) {
1336  TRACE_SID_TXS(s->id, tx, "DetectRunInspectRuleHeader() no match");
1337  return -1;
1338  }
1339  if (!DetectEnginePktInspectionRun(tv, det_ctx, s, f, p, NULL)) {
1340  TRACE_SID_TXS(s->id, tx, "DetectEnginePktInspectionRun no match");
1341  return -1;
1342  }
1343  /* stream mpm and negated mpm sigs can end up here with wrong proto */
1344  if (!(AppProtoEquals(s->alproto, f->alproto) || s->alproto == ALPROTO_UNKNOWN)) {
1345  TRACE_SID_TXS(s->id, tx, "alproto mismatch");
1346  return -1;
1347  }
1348  } else {
1349  TRACE_SID_TXS(s->id, tx, "continue, inspect_flags %x", inspect_flags);
1350  }
1351 
1352  const DetectEngineAppInspectionEngine *engine = s->app_inspect;
1353  do {
1354  TRACE_SID_TXS(s->id, tx, "engine %p inspect_flags %x", engine, inspect_flags);
1355 
1356  // also if it is not the same direction, but
1357  // this is a transactional signature, and we are toclient
1358  if (!(inspect_flags & BIT_U32(engine->id)) &&
1359  (direction == engine->dir || ((s->flags & SIG_FLAG_TXBOTHDIR) && direction == 1))) {
1360 
1362  AppLayerParserSupportsSubStates(engine->alproto) && engine->sub_state == 0);
1364  !AppLayerParserSupportsSubStates(engine->alproto) && engine->sub_state != 0);
1365 
1366  if (engine->alproto != ALPROTO_UNKNOWN && // app-layer-events is registered for each
1367  // proto this way
1368  tx->tx_type != engine->sub_state) {
1369  TRACE_SID_TXS(s->id, tx,
1370  "skip because engine alproto %s sub_state %u != tx_type %u (engine "
1371  "progress %u)",
1372  AppProtoToString(engine->alproto), engine->sub_state, tx->tx_type,
1373  engine->progress);
1374  engine = engine->next;
1375  continue;
1376  }
1377  TRACE_SID_TXS(s->id, tx,
1378  "inspecting engine alproto %s sub_state %u == tx_type %u (engine progress %u)",
1379  AppProtoToString(engine->alproto), engine->sub_state, tx->tx_type,
1380  engine->progress);
1381 
1382  void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, f->alproto, engine->alproto, flow_flags);
1383  if (tx_ptr == NULL) {
1384  TRACE_SID_TXS(s->id, tx, "no tx_ptr after DetectGetInnerTx");
1385  if (engine->alproto != ALPROTO_UNKNOWN) {
1386  TRACE_SID_TXS(s->id, tx, "no tx_ptr skip engine");
1387  /* special case: file_data on 'alert tcp' will have engines
1388  * in the list that are not for us. */
1389  engine = engine->next;
1390  continue;
1391  } else {
1392  tx_ptr = tx->tx_ptr;
1393  }
1394  }
1395  TRACE_SID_TXS(s->id, tx, "tx_ptr %p", tx_ptr);
1396 
1397  /* engines are sorted per progress, except that the one with
1398  * mpm/prefilter enabled is first */
1399  if (tx->tx_progress < engine->progress) {
1400  SCLogDebug("tx progress %d < engine progress %d",
1401  tx->tx_progress, engine->progress);
1402  break;
1403  }
1404  if (engine->mpm) {
1405  if (tx->tx_progress > engine->progress) {
1406  TRACE_SID_TXS(s->id, tx,
1407  "engine->mpm: t->tx_progress %u > engine->progress %u, so set "
1408  "mpm_before_progress",
1409  tx->tx_progress, engine->progress);
1410  mpm_before_progress = true;
1411  } else if (tx->tx_progress == engine->progress) {
1412  TRACE_SID_TXS(s->id, tx,
1413  "engine->mpm: t->tx_progress %u == engine->progress %u, so set "
1414  "mpm_in_progress",
1415  tx->tx_progress, engine->progress);
1416  if ((p->flags & PKT_PSEUDO_DETECTLOG_FLUSH) == 0) {
1417  mpm_in_progress = true;
1418  }
1419  }
1420  }
1421 
1422  uint8_t engine_flags = flow_flags;
1423  if (direction != engine->dir) {
1424  engine_flags = flow_flags ^ (STREAM_TOCLIENT | STREAM_TOSERVER);
1425  }
1426  /* run callback: but bypass stream callback if we can */
1427  uint8_t match;
1428  if (unlikely(engine->stream && can->stream_stored)) {
1429  match = can->stream_result;
1430  TRACE_SID_TXS(s->id, tx, "stream skipped, stored result %d used instead", match);
1431  } else if (engine->v2.Callback == NULL) {
1432  /* TODO is this the cleanest way to support a non-app sig on a app hook? */
1433 
1434  if (tx->tx_progress > engine->progress) {
1435  mpm_before_progress = true; // TODO needs a new name now
1436  }
1437 
1438  /* we don't have to store a "hook" match, also don't want to keep any state to make
1439  * sure the hook gets invoked again until tx progress progresses. */
1440  if ((s->flags & SIG_FLAG_FW_HOOK_LTE) == 0 && tx->tx_progress <= engine->progress) {
1441  return 1; // DETECT_ENGINE_INSPECT_SIG_MATCH;
1442  }
1443 
1444  /* if progress > engine progress, track state to avoid additional matches */
1446  } else {
1447  KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list);
1448  DEBUG_VALIDATE_BUG_ON(engine->v2.Callback == NULL);
1449  match = engine->v2.Callback(
1450  de_ctx, det_ctx, engine, s, f, engine_flags, alstate, tx_ptr, tx->tx_id);
1451  TRACE_SID_TXS(s->id, tx, "engine %p match %d", engine, match);
1452  if (engine->stream) {
1453  can->stream_stored = true;
1454  can->stream_result = match;
1455  TRACE_SID_TXS(s->id, tx, "stream ran, store result %d for next tx (if any)", match);
1456  }
1457  }
1458  if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
1459  inspect_flags |= BIT_U32(engine->id);
1460  engine = engine->next;
1461  total_matches++;
1462  continue;
1463  } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
1464  /* if the file engine matched, but indicated more
1465  * files are still in progress, we don't set inspect
1466  * flags as these would end inspection for this tx */
1467  engine = engine->next;
1468  total_matches++;
1469  continue;
1470  } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) {
1471  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1472  inspect_flags |= BIT_U32(engine->id);
1473  } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES) {
1474  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1475  inspect_flags |= BIT_U32(engine->id);
1476  file_no_match = 1;
1477  }
1478  /* implied DETECT_ENGINE_INSPECT_SIG_NO_MATCH */
1479  if (engine->mpm && mpm_before_progress) {
1480  inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
1481  inspect_flags |= BIT_U32(engine->id);
1482  }
1483  break;
1484  } else if (!(inspect_flags & BIT_U32(engine->id)) && s->flags & SIG_FLAG_TXBOTHDIR &&
1485  direction != engine->dir) {
1486  TRACE_SID_TXS(s->id, tx, "handle bidir engine");
1487 
1488  // for transactional rules, the engines on the opposite direction
1489  // are ordered by progress on the different side
1490  // so we have a two mixed-up lists, and we skip the elements
1491  if (direction == 0 && engine->next == NULL) {
1492  // do not match yet on request only
1493  break;
1494  }
1495  engine = engine->next;
1496  continue;
1497  }
1498 
1499  engine = engine->next;
1500  } while (engine != NULL);
1501  TRACE_SID_TXS(s->id, tx, "inspect_flags %x, total_matches %u, engine %p",
1502  inspect_flags, total_matches, engine);
1503 
1504  bool full_match = false;
1505  if (engine == NULL && total_matches) {
1506  inspect_flags |= DE_STATE_FLAG_FULL_INSPECT;
1507  TRACE_SID_TXS(s->id, tx, "MATCH");
1508  full_match = true;
1509  }
1510 
1511  if (stored_flags) {
1512  *stored_flags = inspect_flags;
1513  TRACE_SID_TXS(s->id, tx, "continue inspect flags %08x", inspect_flags);
1514  } else {
1515  // store... or? If tx is done we might not want to come back to this tx
1516 
1517  // also... if mpmid tracking is enabled, we won't do a sig again for this tx...
1518  TRACE_SID_TXS(s->id, tx, "start inspect flags %08x", inspect_flags);
1519  if (inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
1520  if (file_no_match) {
1521  /* if we have a mismatch on a file sig, we need to keep state.
1522  * We may get another file on the same tx (for http and smtp
1523  * at least), so for a new file we need to re-eval the sig.
1524  * Thoughts / TODO:
1525  * - not for some protos that have 1 file per tx (e.g. nfs)
1526  * - maybe we only need this for file sigs that mix with
1527  * other matches? E.g. 'POST + filename', is different than
1528  * just 'filename'.
1529  */
1530  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1531  inspect_flags, flow_flags, file_no_match);
1532  }
1533  } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) && mpm_before_progress) {
1534  TRACE_SID_TXS(s->id, tx, "no need to store match sig, "
1535  "mpm won't trigger for it anymore");
1536 
1537  if (inspect_flags & DE_STATE_FLAG_FILE_INSPECT) {
1538  TRACE_SID_TXS(s->id, tx, "except that for new files, "
1539  "we may have to revisit anyway");
1540  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1541  inspect_flags, flow_flags, file_no_match);
1542  }
1543  } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) == 0 && mpm_in_progress) {
1544  TRACE_SID_TXS(s->id, tx, "no need to store no-match sig, "
1545  "mpm will revisit it");
1546  return -2; /* no match, but not final: mpm will revisit it */
1547  } else if (inspect_flags != 0 || file_no_match != 0) {
1548  TRACE_SID_TXS(s->id, tx, "storing state: flags %08x", inspect_flags);
1549  DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s,
1550  inspect_flags, flow_flags, file_no_match);
1551  } else {
1552  if (inspect_flags == 0) {
1553  TRACE_SID_TXS(s->id, tx, "no match: inspect_flags %08x", inspect_flags);
1554  return -1;
1555  }
1556  }
1557  }
1558  if (full_match) {
1559  return 1;
1560  /* can't be a partial match if we're at the end state */
1561  } else if ((inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) == 0 &&
1562  tx->tx_progress < tx->tx_end_state) {
1563  return 0;
1564  } else {
1565  return -1;
1566  }
1567 }
1568 
1569 #define NO_TX \
1570  { \
1571  NULL, 0, NULL, NULL, 0, 0, 0, 0, false, 0, \
1572  }
1573 
1574 /** \internal
1575  * \brief get a DetectTransaction object
1576  * \retval struct filled with relevant info or all nulls/0s
1577  */
1578 static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alproto,
1579  const uint64_t tx_id, void *tx_ptr, const uint8_t flow_flags)
1580 {
1581  AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx_ptr);
1582  const uint8_t tx_progress =
1583  (uint8_t)AppLayerParserGetStateProgress(ipproto, alproto, tx_ptr, flow_flags);
1585 
1586  const uint8_t e_tx_end_state =
1587  AppLayerParserGetTxEndState(ipproto, alproto, tx_ptr, flow_flags);
1588  DEBUG_VALIDATE_BUG_ON(e_tx_end_state >= APP_LAYER_MAX_PROGRESS);
1589 
1590  bool updated = (flow_flags & STREAM_TOSERVER) ? txd->updated_ts : txd->updated_tc;
1591  if (!updated && tx_progress < e_tx_end_state && ((flow_flags & STREAM_EOF) == 0)) {
1592  DetectTransaction no_tx = NO_TX;
1593  return no_tx;
1594  }
1595  const uint8_t inspected_flag =
1596  (flow_flags & STREAM_TOSERVER) ? APP_LAYER_TX_INSPECTED_TS : APP_LAYER_TX_INSPECTED_TC;
1597  if (unlikely(txd->flags & inspected_flag)) {
1598  SCLogDebug("%" PRIu64 " tx already fully inspected for %s. Flags %02x", tx_id,
1599  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
1600  DetectTransaction no_tx = NO_TX;
1601  return no_tx;
1602  }
1603  const uint8_t skip_flag = (flow_flags & STREAM_TOSERVER) ? APP_LAYER_TX_SKIP_INSPECT_TS
1604  : APP_LAYER_TX_SKIP_INSPECT_TC;
1605  if (unlikely(txd->flags & skip_flag)) {
1606  SCLogDebug("%" PRIu64 " tx should not be inspected in direction %s. Flags %02x", tx_id,
1607  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
1608  DetectTransaction no_tx = NO_TX;
1609  return no_tx;
1610  }
1611 
1612  if (txd->tx_type != 0) {
1613  SCLogDebug("using tx_type %u", txd->tx_type);
1614  }
1615 
1616  const uint8_t detect_progress =
1617  (flow_flags & STREAM_TOSERVER) ? txd->detect_progress_ts : txd->detect_progress_tc;
1618 
1619  const int dir_int = (flow_flags & STREAM_TOSERVER) ? 0 : 1;
1620  DetectEngineState *tx_de_state = txd->de_state;
1621  DetectEngineStateDirection *tx_dir_state =
1622  tx_de_state ? &tx_de_state->dir_state[dir_int] : NULL;
1623  DetectTransaction tx = {
1624  .tx_ptr = tx_ptr,
1625  .tx_id = tx_id,
1626  .tx_data_ptr = (struct AppLayerTxData *)txd,
1627  .de_state = tx_dir_state,
1628  .detect_progress = detect_progress,
1629  .detect_progress_orig = detect_progress,
1630  .tx_progress = (uint8_t)tx_progress,
1631  .tx_end_state = e_tx_end_state,
1632  .is_last = false,
1633  .tx_type = txd->tx_type,
1634  };
1635  return tx;
1636 }
1637 
1638 static inline void StoreDetectProgress(
1639  DetectTransaction *tx, const uint8_t flow_flags, const uint8_t progress)
1640 {
1642  if (flow_flags & STREAM_TOSERVER) {
1643  txd->detect_progress_ts = progress;
1644  } else {
1645  txd->detect_progress_tc = progress;
1646  }
1647 }
1648 
1649 // Merge 'state' rules from the regular prefilter
1650 // updates array_idx on the way
1651 static inline void RuleMatchCandidateMergeStateRules(
1652  DetectEngineThreadCtx *det_ctx, uint32_t *array_idx, bool *fw_lte)
1653 {
1654  // Now, we will merge 2 sorted lists :
1655  // the one in det_ctx->tx_candidates
1656  // and the one in det_ctx->match_array
1657  // For match_array, we take only the relevant elements where s->app_inspect != NULL
1658 
1659  // Basically, we iterate at the same time over the 2 lists
1660  // comparing and taking an element from either.
1661 
1662  // Trick is to do so in place in det_ctx->tx_candidates,
1663  // so as to minimize the number of moves in det_ctx->tx_candidates.
1664  // For this, the algorithm traverses the lists in reverse order.
1665  // Otherwise, if the first element of match_array was to be put before
1666  // all tx_candidates, we would need to shift all tx_candidates
1667 
1668  // Retain the number of elements sorted in tx_candidates before merge
1669  uint32_t j = *array_idx;
1670  // First loop only counting the number of elements to add
1671  for (uint32_t i = 0; i < det_ctx->match_array_cnt; i++) {
1672  const Signature *s = det_ctx->match_array[i];
1673  if (s->app_inspect != NULL) {
1674  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
1675  *fw_lte = true;
1676  }
1677  (*array_idx)++;
1678  }
1679  }
1680  // Future number of elements in tx_candidates after merge
1681  uint32_t k = *array_idx;
1682 
1683  if (k == j) {
1684  // no new element from match_array to merge in tx_candidates
1685  return;
1686  }
1687 
1688  // variable i is for all elements of match_array (even not relevant ones)
1689  // variable j is for elements of tx_candidates before merge
1690  // variable k is for elements of tx_candidates after merge
1691  for (uint32_t i = det_ctx->match_array_cnt; i > 0;) {
1692  const Signature *s = det_ctx->match_array[i - 1];
1693  if (s->app_inspect == NULL) {
1694  // no relevant element, get the next one from match_array
1695  i--;
1696  continue;
1697  }
1698  // we have one element from match_array to merge in tx_candidates
1699  k--;
1700  if (j > 0) {
1701  // j > 0 means there is still at least one element in tx_candidates to merge
1702  const RuleMatchCandidateTx *s0 = &det_ctx->tx_candidates[j - 1];
1703  if (s->iid <= s0->id) {
1704  // get next element from previous tx_candidates
1705  j--;
1706  // take the element from tx_candidates before merge
1707  det_ctx->tx_candidates[k].s = det_ctx->tx_candidates[j].s;
1708  det_ctx->tx_candidates[k].id = det_ctx->tx_candidates[j].id;
1709  det_ctx->tx_candidates[k].fw_lte_counted = det_ctx->tx_candidates[j].fw_lte_counted;
1710  det_ctx->tx_candidates[k].fw_lte_header_ok =
1711  det_ctx->tx_candidates[j].fw_lte_header_ok;
1712  det_ctx->tx_candidates[k].flags = det_ctx->tx_candidates[j].flags;
1713  det_ctx->tx_candidates[k].stream_reset = det_ctx->tx_candidates[j].stream_reset;
1714  continue;
1715  }
1716  } // otherwise
1717  // get next element from match_array
1718  i--;
1719  // take the element from match_array
1720  det_ctx->tx_candidates[k].s = s;
1721  det_ctx->tx_candidates[k].id = s->iid;
1722  det_ctx->tx_candidates[k].fw_lte_counted = false;
1723  det_ctx->tx_candidates[k].fw_lte_header_ok = false;
1724  det_ctx->tx_candidates[k].flags = NULL;
1725  det_ctx->tx_candidates[k].stream_reset = 0;
1726  }
1727  // Even if k > 0 or j > 0, the loop is over. (Note that j == k now)
1728  // The remaining elements in tx_candidates up to k were already sorted
1729  // and come before any other element later in the list
1730 }
1731 
1738  bool last_fw_rule; /**< processing the last fw rule, so we need to eval all hooks after it. */
1739  /** det_ctx->fw_lte_cover holds the counts for this walk. The counts answer
1740  * "does another pending rule cover hook H": per hook, how many pending LTE
1741  * rules cover it (their own hook and every prior hook). Progress values
1742  * stay under APP_LAYER_MAX_PROGRESS. */
1744 };
1745 
1746 /** \internal
1747  * \brief initialize the per-thread LTE hook coverage for this walk.
1748  *
1749  * The counts live in the thread ctx so IDS traffic does not pay to clear them.
1750  * They are cleared lazily, on the first LTE rule of the walk.
1751  */
1752 static inline void DetectFwEnsureLteCoverage(
1753  DetectEngineThreadCtx *det_ctx, struct DetectFirewallAppTxState *fw_state)
1754 {
1755  if (!fw_state->fw_lte_cover_active) {
1756  memset(det_ctx->fw_lte_cover, 0, sizeof(det_ctx->fw_lte_cover));
1757  fw_state->fw_lte_cover_active = true;
1758  }
1759 }
1760 
1761 /** \internal
1762  * \brief build the per hook coverage of the pending LTE rules.
1763  *
1764  * Counts, per hook, how many pending LTE rules cover it (their own hook and
1765  * every prior hook). The candidate list is sorted, so duplicates - the state
1766  * store and the per-state registrations can both add a rule - are adjacent.
1767  */
1768 static void DetectFwBuildLteCoverage(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f,
1769  struct DetectFirewallAppTxState *fw_state, const uint32_t array_idx)
1770 {
1771  DetectFwEnsureLteCoverage(det_ctx, fw_state);
1772  for (uint32_t i = 0; i < array_idx; i++) {
1773  const Signature *s = det_ctx->tx_candidates[i].s;
1774  /* only firewall rules implement the per-state policy: a threat
1775  * detection rule using the <hook header must not count as coverage */
1776  if (!(s->flags & SIG_FLAG_FW_HOOK_LTE) || !(s->flags & SIG_FLAG_FIREWALL)) {
1777  continue;
1778  }
1779  RuleMatchCandidateTx *can = &det_ctx->tx_candidates[i];
1780  can->fw_lte_counted = false;
1781  const uint32_t *flags = can->flags;
1782  if (flags == NULL) {
1783  if (!DetectRunInspectRuleHeader(p, f, s, s->flags)) {
1784  /* an out of scope rule never covered anything */
1785  continue;
1786  }
1787  /* the walk inspects this candidate with the same arguments, so it
1788  * can skip repeating the header check */
1789  can->fw_lte_header_ok = true;
1790  }
1791  if (flags != NULL &&
1793  /* already resolved in an earlier pass */
1794  continue;
1795  }
1796  /* duplicates of the same signature (state store + per-state
1797  * registrations) are adjacent: the candidate list is sorted by id with
1798  * the flagged entry first */
1800  i > 0 && det_ctx->tx_candidates[i].id < det_ctx->tx_candidates[i - 1].id);
1801  if (i > 0 && det_ctx->tx_candidates[i - 1].s == s) {
1802  continue;
1803  }
1805  /* defensive: parse rejects this; skip it so the arrays stay in
1806  * bounds and the rule applies its own default policy */
1808  continue;
1809  }
1810  can->fw_lte_counted = true;
1811  for (uint16_t h = 0; h <= s->app_progress_hook; h++) {
1812  det_ctx->fw_lte_cover[h]++;
1813  }
1814  }
1815 }
1816 
1817 /** \internal
1818  * \brief check if a pending LTE rule other than the current one covers its hook.
1819  */
1820 static inline bool DetectFwOtherLteCoversHook(DetectEngineThreadCtx *det_ctx,
1821  const struct DetectFirewallAppTxState *fw_state, const Signature *s, const bool counted)
1822 {
1823  if (!fw_state->fw_lte_cover_active) {
1824  /* no LTE candidate in this walk, so nothing covers the hook */
1825  return false;
1826  }
1829  return false;
1830  }
1831  const uint32_t covered = det_ctx->fw_lte_cover[s->app_progress_hook];
1832  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
1833  /* an uncounted candidate (header mismatch, already retired) carries
1834  * no own count in the coverage */
1835  return covered > (counted ? 1 : 0);
1836  }
1837  return covered > 0;
1838 }
1839 
1840 /** \internal
1841  * \brief count an LTE rule appended mid-walk into the hook coverage.
1842  *
1843  * Appended candidates are the tail of the list, so duplicates cannot be
1844  * detected by adjacency like in DetectFwBuildLteCoverage().
1845  */
1846 static inline void DetectFwCountAppendedLteRule(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f,
1847  struct DetectFirewallAppTxState *fw_state, const Signature *s, const uint32_t can_idx)
1848 {
1849  if (!(s->flags & SIG_FLAG_FW_HOOK_LTE) || !(s->flags & SIG_FLAG_FIREWALL) ||
1851  !DetectRunInspectRuleHeader(p, f, s, s->flags)) {
1852  return;
1853  }
1854  for (uint32_t k = 0; k < can_idx; k++) {
1855  if (det_ctx->tx_candidates[k].s == s && det_ctx->tx_candidates[k].fw_lte_counted) {
1856  return;
1857  }
1858  }
1859  DetectFwEnsureLteCoverage(det_ctx, fw_state);
1860  for (uint16_t h = 0; h <= s->app_progress_hook; h++) {
1861  det_ctx->fw_lte_cover[h]++;
1862  }
1863  det_ctx->tx_candidates[can_idx].fw_lte_counted = true;
1864  det_ctx->tx_candidates[can_idx].fw_lte_header_ok = true;
1865 }
1866 
1867 /** \internal
1868  * \brief remove an LTE rule that resolved definitively from the hook coverage.
1869  */
1870 static void DetectFwRetireLteRule(DetectEngineThreadCtx *det_ctx, RuleMatchCandidateTx *can)
1871 {
1872  const Signature *s = can->s;
1875  return;
1876  }
1877  for (uint16_t h = 0; h <= s->app_progress_hook; h++) {
1878  /* the caller only retires counted candidates: a zero here means the
1879  * accounting is broken, not a legitimate case */
1880  DEBUG_VALIDATE_BUG_ON(det_ctx->fw_lte_cover[h] == 0);
1881  if (det_ctx->fw_lte_cover[h] > 0) {
1882  det_ctx->fw_lte_cover[h]--;
1883  }
1884  }
1885  /* the candidate no longer contributes to the counts */
1886  can->fw_lte_counted = false;
1887 }
1888 
1889 static inline void DetectRunAppendDefaultAppPolicyAlert(DetectEngineThreadCtx *det_ctx, Packet *p,
1890  const bool apply_to_packet, const DetectTransaction *tx,
1891  const struct DetectFirewallAppPolicy *ap)
1892 {
1893  if (EngineModeIsFirewall()) {
1894  const Signature *s = ap->alert_signature;
1895  BUG_ON(s == NULL);
1896  uint8_t alert_flags = apply_to_packet ? PACKET_ALERT_FLAG_APPLY_ACTION_TO_PACKET : 0;
1897  AlertQueueAppendAppTxFromPacket(det_ctx, s, p, tx->tx_id, tx->tx_type, alert_flags);
1898  }
1899 }
1900 
1901 /** \internal
1902  * \brief apply default policy
1903  * \param p packet to apply policy to
1904  * \param alproto app proto
1905  * \param progress hook / progress value to apply the policy to
1906  *
1907  * \note alproto and progress are unused right now, will be used
1908  * to look up configurable default policies later
1909  */
1910 static struct DetectFirewallPolicy DetectFirewallApplyDefaultAppPolicy(
1911  DetectEngineThreadCtx *det_ctx, const struct DetectFirewallPolicies *policies,
1912  const DetectTransaction *tx, Packet *p, const AppProto alproto, const uint8_t direction,
1913  const uint8_t progress)
1914 {
1915  const uint8_t dir_flags = direction & (STREAM_TOSERVER | STREAM_TOCLIENT);
1916 
1917  SCLogDebug("packet %" PRIu64 ": tx type %u", PcapPacketCntGet(p), tx->tx_type);
1918 
1919  const struct DetectFirewallPolicy drop_policy = { .action = ACTION_DROP,
1920  .action_scope = ACTION_SCOPE_FLOW };
1921  const struct DetectFirewallAppPolicy lookup = {
1922  .alproto = alproto, .sub_state = tx->tx_type, .progress = progress, .direction = dir_flags
1923  };
1924  const struct DetectFirewallPolicy *policy = NULL;
1925  const struct DetectFirewallAppPolicy *ap =
1926  HashTableLookup(policies->app_policies, (void *)&lookup, 0);
1927  /* table should be fully populated, so this should not be able to fail.
1928  * However as it continues to confuse tooling, at a fallback. */
1929  DEBUG_VALIDATE_BUG_ON(ap == NULL);
1930  if (likely(ap != NULL)) {
1931  policy = &ap->policy;
1932  } else {
1933  policy = &drop_policy;
1934  }
1935  if (policy->action & ACTION_DROP) {
1936  SCLogDebug("dropping packet PKT_DROP_REASON_FW_DEFAULT_APP_POLICY");
1939  SCLogDebug("dropping flow");
1940  FlowSetDropAction(p->flow, FLOW_ACTION_BY_FIREWALL);
1941  }
1942  if (policy->action & ACTION_ALERT) {
1943  DetectRunAppendDefaultAppPolicyAlert(det_ctx, p, true, tx, ap);
1944  }
1945  } else if (policy->action & ACTION_ACCEPT) {
1946  /* should the accept be applied to the packet?
1947  * ACTION_SCOPE_FLOW: yes
1948  * ACTION_SCOPE_TX: only if last_tx
1949  * ACTION_SCOPE_HOOK: only if last_tx and hook is highest available hook
1950  */
1951  const bool last_hook = progress == tx->tx_progress;
1952  bool apply_to_packet = false;
1953 
1954  switch (policy->action_scope) {
1955  case ACTION_SCOPE_FLOW:
1957  apply_to_packet = true;
1958  break;
1959  case ACTION_SCOPE_TX:
1960  tx->tx_data_ptr->flags |= APP_LAYER_TX_ACCEPT;
1961  apply_to_packet = tx->is_last;
1962  break;
1963  case ACTION_SCOPE_HOOK:
1964  apply_to_packet = tx->is_last && last_hook;
1965  break;
1966  default:
1967  /* should be unreachable */
1969  break;
1970  }
1971  SCLogDebug("packet %" PRIu64 " hook %u default policy ACCEPT, apply_to_packet:%s",
1972  PcapPacketCntGet(p), progress, BOOL2STR(apply_to_packet));
1973 
1974  if (policy->action & ACTION_ALERT) {
1975  SCLogDebug("policy alert, do the append");
1976  DetectRunAppendDefaultAppPolicyAlert(det_ctx, p, apply_to_packet, tx, ap);
1977  } else if (apply_to_packet) {
1978  SCLogDebug("default accept: last_tx");
1979  DetectRunAppendDefaultAccept(det_ctx, p);
1980  }
1981  } else {
1982  /* should be unreachable */
1984  }
1985  return *policy;
1986 }
1987 
1988 /** \internal
1989  * \brief run default policies for hook(s)
1990  *
1991  * For a range of hooks look up the policy and apply it.
1992  *
1993  * \param is_last is this tx the last we have? Used to check if an action needs to be applied to
1994  * the packet.
1995  *
1996  * \retval DETECT_TX_FW_FC_BREAK rest of rules shouldn't be inspected
1997  * \retval DETECT_TX_FW_FC_SKIP skip current firewall rule
1998  * \retval DETECT_TX_FW_FC_OK no action needed
1999  */
2000 static enum DetectTxFirewallFlowControl DetectFirewallApplyDefaultPolicies(
2001  DetectEngineThreadCtx *det_ctx, const struct DetectFirewallPolicies *policies,
2002  DetectTransaction *tx, Packet *p, const AppProto alproto, const uint8_t direction,
2003  const uint8_t start_hook, const uint8_t end_hook)
2004 {
2005  DEBUG_VALIDATE_BUG_ON(start_hook > end_hook);
2006 
2007  const bool need_verdict =
2008  tx->is_last && (end_hook == tx->tx_end_state || end_hook == tx->tx_progress);
2009  SCLogDebug("need_verdict:%s is_last:%s end_hook:%u tx->tx_end_state:%u tx->progress: %u",
2010  BOOL2STR(need_verdict), BOOL2STR(tx->is_last), end_hook, tx->tx_end_state,
2011  tx->tx_progress);
2012 
2013  for (uint8_t hook = start_hook; hook <= end_hook; hook++) {
2014  const bool apply_to_packet =
2015  tx->is_last && (hook == tx->tx_end_state || hook == tx->tx_progress);
2016 
2017  SCLogDebug("%" PRIu64 ": %s default policy for hook %u, apply_to_packet %s",
2018  PcapPacketCntGet(p), direction & STREAM_TOSERVER ? "toserver" : "toclient", hook,
2019  BOOL2STR(apply_to_packet));
2020 
2021  const struct DetectFirewallPolicy policy = DetectFirewallApplyDefaultAppPolicy(
2022  det_ctx, policies, tx, p, alproto, direction, hook);
2023  SCLogDebug("fw: hook:%u policy:%02x apply_to_packet:%s", hook, policy.action,
2024  BOOL2STR(apply_to_packet));
2025  if (policy.action & ACTION_DROP) {
2026  SCLogDebug("fw: action %02x", policy.action);
2027  return DETECT_TX_FW_FC_BREAK;
2028 
2029  } else if (policy.action & ACTION_ACCEPT) {
2030  SCLogDebug("fw: accept hook %u action %02x", hook, policy.action);
2031 
2032  /* accepting flow, so skip rest of the fw rules */
2033  if (policy.action_scope == ACTION_SCOPE_FLOW) {
2034  SCLogDebug("fw: accept flow");
2035  return DETECT_TX_FW_FC_SKIP;
2036 
2037  /* accepting flow, so skip rest of the fw rules for this tx */
2038  } else if (policy.action_scope == ACTION_SCOPE_TX) {
2039  return DETECT_TX_FW_FC_SKIP;
2040 
2041  } else if (policy.action_scope == ACTION_SCOPE_HOOK) {
2042  /* we're done */
2043  if (apply_to_packet) {
2044  return DETECT_TX_FW_FC_SKIP;
2045  }
2046  } else {
2048  }
2049  } else {
2051  }
2052  }
2053 
2054  /* if the tx progress is at end_hook state, it means the rule that called us cannot
2055  * match: it's app_progress_hook is not yet available. In this can we need to set
2056  * a default accept. This happens if we got only `accept:hook` policies. */
2057  if (need_verdict) {
2058  SCLogDebug("default accept: last tx and progress at end_hook %u", end_hook);
2059  DetectRunAppendDefaultAccept(det_ctx, p);
2060  /* break as we can't match the calling signature */
2061  return DETECT_TX_FW_FC_BREAK;
2062  }
2063 
2064  return DETECT_TX_FW_FC_OK;
2065 }
2066 
2067 /** \internal
2068  * \brief run pre-rule inspection firewall policy checks
2069  *
2070  * Check for:
2071  * - check if we're in accept:tx mode
2072  * - check for missing accept hooks
2073  * -
2074  *
2075  * \retval DETECT_TX_FW_FC_OK no action needed
2076  * \retval DETECT_TX_FW_FC_BREAK rest of rules shouldn't be inspected
2077  * \retval DETECT_TX_FW_FC_SKIP skip this rule
2078  */
2079 static enum DetectTxFirewallFlowControl DetectRunTxPreCheckFirewallPolicy(
2080  DetectEngineThreadCtx *det_ctx, Packet *p, DetectTransaction *tx, const uint8_t direction,
2081  const Signature *s, const uint32_t can_idx, const bool lte_counted,
2082  struct DetectFirewallAppTxState *fw_state)
2083 {
2084  SCLogDebug("packet %" PRIu64 ": running pre-checks before sid %u", PcapPacketCntGet(p), s->id);
2085 
2086  /* enforce skip app filter. If a prior rule caused a fw_skip_app_filter set, we will skip
2087  * each fw rule from now. Non-FW rules will just be inspected. Non-FW need to hit this
2088  * path to help put into effect the FLOW_ACTION_ACCEPT/APP_LAYER_TX_ACCEPT and call
2089  * the default policy enforcement. */
2090  if (fw_state->fw_skip_app_filter) {
2091  if ((s->flags & SIG_FLAG_FIREWALL) != 0) {
2092  return DETECT_TX_FW_FC_SKIP;
2093  } else {
2094  return DETECT_TX_FW_FC_OK;
2095  }
2096  }
2097  if (p->flow->flags & FLOW_ACTION_ACCEPT) {
2098  fw_state->fw_skip_app_filter = true;
2099  SCLogDebug("default accept due to flow accept");
2100  DetectRunAppendDefaultAccept(det_ctx, p);
2101 
2102  if (s->flags & SIG_FLAG_FIREWALL) {
2103  return DETECT_TX_FW_FC_SKIP;
2104  }
2105  }
2106  /* skip fw rules if we're in accept:tx mode */
2107  if (tx->tx_data_ptr->flags & APP_LAYER_TX_ACCEPT) {
2108  /* append a blank accept:packet action for the APP_LAYER_TX_ACCEPT,
2109  * if this is the last tx */
2110  fw_state->fw_skip_app_filter = true;
2111  const bool accept_tx_applies_to_packet = tx->is_last;
2112  if (accept_tx_applies_to_packet) {
2113  SCLogDebug("accept:tx: should be applied to the packet");
2114  DetectRunAppendDefaultAccept(det_ctx, p);
2115  }
2116 
2117  if (s->flags & SIG_FLAG_FIREWALL) {
2118  SCLogDebug("APP_LAYER_TX_ACCEPT, so skip rule");
2119  return DETECT_TX_FW_FC_SKIP;
2120  }
2121 
2122  /* threat detect rules will be inspected */
2123  return DETECT_TX_FW_FC_OK;
2124  }
2125 
2126  /* handle missing rules case */
2127  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2128  SCLogDebug("SIG_FLAG_FW_HOOK_LTE");
2129  return DETECT_TX_FW_FC_OK; // TODO check for other cases
2130  }
2131 
2132  if (can_idx == 0) {
2133  SCLogDebug("check if prior hooks are satisfied: s->app_progress_hook %u, "
2134  "tx->detect_progress_orig %u",
2136 
2137  if (DetectFwOtherLteCoversHook(det_ctx, fw_state, s, lte_counted)) {
2138  SCLogDebug("later LTE in-progress rule brought us here: us:%u covered:%u",
2140  return DETECT_TX_FW_FC_OK;
2141  }
2142 
2143  /* if our first rule is beyond the starting state, we need to check if
2144  * there are rules missing for states in between. */
2145  if (s->app_progress_hook > tx->detect_progress_orig) {
2146  SCLogDebug("missing fw rules at list start: sid %u, progress %u (%u:%u)", s->id,
2148  /* if this rule was after the state we expected meaning that there are
2149  * no rules for that state. Invoke the default policies. */
2150  enum DetectTxFirewallFlowControl r = DetectFirewallApplyDefaultPolicies(det_ctx,
2151  det_ctx->de_ctx->fw_policies, tx, p, s->alproto, direction,
2153  if (r != DETECT_TX_FW_FC_OK) {
2154  /* both SKIP and BREAK mean: no more fw rules to inspect.
2155  * SKIP applies to just this TX.
2156  * DROP applies to everything. */
2157  fw_state->fw_skip_app_filter = true;
2158  }
2159  return r;
2160  }
2161  }
2162  return DETECT_TX_FW_FC_OK;
2163 }
2164 
2165 /**
2166  * \internal
2167  * \brief Check and update firewall rules state.
2168  *
2169  * \param fw_state pointer to flow control state
2170  *
2171  * \retval DETECT_TX_FW_FC_OK no action needed
2172  * \retval DETECT_TX_FW_FC_BREAK rest of rules shouldn't inspected
2173  * \retval DETECT_TX_FW_FC_SKIP skip this rule
2174  */
2175 static enum DetectTxFirewallFlowControl DetectRunTxCheckRuleState(DetectEngineThreadCtx *det_ctx,
2176  Packet *p, Flow *f, DetectTransaction *tx, const Signature *s, const uint32_t can_idx,
2177  const uint32_t can_size, const bool lte_counted, struct DetectFirewallAppTxState *fw_state)
2178 {
2179  if (s->flags & SIG_FLAG_FIREWALL) {
2180  /* check if the next sig is on the same progress hook. If not, we need to apply our
2181  * default policy in case the current sig doesn't apply one. If the next sig has a
2182  * progress beyond our progress + 1, it means the next progress has no rules and needs
2183  * the default policy applied. But only after we evaluate the current rule first, as
2184  * that may override it. */
2185 
2186  if (can_idx + 1 < can_size) {
2187  const Signature *next_s = det_ctx->tx_candidates[can_idx + 1].s;
2188  SCLogDebug(
2189  "peek: peeking at sid %u / progress %u", next_s->id, next_s->app_progress_hook);
2190  if (next_s->flags & SIG_FLAG_FIREWALL) {
2191  if (s->app_progress_hook != next_s->app_progress_hook) {
2192  if (DetectFwOtherLteCoversHook(det_ctx, fw_state, s, lte_counted)) {
2193  SCLogDebug("we have another LTE in-progress. Us:%u covered:%u",
2195  } else {
2196  SCLogDebug("peek: next sid progress %u != current progress %u, so current "
2197  "is last for progress",
2198  next_s->app_progress_hook, s->app_progress_hook);
2199  fw_state->fw_last_for_progress = true;
2200 
2201  if (next_s->app_progress_hook - s->app_progress_hook > 1) {
2202  SCLogDebug("peek: missing progress, so we'll drop that unless we get a "
2203  "sweeping accept first");
2204  fw_state->fw_next_progress_missing = true;
2205  }
2206  }
2207  }
2208  } else {
2209  SCLogDebug("peek: next sid not a fw rule, so current is last for progress");
2210  fw_state->fw_last_for_progress = true;
2211  fw_state->last_fw_rule = true;
2212  }
2213  } else {
2214  SCLogDebug("peek: no peek beyond last rule");
2215  if (!DetectFwOtherLteCoversHook(det_ctx, fw_state, s, lte_counted)) {
2216  if (s->app_progress_hook < tx->tx_progress) {
2217  SCLogDebug("peek: there are no rules to allow the state after this rule");
2218  fw_state->fw_next_progress_missing = true;
2219  }
2220  fw_state->fw_last_for_progress = true;
2221  fw_state->last_fw_rule = true;
2222  }
2223  }
2224 
2225  if (fw_state->skip_fw_hook == true) {
2226  if (s->app_progress_hook <= fw_state->skip_before_progress) {
2227  return DETECT_TX_FW_FC_SKIP;
2228  }
2229  fw_state->skip_fw_hook = false;
2230  }
2231  } else {
2232  /* fw mode, we skip anything after the fw rules if:
2233  * - flow pass is set
2234  * - packet pass (e.g. exception policy) */
2236  SCLogDebug("skipping firewall rule %u", s->id);
2237  return DETECT_TX_FW_FC_BREAK;
2238  }
2239  }
2240  return DETECT_TX_FW_FC_OK;
2241 }
2242 
2243 // TODO move into det_ctx?
2245 static void DetectRunAppendDefaultAccept(DetectEngineThreadCtx *det_ctx, Packet *p)
2246 {
2248  SCLogDebug("packet %" PRIu64 ": appending default firewall accept", PcapPacketCntGet(p));
2249  memset(&default_accept, 0, sizeof(default_accept));
2252  default_accept.iid = UINT32_MAX;
2256  DETECT_TABLE_APP_FILTER; // TODO review, hope this makes it last in sorting
2258 }
2259 
2260 /** \internal
2261  * \brief see if the accept rule needs to apply to the packet
2262  */
2263 static inline bool ApplyAcceptToPacket(const DetectTransaction *tx, const Signature *s)
2264 {
2265  if ((s->flags & SIG_FLAG_FIREWALL) == 0) {
2266  return false;
2267  }
2268  if ((s->action & ACTION_ACCEPT) == 0) {
2269  return false;
2270  }
2271 
2272  /* for accept:tx we need:
2273  * - packet will only be accepted if this is set on the last tx
2274  */
2275  if (s->action_scope == ACTION_SCOPE_TX) {
2276  if (tx->is_last) {
2277  return true;
2278  }
2279  }
2280  /* for accept:hook we need a bit more checking:
2281  * - packet will only be accepted if this is set on the last tx
2282  * - the hook accepted should be the last progress available. */
2283  if (s->action_scope == ACTION_SCOPE_HOOK) {
2284  if (tx->is_last && (s->app_progress_hook == tx->tx_progress)) {
2285  return true;
2286  }
2287  }
2288  return false;
2289 }
2290 
2291 /** \internal
2292  * \brief apply an accept, but do check policies when needed
2293  *
2294  * Updates flow control where needed.
2295  *
2296  * */
2297 static void DetectRunTxFirewallApplyAccept(DetectEngineThreadCtx *det_ctx, Packet *p,
2298  const uint8_t direction, const Signature *s, DetectTransaction *tx,
2299  struct DetectFirewallAppTxState *fw_state)
2300 {
2301  const enum ActionScope as = s->action_scope;
2302  /* accept:hook: jump to first rule of next state.
2303  * Implemented as skip until the first rule of next state. */
2304  if (as == ACTION_SCOPE_HOOK) {
2305  fw_state->skip_fw_hook = true;
2306  fw_state->skip_before_progress = s->app_progress_hook;
2307 
2308  SCLogDebug("fw match sid:%u hook:%u", s->id, s->app_progress_hook);
2309  SCLogDebug("fw fw_skip_app_filter:%s skip_fw_hook:%s "
2310  "skip_before_progress:%u fw_last_for_progress:%s fw_next_progress_missing:%s",
2311  BOOL2STR(fw_state->fw_skip_app_filter), BOOL2STR(fw_state->skip_fw_hook),
2312  fw_state->skip_before_progress, BOOL2STR(fw_state->fw_last_for_progress),
2313  BOOL2STR(fw_state->fw_next_progress_missing));
2314  /* if there is no fw rule for the next progress value,
2315  * we invoke the defaul policies for the remaining available hooks.
2316  * Only when the tx walked over this rule's hook: at progress == hook
2317  * the sweep range would start above its end. */
2318  if (fw_state->fw_next_progress_missing && tx->tx_progress > s->app_progress_hook) {
2319  /* only states the packet actually walked over: states beyond the
2320  * current progress have not been reached, their defaults must not
2321  * decide this packet */
2322  const uint8_t last_hook = fw_state->last_fw_rule
2323  ? tx->tx_progress
2324  : MIN(tx->tx_progress, s->app_progress_hook + 1);
2326  DetectFirewallApplyDefaultPolicies(det_ctx, det_ctx->de_ctx->fw_policies, tx, p,
2327  s->alproto, direction, s->app_progress_hook + 1, last_hook);
2328  if (r == DETECT_TX_FW_FC_BREAK) {
2329  fw_state->fw_skip_app_filter = true;
2330  return;
2331  }
2332  }
2333  } else if (as == ACTION_SCOPE_TX) {
2335  fw_state->skip_fw_hook = true;
2336  fw_state->skip_before_progress = tx->tx_end_state + 1; // skip all hooks
2337  SCLogDebug("accept:tx applied, skip_fw_hook, skip_before_progress %u",
2338  fw_state->skip_before_progress);
2339  } else if (as == ACTION_SCOPE_PACKET) {
2340  fw_state->fw_skip_app_filter = true;
2341  } else if (as == ACTION_SCOPE_FLOW) {
2342  SCLogDebug("sid %u: ACTION_ACCEPT with ACTION_SCOPE_FLOW", s->id);
2343  fw_state->fw_skip_app_filter = true;
2344  }
2345 }
2346 
2347 /**
2348  * \internal
2349  * \brief check if there are no (fw) rules, and apply the default policies if so
2350  *
2351  * \retval 3 policies handled, continue with inspection
2352  * \retval 2 continue with next tx
2353  * \retval 1 done with inspection
2354  * \retval 0 ok, continue as normal. No policies applied.
2355  */
2356 static int DetectTxFirewallNoRulesApplyPolicies(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f,
2357  DetectTransaction *tx, const AppProto alproto, const uint8_t flow_flags, const int rule_cnt)
2358 {
2359  /* if there are no rules / rule candidates, handling invoking the default
2360  * policy. */
2361  if (rule_cnt == 0 || (det_ctx->tx_candidates[0].s->flags & SIG_FLAG_FIREWALL) == 0) {
2362  /* if there are no rules, make sure to handle accept:flow and accept:tx */
2363  if (rule_cnt == 0) {
2364  if (f->flags & FLOW_ACTION_ACCEPT) {
2365  SCLogDebug("default accept:flow: no rules");
2366  DetectRunAppendDefaultAccept(det_ctx, p);
2367  return 1;
2368  }
2369  if (tx->tx_data_ptr->flags & APP_LAYER_TX_ACCEPT) {
2370  /* current tx is the last we have, append a blank accept:packet */
2371  if (tx->is_last) {
2372  SCLogDebug("default accept:tx: no rules");
2373  DetectRunAppendDefaultAccept(det_ctx, p);
2374  return 1;
2375  }
2376  return 2;
2377  }
2378  }
2379 
2380  /* if there are no fw rules, handle default policies */
2381  if ((f->flags & FLOW_ACTION_ACCEPT) == 0 &&
2382  (tx->tx_data_ptr->flags & APP_LAYER_TX_ACCEPT) == 0) {
2383  /* No rules to eval, so we need to see if there are default policies to apply.
2384  * Start at last inspected progress and check each hook. If all hooks accepted,
2385  * apply the accept to the packet. */
2386  SCLogDebug("tx.detect_progress_orig %u tx.tx_progress %u", tx->detect_progress_orig,
2387  tx->tx_progress);
2389  DetectFirewallApplyDefaultPolicies(det_ctx, det_ctx->de_ctx->fw_policies, tx, p,
2390  alproto, flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT),
2392  SCLogDebug("r %u", r);
2393  if (r == DETECT_TX_FW_FC_BREAK)
2394  return 1;
2395  if (r == DETECT_TX_FW_FC_SKIP)
2396  return 2;
2397  /* continue with TD rules */
2398  SCLogDebug("continue with TD rules");
2399  return 3;
2400  }
2401  }
2402  return 0;
2403 }
2404 
2405 /** \internal
2406  * \brief handle a full rule match for a firewall rule
2407  *
2408  * For a drop/reject rule, excute action immediately.
2409  * For an accept rule, add an alert even to the queue. This will
2410  * allow TD rules to override the accept.
2411  */
2412 static void DetectRunTxFirewallRuleFullMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
2413  DetectTransaction *tx, struct DetectFirewallAppTxState *fw_state, Flow *f, Packet *p,
2414  const uint8_t flow_flags)
2415 {
2416  if (s->action & ACTION_ACCEPT) {
2417  /* add alert now, as ApplyAccept may also trigger
2418  * policy matches that could add alerts. */
2419  SCLogDebug("append alert");
2420  /* see if we need to apply tx/hook accept to the packet. This can be needed
2421  * when we've completed the inspection so far for an incomplete tx, and an
2422  * accept:tx or accept:hook is the last match.*/
2423  const bool fw_accept_to_packet = ApplyAcceptToPacket(tx, s);
2424  if (fw_accept_to_packet) {
2425  SCLogDebug("packet %" PRIu64 ": apply accept to packet", PcapPacketCntGet(p));
2426  SCLogDebug("accept:(tx|hook): should be applied to the packet");
2427  AlertQueueAppendAppTx(det_ctx, s, p, tx->tx_id, tx->tx_type,
2429  } else {
2430  AlertQueueAppendAppTx(det_ctx, s, p, tx->tx_id, tx->tx_type, 0);
2431  }
2432  DetectRunTxFirewallApplyAccept(det_ctx, p, flow_flags, s, tx, fw_state);
2433  } else if (s->action & ACTION_DROP) {
2434  SCLogDebug("drop packet because of rule with drop action");
2436  if (s->action_scope == ACTION_SCOPE_FLOW) {
2437  SCLogDebug("drop flow because of rule with drop action");
2438  FlowSetDropAction(f, FLOW_ACTION_BY_FIREWALL);
2439  }
2440  SCLogDebug("append alert");
2441  AlertQueueAppendAppTx(det_ctx, s, p, tx->tx_id, tx->tx_type, 0);
2442  } else {
2443  SCLogDebug("append alert");
2444  AlertQueueAppendAppTx(det_ctx, s, p, tx->tx_id, tx->tx_type, 0);
2445  }
2446 }
2447 
2448 /** \internal
2449  * \brief handle a partial match for firewall rules
2450  *
2451  * Currently only used for LTE mode. Regardless of the final action,
2452  * the partial match acts as a `accept:hook`.
2453  *
2454  * A default accept is appended. TD has a chance to override this accept.
2455  *
2456  * \retval 1 accept partial, caller must break loop
2457  * \retval 0 ok, caller must continue as normal
2458  */
2459 static int DetectRunTxFirewallRulePartialMatch(
2460  DetectEngineThreadCtx *det_ctx, const Signature *s, const DetectTransaction *tx, Packet *p)
2461 {
2462  if ((s->flags & SIG_FLAG_FIREWALL) && (s->action & ACTION_ACCEPT)) {
2463  /* partial match always uses ACTION_SCOPE_HOOK. Final action only on the full
2464  * match */
2465  if (tx->is_last) {
2466  SCLogDebug("need to apply accept to packet");
2467  DetectRunAppendDefaultAccept(det_ctx, p);
2468  }
2469  if (s->action_scope == ACTION_SCOPE_FLOW) {
2470  SCLogDebug("only applying accept:flow on full match, downgrading to "
2471  "accept:hook");
2472  }
2473  return 1;
2474  }
2475  return 0;
2476 }
2477 
2478 /** \internal
2479  * \brief handle the no-match case for a firewall rule
2480  *
2481  * If the rule did not match we need to see if we need invoke the default
2482  * policy for this hook. If that is the case, we handle a drop by telling the
2483  * caller about it. Flow control for various accept options is handled by the
2484  * next rule.
2485  *
2486  * \retval 1 dropped by policy, caller must return
2487  * \retval 0 ok, caller must continue as normal
2488  */
2489 static int DetectRunTxFirewallRuleNoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
2490  DetectTransaction *tx, struct DetectFirewallAppTxState *fw_state, Packet *p,
2491  const uint8_t flow_flags)
2492 {
2493  if (fw_state->fw_last_for_progress && (s->flags & SIG_FLAG_FIREWALL)) {
2494  SCLogDebug("%" PRIu64 ": %s default policy for progress %u", PcapPacketCntGet(p),
2495  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", s->app_progress_hook);
2496  /* if this rule was the last for our progress state, and it didn't match,
2497  * we have to invoke the default policy. We only check the current rule hook.
2498  * DROP is immediate, flow control for various accept options is handled by
2499  * the DetectRunTxPreCheckFirewallPolicy function for the next rule. */
2500  const struct DetectFirewallPolicy policy = DetectFirewallApplyDefaultAppPolicy(det_ctx,
2501  det_ctx->de_ctx->fw_policies, tx, p, s->alproto, flow_flags, s->app_progress_hook);
2502  SCLogDebug("fw_last_for_progress policy %02x", policy.action);
2503  if (policy.action & ACTION_DROP) {
2504  return 1;
2505  }
2506  /* an accept with tx or flow scope already carries the verdict. For an
2507  * accept:hook (which does not apply to this packet) the states walked
2508  * over must still be decided: if the tx progressed beyond this rule's
2509  * hook and there is no rule for the states in between, their default
2510  * policies must be applied too - same as the match path does.
2511  * Without this a packet that crosses two states (e.g. a hello
2512  * completing into the certificate phase) would be decided by the
2513  * packet default policy even though the app policy for the current
2514  * state says accept. */
2515  if ((policy.action & ACTION_ACCEPT) && policy.action_scope == ACTION_SCOPE_HOOK &&
2516  fw_state->fw_next_progress_missing && tx->tx_progress > s->app_progress_hook) {
2517  /* only states the packet actually walked over (see the match
2518  * path) */
2519  const uint8_t last_hook = fw_state->last_fw_rule
2520  ? tx->tx_progress
2521  : MIN(tx->tx_progress, s->app_progress_hook + 1);
2523  DetectFirewallApplyDefaultPolicies(det_ctx, det_ctx->de_ctx->fw_policies, tx, p,
2524  s->alproto, flow_flags, s->app_progress_hook + 1, last_hook);
2525  if (r == DETECT_TX_FW_FC_BREAK) {
2526  /* the sweep dropped the packet: same as a current-hook
2527  * policy drop, the caller must stop the walk */
2528  fw_state->fw_skip_app_filter = true;
2529  return 1;
2530  }
2531  }
2532  }
2533  return 0;
2534 }
2535 
2536 /** \internal
2537  * \brief handle full match on rule when state didn't progress yet
2538  *
2539  * For a full rule match on a certain hook, we need to continue to enforce the
2540  * match as long as the tx progress doesn't move beyond that hook.
2541  */
2542 static void DetectRunTxFirewallRuleStatefulReApplyMatch(DetectEngineThreadCtx *det_ctx,
2543  const Signature *s, DetectTransaction *tx, struct DetectFirewallAppTxState *fw_state,
2544  Packet *p, const uint8_t flow_flags)
2545 {
2546  /* if we're still in the same progress state as an earlier full
2547  * match, we need to apply the same accept */
2548  if ((s->flags & SIG_FLAG_FIREWALL) && (s->action & ACTION_ACCEPT) &&
2549  s->app_progress_hook == tx->tx_progress) {
2550  const bool fw_accept_to_packet = ApplyAcceptToPacket(tx, s);
2551  DetectRunTxFirewallApplyAccept(det_ctx, p, flow_flags, s, tx, fw_state);
2552  if (fw_accept_to_packet) {
2553  SCLogDebug("packet %" PRIu64 ": apply accept to packet", PcapPacketCntGet(p));
2554  DetectRunAppendDefaultAccept(det_ctx, p);
2555  }
2556  }
2557 }
2558 
2559 static void DetectRunTx(ThreadVars *tv,
2561  DetectEngineThreadCtx *det_ctx,
2562  Packet *p,
2563  Flow *f,
2564  DetectRunScratchpad *scratch)
2565 {
2566  const uint8_t flow_flags = scratch->flow_flags;
2567  const SigGroupHead * const sgh = scratch->sgh;
2568  void * const alstate = f->alstate;
2569  const uint8_t ipproto = f->proto;
2570  const AppProto alproto = f->alproto;
2571 
2572  const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
2573  uint64_t tx_id_min = AppLayerParserGetTransactionInspectId(f->alparser, flow_flags);
2574  AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
2575  AppLayerGetTxIterState state = { 0 };
2576 
2577  uint32_t tx_inspected = 0;
2578  const bool have_fw_rules = EngineModeIsFirewall();
2579  /* if we skipped the last tx, we did not have a chance to apply a fw accept to the packet. Since
2580  * the tx is skipped, we should consider it accepted. */
2581  bool last_tx_skipped = false;
2582 
2583  SCLogDebug("packet %" PRIu64, PcapPacketCntGet(p));
2584  SCLogDebug("total_txs %" PRIu64, total_txs);
2585 
2586  while (1) {
2587  AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id_min, total_txs, &state);
2588  if (ires.tx_ptr == NULL) {
2589  SCLogDebug("%p/%" PRIu64 " no transaction to inspect", ires.tx_ptr, tx_id_min);
2590  break;
2591  }
2592 
2593  DetectTransaction tx = GetDetectTx(ipproto, alproto, ires.tx_id, ires.tx_ptr, flow_flags);
2594  if (tx.tx_ptr == NULL) {
2595  SCLogDebug("%p/%"PRIu64" no transaction to inspect",
2596  tx.tx_ptr, tx_id_min);
2597  last_tx_skipped = !ires.has_next;
2598  tx_id_min++; // next (if any) run look for +1
2599  goto next;
2600  }
2601  tx.is_last = !ires.has_next;
2602  tx_id_min = tx.tx_id + 1; // next look for cur + 1
2603  tx_inspected++;
2604 
2605  SCLogDebug("%p/%" PRIu64 " txd flags %02x", tx.tx_ptr, tx.tx_id, tx.tx_data_ptr->flags);
2606  SCLogDebug("%p/%" PRIu64 " is_last %s", tx.tx_ptr, tx.tx_id, BOOL2STR(tx.is_last));
2607 
2608  det_ctx->tx_id = tx.tx_id;
2609  det_ctx->tx_id_set = true;
2610  det_ctx->p = p;
2611 
2612  bool do_sort = false; // do we need to sort the tx candidate list?
2613  bool fw_lte_candidates = false; // does the list have a pending LTE rule?
2614  uint32_t array_idx = 0;
2615  uint32_t total_rules = det_ctx->match_array_cnt;
2616  total_rules += (tx.de_state ? tx.de_state->cnt : 0);
2617 
2618  /* run prefilter engines and merge results into a candidates array */
2619  if (sgh && sgh->tx_engines) {
2621  DetectRunPrefilterTx(det_ctx, sgh, p, ipproto, flow_flags, alproto,
2622  alstate, &tx);
2624  SCLogDebug("%p/%"PRIu64" rules added from prefilter: %u candidates",
2625  tx.tx_ptr, tx.tx_id, det_ctx->pmq.rule_id_array_cnt);
2626 
2627  total_rules += det_ctx->pmq.rule_id_array_cnt;
2628  if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, total_rules))) {
2629  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
2630  }
2631 
2632  for (uint32_t i = 0; i < det_ctx->pmq.rule_id_array_cnt; i++) {
2633  const Signature *s = de_ctx->sig_array[det_ctx->pmq.rule_id_array[i]];
2634  const SigIntId id = s->iid;
2635  det_ctx->tx_candidates[array_idx].s = s;
2636  det_ctx->tx_candidates[array_idx].id = id;
2637  det_ctx->tx_candidates[array_idx].flags = NULL;
2638  det_ctx->tx_candidates[array_idx].fw_lte_counted = false;
2639  det_ctx->tx_candidates[array_idx].fw_lte_header_ok = false;
2640  det_ctx->tx_candidates[array_idx].stream_reset = 0;
2641  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2642  fw_lte_candidates = true;
2643  }
2644  array_idx++;
2645  }
2646  PMQ_RESET(&det_ctx->pmq);
2647  } else {
2648  if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, total_rules))) {
2649  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
2650  }
2651  }
2652 
2653  /* merge 'state' rules from the regular prefilter */
2654 #ifdef PROFILING
2655  uint32_t x = array_idx;
2656 #endif
2657  RuleMatchCandidateMergeStateRules(det_ctx, &array_idx, &fw_lte_candidates);
2658 
2659  /* merge stored state into results */
2660  if (tx.de_state != NULL) {
2661  const uint32_t old = array_idx;
2662 
2663  /* if tx.de_state->flags has 'new file' set and sig below has
2664  * 'file inspected' flag, reset the file part of the state */
2665  const bool have_new_file = (tx.de_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_NEW);
2666  if (have_new_file) {
2667  SCLogDebug("%p/%"PRIu64" destate: need to consider new file",
2668  tx.tx_ptr, tx.tx_id);
2670  }
2671 
2672  SigIntId state_cnt = 0;
2673  DeStateStore *tx_store = tx.de_state->head;
2674  for (; tx_store != NULL; tx_store = tx_store->next) {
2675  SCLogDebug("tx_store %p", tx_store);
2676 
2677  SigIntId store_cnt = 0;
2678  for (store_cnt = 0;
2679  store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx.de_state->cnt;
2680  store_cnt++, state_cnt++)
2681  {
2682  DeStateStoreItem *item = &tx_store->store[store_cnt];
2683  SCLogDebug("rule id %u, inspect_flags %u", item->sid, item->flags);
2684  if (have_new_file && (item->flags & DE_STATE_FLAG_FILE_INSPECT)) {
2685  /* remove part of the state. File inspect engine will now
2686  * be able to run again */
2688  SCLogDebug("rule id %u, post file reset inspect_flags %u", item->sid, item->flags);
2689  }
2690 
2691  const Signature *ss = de_ctx->sig_array[item->sid];
2692  det_ctx->tx_candidates[array_idx].s = ss;
2693  det_ctx->tx_candidates[array_idx].id = item->sid;
2694  det_ctx->tx_candidates[array_idx].flags = &item->flags;
2695  det_ctx->tx_candidates[array_idx].fw_lte_counted = false;
2696  det_ctx->tx_candidates[array_idx].fw_lte_header_ok = false;
2697  det_ctx->tx_candidates[array_idx].stream_reset = 0;
2698  if (ss->flags & SIG_FLAG_FW_HOOK_LTE) {
2699  fw_lte_candidates = true;
2700  }
2701  array_idx++;
2702  }
2703  }
2704  do_sort |= (array_idx > old); // sort if continue list adds sids
2705  SCLogDebug("%p/%" PRIu64 " rules added from 'continue' list: %u", tx.tx_ptr, tx.tx_id,
2706  array_idx - old);
2707  }
2708  if (do_sort) {
2709  qsort(det_ctx->tx_candidates, array_idx, sizeof(RuleMatchCandidateTx),
2710  DetectRunTxSortHelper);
2711  }
2712 
2713 #ifdef PROFILING
2714  if (array_idx >= de_ctx->profile_match_logging_threshold)
2715  RulesDumpTxMatchArray(det_ctx, scratch->sgh, p, tx.tx_id, array_idx, x);
2716 #endif
2717 
2718 #ifdef DEBUG
2719  for (uint32_t i = 0; i < array_idx; i++) {
2720  RuleMatchCandidateTx *can = &det_ctx->tx_candidates[i];
2721  const Signature *s = det_ctx->tx_candidates[i].s;
2722  SCLogDebug("%u: sid %u flags %p", i, s->id, can->flags);
2723  }
2724 #endif
2725 
2726  /* Only firewall mode uses the per-tx firewall state. The LTE flag is
2727  * tracked where the candidates are added: the list mixes fw and TD
2728  * rules across tables in iid order, so a scan cannot stop early. */
2729  struct DetectFirewallAppTxState fw_state = { 0 };
2730  if (have_fw_rules && fw_lte_candidates) {
2731  DetectFwBuildLteCoverage(det_ctx, p, f, &fw_state, array_idx);
2732  }
2733 
2734  SCLogDebug("%s: tx_progress %u tx %p have_fw_rules %s array_idx %u detect_progress_orig %u "
2735  "cur detect_progress %u",
2736  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", tx.tx_progress,
2737  tx.tx_data_ptr, BOOL2STR(have_fw_rules), array_idx, tx.detect_progress_orig,
2738  tx.detect_progress);
2739 
2740  if (have_fw_rules) {
2741  /* if there are no firewall rules to consider, handle invoking the default
2742  * policies. */
2743  const int r = DetectTxFirewallNoRulesApplyPolicies(
2744  det_ctx, p, f, &tx, alproto, flow_flags, array_idx);
2745  if (r == 1) {
2746  SCLogDebug("done");
2747  return;
2748  } else if (r == 2) {
2749  goto next_tx_fw; /* next tx, need to clean up buffers */
2750  }
2751  }
2752 
2753  /* run rules: inspect the match candidates */
2754  for (uint32_t i = 0; i < array_idx; i++) {
2755  RuleMatchCandidateTx *can = &det_ctx->tx_candidates[i];
2756  const Signature *s = det_ctx->tx_candidates[i].s;
2757  uint32_t *inspect_flags = det_ctx->tx_candidates[i].flags;
2758 
2759  SCLogDebug("%" PRIu64 ": sid:%u: %s tx %u/%u/%u sig %u", PcapPacketCntGet(p), s->id,
2760  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", tx.tx_progress,
2762 
2763  if (have_fw_rules) {
2764  const enum DetectTxFirewallFlowControl fw_r = DetectRunTxPreCheckFirewallPolicy(
2765  det_ctx, p, &tx, flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT), s, i,
2766  can->fw_lte_counted, &fw_state);
2767  SCLogDebug("fw fw_skip_app_filter:%s skip_fw_hook:%s "
2768  "skip_before_progress:%u fw_last_for_progress:%s "
2769  "fw_next_progress_missing:%s",
2770  BOOL2STR(fw_state.fw_skip_app_filter), BOOL2STR(fw_state.skip_fw_hook),
2773  if (fw_r == DETECT_TX_FW_FC_SKIP) {
2774  continue;
2775  } else if (fw_r == DETECT_TX_FW_FC_BREAK) {
2776  break;
2777  }
2778 
2779  fw_state.fw_last_for_progress = false;
2780  fw_state.fw_next_progress_missing = false; // reset
2781  }
2782 
2783  /* deduplicate: rules_array is sorted, but not deduplicated:
2784  * both mpm and stored state could give us the same sid.
2785  * As they are back to back in that case we can check for it
2786  * here. We select the stored state one as that comes first
2787  * in the array. */
2788  while ((i + 1) < array_idx &&
2789  det_ctx->tx_candidates[i].s == det_ctx->tx_candidates[i + 1].s) {
2790  SCLogDebug("%p/%" PRIu64 " inspecting SKIP NEXT: sid %u (%u), flags %08x",
2791  tx.tx_ptr, tx.tx_id, s->id, s->iid, inspect_flags ? *inspect_flags : 0);
2792  i++;
2793  }
2794 
2795  SCLogDebug("%p/%" PRIu64 " inspecting: sid %u (%u), flags %08x", tx.tx_ptr, tx.tx_id,
2796  s->id, s->iid, inspect_flags ? *inspect_flags : 0);
2797 
2798  if (inspect_flags) {
2799  if (*inspect_flags & DE_STATE_FLAG_FULL_INSPECT) {
2800  SCLogDebug("%p/%" PRIu64
2801  " inspecting: sid %u (%u), flags %08x DE_STATE_FLAG_FULL_INSPECT",
2802  tx.tx_ptr, tx.tx_id, s->id, s->iid, *inspect_flags);
2803 
2804  /* if we're still in the same progress state as an earlier full
2805  * match, we need to apply the same accept */
2806  if (have_fw_rules) {
2807  DetectRunTxFirewallRuleStatefulReApplyMatch(
2808  det_ctx, s, &tx, &fw_state, p, flow_flags);
2809  }
2810  continue;
2811  }
2812  if (*inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
2813  SCLogDebug("%p/%" PRIu64
2814  " inspecting: sid %u (%u), flags %08x DE_STATE_FLAG_SIG_CANT_MATCH",
2815  tx.tx_ptr, tx.tx_id, s->id, s->iid, *inspect_flags);
2816  continue;
2817  }
2818 
2819  /* continue previous inspection */
2820  SCLogDebug("%p/%" PRIu64 " Continuing sid %u", tx.tx_ptr, tx.tx_id, s->id);
2821  } else {
2822  /* start new inspection */
2823  SCLogDebug("%p/%"PRIu64" Start sid %u", tx.tx_ptr, tx.tx_id, s->id);
2824  }
2825 
2826  if (have_fw_rules) {
2827  /* check if we should run this rule and update the firewall flow state */
2828  const enum DetectTxFirewallFlowControl fw_r = DetectRunTxCheckRuleState(
2829  det_ctx, p, f, &tx, s, i, array_idx, can->fw_lte_counted, &fw_state);
2830  SCLogDebug("fw fw_skip_app_filter:%s skip_fw_hook:%s "
2831  "skip_before_progress:%u fw_last_for_progress:%s "
2832  "fw_next_progress_missing:%s",
2833  BOOL2STR(fw_state.fw_skip_app_filter), BOOL2STR(fw_state.skip_fw_hook),
2836  if (fw_r == DETECT_TX_FW_FC_SKIP)
2837  continue;
2838  else if (fw_r == DETECT_TX_FW_FC_BREAK)
2839  break;
2840  }
2841 
2842  /* call individual rule inspection */
2844  const int r = DetectRunTxInspectRule(tv, de_ctx, det_ctx, p, f, flow_flags,
2845  alstate, &tx, s, inspect_flags, can, scratch);
2846  SCLogDebug("s %u r %d", s->id, r);
2847  if (have_fw_rules && r == -1 && (s->flags & SIG_FLAG_FW_HOOK_LTE) &&
2848  can->fw_lte_counted && tx.tx_progress >= s->app_progress_hook) {
2849  DetectFwRetireLteRule(det_ctx, can);
2850  }
2851  if (r == 1) {
2852  /* match */
2853  DetectRunPostMatch(tv, det_ctx, p, s);
2854 
2855  SCLogDebug(
2856  "%p/%" PRIu64 " sig %u (%u) matched", tx.tx_ptr, tx.tx_id, s->id, s->iid);
2857 
2858  if ((s->flags & SIG_FLAG_FIREWALL) == 0) {
2859  AlertQueueAppendAppTx(det_ctx, s, p, tx.tx_id, tx.tx_type, 0);
2860  } else {
2861  DetectRunTxFirewallRuleFullMatch(det_ctx, s, &tx, &fw_state, f, p, flow_flags);
2862  }
2863  } else if (r == 0) {
2864  SCLogDebug("sid %u partial match", s->id);
2865  if (DetectRunTxFirewallRulePartialMatch(det_ctx, s, &tx, p) == 1) {
2866  break;
2867  }
2868  } else if (r == -1) {
2869  if ((s->flags & SIG_FLAG_FIREWALL) != 0 &&
2870  DetectRunTxFirewallRuleNoMatch(det_ctx, s, &tx, &fw_state, p, flow_flags) ==
2871  1) {
2872  return;
2873  }
2874  } /* r == -2: no match, but not final: the rule is revisited, so a
2875  * hook default now could decide the packet before the revisit can */
2876  DetectVarProcessList(det_ctx, p->flow, p);
2877  RULE_PROFILING_END(det_ctx, s, r == 1, p);
2878 
2879  if (det_ctx->post_rule_work_queue.len > 0) {
2880  SCLogDebug("%p/%" PRIu64 " post_rule_work_queue len %u", tx.tx_ptr, tx.tx_id,
2881  det_ctx->post_rule_work_queue.len);
2882  /* run post match prefilter engines on work queue */
2883  PrefilterPostRuleMatch(det_ctx, scratch->sgh, p, f);
2884 
2885  uint32_t prev_array_idx = array_idx;
2886 
2887  /* Check if there is room for the pmq results before appending them. */
2888  const uint32_t needed = array_idx + det_ctx->pmq.rule_id_array_cnt;
2889  if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, needed))) {
2890  RuleMatchCandidateTxArrayExpand(det_ctx, needed);
2891  }
2892 
2893  for (uint32_t j = 0; j < det_ctx->pmq.rule_id_array_cnt; j++) {
2894  const Signature *ts = de_ctx->sig_array[det_ctx->pmq.rule_id_array[j]];
2895  if (ts->app_inspect != NULL) {
2896  const SigIntId id = ts->iid;
2897  det_ctx->tx_candidates[array_idx].s = ts;
2898  det_ctx->tx_candidates[array_idx].id = id;
2899  det_ctx->tx_candidates[array_idx].fw_lte_counted = false;
2900  det_ctx->tx_candidates[array_idx].fw_lte_header_ok = false;
2901  det_ctx->tx_candidates[array_idx].flags = NULL;
2902  det_ctx->tx_candidates[array_idx].stream_reset = 0;
2903 
2904  /* a mid-walk enabled LTE rule must count as coverage
2905  * for the remaining checks of this walk */
2906  if (have_fw_rules) {
2907  DetectFwCountAppendedLteRule(det_ctx, p, f, &fw_state, ts, array_idx);
2908  }
2909  array_idx++;
2910 
2911  SCLogDebug("%p/%" PRIu64 " rule %u (%u) added from 'post match' prefilter",
2912  tx.tx_ptr, tx.tx_id, ts->id, id);
2913  }
2914  }
2915  SCLogDebug("%p/%" PRIu64 " rules added from 'post match' prefilter: %u", tx.tx_ptr,
2916  tx.tx_id, array_idx - prev_array_idx);
2917  if (prev_array_idx != array_idx) {
2918  /* sort, but only part of array we're still going to process */
2919  qsort(det_ctx->tx_candidates + i, array_idx - i, sizeof(RuleMatchCandidateTx),
2920  DetectRunTxSortHelper);
2921  }
2922  det_ctx->post_rule_work_queue.len = 0;
2923  PMQ_RESET(&det_ctx->pmq);
2924  }
2925  }
2926 
2927  det_ctx->tx_id = 0;
2928  det_ctx->tx_id_set = false;
2929  det_ctx->p = NULL;
2930 
2931  /* see if we have any updated state to store in the tx */
2932 
2933  /* this side of the tx is done */
2934  if (tx.tx_progress >= tx.tx_end_state) {
2935  SCLogDebug("%" PRIu64 ": %s tx done", PcapPacketCntGet(p),
2936  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient");
2937  const uint8_t inspected_flag = (flow_flags & STREAM_TOSERVER)
2940  tx.tx_data_ptr->flags |= inspected_flag;
2941  SCLogDebug("%p/%" PRIu64 " tx is done for direction %s. Progress %02x", tx.tx_ptr,
2942  tx.tx_id, flow_flags & STREAM_TOSERVER ? "toserver" : "toclient",
2943  tx.detect_progress);
2944  }
2945 
2946  if (tx.detect_progress != tx.detect_progress_orig) {
2947  SCLogDebug("%" PRIu64 ": %s tx state change %u -> %u", PcapPacketCntGet(p),
2948  flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", tx.detect_progress_orig,
2949  tx.detect_progress);
2950  SCLogDebug("%p/%" PRIu64 " Storing new progress %02x (was %02x)", tx.tx_ptr, tx.tx_id,
2952 
2953  StoreDetectProgress(&tx, flow_flags, tx.detect_progress);
2954  }
2955  next_tx_fw:
2956  InspectionBufferClean(det_ctx);
2957 
2958  next:
2959  if (!ires.has_next)
2960  break;
2961  }
2962 
2963  SCLogDebug("packet %" PRIu64 ": tx_inspected %u", PcapPacketCntGet(p), tx_inspected);
2964  if (have_fw_rules) {
2965  if (tx_inspected == 0) {
2966  /* if all tables have been bypassed, we accept:packet */
2967  SCLogDebug("default accept: no app inspect performed");
2968  DetectRunAppendDefaultAccept(det_ctx, p);
2969  } else if (last_tx_skipped) {
2970  /* if the last tx was skipped, we need to apply accept:packet */
2971  // TODO should we check drops first?
2973  SCLogDebug("default accept: last tx skipped");
2974  DetectRunAppendDefaultAccept(det_ctx, p);
2975  }
2976  }
2977 }
2978 
2979 static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2980  Packet *p, Flow *f, DetectRunScratchpad *scratch)
2981 {
2982  const SigGroupHead *const sgh = scratch->sgh;
2983  const AppProto alproto = f->alproto;
2984 
2985  /* for TCP, limit inspection to pseudo packets or real packet that did
2986  * an app-layer update. */
2987  if (p->proto == IPPROTO_TCP && !PKT_IS_PSEUDOPKT(p) &&
2988  ((PKT_IS_TOSERVER(p) && (f->flags & FLOW_TS_APP_UPDATED) == 0) ||
2989  (PKT_IS_TOCLIENT(p) && (f->flags & FLOW_TC_APP_UPDATED) == 0))) {
2990  SCLogDebug("pcap_cnt %" PRIu64 ": %s: skip frame inspection for TCP w/o APP UPDATE",
2991  PcapPacketCntGet(p), PKT_IS_TOSERVER(p) ? "toserver" : "toclient");
2992  return;
2993  }
2994  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
2995  if (frames_container == NULL) {
2996  return;
2997  }
2998  Frames *frames;
2999  if (PKT_IS_TOSERVER(p)) {
3000  frames = &frames_container->toserver;
3001  } else {
3002  frames = &frames_container->toclient;
3003  }
3004 
3005  for (uint32_t idx = 0; idx < frames->cnt; idx++) {
3006  SCLogDebug("frame %u", idx);
3007  Frame *frame = FrameGetByIndex(frames, idx);
3008  if (frame == NULL) {
3009  continue;
3010  }
3011 
3012  det_ctx->frame_inspect_progress = 0;
3013  uint32_t array_idx = 0;
3014  uint32_t total_rules = det_ctx->match_array_cnt;
3015 
3016  /* run prefilter engines and merge results into a candidates array */
3017  if (sgh->frame_engines) {
3018  // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX);
3019  DetectRunPrefilterFrame(det_ctx, sgh, p, frames, frame, alproto);
3020  // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX);
3021  SCLogDebug("%p/%" PRIi64 " rules added from prefilter: %u candidates", frame, frame->id,
3022  det_ctx->pmq.rule_id_array_cnt);
3023 
3024  total_rules += det_ctx->pmq.rule_id_array_cnt;
3025 
3026  if (!(RuleMatchCandidateTxArrayHasSpace(
3027  det_ctx, total_rules))) { // TODO is it safe to overload?
3028  RuleMatchCandidateTxArrayExpand(det_ctx, total_rules);
3029  }
3030 
3031  for (uint32_t i = 0; i < det_ctx->pmq.rule_id_array_cnt; i++) {
3032  const Signature *s = de_ctx->sig_array[det_ctx->pmq.rule_id_array[i]];
3033  const SigIntId id = s->iid;
3034  det_ctx->tx_candidates[array_idx].s = s;
3035  det_ctx->tx_candidates[array_idx].id = id;
3036  det_ctx->tx_candidates[array_idx].flags = NULL;
3037  det_ctx->tx_candidates[array_idx].fw_lte_counted = false;
3038  det_ctx->tx_candidates[array_idx].fw_lte_header_ok = false;
3039  det_ctx->tx_candidates[array_idx].stream_reset = 0;
3040  array_idx++;
3041  }
3042  PMQ_RESET(&det_ctx->pmq);
3043  }
3044  /* merge 'state' rules from the regular prefilter */
3045  uint32_t x = array_idx;
3046  for (uint32_t i = 0; i < det_ctx->match_array_cnt; i++) {
3047  const Signature *s = det_ctx->match_array[i];
3048  if (s->frame_inspect != NULL) {
3049  const SigIntId id = s->iid;
3050  det_ctx->tx_candidates[array_idx].s = s;
3051  det_ctx->tx_candidates[array_idx].id = id;
3052  det_ctx->tx_candidates[array_idx].flags = NULL;
3053  det_ctx->tx_candidates[array_idx].fw_lte_counted = false;
3054  det_ctx->tx_candidates[array_idx].fw_lte_header_ok = false;
3055  det_ctx->tx_candidates[array_idx].stream_reset = 0;
3056  array_idx++;
3057 
3058  SCLogDebug("%p/%" PRIi64 " rule %u (%u) added from 'match' list", frame, frame->id,
3059  s->id, id);
3060  }
3061  }
3062  SCLogDebug("%p/%" PRIi64 " rules added from 'match' list: %u", frame, frame->id,
3063  array_idx - x);
3064  (void)x;
3065 
3066  /* run rules: inspect the match candidates */
3067  for (uint32_t i = 0; i < array_idx; i++) {
3068  const Signature *s = det_ctx->tx_candidates[i].s;
3069 
3070  /* deduplicate: rules_array is sorted, but not deduplicated.
3071  * As they are back to back in that case we can check for it
3072  * here. We select the stored state one as that comes first
3073  * in the array. */
3074  while ((i + 1) < array_idx &&
3075  det_ctx->tx_candidates[i].s == det_ctx->tx_candidates[i + 1].s) {
3076  i++;
3077  }
3078  SCLogDebug("%p/%" PRIi64 " inspecting: sid %u (%u)", frame, frame->id, s->id, s->iid);
3079 
3080  /* start new inspection */
3081  SCLogDebug("%p/%" PRIi64 " Start sid %u", frame, frame->id, s->id);
3082 
3083  /* call individual rule inspection */
3085  bool r = DetectRunInspectRuleHeader(p, f, s, s->flags);
3086  if (r) {
3087  r = DetectRunFrameInspectRule(tv, det_ctx, s, f, p, frames, frame);
3088  if (r) {
3089  /* match */
3090  DetectRunPostMatch(tv, det_ctx, p, s);
3091  det_ctx->frame_id = frame->id;
3092  SCLogDebug(
3093  "%p/%" PRIi64 " sig %u (%u) matched", frame, frame->id, s->id, s->iid);
3094  const uint8_t alert_flags =
3096  if (frame->flags & FRAME_FLAG_TX_ID_SET) {
3097  const uint8_t ipproto = p->proto;
3098  uint8_t sub_state = 0;
3099  void *tx = AppLayerParserGetTx(
3100  ipproto, alproto, p->flow->alstate, frame->tx_id);
3101  if (tx) {
3102  AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx);
3103  sub_state = txd->tx_type;
3104  }
3105  AlertQueueAppendAppTx(det_ctx, s, p, frame->tx_id, sub_state, alert_flags);
3106  } else {
3107  AlertQueueAppendPacket(det_ctx, s, p, alert_flags);
3108  }
3109  }
3110  }
3111  DetectVarProcessList(det_ctx, p->flow, p);
3112  RULE_PROFILING_END(det_ctx, s, r == 1, p);
3113  }
3114 
3115  /* update Frame::inspect_progress here instead of in the code above. The reason is that a
3116  * frame might be used more than once in buffers with transforms. */
3117  if (frame->inspect_progress < det_ctx->frame_inspect_progress) {
3118  frame->inspect_progress = det_ctx->frame_inspect_progress;
3119  SCLogDebug("frame->inspect_progress: %" PRIu64 " -> updated", frame->inspect_progress);
3120  } else {
3121  SCLogDebug(
3122  "frame->inspect_progress: %" PRIu64 " -> not updated", frame->inspect_progress);
3123  }
3124 
3125  SCLogDebug("%p/%" PRIi64 " rules inspected, running cleanup", frame, frame->id);
3126  InspectionBufferClean(det_ctx);
3127  }
3128 }
3129 
3130 static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id)
3131 {
3132  /* technically we need to pass a DetectEngineThreadCtx struct with the
3133  * tenant_id member. But as that member is the first in the struct, we
3134  * can use the id directly. */
3135  return HashTableLookup(h, &id, 0);
3136 }
3137 
3138 static void DetectFlow(ThreadVars *tv,
3140  Packet *p)
3141 {
3142  Flow *const f = p->flow;
3143 
3144  /* we check the flow drop here, and not the packet drop. This is
3145  * to allow stream engine "invalid" drop packets to still be
3146  * evaluated by the stream event rules. */
3147  if (f->flags & FLOW_ACTION_DROP) {
3149  SCReturn;
3150  }
3151 
3152  /* in firewall mode, we still need to run the fw rulesets even for exception policy pass */
3153  bool skip = (p->flags & PKT_NOPACKET_INSPECTION || f->flags & (FLOW_ACTION_PASS));
3154  if (EngineModeIsFirewall() && (f->flags & FLOW_ACTION_ACCEPT) == 0) {
3155  skip = false;
3156  }
3157  if (skip) {
3158  /* enforce prior accept:flow */
3159  if (f->flags & FLOW_ACTION_ACCEPT) {
3160  p->action |= ACTION_ACCEPT;
3161  }
3162  /* hack: if we are in pass the entire flow mode, we need to still
3163  * update the inspect_id forward. So test for the condition here,
3164  * and call the update code if necessary. */
3165  const int pass = (f->flags & (FLOW_ACTION_PASS | FLOW_ACTION_ACCEPT));
3166  if (pass) {
3167  uint8_t flags = STREAM_FLAGS_FOR_PACKET(p);
3169  if (f->alstate) {
3171  }
3172  }
3173  SCLogDebug("p->pcap %" PRIu64 ": no detection on packet, "
3174  "PKT_NOPACKET_INSPECTION is set",
3175  PcapPacketCntGet(p));
3176  return;
3177  }
3178 
3179  /* see if the packet matches one or more of the sigs */
3180  DetectRun(tv, de_ctx, det_ctx, p);
3181 }
3182 
3183 
3184 static void DetectNoFlow(ThreadVars *tv,
3186  Packet *p)
3187 {
3188  /* No need to perform any detection on this packet, if the given flag is set.*/
3190  return;
3191  }
3192 
3193  /* see if the packet matches one or more of the sigs */
3194  DetectRun(tv, de_ctx, det_ctx, p);
3195 }
3196 
3198 {
3199  const DetectEngineCtx *de_ctx = det_ctx->de_ctx;
3200  const SigGroupHead *sgh = de_ctx->pre_flow_sgh;
3201 
3202  SCLogDebug("thread id: %u, packet %" PRIu64 ", sgh %p", tv->id, PcapPacketCntGet(p), sgh);
3203  DetectRunPacketHook(tv, de_ctx, det_ctx, sgh, p, DETECT_FIREWALL_POLICY_PRE_FLOW);
3204  return p->action;
3205 }
3206 
3208 {
3209  const DetectEngineCtx *de_ctx = det_ctx->de_ctx;
3210  const int direction = (PKT_IS_TOCLIENT(p) != 0);
3211  const SigGroupHead *sgh = de_ctx->pre_stream_sgh[direction];
3212 
3213  SCLogDebug("thread id: %u, packet %" PRIu64 ", sgh %p", tv->id, PcapPacketCntGet(p), sgh);
3214  DetectRunPacketHook(tv, de_ctx, det_ctx, sgh, p, DETECT_FIREWALL_POLICY_PRE_STREAM);
3215  return p->action;
3216 }
3217 
3218 /** \brief Detection engine thread wrapper.
3219  * \param tv thread vars
3220  * \param p packet to inspect
3221  * \param data thread specific data
3222  * \param pq packet queue
3223  * \retval TM_ECODE_FAILED error
3224  * \retval TM_ECODE_OK ok
3225  */
3227 {
3229 
3230  DetectEngineCtx *de_ctx = NULL;
3231  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
3232  if (det_ctx == NULL) {
3233  printf("ERROR: Detect has no thread ctx\n");
3234  goto error;
3235  }
3236 
3237  if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) {
3238  (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1);
3239  SCLogDebug("Detect Engine using new det_ctx - %p",
3240  det_ctx);
3241  }
3242 
3243  /* if in MT mode _and_ we have tenants registered, use
3244  * MT logic. */
3245  if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL)
3246  {
3247  uint32_t tenant_id = p->tenant_id;
3248  if (tenant_id == 0)
3249  tenant_id = det_ctx->TenantGetId(det_ctx, p);
3250  if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) {
3251  p->tenant_id = tenant_id;
3252  det_ctx = GetTenantById(det_ctx->mt_det_ctxs_hash, tenant_id);
3253  if (det_ctx == NULL)
3254  return TM_ECODE_OK;
3255  de_ctx = det_ctx->de_ctx;
3256  if (de_ctx == NULL)
3257  return TM_ECODE_OK;
3258 
3259  if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) {
3260  (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1);
3261  SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id);
3262  }
3263  } else {
3264  /* use default if no tenants are registered for this packet */
3265  de_ctx = det_ctx->de_ctx;
3266  }
3267  } else {
3268  de_ctx = det_ctx->de_ctx;
3269  }
3270 
3271  if (p->flow) {
3272  DetectFlow(tv, de_ctx, det_ctx, p);
3273  } else {
3274  DetectNoFlow(tv, de_ctx, det_ctx, p);
3275  }
3276 
3277 #ifdef PROFILE_RULES
3278  /* aggregate statistics */
3279  struct timeval ts;
3280  gettimeofday(&ts, NULL);
3281  if (ts.tv_sec != det_ctx->rule_perf_last_sync) {
3282  SCProfilingRuleThreatAggregate(det_ctx);
3283  det_ctx->rule_perf_last_sync = ts.tv_sec;
3284  }
3285 #endif
3286 
3287  return TM_ECODE_OK;
3288 error:
3289  return TM_ECODE_FAILED;
3290 }
3291 
3292 /** \brief disable file features we don't need
3293  * Called if we have no detection engine.
3294  */
3296 {
3297  DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOSERVER);
3298  DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOCLIENT);
3299 }
3300 
3301 #if defined(UNITTESTS) || defined(FUZZ)
3302 /**
3303  * \brief wrapper for old tests
3304  */
3307 {
3308  if (p->flow) {
3309  DetectFlow(tv, de_ctx, det_ctx, p);
3310  } else {
3311  DetectNoFlow(tv, de_ctx, det_ctx, p);
3312  }
3313 }
3314 #endif
3315 
3316 /*
3317  * TESTS
3318  */
3319 
3320 #ifdef UNITTESTS
3321 #include "tests/detect.c"
3322 #endif
PKT_IS_TOCLIENT
#define PKT_IS_TOCLIENT(p)
Definition: decode.h:240
default_accept
thread_local Signature default_accept
Definition: detect.c:2244
DetectEngineAppInspectionEngine_::stream
bool stream
Definition: detect.h:425
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:147
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:1578
DETECT_TX_FW_FC_SKIP
@ DETECT_TX_FW_FC_SKIP
Definition: detect.c:1180
DetectFirewallPolicies
Definition: detect.h:962
PACKET_ALERT_FLAG_TX_GUESSED
#define PACKET_ALERT_FLAG_TX_GUESSED
Definition: decode.h:280
FLOWFILE_NO_MD5_TC
#define FLOWFILE_NO_MD5_TC
Definition: flow.h:148
SigGroupHead_::tx_engines
PrefilterEngine * tx_engines
Definition: detect.h:1742
DetectEngineAppInspectionEngine_
Definition: detect.h:420
Packet_::proto
uint8_t proto
Definition: decode.h:538
DetectTransaction_::tx_data_ptr
struct AppLayerTxData * tx_data_ptr
Definition: detect-engine-prefilter.h:34
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:424
DE_STATE_CHUNK_SIZE
#define DE_STATE_CHUNK_SIZE
Definition: detect-engine-state.h:55
RuleMatchCandidateTx::stream_stored
bool stream_stored
Definition: detect.h:1275
Frame::inspect_progress
uint64_t inspect_progress
Definition: app-layer-frames.h:59
DetectEngineThreadCtx_::alert_queue_size
uint16_t alert_queue_size
Definition: detect.h:1401
PROF_DETECT_GETSGH
@ PROF_DETECT_GETSGH
Definition: suricata-common.h:463
ts
uint64_t ts
Definition: source-erf-file.c:68
AppLayerTxData::flags
uint8_t flags
Definition: app-layer-parser.h:182
PacketAlerts_::firewall_discarded
uint16_t firewall_discarded
Definition: decode.h:291
DetectEngineAppInspectionEngine_::v2
struct DetectEngineAppInspectionEngine_::@82 v2
SCAppLayerParserStateIssetFlag
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:2079
FLOW_ACTION_BY_FIREWALL
#define FLOW_ACTION_BY_FIREWALL
Definition: flow.h:125
detect-engine.h
detect-engine-proto.h
DetectEngineThreadCtx_::match_array_cnt
SigIntId match_array_cnt
Definition: detect.h:1415
Frame::tx_id
uint64_t tx_id
Definition: app-layer-frames.h:58
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:91
DetectEngineThreadCtx_::counter_alerts
StatsCounterId counter_alerts
Definition: detect.h:1361
detect-dsize.h
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:739
Flow_::flags
uint64_t flags
Definition: flow.h:408
SIG_FLAG_FW_HOOK_LTE
#define SIG_FLAG_FW_HOOK_LTE
Definition: detect.h:255
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:78
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1311
RuleMatchCandidateTx::fw_lte_header_ok
bool fw_lte_header_ok
Definition: detect.h:1271
DetectEngineCtx_::decoder_event_sgh
struct SigGroupHead_ * decoder_event_sgh
Definition: detect.h:1084
FlowGetPacketDirection
int FlowGetPacketDirection(const Flow *f, const Packet *p)
determine the direction of the packet compared to the flow
Definition: flow.c:283
DetectEngineCtx_::flow_gh
DetectEngineLookupFlow flow_gh[FLOW_STATES]
Definition: detect.h:1023
DETECT_TABLE_APP_FILTER
@ DETECT_TABLE_APP_FILTER
Definition: detect.h:570
DE_STATE_FLAG_SIG_CANT_MATCH
#define DE_STATE_FLAG_SIG_CANT_MATCH
Definition: detect-engine-state.h:59
DetectFirewallAppPolicy
Definition: detect.h:951
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:446
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:1731
PostRuleMatchWorkQueue::len
uint32_t len
Definition: detect.h:1299
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1364
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:1730
PACKET_ALERT_FLAG_STATE_MATCH
#define PACKET_ALERT_FLAG_STATE_MATCH
Definition: decode.h:270
DetectEngineCtx_::guess_applayer
bool guess_applayer
Definition: detect.h:1046
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
detect.c
AppLayerTxData::tx_type
uint8_t tx_type
Definition: app-layer-parser.h:215
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
PKT_DROP_REASON_FW_RULES
@ PKT_DROP_REASON_FW_RULES
Definition: decode.h:407
Signature_::app_progress_hook
uint8_t app_progress_hook
Definition: detect.h:729
AppLayerFramesGetContainer
FramesContainer * AppLayerFramesGetContainer(const Flow *f)
Definition: app-layer-parser.c:209
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:1603
PcapPacketCntGet
uint64_t PcapPacketCntGet(const Packet *p)
Definition: decode.c:1193
DetectEngineAppInspectionEngine_::Callback
InspectEngineFuncPtr Callback
Definition: detect.h:439
Signature_::alproto
AppProto alproto
Definition: detect.h:697
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:844
DETECT_TX_FW_FC_OK
@ DETECT_TX_FW_FC_OK
Definition: detect.c:1179
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:783
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:371
AppLayerTxData::de_state
DetectEngineState * de_state
Definition: app-layer-parser.h:223
InspectionBufferClean
void InspectionBufferClean(DetectEngineThreadCtx *det_ctx)
Definition: detect-engine-inspect-buffer.c:30
Flow_::proto
uint8_t proto
Definition: flow.h:381
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:87
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:289
DetectEngineThreadCtx_::tx_id
uint64_t tx_id
Definition: detect.h:1392
SCFlowGetAppProtocol
AppProto SCFlowGetAppProtocol(const Flow *f)
Definition: flow.c:1288
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:372
action-globals.h
FLOWFILE_NO_MAGIC_TS
#define FLOWFILE_NO_MAGIC_TS
Definition: flow.h:139
FramesContainer::toserver
Frames toserver
Definition: app-layer-frames.h:78
Packet_::flags
uint32_t flags
Definition: decode.h:562
ssn
TcpSession ssn
Definition: fuzz_dataset.c:31
Packet_::action
uint8_t action
Definition: decode.h:624
ICMPV4_DEST_UNREACH_IS_VALID
#define ICMPV4_DEST_UNREACH_IS_VALID(p)
Definition: decode-icmpv4.h:253
Frame
Definition: app-layer-frames.h:49
Flow_
Flow data structure.
Definition: flow.h:359
DetectFirewallPacketPolicies
DetectFirewallPacketPolicies
Definition: detect.h:938
PROF_DETECT_ALERT
@ PROF_DETECT_ALERT
Definition: suricata-common.h:474
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1429
SIG_GROUP_HEAD_HAVEFILESHA1
#define SIG_GROUP_HEAD_HAVEFILESHA1
Definition: detect.h:1580
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its normalized string equivalent.
Definition: app-layer-protos.c:53
FLOW_TC_APP_UPDATED
#define FLOW_TC_APP_UPDATED
Definition: flow.h:119
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:995
DetectEngineCtx_::pre_stream_sgh
struct SigGroupHead_ * pre_stream_sgh[2]
Definition: detect.h:1225
DETECT_PROTO_ETHERNET
#define DETECT_PROTO_ETHERNET
Definition: detect-engine-proto.h:33
DetectRunScratchpad
struct DetectRunScratchpad DetectRunScratchpad
DetectFirewallAppPolicy::policy
struct DetectFirewallPolicy policy
Definition: detect.h:956
PROF_DETECT_PF_TX
@ PROF_DETECT_PF_TX
Definition: suricata-common.h:469
Frames::cnt
uint16_t cnt
Definition: app-layer-frames.h:65
Frame::id
int64_t id
Definition: app-layer-frames.h:57
DetectFirewallPolicies::pkt_policy_signatures
Signature * pkt_policy_signatures[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:965
DetectEngineThreadCtx_::p
Packet * p
Definition: detect.h:1396
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:146
RuleMatchCandidateTx::id
SigIntId id
Definition: detect.h:1269
PROF_DETECT_CLEANUP
@ PROF_DETECT_CLEANUP
Definition: suricata-common.h:476
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:245
ACTION_SCOPE_FLOW
@ ACTION_SCOPE_FLOW
Definition: action-globals.h:45
NO_TX
#define NO_TX
Definition: detect.c:1569
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:236
HashTable_
Definition: util-hash.h:35
SIG_FLAG_TXBOTHDIR
#define SIG_FLAG_TXBOTHDIR
Definition: detect.h:253
MIN
#define MIN(x, y)
Definition: suricata-common.h:413
Packet_::sig_mask
SignatureMask sig_mask
Definition: decode.h:553
Frames
Definition: app-layer-frames.h:64
FramesContainer
Definition: app-layer-frames.h:77
DetectFirewallAppTxState::fw_skip_app_filter
bool fw_skip_app_filter
Definition: detect.c:1733
PacketAlerts_::drop
PacketAlert drop
Definition: decode.h:296
DetectEngineThreadCtx_::counter_alerts_overflow
StatsCounterId counter_alerts_overflow
Definition: detect.h:1363
DetectRunScratchpad
Definition: detect.c:70
SIG_GROUP_HEAD_HAVERAWSTREAM
#define SIG_GROUP_HEAD_HAVERAWSTREAM
Definition: detect.h:1574
FLOW_ACTION_DROP
#define FLOW_ACTION_DROP
Definition: flow.h:69
DetectFirewallAppTxState::fw_lte_cover_active
bool fw_lte_cover_active
Definition: detect.c:1743
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:107
FLOWFILE_NONE
#define FLOWFILE_NONE
Definition: flow.h:171
detect-engine-frame.h
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:3305
p
Packet * p
Definition: fuzz_dataset.c:30
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:759
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:234
PKT_NOPAYLOAD_INSPECTION
#define PKT_NOPAYLOAD_INSPECTION
Definition: decode.h:1297
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:1367
Detect
TmEcode Detect(ThreadVars *tv, Packet *p, void *data)
Detection engine thread wrapper.
Definition: detect.c:3226
detect-engine-payload.h
DetectEngineThreadCtx_::counter_firewall_discarded_alerts
StatsCounterId counter_firewall_discarded_alerts
Definition: detect.h:1365
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:547
EngineModeIsFirewall
bool EngineModeIsFirewall(void)
Definition: suricata.c:240
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:244
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:438
DetectFirewallAppTxState::skip_before_progress
uint8_t skip_before_progress
Definition: detect.c:1735
AppLayerGetTxIterTuple::tx_ptr
void * tx_ptr
Definition: app-layer-parser.h:160
SigMatchData_
Data needed for Match()
Definition: detect.h:369
DetectFirewallAppPolicy::alert_signature
Signature * alert_signature
Definition: detect.h:959
DeStateStoreItem_::sid
SigIntId sid
Definition: detect-engine-state.h:77
RuleMatchCandidateTx::s
const Signature * s
Definition: detect.h:1281
KEYWORD_PROFILING_START
#define KEYWORD_PROFILING_START
Definition: util-profiling.h:50
SigMatchData_::type
uint16_t type
Definition: detect.h:370
DetectEngineCtx_::version
uint32_t version
Definition: detect.h:1080
DetectFirewallPolicy::action
uint8_t action
Definition: detect.h:947
DisableDetectFlowFileFlags
void DisableDetectFlowFileFlags(Flow *f)
disable file features we don't need Called if we have no detection engine.
Definition: detect.c:3295
AppLayerParserGetTransactionInspectId
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
Definition: app-layer-parser.c:813
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:637
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:643
Signature_::frame_inspect
DetectEngineFrameInspectionEngine * frame_inspect
Definition: detect.h:755
PROF_DETECT_PF_SORT2
@ PROF_DETECT_PF_SORT2
Definition: suricata-common.h:472
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:406
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:252
KEYWORD_PROFILING_END
#define KEYWORD_PROFILING_END(ctx, type, m)
Definition: util-profiling.h:64
detect-flowvar.h
RuleMatchCandidateTx::fw_lte_counted
bool fw_lte_counted
Definition: detect.h:1270
DetectEngineThreadCtx_::mt_det_ctxs_hash
HashTable * mt_det_ctxs_hash
Definition: detect.h:1328
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:1998
SIG_FLAG_FIREWALL
#define SIG_FLAG_FIREWALL
Definition: detect.h:249
Flow_::sgh_toserver
const struct SigGroupHead_ * sgh_toserver
Definition: flow.h:491
PROF_DETECT_TX_UPDATE
@ PROF_DETECT_TX_UPDATE
Definition: suricata-common.h:475
DetectEngineAppInspectionEngine_::id
uint8_t id
Definition: detect.h:423
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:212
StatsCounterAvgAddI64
void StatsCounterAvgAddI64(StatsThreadContext *stats, StatsCounterAvgId id, int64_t x)
Definition: counters.c:238
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:428
FLOWFILE_INIT
#define FLOWFILE_INIT
Definition: flow.h:136
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:483
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:152
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:128
FramesContainer::toclient
Frames toclient
Definition: app-layer-frames.h:79
DetectEngineCtx_::pre_flow_sgh
struct SigGroupHead_ * pre_flow_sgh
Definition: detect.h:1230
DetectEngineThreadCtx_::tx_candidates
RuleMatchCandidateTx * tx_candidates
Definition: detect.h:1417
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:73
Signature_::addr_src_match4
DetectMatchAddressIPv4 * addr_src_match4
Definition: detect.h:736
decode.h
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:52
DetectEngineCtx_::fw_policies
struct DetectFirewallPolicies * fw_policies
Definition: detect.h:1026
DETECT_PROTO_ARP
#define DETECT_PROTO_ARP
Definition: detect-engine-proto.h:34
TOSERVER
#define TOSERVER
Definition: flow.h:45
DetectTransaction_::tx_end_state
const uint8_t tx_end_state
Definition: detect-engine-prefilter.h:44
DetectEngineThreadCtx_::counter_mpm_list
StatsCounterAvgId counter_mpm_list
Definition: detect.h:1369
AppLayerTxData
Definition: app-layer-parser.h:172
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:239
DetectFirewallAppTxState::skip_fw_hook
bool skip_fw_hook
Definition: detect.c:1734
Prefilter
void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags, const SignatureMask mask)
Definition: detect-engine-prefilter.c:244
DetectTransaction_::detect_progress_orig
const uint8_t detect_progress_orig
Definition: detect-engine-prefilter.h:41
DetectEngineThreadCtx_
Definition: detect.h:1316
DEBUG_VALIDATE_PACKET
#define DEBUG_VALIDATE_PACKET(p)
Definition: util-validate.h:108
DeStateStoreItem_::flags
uint32_t flags
Definition: detect-engine-state.h:76
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1305
DetectTransaction_::detect_progress
uint8_t detect_progress
Definition: detect-engine-prefilter.h:39
AlertQueueAppendAppTxFromPacket
void AlertQueueAppendAppTxFromPacket(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, const uint8_t sub_state, uint8_t alert_flags)
Append signature to local packet alert queue for later preprocessing This does not automatically set ...
Definition: detect-engine-alert.c:435
BIT_U32
#define BIT_U32(n)
Definition: suricata-common.h:422
DetectEngineThreadCtx_::tx_candidates_size
uint32_t tx_candidates_size
Definition: detect.h:1418
FRAME_FLAG_TX_ID_SET
#define FRAME_FLAG_TX_ID_SET
Definition: app-layer-frames.h:42
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1313
DETECT_TX_FW_FC_BREAK
@ DETECT_TX_FW_FC_BREAK
Definition: detect.c:1181
PKT_IS_FRAGMENT
#define PKT_IS_FRAGMENT
Definition: decode.h:1335
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:894
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:193
AppLayerGetTxIterTuple::tx_id
uint64_t tx_id
Definition: app-layer-parser.h:161
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
DeStateStore_::next
struct DeStateStore_ * next
Definition: detect-engine-state.h:82
DetectTransaction_::is_last
bool is_last
Definition: detect-engine-prefilter.h:45
Packet_::sp
Port sp
Definition: decode.h:523
FLOWFILE_NO_SHA256_TS
#define FLOWFILE_NO_SHA256_TS
Definition: flow.h:155
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:1350
FLOW_PKT_TOCLIENT_FIRST
#define FLOW_PKT_TOCLIENT_FIRST
Definition: flow.h:240
DetectFirewallPolicies::pkt
struct DetectFirewallPolicy pkt[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:964
StreamReassembleRawHasDataReady
bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p)
does the stream engine have data to inspect?
Definition: stream-tcp-reassemble.c:1508
detect-engine-port.h
PktSrcToString
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition: decode.c:894
DetectFirewallAppPolicy::progress
uint8_t progress
Definition: detect.h:954
DetectPort_
Port structure for detection engine.
Definition: detect.h:223
PacketAlerts_::discarded
uint16_t discarded
Definition: decode.h:290
app-layer-parser.h
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:753
ThreadVars_::id
int id
Definition: threadvars.h:85
AppLayerParserGetStateProgress
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *tx, uint8_t flags)
get the progress value for a tx/protocol
Definition: app-layer-parser.c:1199
util-detect.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:322
detect-engine-profile.h
Flow_::sgh_toclient
const struct SigGroupHead_ * sgh_toclient
Definition: flow.h:488
DetectEngineThreadCtx_::base64_decoded_len
int base64_decoded_len
Definition: detect.h:1399
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:270
RuleMatchCandidateTx::stream_result
uint8_t stream_result
Definition: detect.h:1276
Signature_::action
uint8_t action
Definition: detect.h:707
util-profiling.h
DetectTransaction_::tx_id
const uint64_t tx_id
Definition: detect-engine-prefilter.h:33
DetectEngineLookupFlow_::udp
DetectPort * udp
Definition: detect.h:893
DetectEngineThreadCtx_::raw_stream_progress
uint64_t raw_stream_progress
Definition: detect.h:1337
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:693
RuleMatchCandidateTxArrayFree
void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx)
Definition: detect.c:1197
AppLayerGetTxIterState
Definition: app-layer-parser.h:148
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:516
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:1393
detect-engine-alert.h
AppLayerTxData::guessed_applayer_logged
uint8_t guessed_applayer_logged
Definition: app-layer-parser.h:202
DetectEngineThreadCtx_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1358
PROF_DETECT_IPONLY
@ PROF_DETECT_IPONLY
Definition: suricata-common.h:464
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:3197
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:1504
DetectTransaction_::tx_type
const uint8_t tx_type
Definition: detect-engine-prefilter.h:48
DetectFirewallAppTxState::last_fw_rule
bool last_fw_rule
Definition: detect.c:1738
detect-replace.h
AppLayerGetTxIterTuple
Definition: app-layer-parser.h:159
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:719
AppLayerTxData::detect_progress_ts
uint8_t detect_progress_ts
Definition: app-layer-parser.h:210
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:237
SigGroupHead_::frame_engines
PrefilterEngine * frame_engines
Definition: detect.h:1743
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:293
Signature_::sp
DetectPort * sp
Definition: detect.h:747
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1219
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:282
DETECT_FIREWALL_POLICY_PRE_STREAM
@ DETECT_FIREWALL_POLICY_PRE_STREAM
Definition: detect.h:941
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:829
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:494
RuleMatchCandidateTx::flags
uint32_t * flags
Definition: detect.h:1272
PACKET_ALERT_FLAG_FRAME
#define PACKET_ALERT_FLAG_FRAME
Definition: decode.h:278
Frame::flags
uint8_t flags
Definition: app-layer-frames.h:51
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:421
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:156
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:1087
APP_LAYER_MAX_PROGRESS
#define APP_LAYER_MAX_PROGRESS
Definition: app-layer-parser.h:81
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:40
th_v
ThreadVars * th_v
Definition: fuzz_dataset.c:29
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:1636
Packet_::tenant_id
uint32_t tenant_id
Definition: decode.h:678
Packet_::flow
struct Flow_ * flow
Definition: decode.h:564
DetectEngineStateResetTxs
void DetectEngineStateResetTxs(Flow *f)
Reset de state for active tx' To be used on detect engine reload.
Definition: detect-engine-state.c:258
FLOWFILE_NO_MAGIC_TC
#define FLOWFILE_NO_MAGIC_TC
Definition: flow.h:140
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:246
ActionScope
ActionScope
Definition: action-globals.h:42
DETECT_FIREWALL_POLICY_PACKET_FILTER
@ DETECT_FIREWALL_POLICY_PACKET_FILTER
Definition: detect.h:939
AppLayerTxData::updated_tc
bool updated_tc
Definition: app-layer-parser.h:179
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:714
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:550
PROF_DETECT_SETUP
@ PROF_DETECT_SETUP
Definition: suricata-common.h:462
DetectEngineStateDirection_
Definition: detect-engine-state.h:85
DetectEngineThreadCtx_::frame_inspect_progress
uint64_t frame_inspect_progress
Definition: detect.h:1394
DetectEngineCtx_::profile_match_logging_threshold
uint32_t profile_match_logging_threshold
Definition: detect.h:1119
FLOW_TS_APP_UPDATED
#define FLOW_TS_APP_UPDATED
Definition: flow.h:118
Signature_::proto
DetectProto * proto
Definition: detect.h:711
AppLayerParserGetTxData
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:1420
FatalError
#define FatalError(...)
Definition: util-debug.h:517
DetectFirewallAppTxState::fw_next_progress_missing
bool fw_next_progress_missing
Definition: detect.c:1737
AppLayerTxData::detect_progress_tc
uint8_t detect_progress_tc
Definition: app-layer-parser.h:211
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:297
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
DetectFirewallAppTxState
Definition: detect.c:1732
AlertQueueAppendPacket
void AlertQueueAppendPacket(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint8_t alert_flags)
Append signature to local packet alert queue for later preprocessing.
Definition: detect-engine-alert.c:445
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:720
StreamReassembleRawUpdateProgress
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
update stream engine after detection
Definition: stream-tcp-reassemble.c:1554
FLOWFILE_NO_SHA1_TS
#define FLOWFILE_NO_SHA1_TS
Definition: flow.h:151
PROF_DETECT_RULES
@ PROF_DETECT_RULES
Definition: suricata-common.h:465
APP_LAYER_TX_INSPECTED_TS
#define APP_LAYER_TX_INSPECTED_TS
Definition: app-layer-parser.h:51
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:747
PacketAlerts_::suppressed
uint16_t suppressed
Definition: decode.h:292
PACKET_PROFILING_DETECT_START
#define PACKET_PROFILING_DETECT_START(p, id)
Definition: util-profiling.h:214
DetectEngineThreadCtx_::replace
const Signature ** replace
Definition: detect.h:1410
DetectFirewallPolicy
Definition: detect.h:946
PKT_PSEUDO_DETECTLOG_FLUSH
#define PKT_PSEUDO_DETECTLOG_FLUSH
Definition: decode.h:1353
Signature_::iid
SigIntId iid
Definition: detect.h:704
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:54
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Packet_::pkt_src
uint8_t pkt_src
Definition: decode.h:626
DetectEngineAppInspectionEngine_::sub_state
uint8_t sub_state
Definition: detect.h:431
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:738
Flow_::alstate
void * alstate
Definition: flow.h:484
Signature_::id
uint32_t id
Definition: detect.h:741
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:1043
RuleMatchCandidateTx::stream_reset
uint32_t stream_reset
Definition: detect.h:1278
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
DetectEngineThreadCtx_::fw_lte_cover
uint32_t fw_lte_cover[APP_LAYER_MAX_PROGRESS]
Definition: detect.h:1423
detect-parse.h
Signature_
Signature container.
Definition: detect.h:692
AppLayerGetTxIterTuple::has_next
bool has_next
Definition: app-layer-parser.h:162
PACKET_ALERT_FLAG_TX
#define PACKET_ALERT_FLAG_TX
Definition: decode.h:274
DetectFirewallAppTxState::fw_last_for_progress
bool fw_last_for_progress
Definition: detect.c:1736
AppLayerParserGetTxEndState
uint8_t AppLayerParserGetTxEndState(uint8_t ipproto, AppProto alproto, void *tx, uint8_t flags)
get the end state (progress) for a transaction.
Definition: app-layer-parser.c:1177
PKT_DROP_REASON_FW_DEFAULT_APP_POLICY
@ PKT_DROP_REASON_FW_DEFAULT_APP_POLICY
Definition: decode.h:409
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
TRACE_SID_TXS
#define TRACE_SID_TXS(sid, txs,...)
Definition: detect.c:1260
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:238
DetectEngineThreadCtx_::tx_id_set
bool tx_id_set
Definition: detect.h:1390
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:1444
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:1014
Packet_::dst
Address dst
Definition: decode.h:521
DETECT_FIREWALL_POLICY_PRE_FLOW
@ DETECT_FIREWALL_POLICY_PRE_FLOW
Definition: detect.h:940
PROF_DETECT_TX
@ PROF_DETECT_TX
Definition: suricata-common.h:466
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:422
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:726
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1292
PrefilterPostRuleMatch
void PrefilterPostRuleMatch(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, Flow *f)
invoke post-rule match "prefilter" engines
Definition: detect-engine-prefilter.c:221
DetectGetInnerTx
void * DetectGetInnerTx(void *tx_ptr, AppProto alproto, AppProto engine_alproto, uint8_t flow_flags)
Definition: detect.c:1270
DetectPreStream
uint8_t DetectPreStream(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p)
Definition: detect.c:3207
PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY
@ PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY
Definition: decode.h:408
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:1355
DetectEngineThreadCtx_::mt_det_ctxs_cnt
uint32_t mt_det_ctxs_cnt
Definition: detect.h:1326
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:232
likely
#define likely(expr)
Definition: util-optimize.h:32
IPPROTO_SCTP
#define IPPROTO_SCTP
Definition: decode.h:1273
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:1370
AppLayerParserSupportsSubStates
bool AppLayerParserSupportsSubStates(const AppProto alproto)
Definition: app-layer-parser.c:1356
DetectFirewallAppPolicy::alproto
AppProto alproto
Definition: detect.h:952
DetectFirewallPolicies::app_policies
HashTable * app_policies
Definition: detect.h:968
DetectTransaction_::tx_progress
const uint8_t tx_progress
Definition: detect-engine-prefilter.h:43
DetectEngineCtx_::io_ctx
DetectEngineIPOnlyCtx io_ctx
Definition: detect.h:1037
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:735
FlowGetDisruptionFlags
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags)
get 'disruption' flags: GAP/DEPTH/PASS
Definition: flow.c:1168
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:718
DetectFirewallPolicy::action_scope
uint8_t action_scope
Definition: detect.h:948
DetectTxFirewallFlowControl
DetectTxFirewallFlowControl
Definition: detect.c:1178
DeStateStoreItem_
Definition: detect-engine-state.h:75
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:717
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
Packet_::dp
Port dp
Definition: decode.h:531
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::sig_array_len
uint32_t sig_array_len
Definition: detect.h:1015
SIG_GROUP_HEAD_HAVEFILESHA256
#define SIG_GROUP_HEAD_HAVEFILESHA256
Definition: detect.h:1581
AlertQueueAppendAppTx
void AlertQueueAppendAppTx(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, uint8_t sub_state, uint8_t alert_flags)
Append signature to local packet alert queue for later preprocessing.
Definition: detect-engine-alert.c:423
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:120
Signature_::type
enum SignatureType type
Definition: detect.h:695
StatsCounterAddI64
void StatsCounterAddI64(StatsThreadContext *stats, StatsCounterId id, int64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:144
SigGroupHead_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1736
AppLayerParserGetTxCnt
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
Definition: app-layer-parser.c:1212
DetectFirewallAppPolicy::direction
uint8_t direction
Definition: detect.h:955
AppLayerParserHasDecoderEvents
bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate)
Definition: app-layer-parser.c:1747
FLOW_PKT_TOSERVER_FIRST
#define FLOW_PKT_TOSERVER_FIRST
Definition: flow.h:239
DetectEngineLookupFlow_::tcp
DetectPort * tcp
Definition: detect.h:892
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
detect-engine-address.h
Flow_::tenant_id
uint32_t tenant_id
Definition: flow.h:429
Packet_::src
Address src
Definition: decode.h:520
SigMatchSignaturesGetSgh
const SigGroupHead * SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p)
Get the SigGroupHead for a packet.
Definition: detect.c:293
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:1184
APP_LAYER_TX_INSPECTED_TC
#define APP_LAYER_TX_INSPECTED_TC
Definition: app-layer-parser.h:52
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:247
DetectPortLookupGroup
DetectPort * DetectPortLookupGroup(DetectPort *dp, uint16_t port)
Function that find the group matching port in a group head.
Definition: detect-engine-port.c:584
DetectEngineThreadCtx_::post_rule_work_queue
PostRuleMatchWorkQueue post_rule_work_queue
Definition: detect.h:1427
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1307
detect-engine-threshold.h
Signature_::mask
SignatureMask mask
Definition: detect.h:703
AppLayerTxData::updated_ts
bool updated_ts
Definition: app-layer-parser.h:180
app-layer.h
RuleMatchCandidateTx
Definition: detect.h:1268
DetectEngineThreadCtx_::TenantGetId
uint32_t(* TenantGetId)(const void *, const Packet *p)
Definition: detect.h:1333
DetectEngineAppInspectionEngine_::progress
uint8_t progress
Definition: detect.h:430
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:38
PacketEngineEvents_::cnt
uint8_t cnt
Definition: decode.h:310
f
Flow f
Definition: fuzz_dataset.c:32
Flow_::de_ctx_version
uint32_t de_ctx_version
Definition: flow.h:469
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:114
DetectEngineThreadCtx_::match_array
Signature ** match_array
Definition: detect.h:1407