mirror of
https://github.com/OISF/suricata.git
synced 2026-06-09 00:42:45 -04:00
Merge ad8ec74978 into 54322f38f8
This commit is contained in:
commit
878fa1a1e6
18 changed files with 298 additions and 79 deletions
|
|
@ -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
|
||||
-----------------------------
|
||||
|
||||
|
|
|
|||
34
doc/userguide/firewall/firewall-stats.rst
Normal file
34
doc/userguide/firewall/firewall-stats.rst
Normal 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.
|
||||
|
|
@ -5,3 +5,4 @@ Firewall Mode
|
|||
|
||||
firewall-design
|
||||
firewall-example
|
||||
firewall-stats
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
116
src/decode.c
116
src/decode.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
23
src/decode.h
23
src/decode.h
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
17
src/detect.c
17
src/detect.c
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue