diff --git a/doc/userguide/firewall/firewall-design.rst b/doc/userguide/firewall/firewall-design.rst index d3f5cfb475..0849e36891 100644 --- a/doc/userguide/firewall/firewall-design.rst +++ b/doc/userguide/firewall/firewall-design.rst @@ -122,6 +122,11 @@ alert action in firewall rules. The effect will be the creation of an alert event when the firewall rule matches. +For application layer transactions the alert event carries a ``firewall`` object with +the resolved ``policy`` and, when the protocol registers a state name callback, the +``hook`` the rule was registered at. Protocols without such a callback (``quic``, +``modbus``, ``rdp``) omit the ``hook`` key; the policy is still reported. + config ~~~~~~ diff --git a/src/detect-parse.c b/src/detect-parse.c index 714a7de33f..abd3ae60e2 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1575,6 +1575,8 @@ static int SigParseProtoHookApp( s->init_data->hook.t.app.app_progress); s->app_progress_hook = s->init_data->hook.t.app.app_progress; + /* the hook parser only accepts known sub states of the protocol */ + s->sub_state = s->init_data->hook.t.app.sub_state; return 0; } @@ -4187,6 +4189,7 @@ static int AddAppPolicySignature(struct DetectFirewallAppPolicy *pol) return -1; } s->app_progress_hook = pol->progress; + s->sub_state = pol->sub_state; s->action = pol->policy.action; s->action_scope = pol->policy.action_scope; s->alproto = pol->alproto; diff --git a/src/detect.h b/src/detect.h index 075ce7564c..e688529af7 100644 --- a/src/detect.h +++ b/src/detect.h @@ -727,6 +727,10 @@ typedef struct Signature_ { /** firewall: progress value for this signature */ uint8_t app_progress_hook; + /** firewall: sub state (transaction type) of the hook on protocols with sub + * states (http2 stream/global, DoH2); 0 when the hook has no sub state. + * Signatures are zero initialized, so unused stays 0. */ + uint8_t sub_state; DetectMatchAddressIPv4 *addr_dst_match4; DetectMatchAddressIPv4 *addr_src_match4; diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 6937c4933a..5837f63a09 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -662,20 +662,35 @@ static void AlertJsonAddFirewall(SCJsonBuilder *jb, const Signature *s) const char *hook = NULL; char hook_string[256]; switch (s->detect_table) { - case DETECT_TABLE_APP_FILTER: - if (s->flags & SIG_FLAG_TOSERVER) { - hook = AppLayerParserGetStateNameById( - IPPROTO_TCP, s->alproto, s->app_progress_hook, STREAM_TOSERVER); - } else { - hook = AppLayerParserGetStateNameById( - IPPROTO_TCP, s->alproto, s->app_progress_hook, STREAM_TOCLIENT); + case DETECT_TABLE_APP_FILTER: { + const uint8_t dir_flag = + (s->flags & SIG_FLAG_TOSERVER) ? STREAM_TOSERVER : STREAM_TOCLIENT; + if (s->sub_state != 0 && AppLayerParserSupportsSubStates(s->alproto)) { + /* sub state rules (http2 stream/global): resolve the state in + * the sub state table and keep the sub state in the name */ + const char *state = AppLayerParserGetSubStateProgressName( + s->alproto, s->sub_state, s->app_progress_hook, dir_flag); + const char *sub_state_name = + AppLayerParserGetSubStateName(s->alproto, s->sub_state); + if (state != NULL && sub_state_name != NULL) { + snprintf(hook_string, sizeof(hook_string), "%s:%s:%s", + AppProtoToString(s->alproto), sub_state_name, state); + hook = hook_string; + } } - if (hook) { - snprintf(hook_string, sizeof(hook_string), "%s:%s", AppProtoToString(s->alproto), - hook); - hook = hook_string; + if (hook == NULL) { + /* no sub state, or the sub state lookup failed: fall back to + * the plain per-protocol state name */ + hook = AppLayerParserGetStateNameById( + IPPROTO_TCP, s->alproto, s->app_progress_hook, dir_flag); + if (hook != NULL) { + snprintf(hook_string, sizeof(hook_string), "%s:%s", + AppProtoToString(s->alproto), hook); + hook = hook_string; + } } break; + } case DETECT_TABLE_PACKET_FILTER: hook = "packet:filter"; break;