Allows dropping of packets before a flow is created/updated.
Directionless as direction is inferred from the flow.
Ticket: #7714.
"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 ",
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;
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;
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,
};
/* 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,
}
}
+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
*
} 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);
}
}
}
}
+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);
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;
{
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) {
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:
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) {
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;
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 */
};
};
enum FirewallTable {
+ FIREWALL_TABLE_PACKET_PRE_FLOW,
FIREWALL_TABLE_PACKET_PRE_STREAM,
FIREWALL_TABLE_PACKET_FILTER,
FIREWALL_TABLE_PACKET_TD,
/** 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;
/**
/* 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);
}
/* 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);
FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_DETECT);
}
+pre_flow_drop:
// Outputs.
OutputLoggerLog(tv, p, fw->output_thread);