firewall: support multi-action statements in rules

For firewall rules, allow multiple actions to be specified in a list

        accept:flow,pass:flow,alert
        accept:flow,alert
        accept:flow,pass:flow

It is mandatory to make the first action the primary firewall policy
action: accept, drop, reject.

Ticket: #8480.
(cherry picked from commit e76728a536)
pull/15572/head
Victor Julien 5 months ago
parent c17728c5e7
commit 1fb2f0bfa3

@ -160,8 +160,20 @@ static inline void RuleActionToFlow(const uint8_t action, Flow *f)
SCLogDebug("setting flow action pass");
}
// TODO pass and accept could be set at the same time?
if (action & (ACTION_DROP | ACTION_REJECT_ANY | ACTION_PASS)) {
/* pass:flow can be set if accept:flow is present */
if (action & ACTION_PASS) {
if (f->flags & (FLOW_ACTION_DROP | FLOW_ACTION_PASS)) {
/* drop or pass already set. First to set wins. */
SCLogDebug("not setting %s flow already set to %s",
(action & ACTION_PASS) ? "pass" : "drop",
(f->flags & FLOW_ACTION_DROP) ? "drop" : "pass");
} else {
f->flags |= FLOW_ACTION_PASS;
SCLogDebug("setting flow action pass");
}
// TODO firewall drop:flow should override FLOW_ACTION_PASS
} else if (action & (ACTION_DROP | ACTION_REJECT_ANY)) {
if (f->flags & (FLOW_ACTION_DROP | FLOW_ACTION_PASS | FLOW_ACTION_ACCEPT)) {
/* drop or pass already set. First to set wins. */
SCLogDebug("not setting %s flow already set to %s",
@ -172,10 +184,6 @@ static inline void RuleActionToFlow(const uint8_t action, Flow *f)
f->flags |= FLOW_ACTION_DROP;
SCLogDebug("setting flow action drop");
}
if (action & ACTION_PASS) {
f->flags |= FLOW_ACTION_PASS;
SCLogDebug("setting flow action pass");
}
}
}
}
@ -217,10 +225,7 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac
DEBUG_VALIDATE_BUG_ON(!PacketCheckAction(p, ACTION_DROP));
} else {
if (pa->action & ACTION_PASS) {
SCLogDebug("[packet %p][PASS sid %u]", p, s->id);
// nothing to set in the packet
} else if (pa->action & ACTION_ACCEPT) {
if (pa->action & ACTION_ACCEPT) {
const enum ActionScope as = pa->s->action_scope;
SCLogDebug("packet %" PRIu64 ": ACCEPT %u as:%u flags:%02x", p->pcap_cnt, s->id, as,
pa->flags);
@ -231,6 +236,9 @@ static void PacketApplySignatureActions(Packet *p, const Signature *s, const Pac
}
} else if (pa->action & (ACTION_ALERT | ACTION_CONFIG)) {
// nothing to set in the packet
} else if (pa->action & ACTION_PASS) {
SCLogDebug("[packet %p][PASS sid %u]", p, s->id);
// nothing to set in the packet
} else if (pa->action != 0) {
DEBUG_VALIDATE_BUG_ON(1); // should be unreachable
}

@ -1553,7 +1553,7 @@ static uint8_t ActionStringToFlags(const char *action)
* Signature.
* \retval -1 On failure.
*/
static int SigParseAction(Signature *s, const char *action_in)
static int SigParseActionDo(Signature *s, const char *action_in, const int idx)
{
char action[32];
strlcpy(action, action_in, sizeof(action));
@ -1576,6 +1576,23 @@ static int SigParseAction(Signature *s, const char *action_in)
if (flags == 0)
return -1;
if (s->init_data->firewall_rule) {
if (idx == 0 &&
!(flags & (ACTION_ACCEPT | ACTION_DROP | ACTION_REJECT_ANY | ACTION_CONFIG))) {
SCLogError("only accept, config, drop and reject actions allowed as primary action "
"firewall "
"rules");
return -1;
}
if (idx > 0 &&
(flags & (ACTION_ACCEPT | ACTION_DROP | ACTION_REJECT_ANY | ACTION_CONFIG))) {
SCLogError("accept, config, drop and reject actions not allowed as secondary action "
"firewall "
"rules");
return -1;
}
}
/* parse scope, if any */
if (o) {
uint8_t scope_flags = 0;
@ -1590,7 +1607,6 @@ static int SigParseAction(Signature *s, const char *action_in)
o, action_in);
return -1;
}
s->action_scope = scope_flags;
} else if (flags & (ACTION_ACCEPT)) {
if (strcmp(o, "packet") == 0) {
scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
@ -1607,7 +1623,6 @@ static int SigParseAction(Signature *s, const char *action_in)
o, action_in);
return -1;
}
s->action_scope = scope_flags;
} else if (flags & (ACTION_CONFIG)) {
if (strcmp(o, "packet") == 0) {
scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
@ -1616,13 +1631,17 @@ static int SigParseAction(Signature *s, const char *action_in)
action_in);
return -1;
}
s->action_scope = scope_flags;
} else {
SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
"'drop', 'pass' and 'reject'",
o, action_in);
return -1;
}
if (s->action_scope != 0 && s->action_scope != scope_flags) {
SCLogError("multi-action rules cannot use different action scopes");
return -1;
}
s->action_scope = scope_flags;
}
/* require explicit action scope for fw rules */
@ -1635,14 +1654,37 @@ static int SigParseAction(Signature *s, const char *action_in)
SCLogError("'accept' action only supported for firewall rules");
return -1;
}
s->action |= flags;
return 0;
}
if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
SCLogError("'pass' action not supported for firewall rules");
return -1;
static int SigParseAction(Signature *s, const char *action_in)
{
/* multi-action rules are only supported for firewall rules at this time. */
if (!s->init_data->firewall_rule)
return SigParseActionDo(s, action_in, 0);
int r = 0;
char *copy = SCStrdup(action_in);
if (copy == NULL)
FatalError("could not duplicate opt string");
int i = 0;
char *xsaveptr = NULL;
char *a = strtok_r(copy, ",", &xsaveptr);
while (a != NULL) {
if (SigParseActionDo(s, a, i) < 0) {
r = -1;
break;
}
a = strtok_r(NULL, ",", &xsaveptr);
i++;
}
s->action = flags;
return 0;
SCFree(copy);
SCLogDebug("s->action %02x", s->action);
return r;
}
/**

Loading…
Cancel
Save