This commit is contained in:
Juliana Fajardini Reichow 2026-05-26 10:24:48 -03:00 committed by GitHub
commit 878fa1a1e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 298 additions and 79 deletions

View file

@ -2805,6 +2805,31 @@ use of.
vista: []
windows2k3: []
Suricata as a Firewall options (experimental)
---------------------------------------------
It is possible to run Suricata as a firewall.
Please read :ref:`Firewall Mode Design <firewall mode design>` before using this.
The existing yaml configuration options are listed below. If the engine is run
in firewall mode, dedicated stats counters will be added to the stats logs.
To see the stats counters reported for the firewall, refer to :ref:`firewall mode stats`.
To see the stats reported for the firewall mode, refer to :ref:`firewall mode stats`.
firewall:
# toggle to enable firewall mode
#enabled: no
# Firewall rule file are in their own path and are not managed
# by Suricata-Update.
#rule-path: /etc/suricata/firewall/
# List of files with firewall rules. Order matters, files are loaded
# in order and rules are applied in that order (per state, see docs)
#rule-files:
# - firewall.rules
Engine analysis and profiling
-----------------------------

View file

@ -0,0 +1,34 @@
.. _firewall mode stats:
Firewall Mode Stats
*******************
Statistics counters for the firewall mode cover:
- drop reasons: ``stats.firewall.drop_reason``
- discarded alerts: ``stats.firewall.discarded_alerts``
- blocked packets: ``stats.firewall.blocked``
- accepted packets: ``stats.firewall.accepted``
- rejected packets: ``stats.firewall.rejected``
These will be present in the stats logs if the engine is run in firewall mode,
only.
Drop reasons
============
If a drop was caused by the firewall, the corresponding counter will be incremented. The existing ones are:
- ``rules``: a firewall rule triggered the drop
- ``default_packet_policy``: drop caused by the default fail closed firewall behavior, on the packet hook level
- ``default_app_policy``: drop caused by the default fail close firewall behavior, on the app-layer hook level
- ``pre_flow_hook``: drop caused by the pre-flow hook
- ``pre_stream_hook``: drop caused by the pre-stream hook
- ``flow_drop``: the whole flow was dropped after a firewall action.
Discarded alerts
================
In Firewall mode, alerts generated *after* a drop are discarded.
These are reported with the counter ``stats.firewall.discarded_alerts``.
Note that the drop may be caused by non-firewall rules.

View file

@ -5,3 +5,4 @@ Firewall Mode
firewall-design
firewall-example
firewall-stats

View file

@ -7352,7 +7352,7 @@
},
"alert_queue_overflow": {
"type": "integer",
"description": "Count of alerts discarded due to alert queue overflow or a drop in firewall mode"
"description": "Count of alerts discarded due to alert queue overflow"
},
"alerts_suppressed": {
"type": "integer",
@ -7521,6 +7521,60 @@
}
}
},
"firewall": {
"type": "object",
"additionalProperties": false,
"properties": {
"accepted": {
"type": "integer",
"description": "Count of accepted packets due to firewall policies"
},
"blocked": {
"type": "integer",
"description": "Count of blocked packets due to firewall policies"
},
"discarded_alerts": {
"type": "integer",
"description": "Count of alerts discarded due to a drop while in firewall mode"
},
"drop_reason": {
"type": "object",
"additionalProperties": false,
"properties": {
"default_app_policy": {
"type": "integer",
"description":
"Count of packets dropped due to firewall's mode default app policy"
},
"default_packet_policy": {
"type": "integer",
"description":
"Count of packets dropped due to firewall's mode default packet policy"
},
"flow_drop": {
"type": "integer",
"description": "Count of packets dropped due to a firewall policy that led to flow drop"
},
"pre_flow_hook": {
"type": "integer",
"description": "Count of packets dropped due to pre-flow hook"
},
"pre_stream_hook": {
"type": "integer",
"description": "Count of packets dropped due to pre-stream hook"
},
"rules": {
"type": "integer",
"description": "Count of packets dropped due to firewall rules"
}
}
},
"rejected": {
"type": "integer",
"description": "Count of packets rejected due to firewall policies"
}
}
},
"flow": {
"type": "object",
"description": "Stats on flow-related diagnostics",
@ -7938,16 +7992,6 @@
"description":
"Number of packets dropped due to decoding errors"
},
"default_app_policy": {
"type": "integer",
"description":
"Number of packets dropped due to default app policy"
},
"default_packet_policy": {
"type": "integer",
"description":
"Number of packets dropped due to default packet policy"
},
"defrag_error": {
"type": "integer",
"description":
@ -7958,6 +8002,10 @@
"description":
"Number of packets dropped due to defrag memcap exception policy"
},
"exception_policy_flow_drop": {
"type": "integer",
"description": "Number of packets dropped due to an exception policy flow dropping"
},
"flow_drop": {
"type": "integer",
"description": "Number of packets dropped due to dropped flows"
@ -7971,16 +8019,6 @@
"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 ",
"type": "integer"
},
"rules": {
"type": "integer",
"description": "Number of packets dropped due to rule actions"
@ -8029,7 +8067,7 @@
},
"replaced": {
"type": "integer",
"description": "Number of replaced packets"
"description": "Number of packets replaced by the stream engine or based on a match of the 'replaced' keyword."
}
}
},

View file

@ -248,8 +248,8 @@ SID201=$(jq -c 'select(.alert.signature_id==201)' ./eve.json | wc -l)
SID202=$(jq -c 'select(.alert.signature_id==202)' ./eve.json | wc -l)
echo "SID201 $SID201 SID202 $SID202"
ACCEPTED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.accepted')
BLOCKED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.blocked')
ACCEPTED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.firewall.accepted')
BLOCKED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.firewall.blocked')
KERNEL_PACKETS=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.capture.kernel_packets')
echo "ACCEPTED $ACCEPTED BLOCKED $BLOCKED KERNEL_PACKETS $KERNEL_PACKETS"
@ -303,6 +303,7 @@ fi
echo "* dumping some stats..."
cat ./eve.json | jq -c 'select(.http)'|tail -n1|jq
cat ./eve.json | jq -c 'select(.stats)|.stats.ips'|tail -n1|jq
cat ./eve.json | jq -c 'select(.stats)|.stats.firewall'|tail -n1|jq
cat ./eve.json | jq -c 'select(.stats)|.stats.capture'|tail -n1|jq
echo "* dumping some stats... done"

View file

@ -268,8 +268,8 @@ SID201=$(jq -c 'select(.alert.signature_id==201)' ./eve.json | wc -l)
SID202=$(jq -c 'select(.alert.signature_id==202)' ./eve.json | wc -l)
echo "SID201 $SID201 SID202 $SID202"
ACCEPTED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.accepted')
BLOCKED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.blocked')
ACCEPTED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.firewall.accepted')
BLOCKED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.firewall.blocked')
echo "ACCEPTED $ACCEPTED BLOCKED $BLOCKED"
if [ $ACCEPTED -eq 0 ]; then
@ -317,6 +317,7 @@ fi
echo "* dumping some stats..."
cat ./eve.json | jq -c 'select(.http)'|tail -n1|jq
cat ./eve.json | jq -c 'select(.stats)|.stats.firewall'|tail -n1|jq
cat ./eve.json | jq -c 'select(.stats)|.stats.ips'|tail -n1|jq
echo "* dumping some stats... done"

View file

@ -934,6 +934,8 @@ const char *PacketDropReasonToString(enum PacketDropReason r)
return "flow memcap";
case PKT_DROP_REASON_FLOW_DROP:
return "flow drop";
case PKT_DROP_REASON_EP_FLOW_DROP:
return "exception policy flow drop";
case PKT_DROP_REASON_STREAM_ERROR:
return "stream error";
case PKT_DROP_REASON_STREAM_MEMCAP:
@ -956,14 +958,18 @@ const char *PacketDropReasonToString(enum PacketDropReason r)
return "nfq error";
case PKT_DROP_REASON_INNER_PACKET:
return "tunnel packet drop";
case PKT_DROP_REASON_DEFAULT_PACKET_POLICY:
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_FLOW_PRE_HOOK:
return "pre flow hook";
case PKT_DROP_REASON_FW_RULES:
return "firewall rules";
case PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY:
return "firewall default packet policy";
case PKT_DROP_REASON_FW_DEFAULT_APP_POLICY:
return "firewall default app policy";
case PKT_DROP_REASON_FW_STREAM_PRE_HOOK:
return "firewall pre stream hook";
case PKT_DROP_REASON_FW_FLOW_PRE_HOOK:
return "firewall pre flow hook";
case PKT_DROP_REASON_FW_FLOW_DROP:
return "firewall flow drop";
case PKT_DROP_REASON_NOT_SET:
case PKT_DROP_REASON_MAX:
return NULL;
@ -984,6 +990,8 @@ static const char *PacketDropReasonToJsonString(enum PacketDropReason r)
return "ips.drop_reason.flow_memcap";
case PKT_DROP_REASON_FLOW_DROP:
return "ips.drop_reason.flow_drop";
case PKT_DROP_REASON_EP_FLOW_DROP:
return "ips.drop_reason.exception_policy_flow_drop";
case PKT_DROP_REASON_STREAM_ERROR:
return "ips.drop_reason.stream_error";
case PKT_DROP_REASON_STREAM_MEMCAP:
@ -1006,14 +1014,18 @@ static const char *PacketDropReasonToJsonString(enum PacketDropReason r)
return "ips.drop_reason.nfq_error";
case PKT_DROP_REASON_INNER_PACKET:
return "ips.drop_reason.tunnel_packet_drop";
case PKT_DROP_REASON_DEFAULT_PACKET_POLICY:
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_FLOW_PRE_HOOK:
return "ips.drop_reason.pre_flow_hook";
case PKT_DROP_REASON_FW_RULES:
return "firewall.drop_reason.rules";
case PKT_DROP_REASON_FW_STREAM_PRE_HOOK:
return "firewall.drop_reason.pre_stream_hook";
case PKT_DROP_REASON_FW_FLOW_PRE_HOOK:
return "firewall.drop_reason.pre_flow_hook";
case PKT_DROP_REASON_FW_FLOW_DROP:
return "firewall.drop_reason.flow_drop";
case PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY:
return "firewall.drop_reason.default_packet_policy";
case PKT_DROP_REASON_FW_DEFAULT_APP_POLICY:
return "firewall.drop_reason.default_app_policy";
case PKT_DROP_REASON_NOT_SET:
case PKT_DROP_REASON_MAX:
return NULL;
@ -1026,27 +1038,73 @@ typedef struct CaptureStats_ {
StatsCounterId counter_ips_blocked;
StatsCounterId counter_ips_rejected;
StatsCounterId counter_ips_replaced;
StatsCounterId counter_fw_accepted;
StatsCounterId counter_fw_blocked;
StatsCounterId counter_fw_rejected;
StatsCounterId counter_drop_reason[PKT_DROP_REASON_MAX];
} CaptureStats;
thread_local CaptureStats t_capture_stats;
static bool VerdictByFirewall(const Packet *p)
{
if (!EngineModeIsFirewall()) {
return false;
}
if (p->drop_reason >= PKT_DROP_REASON_FW_RULES) {
return true;
}
return false;
}
void CaptureStatsUpdate(ThreadVars *tv, const Packet *p)
{
if (!EngineModeIsIPS() || PKT_IS_PSEUDOPKT(p))
return;
CaptureStats *s = &t_capture_stats;
if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) {
StatsCounterIncr(&tv->stats, s->counter_ips_rejected);
} else if (unlikely(PacketCheckAction(p, ACTION_DROP))) {
StatsCounterIncr(&tv->stats, s->counter_ips_blocked);
} else if (unlikely(p->flags & PKT_STREAM_MODIFIED)) {
StatsCounterIncr(&tv->stats, s->counter_ips_replaced);
if (EngineModeIsFirewall()) {
/** The firewall mode and its stats counters should work as when there are two different
* devices for the firewall control and the IPS control.
* As such, if the firewall blocks a packet, it won't reach the IPS level of evaluation,
* so won't be counted in either stats.
* When the firewall accepts a packet, it can still be blocked, rejected or accepted by
* IPS rules and policies.
*/
if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) {
if (VerdictByFirewall(p)) {
StatsCounterIncr(&tv->stats, s->counter_fw_rejected);
} else {
StatsCounterIncr(&tv->stats, s->counter_fw_accepted);
StatsCounterIncr(&tv->stats, s->counter_ips_rejected);
}
} else if (PacketCheckAction(p, ACTION_DROP)) {
if (VerdictByFirewall(p)) {
StatsCounterIncr(&tv->stats, s->counter_fw_blocked);
} else {
/* If a packet was dropped by IPS, it had to first be accepted by the firewall, to
* reach the IPS flow control */
StatsCounterIncr(&tv->stats, s->counter_fw_accepted);
StatsCounterIncr(&tv->stats, s->counter_ips_blocked);
}
} else if (PacketCheckAction(p, ACTION_ACCEPT)) {
StatsCounterIncr(&tv->stats, s->counter_fw_accepted);
StatsCounterIncr(&tv->stats, s->counter_ips_accepted);
}
} else {
StatsCounterIncr(&tv->stats, s->counter_ips_accepted);
if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) {
StatsCounterIncr(&tv->stats, s->counter_ips_rejected);
} else if (unlikely(PacketCheckAction(p, ACTION_DROP))) {
StatsCounterIncr(&tv->stats, s->counter_ips_blocked);
} else if (unlikely(p->flags & PKT_STREAM_MODIFIED)) {
StatsCounterIncr(&tv->stats, s->counter_ips_replaced);
} else {
StatsCounterIncr(&tv->stats, s->counter_ips_accepted);
}
}
if (p->drop_reason != PKT_DROP_REASON_NOT_SET) {
StatsCounterIncr(&tv->stats, s->counter_drop_reason[p->drop_reason]);
}
@ -1060,11 +1118,21 @@ void CaptureStatsSetup(ThreadVars *tv)
s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", &tv->stats);
s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", &tv->stats);
s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", &tv->stats);
for (int i = PKT_DROP_REASON_NOT_SET; i < PKT_DROP_REASON_MAX; i++) {
for (int i = PKT_DROP_REASON_NOT_SET; i <= PKT_DROP_REASON_NON_FW_MAX; i++) {
const char *name = PacketDropReasonToJsonString(i);
if (name != NULL)
s->counter_drop_reason[i] = StatsRegisterCounter(name, &tv->stats);
}
if (EngineModeIsFirewall()) {
s->counter_fw_accepted = StatsRegisterCounter("firewall.accepted", &tv->stats);
s->counter_fw_blocked = StatsRegisterCounter("firewall.blocked", &tv->stats);
s->counter_fw_rejected = StatsRegisterCounter("firewall.rejected", &tv->stats);
for (int i = PKT_DROP_REASON_FW_RULES; i < PKT_DROP_REASON_MAX; i++) {
const char *name = PacketDropReasonToJsonString(i);
if (name != NULL)
s->counter_drop_reason[i] = StatsRegisterCounter(name, &tv->stats);
}
}
}
}

View file

@ -248,7 +248,7 @@ struct PacketContextData {
* found in this packet */
typedef struct PacketAlert_ {
SigIntId iid; /* Internal ID, used for sorting */
uint8_t action; /* Internal num, used for thresholding */
uint8_t action; /* Rule or threshold action to be applied to packet */
uint8_t flags;
const struct Signature_ *s;
uint64_t tx_id; /* Used for sorting */
@ -287,6 +287,7 @@ extern uint16_t packet_alert_max;
typedef struct PacketAlerts_ {
uint16_t cnt;
uint16_t discarded;
uint16_t firewall_discarded; /* alerts discarded after a drop, in fw mode*/
uint16_t suppressed;
PacketAlert *alerts;
/* single pa used when we're dropping,
@ -385,6 +386,7 @@ enum PacketDropReason {
PKT_DROP_REASON_DEFRAG_MEMCAP,
PKT_DROP_REASON_FLOW_MEMCAP,
PKT_DROP_REASON_FLOW_DROP,
PKT_DROP_REASON_EP_FLOW_DROP,
PKT_DROP_REASON_APPLAYER_ERROR,
PKT_DROP_REASON_APPLAYER_MEMCAP,
PKT_DROP_REASON_RULES,
@ -394,12 +396,19 @@ enum PacketDropReason {
PKT_DROP_REASON_STREAM_MIDSTREAM,
PKT_DROP_REASON_STREAM_REASSEMBLY,
PKT_DROP_REASON_STREAM_URG,
PKT_DROP_REASON_NFQ_ERROR, /**< no nfq verdict, must be error */
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_FLOW_PRE_HOOK, /**< drop issued in the pre_flow hook */
PKT_DROP_REASON_NFQ_ERROR, /**< no nfq verdict, must be error */
PKT_DROP_REASON_INNER_PACKET, /**< drop issued by inner (tunnel) packet */
/** If more non-firewall drop reasons are added, make sure not to "break" PKT_DROP_REASON_NON_FW_MAX
*/
/* Limiter for non-firewall drop reasons. */
#define PKT_DROP_REASON_NON_FW_MAX PKT_DROP_REASON_INNER_PACKET
/** Firewall-related reasons only */
PKT_DROP_REASON_FW_RULES,
PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY, /**< drop issued by default packet policy */
PKT_DROP_REASON_FW_DEFAULT_APP_POLICY, /**< drop issued by default app policy */
PKT_DROP_REASON_FW_STREAM_PRE_HOOK, /**< drop issued in the pre_stream hook */
PKT_DROP_REASON_FW_FLOW_PRE_HOOK, /**< drop issued in the pre_flow hook */
PKT_DROP_REASON_FW_FLOW_DROP,
PKT_DROP_REASON_MAX,
};

View file

@ -154,7 +154,7 @@ int PacketAlertCheck(Packet *p, uint32_t sid)
}
#endif
static inline void RuleActionToFlow(const uint8_t action, Flow *f)
static inline void RuleActionToFlow(const uint8_t action, Flow *f, const bool fw_rule)
{
if (action & ACTION_ACCEPT) {
f->flags |= FLOW_ACTION_ACCEPT;
@ -187,6 +187,10 @@ static inline void RuleActionToFlow(const uint8_t action, Flow *f)
}
}
}
if (fw_rule) {
f->flags |= FLOW_ACTION_BY_FIREWALL;
}
}
/** \brief Apply action(s) and Set 'drop' sig info,
@ -199,15 +203,17 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac
SCLogDebug("packet %" PRIu64 " sid %u action %02x alert_flags %02x", PcapPacketCntGet(p), s->id,
pa->action, pa->flags);
const bool is_fw_rule = s->flags & SIG_FLAG_FIREWALL ? true : false;
/* REJECT also sets ACTION_DROP, just make it more visible with this check */
if (pa->action & ACTION_DROP_REJECT) {
uint8_t drop_reason = PKT_DROP_REASON_RULES;
if (s->detect_table == DETECT_TABLE_PACKET_PRE_STREAM) {
drop_reason = PKT_DROP_REASON_STREAM_PRE_HOOK;
} else if (s->detect_table == DETECT_TABLE_PACKET_PRE_FLOW) {
drop_reason = PKT_DROP_REASON_FLOW_PRE_HOOK;
uint8_t drop_reason = is_fw_rule ? PKT_DROP_REASON_FW_RULES : PKT_DROP_REASON_RULES;
if (is_fw_rule) {
if (s->detect_table == DETECT_TABLE_PACKET_PRE_STREAM) {
drop_reason = PKT_DROP_REASON_FW_STREAM_PRE_HOOK;
} else if (s->detect_table == DETECT_TABLE_PACKET_PRE_FLOW) {
drop_reason = PKT_DROP_REASON_FW_FLOW_PRE_HOOK;
}
}
/* PacketDrop will update the packet action, too */
PacketDrop(p, pa->action,
(pa->flags & PACKET_ALERT_FLAG_RATE_FILTER_MODIFIED)
@ -221,7 +227,7 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac
p->alerts.drop.s = (Signature *)s;
}
if ((p->flow != NULL) && (pa->flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) {
RuleActionToFlow(pa->action, p->flow);
RuleActionToFlow(pa->action, p->flow, is_fw_rule);
}
DEBUG_VALIDATE_BUG_ON(!PacketCheckAction(p, ACTION_DROP));
@ -246,7 +252,7 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac
if ((pa->action & (ACTION_PASS | ACTION_ACCEPT)) && (p->flow != NULL) &&
(pa->flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) {
RuleActionToFlow(pa->action, p->flow);
RuleActionToFlow(pa->action, p->flow, is_fw_rule);
}
}
}
@ -546,9 +552,10 @@ static inline void PacketAlertFinalizeProcessQueue(
}
}
/* skip firewall sigs following a drop: IDS mode still shows alerts after an alert. */
/* skip firewall sigs following a drop: IDS mode still shows alerts after a drop. */
if ((s->flags & SIG_FLAG_FIREWALL) && dropped) {
p->alerts.discarded++;
SCLogDebug("Skippig firewall signature after a drop.");
p->alerts.firewall_discarded++;
/* Thresholding removes this alert */
} else if (res == 0 || res == 2 || (s->action & (ACTION_ALERT | ACTION_PASS)) == 0) {
@ -576,6 +583,7 @@ static inline void PacketAlertFinalizeProcessQueue(
// TODO we can also drop if alert is suppressed, right?
if (s->action & ACTION_DROP) {
SCLogDebug("sid:%u led to a drop that will skip any firewall alerts", s->id);
dropped = true;
}
} else {

View file

@ -3421,6 +3421,10 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", &tv->stats);
det_ctx->counter_alerts_overflow =
StatsRegisterCounter("detect.alert_queue_overflow", &tv->stats);
if (EngineModeIsFirewall()) {
det_ctx->counter_firewall_discarded_alerts =
StatsRegisterCounter("firewall.discarded_alerts", &tv->stats);
}
det_ctx->counter_alerts_suppressed =
StatsRegisterCounter("detect.alerts_suppressed", &tv->stats);
@ -3504,6 +3508,10 @@ DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", &tv->stats);
det_ctx->counter_alerts_overflow =
StatsRegisterCounter("detect.alert_queue_overflow", &tv->stats);
if (EngineModeIsFirewall()) {
det_ctx->counter_firewall_discarded_alerts =
StatsRegisterCounter("firewall.discarded_alerts", &tv->stats);
}
det_ctx->counter_alerts_suppressed =
StatsRegisterCounter("detect.alerts_suppressed", &tv->stats);
#ifdef PROFILING

View file

@ -3737,7 +3737,7 @@ static int DoParsePolicy(const char *policy_name, struct DetectFirewallPolicy *p
int idx = 0;
SCConfNode *paction = NULL;
TAILQ_FOREACH (paction, &policy_actions->head, next) {
SCLogNotice("fw: %s => %s", policy_name, paction->val);
SCLogDebug("fw: %s => %s", policy_name, paction->val);
if (SigParseActionDo(paction->val, idx, true, &action, &action_scope) < 0)
return -1;
idx++;

View file

@ -697,9 +697,9 @@ static uint8_t DetectRunApplyPacketPolicy(const DetectEngineCtx *de_ctx,
DEBUG_VALIDATE_BUG_ON(de_ctx->fw_policies == NULL);
const struct DetectFirewallPolicy *pol = &de_ctx->fw_policies->pkt[policy];
if (pol->action & ACTION_DROP) {
SCLogDebug("packet %" PRIu64 ": drop PKT_DROP_REASON_DEFAULT_PACKET_POLICY",
SCLogDebug("packet %" PRIu64 ": drop PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY",
PcapPacketCntGet(p));
PacketDrop(p, pol->action, PKT_DROP_REASON_DEFAULT_PACKET_POLICY);
PacketDrop(p, pol->action, PKT_DROP_REASON_FW_DEFAULT_PACKET_POLICY);
} else if (pol->action & ACTION_ACCEPT) {
SCLogDebug("packet %" PRIu64 ": accept", PcapPacketCntGet(p));
if (pol->action_scope == ACTION_SCOPE_PACKET) {
@ -1012,6 +1012,7 @@ static DetectRunScratchpad DetectRunSetup(const DetectEngineCtx *de_ctx,
det_ctx->alert_queue_size = 0;
p->alerts.drop.action = 0;
p->alerts.firewall_discarded = 0;
#ifdef DEBUG
if (p->flags & PKT_STREAM_ADD) {
@ -1104,6 +1105,10 @@ static inline void DetectRunPostRules(ThreadVars *tv, const DetectEngineCtx *de_
StatsCounterAddI64(
&tv->stats, det_ctx->counter_alerts_overflow, (uint64_t)p->alerts.discarded);
}
if (p->alerts.firewall_discarded > 0) {
StatsCounterAddI64(&tv->stats, det_ctx->counter_firewall_discarded_alerts,
(uint64_t)p->alerts.firewall_discarded);
}
if (p->alerts.suppressed > 0) {
StatsCounterAddI64(
&tv->stats, det_ctx->counter_alerts_suppressed, (uint64_t)p->alerts.suppressed);
@ -1649,11 +1654,12 @@ static const struct DetectFirewallPolicy *DetectFirewallApplyDefaultAppPolicy(
}
if (policy->action & ACTION_DROP) {
SCLogDebug("dropping packet PKT_DROP_REASON_DEFAULT_APP_POLICY");
PacketDrop(p, policy->action, PKT_DROP_REASON_DEFAULT_APP_POLICY);
SCLogDebug("dropping packet PKT_DROP_REASON_FW_DEFAULT_APP_POLICY");
PacketDrop(p, policy->action, PKT_DROP_REASON_FW_DEFAULT_APP_POLICY);
if (policy->action_scope == ACTION_SCOPE_FLOW) {
SCLogDebug("dropping flow");
p->flow->flags |= FLOW_ACTION_DROP;
p->flow->flags |= FLOW_ACTION_BY_FIREWALL;
}
} else if (policy->action & ACTION_ACCEPT) {
if (policy->action_scope == ACTION_SCOPE_FLOW) {
@ -2332,10 +2338,11 @@ static void DetectRunTx(ThreadVars *tv,
}
} else if (s->action & ACTION_DROP) {
SCLogDebug("drop packet because of rule with drop action");
PacketDrop(p, s->action, PKT_DROP_REASON_RULES);
PacketDrop(p, s->action, PKT_DROP_REASON_FW_RULES);
if (s->action_scope == ACTION_SCOPE_FLOW) {
SCLogDebug("drop flow because of rule with drop action");
f->flags |= FLOW_ACTION_DROP;
f->flags |= FLOW_ACTION_BY_FIREWALL;
}
}
}

View file

@ -1329,6 +1329,8 @@ typedef struct DetectEngineThreadCtx_ {
StatsCounterId counter_alerts;
/** id for discarded alerts counter */
StatsCounterId counter_alerts_overflow;
/** id for firewall discarded alerts counter */
StatsCounterId counter_firewall_discarded_alerts;
/** id for suppressed alerts counter */
StatsCounterId counter_alerts_suppressed;
#ifdef PROFILING

View file

@ -369,7 +369,7 @@ static inline void FlowWorkerStreamTCPUpdate(ThreadVars *tv, FlowWorkerThreadDat
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);
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FW_STREAM_PRE_HOOK);
return;
}
}
@ -427,7 +427,11 @@ static inline void FlowWorkerStreamTCPUpdate(ThreadVars *tv, FlowWorkerThreadDat
}
if (FlowChangeProto(p->flow) && p->flow->flags & FLOW_ACTION_DROP) {
// in case f->flags & FLOW_ACTION_DROP was set by one of the dequeued packets
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FLOW_DROP);
if (p->flow->flags & FLOW_ACTION_BY_FIREWALL) {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FW_FLOW_DROP);
} else {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FLOW_DROP);
}
}
}
@ -569,7 +573,7 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data)
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);
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FW_FLOW_PRE_HOOK);
goto pre_flow_drop;
}
}

View file

@ -535,7 +535,13 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars
}
if (f->flags & FLOW_ACTION_DROP) {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FLOW_DROP);
if (f->flags & FLOW_ACTION_BY_FIREWALL) {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FW_FLOW_DROP);
} else if (f->flags & FLOW_ACTION_BY_EXCEPTION_POLICY) {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_EP_FLOW_DROP);
} else {
PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_FLOW_DROP);
}
}
if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {

View file

@ -121,6 +121,11 @@ typedef struct AppLayerParserState_ AppLayerParserState;
/** next packet in toserver direction will act on updated app-layer state */
#define FLOW_TS_APP_UPDATE_NEXT BIT_U64(31)
/** Flow action issued by firewall */
#define FLOW_ACTION_BY_FIREWALL BIT_U64(32)
/** Flow action issued by exception policy */
#define FLOW_ACTION_BY_EXCEPTION_POLICY BIT_U64(33)
/* File flags */
#define FLOWFILE_INIT 0

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2022 Open Information Security Foundation
/* Copyright (C) 2007-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -136,6 +136,7 @@ void PacketReinit(Packet *p)
#define RESET_PKT_LEN(p) ((p)->pktlen = 0)
RESET_PKT_LEN(p);
p->alerts.discarded = 0;
p->alerts.firewall_discarded = 0;
p->alerts.suppressed = 0;
p->alerts.drop.action = 0;
if (p->alerts.cnt > 0) {

View file

@ -163,6 +163,7 @@ void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDro
SCLogDebug("EXCEPTION_POLICY_DROP_FLOW");
if (p->flow) {
p->flow->flags |= FLOW_ACTION_DROP;
p->flow->flags |= FLOW_ACTION_BY_EXCEPTION_POLICY;
FlowSetNoPayloadInspectionFlag(p->flow);
StreamTcpDisableAppLayer(p->flow);
}