"type": "integer",
"description": "Number of packets dropped due to no NFQ verdict"
},
+ "pre_stream_hook": {
+ "description":
+ "Number of packets dropped in the pre_stream hook ",
+ "type": "integer"
+ },
"rules": {
"type": "integer",
"description": "Number of packets dropped due to rule actions"
return "default packet policy";
case PKT_DROP_REASON_DEFAULT_APP_POLICY:
return "default app policy";
+ case PKT_DROP_REASON_STREAM_PRE_HOOK:
+ return "pre stream hook";
case PKT_DROP_REASON_NOT_SET:
case PKT_DROP_REASON_MAX:
return NULL;
return "ips.drop_reason.default_packet_policy";
case PKT_DROP_REASON_DEFAULT_APP_POLICY:
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_NOT_SET:
case PKT_DROP_REASON_MAX:
return NULL;
PKT_DROP_REASON_INNER_PACKET, /**< drop issued by inner (tunnel) packet */
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_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;
+
/* PacketDrop will update the packet action, too */
PacketDrop(p, pa->action,
(pa->flags & PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED)
? PKT_DROP_REASON_RULES_THRESHOLD
- : PKT_DROP_REASON_RULES);
+ : drop_reason);
SCLogDebug("[packet %p][DROP sid %u]", p, s->id);
if (p->alerts.drop.action == 0) {
#include "detect-flow.h"
#include "detect-config.h"
#include "detect-flowbits.h"
+
#include "app-layer-events.h"
#include "util-port-interval-tree.h"
SigGroupHeadAppendSig(de_ctx, &de_ctx->decoder_event_sgh, s);
}
+static void DetectEngineAddSigToPreStreamHook(DetectEngineCtx *de_ctx, Signature *s)
+{
+ SCLogDebug("adding signature %" PRIu32 " to the pre_stream hook sgh", s->id);
+
+ if ((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) ==
+ (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) {
+ SigGroupHeadAppendSig(de_ctx, &de_ctx->pre_stream_sgh[0], s);
+ SigGroupHeadAppendSig(de_ctx, &de_ctx->pre_stream_sgh[1], s);
+ } else if (s->flags & SIG_FLAG_TOSERVER) {
+ SigGroupHeadAppendSig(de_ctx, &de_ctx->pre_stream_sgh[0], s);
+ } else if (s->flags & SIG_FLAG_TOCLIENT) {
+ SigGroupHeadAppendSig(de_ctx, &de_ctx->pre_stream_sgh[1], s);
+ }
+}
+
/**
* \brief Fill the global src group head, with the sigs included
*
IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, s);
} else if (s->type == SIG_TYPE_DEONLY) {
DetectEngineAddDecoderEventSig(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_STREAM) {
+ DetectEngineAddSigToPreStreamHook(de_ctx, s);
}
}
SigGroupHeadBuildMatchArray(de_ctx, de_ctx->decoder_event_sgh, max_idx);
}
+static void DetectEngineBuildPreStreamHookSghs(DetectEngineCtx *de_ctx)
+{
+ uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx);
+ if (de_ctx->pre_stream_sgh[0] != NULL) {
+ SigGroupHeadSetSigCnt(de_ctx->pre_stream_sgh[0], max_idx);
+ SigGroupHeadBuildMatchArray(de_ctx, de_ctx->pre_stream_sgh[0], max_idx);
+ PrefilterSetupRuleGroup(de_ctx, de_ctx->pre_stream_sgh[0]);
+ }
+ if (de_ctx->pre_stream_sgh[1] != NULL) {
+ SigGroupHeadSetSigCnt(de_ctx->pre_stream_sgh[1], max_idx);
+ SigGroupHeadBuildMatchArray(de_ctx, de_ctx->pre_stream_sgh[1], max_idx);
+ PrefilterSetupRuleGroup(de_ctx, de_ctx->pre_stream_sgh[1]);
+ }
+
+ if (de_ctx->pre_stream_sgh[0] != NULL || de_ctx->pre_stream_sgh[1] != NULL) {
+ de_ctx->PreStreamHook = DetectPreStream;
+ }
+}
+
int SigPrepareStage3(DetectEngineCtx *de_ctx)
{
/* prepare the decoder event sgh */
DetectEngineBuildDecoderEventSgh(de_ctx);
+
+ /* pre_stream hook sghs */
+ DetectEngineBuildPreStreamHookSghs(de_ctx);
+
return 0;
}
if (de_ctx->decoder_event_sgh)
SigGroupHeadFree(de_ctx, de_ctx->decoder_event_sgh);
de_ctx->decoder_event_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 (de_ctx->pre_stream_sgh[1])
+ SigGroupHeadFree(de_ctx, de_ctx->pre_stream_sgh[1]);
+ de_ctx->pre_stream_sgh[1] = NULL;
for (int f = 0; f < FLOW_STATES; f++) {
for (int p = 0; p < 256; p++) {
{
if (strcmp(str, "flow_start") == 0) {
return SIGNATURE_HOOK_PKT_FLOW_START;
+ } else if (strcmp(str, "pre_stream") == 0) {
+ return SIGNATURE_HOOK_PKT_PRE_STREAM;
} else if (strcmp(str, "all") == 0) {
return SIGNATURE_HOOK_PKT_ALL;
}
return "not set";
case SIGNATURE_HOOK_PKT_FLOW_START:
return "flow_start";
+ case SIGNATURE_HOOK_PKT_PRE_STREAM:
+ return "pre_stream";
case SIGNATURE_HOOK_PKT_ALL:
return "all";
}
enum FirewallTable table;
if (s->flags & SIG_FLAG_FIREWALL) {
if (s->type == SIG_TYPE_PKT) {
- table = FIREWALL_TABLE_PACKET_FILTER;
+ 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
+ table = FIREWALL_TABLE_PACKET_FILTER;
} else if (s->type == SIG_TYPE_APP_TX) {
table = FIREWALL_TABLE_APP_FILTER;
} else {
SCReturn;
}
+/** \internal
+ */
+static void DetectRunPacketHook(ThreadVars *th_v, const DetectEngineCtx *de_ctx,
+ DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p)
+{
+ SCEnter();
+ SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt,
+ p->flow ? (FlowGetPacketDirection(p->flow, p) == TOSERVER ? "toserver" : "toclient")
+ : "noflow",
+ PktSrcToString(p->pkt_src));
+
+ /* Load the Packet's flow early, even though it might not be needed.
+ * Mark as a constant pointer, although the flow itself can change. */
+ Flow *const pflow = p->flow;
+
+ DetectRunScratchpad scratch = DetectRunSetup(de_ctx, det_ctx, p, pflow);
+ scratch.sgh = sgh;
+
+ /* if we didn't get a sig group head, we
+ * have nothing to do.... */
+ if (scratch.sgh == NULL) {
+ SCLogDebug("no sgh for this packet, nothing to match against");
+ goto end;
+ }
+
+ /* run the prefilters for packets */
+ DetectRunPrefilterPkt(th_v, de_ctx, det_ctx, p, &scratch);
+
+ // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); // TODO
+ /* inspect the rules against the packet */
+ const uint8_t pkt_policy = DetectRulePacketRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
+ // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_RULES);
+ if (pkt_policy & (ACTION_DROP | ACTION_ACCEPT)) {
+ goto end;
+ }
+
+end:
+ DetectRunPostRules(th_v, de_ctx, det_ctx, p, pflow, &scratch);
+
+ DetectRunCleanup(det_ctx, p, pflow);
+ SCReturn;
+}
+
static void DetectRunPostMatch(ThreadVars *tv,
DetectEngineThreadCtx *det_ctx, Packet *p,
const Signature *s)
DetectRun(tv, de_ctx, det_ctx, p);
}
+uint8_t DetectPreStream(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p)
+{
+ const DetectEngineCtx *de_ctx = det_ctx->de_ctx;
+ const int direction = (PKT_IS_TOCLIENT(p) != 0);
+ const SigGroupHead *sgh = de_ctx->pre_stream_sgh[direction];
+
+ 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;
+}
+
/** \brief Detection engine thread wrapper.
* \param tv thread vars
* \param p packet to inspect
enum SignatureHookPkt {
SIGNATURE_HOOK_PKT_NOT_SET,
SIGNATURE_HOOK_PKT_FLOW_START,
+ SIGNATURE_HOOK_PKT_PRE_STREAM,
SIGNATURE_HOOK_PKT_ALL, /**< match each packet */
};
};
enum FirewallTable {
+ FIREWALL_TABLE_PACKET_PRE_STREAM,
FIREWALL_TABLE_PACKET_FILTER,
FIREWALL_TABLE_PACKET_TD,
FIREWALL_TABLE_APP_FILTER,
uint32_t content_inspect_min_size;
} DetectFileDataCfg;
+typedef uint8_t (*DetectPacketHookFunc)(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p);
+
/**
* \brief Function type for rate filter callback.
*
/* use provided data to be passed to rate_filter_callback. */
void *rate_filter_callback_arg;
+
+ /* Hook for pre_stream engine if it is used. */
+ DetectPacketHookFunc PreStreamHook;
+ /** TCP pre_stream hook rule groups. One per direction. */
+ struct SigGroupHead_ *pre_stream_sgh[2];
+
} DetectEngineCtx;
/**
/* detection api */
TmEcode Detect(ThreadVars *tv, Packet *p, void *data);
+uint8_t DetectPreStream(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p);
SigMatch *SigMatchAlloc(void);
Signature *SigFindSignatureBySidGid(DetectEngineCtx *, uint32_t, uint32_t);
static inline void FlowWorkerStreamTCPUpdate(ThreadVars *tv, FlowWorkerThreadData *fw, Packet *p,
DetectEngineThreadCtx *det_ctx, const bool timeout)
{
+ if (det_ctx != NULL && det_ctx->de_ctx->PreStreamHook != NULL) {
+ const uint8_t action = det_ctx->de_ctx->PreStreamHook(tv, det_ctx, p);
+ if (action & ACTION_DROP) {
+ PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_STREAM_PRE_HOOK);
+ return;
+ }
+ }
+
FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_STREAM);
StreamTcp(tv, p, fw->stream_thread, &fw->pq);
FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_STREAM);