From: Victor Julien Date: Tue, 20 May 2025 14:15:15 +0000 (+0200) Subject: detect: add pre_flow hook X-Git-Tag: suricata-8.0.0-rc1~111 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=df7fe5b0ce082ae4110167155aab563feda182ff;p=thirdparty%2Fsuricata.git detect: add pre_flow hook Allows dropping of packets before a flow is created/updated. Directionless as direction is inferred from the flow. Ticket: #7714. --- diff --git a/etc/schema.json b/etc/schema.json index e3bbbeff11..598cfac181 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -6792,6 +6792,11 @@ "type": "integer", "description": "Number of packets dropped due to no NFQ verdict" }, + "pre_flow_hook": { + "description": + "Number of packets dropped in the pre_flow hook ", + "type": "integer" + }, "pre_stream_hook": { "description": "Number of packets dropped in the pre_stream hook ", diff --git a/src/decode.c b/src/decode.c index f3ef6c22b3..d55d282242 100644 --- a/src/decode.c +++ b/src/decode.c @@ -913,6 +913,8 @@ const char *PacketDropReasonToString(enum PacketDropReason r) return "default app policy"; case PKT_DROP_REASON_STREAM_PRE_HOOK: return "pre stream hook"; + case PKT_DROP_REASON_FLOW_PRE_HOOK: + return "pre flow hook"; case PKT_DROP_REASON_NOT_SET: case PKT_DROP_REASON_MAX: return NULL; @@ -961,6 +963,8 @@ static const char *PacketDropReasonToJsonString(enum PacketDropReason r) return "ips.drop_reason.default_app_policy"; case PKT_DROP_REASON_STREAM_PRE_HOOK: return "ips.drop_reason.pre_stream_hook"; + case PKT_DROP_REASON_FLOW_PRE_HOOK: + return "ips.drop_reason.pre_flow_hook"; case PKT_DROP_REASON_NOT_SET: case PKT_DROP_REASON_MAX: return NULL; diff --git a/src/decode.h b/src/decode.h index 1224f75a85..5a65805d4f 100644 --- a/src/decode.h +++ b/src/decode.h @@ -391,6 +391,7 @@ enum PacketDropReason { PKT_DROP_REASON_DEFAULT_PACKET_POLICY, /**< drop issued by default packet policy */ PKT_DROP_REASON_DEFAULT_APP_POLICY, /**< drop issued by default app policy */ PKT_DROP_REASON_STREAM_PRE_HOOK, /**< drop issued in the pre_stream hook */ + PKT_DROP_REASON_FLOW_PRE_HOOK, /**< drop issued in the pre_flow hook */ PKT_DROP_REASON_MAX, }; diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index d00514fe8e..571b8aede8 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -191,10 +191,14 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac /* REJECT also sets ACTION_DROP, just make it more visible with this check */ if (pa->action & ACTION_DROP_REJECT) { - const uint8_t drop_reason = ((s->flags & SIG_FLAG_FIREWALL) && - s->firewall_table == FIREWALL_TABLE_PACKET_PRE_STREAM) - ? PKT_DROP_REASON_STREAM_PRE_HOOK - : PKT_DROP_REASON_RULES; + uint8_t drop_reason = PKT_DROP_REASON_RULES; + if (s->flags & SIG_FLAG_FIREWALL) { + if (s->firewall_table == FIREWALL_TABLE_PACKET_PRE_STREAM) { + drop_reason = PKT_DROP_REASON_STREAM_PRE_HOOK; + } else if (s->firewall_table == FIREWALL_TABLE_PACKET_PRE_FLOW) { + drop_reason = PKT_DROP_REASON_FLOW_PRE_HOOK; + } + } /* PacketDrop will update the packet action, too */ PacketDrop(p, pa->action, diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 9a524cd2af..519c695775 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -1869,6 +1869,12 @@ static void DetectEngineAddSigToPreStreamHook(DetectEngineCtx *de_ctx, Signature } } +static void DetectEngineAddSigToPreFlowHook(DetectEngineCtx *de_ctx, Signature *s) +{ + SCLogDebug("adding signature %" PRIu32 " to the pre_flow hook sgh", s->id); + SigGroupHeadAppendSig(de_ctx, &de_ctx->pre_flow_sgh, s); +} + /** * \brief Fill the global src group head, with the sigs included * @@ -1903,6 +1909,9 @@ int SigPrepareStage2(DetectEngineCtx *de_ctx) } else if (s->type == SIG_TYPE_PKT && s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT && s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_STREAM) { DetectEngineAddSigToPreStreamHook(de_ctx, s); + } else if (s->type == SIG_TYPE_PKT && s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT && + s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_FLOW) { + DetectEngineAddSigToPreFlowHook(de_ctx, s); } } @@ -1940,11 +1949,25 @@ static void DetectEngineBuildPreStreamHookSghs(DetectEngineCtx *de_ctx) } } +static void DetectEngineBuildPreFlowHookSghs(DetectEngineCtx *de_ctx) +{ + if (de_ctx->pre_flow_sgh != NULL) { + uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); + SigGroupHeadSetSigCnt(de_ctx->pre_flow_sgh, max_idx); + SigGroupHeadBuildMatchArray(de_ctx, de_ctx->pre_flow_sgh, max_idx); + PrefilterSetupRuleGroup(de_ctx, de_ctx->pre_flow_sgh); + de_ctx->PreFlowHook = DetectPreFlow; + } +} + int SigPrepareStage3(DetectEngineCtx *de_ctx) { /* prepare the decoder event sgh */ DetectEngineBuildDecoderEventSgh(de_ctx); + /* pre_flow hook sgh */ + DetectEngineBuildPreFlowHookSghs(de_ctx); + /* pre_stream hook sghs */ DetectEngineBuildPreStreamHookSghs(de_ctx); @@ -1960,6 +1983,9 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) if (de_ctx->decoder_event_sgh) SigGroupHeadFree(de_ctx, de_ctx->decoder_event_sgh); de_ctx->decoder_event_sgh = NULL; + if (de_ctx->pre_flow_sgh) + SigGroupHeadFree(de_ctx, de_ctx->pre_flow_sgh); + de_ctx->pre_flow_sgh = NULL; if (de_ctx->pre_stream_sgh[0]) SigGroupHeadFree(de_ctx, de_ctx->pre_stream_sgh[0]); de_ctx->pre_stream_sgh[0] = NULL; diff --git a/src/detect-parse.c b/src/detect-parse.c index 1ae277c20a..d526d58219 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1240,6 +1240,8 @@ static enum SignatureHookPkt HookPktFromString(const char *str) { if (strcmp(str, "flow_start") == 0) { return SIGNATURE_HOOK_PKT_FLOW_START; + } else if (strcmp(str, "pre_flow") == 0) { + return SIGNATURE_HOOK_PKT_PRE_FLOW; } else if (strcmp(str, "pre_stream") == 0) { return SIGNATURE_HOOK_PKT_PRE_STREAM; } else if (strcmp(str, "all") == 0) { @@ -1256,6 +1258,8 @@ static const char *HookPktToString(const enum SignatureHookPkt ph) return "not set"; case SIGNATURE_HOOK_PKT_FLOW_START: return "flow_start"; + case SIGNATURE_HOOK_PKT_PRE_FLOW: + return "pre_flow"; case SIGNATURE_HOOK_PKT_PRE_STREAM: return "pre_stream"; case SIGNATURE_HOOK_PKT_ALL: @@ -2461,6 +2465,9 @@ static void DetectFirewallRuleSetTable(Signature *s) if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT && s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_STREAM) table = FIREWALL_TABLE_PACKET_PRE_STREAM; + else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT && + s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_PRE_FLOW) + table = FIREWALL_TABLE_PACKET_PRE_FLOW; else table = FIREWALL_TABLE_PACKET_FILTER; } else if (s->type == SIG_TYPE_APP_TX) { diff --git a/src/detect.c b/src/detect.c index c181072e8e..96ef76a9b7 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2295,6 +2295,16 @@ static void DetectNoFlow(ThreadVars *tv, DetectRun(tv, de_ctx, det_ctx, p); } +uint8_t DetectPreFlow(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p) +{ + const DetectEngineCtx *de_ctx = det_ctx->de_ctx; + const SigGroupHead *sgh = de_ctx->pre_flow_sgh; + + SCLogDebug("thread id: %u, packet %" PRIu64 ", sgh %p", tv->id, p->pcap_cnt, sgh); + DetectRunPacketHook(tv, de_ctx, det_ctx, sgh, p); + return p->action; +} + uint8_t DetectPreStream(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p) { const DetectEngineCtx *de_ctx = det_ctx->de_ctx; diff --git a/src/detect.h b/src/detect.h index 86f1f235ea..477e89f699 100644 --- a/src/detect.h +++ b/src/detect.h @@ -539,6 +539,7 @@ typedef struct SignatureInitDataBuffer_ { enum SignatureHookPkt { SIGNATURE_HOOK_PKT_NOT_SET, SIGNATURE_HOOK_PKT_FLOW_START, + SIGNATURE_HOOK_PKT_PRE_FLOW, SIGNATURE_HOOK_PKT_PRE_STREAM, SIGNATURE_HOOK_PKT_ALL, /**< match each packet */ }; @@ -550,6 +551,7 @@ enum SignatureHookType { }; enum FirewallTable { + FIREWALL_TABLE_PACKET_PRE_FLOW, FIREWALL_TABLE_PACKET_PRE_STREAM, FIREWALL_TABLE_PACKET_FILTER, FIREWALL_TABLE_PACKET_TD, @@ -1145,6 +1147,10 @@ typedef struct DetectEngineCtx_ { /** TCP pre_stream hook rule groups. One per direction. */ struct SigGroupHead_ *pre_stream_sgh[2]; + /* Hook for pre_flow engine if it is used. */ + DetectPacketHookFunc PreFlowHook; + /** pre_flow hook rule groups. Before flow we don't know a direction yet. */ + struct SigGroupHead_ *pre_flow_sgh; } DetectEngineCtx; /** @@ -1708,6 +1714,7 @@ extern SigTableElmt *sigmatch_table; /* detection api */ TmEcode Detect(ThreadVars *tv, Packet *p, void *data); +uint8_t DetectPreFlow(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p); uint8_t DetectPreStream(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p); SigMatch *SigMatchAlloc(void); diff --git a/src/flow-worker.c b/src/flow-worker.c index da64e0753a..585dfa755b 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -574,6 +574,14 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) } /* handle Flow */ + if (det_ctx != NULL && det_ctx->de_ctx->PreFlowHook != NULL) { + const uint8_t action = det_ctx->de_ctx->PreFlowHook(tv, det_ctx, p); + if (action & ACTION_DROP) { + PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FLOW_PRE_HOOK); + goto pre_flow_drop; + } + } + if (p->flags & PKT_WANTS_FLOW) { FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_FLOW); @@ -660,6 +668,7 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_DETECT); } +pre_flow_drop: // Outputs. OutputLoggerLog(tv, p, fw->output_thread);