detect/firewall: support alert in packet default policy

Support `alert` as a secondary action in packet firewall policies.

To implement this a Signature object is created per policy that uses
alert, and this is stored in a array table. When the policy is applied
the signature is looked up and used in the PacketAlert.

Ticket: #8566.
This commit is contained in:
Victor Julien 2026-05-17 16:46:56 +02:00
parent b473ad98ff
commit 1ebbaa419a
4 changed files with 66 additions and 3 deletions

View file

@ -2802,6 +2802,12 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
HashTableFree(de_ctx->non_pf_engine_names);
}
if (de_ctx->fw_policies) {
for (uint32_t i = 0; i < DETECT_FIREWALL_POLICY_SIZE; i++) {
if (de_ctx->fw_policies->pkt_policy_signatures[i]) {
SCFree(de_ctx->fw_policies->pkt_policy_signatures[i]->msg);
SCFree(de_ctx->fw_policies->pkt_policy_signatures[i]);
}
}
HashTableFree(de_ctx->fw_policies->policy_signatures);
}
SCFree(de_ctx->fw_policies);

View file

@ -3828,6 +3828,44 @@ void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *ou
}
}
static int AddPktPolicySignature(struct DetectFirewallPolicies *fw_policies,
struct DetectFirewallPolicy *pol, enum DetectFirewallPacketPolicies pkt_pol)
{
Signature *s = SCCalloc(1, sizeof(*s)); // SigAlloc does way more than we need
if (s == NULL)
return -1;
char msg[256];
switch (pkt_pol) {
case DETECT_FIREWALL_POLICY_PACKET_FILTER:
s->detect_table = DETECT_TABLE_PACKET_FILTER;
break;
case DETECT_FIREWALL_POLICY_PRE_FLOW:
s->detect_table = DETECT_TABLE_PACKET_PRE_FLOW;
break;
case DETECT_FIREWALL_POLICY_PRE_STREAM:
s->detect_table = DETECT_TABLE_PACKET_PRE_STREAM;
break;
}
snprintf(msg, sizeof(msg), "SURICATA FW default packet policy");
s->msg = SCStrdup(msg);
if (s->msg == NULL) {
SCFree(s);
return -1;
}
s->action = pol->action;
s->action_scope = pol->action_scope;
s->flags = SIG_FLAG_FIREWALL;
s->type = SIG_TYPE_PKT;
s->id = 2201000;
s->rev = 1;
s->gid = 1;
s->prio = 3;
fw_policies->pkt_policy_signatures[pkt_pol] = s;
SCLogDebug("added to array");
return 0;
}
static int AddAppPolicySignature(HashTable *ht, const int direction, const AppProto alproto,
const char *app_name, const uint8_t hook, const char *hookname,
struct DetectFirewallPolicy *pol)
@ -4023,6 +4061,11 @@ int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER]);
if (r < 0)
return -1;
if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER].action & ACTION_ALERT)
if (AddPktPolicySignature(fw_policies,
&fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER],
DETECT_FIREWALL_POLICY_PACKET_FILTER) < 0)
return -1;
r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-flow", prefix);
if (r < 0 || (size_t)r >= sizeof(policy_name)) {
@ -4031,6 +4074,10 @@ int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW]);
if (r < 0)
return -1;
if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW].action & ACTION_ALERT)
if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW],
DETECT_FIREWALL_POLICY_PRE_FLOW) < 0)
return -1;
r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-stream", prefix);
if (r < 0 || (size_t)r >= sizeof(policy_name)) {
@ -4039,6 +4086,10 @@ int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM]);
if (r < 0)
return -1;
if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM].action & ACTION_ALERT)
if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM],
DETECT_FIREWALL_POLICY_PRE_STREAM) < 0)
return -1;
for (AppProto a = 0; a < g_alproto_max; a++) {
if (!AppProtoIsValid(a))

View file

@ -693,7 +693,8 @@ static inline bool SkipFwRules(const Packet *p)
* packet:filter accept:hook to the packet as well.
*/
static uint8_t DetectRunApplyPacketPolicy(const DetectEngineCtx *de_ctx,
const enum DetectFirewallPacketPolicies policy, Packet *p, const bool final)
DetectEngineThreadCtx *det_ctx, const enum DetectFirewallPacketPolicies policy, Packet *p,
const bool final)
{
DEBUG_VALIDATE_BUG_ON(de_ctx->fw_policies == NULL);
const struct DetectFirewallPolicy *pol = &de_ctx->fw_policies->pkt[policy];
@ -727,6 +728,10 @@ static uint8_t DetectRunApplyPacketPolicy(const DetectEngineCtx *de_ctx,
/* should be unreachable */
DEBUG_VALIDATE_BUG_ON(1);
}
Signature *s = de_ctx->fw_policies->pkt_policy_signatures[policy];
if (s != NULL) {
AlertQueueAppend(det_ctx, s, p, 0, PACKET_ALERT_FLAG_APPLY_ACTION_TO_PACKET);
}
return p->action;
}
@ -979,7 +984,7 @@ next:
} else {
DEBUG_VALIDATE_BUG_ON(action & ACTION_DROP);
/* non-final call as we may have to consider app-layer still */
action |= DetectRunApplyPacketPolicy(de_ctx, scratch->fw_pkt_policy, p, false);
action |= DetectRunApplyPacketPolicy(de_ctx, det_ctx, scratch->fw_pkt_policy, p, false);
}
}
return action;
@ -1118,7 +1123,7 @@ static inline void DetectRunPostRules(ThreadVars *tv, const DetectEngineCtx *de_
p->pkt_src == PKT_SRC_WIRE) {
SCLogDebug("packet %" PRIu64 ": default action as no verdict set %02x (pkt %s)",
PcapPacketCntGet(p), p->action, PktSrcToString(p->pkt_src));
(void)DetectRunApplyPacketPolicy(de_ctx, scratch->fw_pkt_policy, p, true);
(void)DetectRunApplyPacketPolicy(de_ctx, det_ctx, scratch->fw_pkt_policy, p, true);
DEBUG_VALIDATE_BUG_ON((p->action & (ACTION_DROP | ACTION_ACCEPT)) == 0);
}
}

View file

@ -934,6 +934,7 @@ struct DetectFirewallAppPolicy {
struct DetectFirewallPolicies {
/** policy for packet_filter, pre_flow, pre_stream hooks */
struct DetectFirewallPolicy pkt[DETECT_FIREWALL_POLICY_SIZE];
Signature *pkt_policy_signatures[DETECT_FIREWALL_POLICY_SIZE];
/* hash table with a Signature object per default policy that has `alert` enabled. */
HashTable *policy_signatures;