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