Feature #8386
openTask #8388: firewall: support protocol hooks for all app-layer protocols
firewall: support HTTP2 hook states for per-frame accept/drop decisions
Description
Firewall mode currently supports the full HTTP1 hook chain ( request_started , request_line , request_headers , request_body , request_trailer , request_complete , and corresponding response*_ hooks), enabling granular per-stage accept/drop decisions on HTTP1 traffic.
HTTP2 has no equivalent intermediate hooks registered. Only request_started , request_complete , response_started , and response_complete are recognized. Rules referencing any other http2:* hook fail at load time.
HTTP2's frame-based multiplexed protocol has its own natural hook points that differ from HTTP1's sequential model. Potential hook states that align with the HTTP2 state machine include:- Connection preface sent/received
- SETTINGS frame sent/received/ACK
- Stream opened
- HEADERS frame sent/received
- DATA frame transfer
- Stream half-closed
- Stream closed
- RST_STREAM received
- GOAWAY sent/received
- PING sent/ACK
- WINDOW_UPDATE
- PRIORITY
- Connection closed
At minimum, we need hooks at the HEADERS and DATA frame stages to support the most common firewall use cases (URI-based filtering on HEADERS, content inspection on DATA). Ideally the hook model would also expose stream lifecycle events (stream opened, half-closed, closed, RST_STREAM) to allow firewall rules to make decisions on stream state transitions, and connection-level events (GOAWAY, connection closed) for connection-level policy.
Evidence
The test attempts to use HTTP2 hooks mirroring the HTTP1 per-hook pattern ( ruletype-firewall-16-http-per-hook ). Rules tested:
accept:hook tcp:all any any -> any any (sid:100;) accept:hook http2:request_started any any -> any any (sid:201;) accept:hook http2:request_headers any any -> any any (http.uri; content:"/doc/manual/html/index.html"; sid:202;) accept:hook http2:request_body any any -> any any (sid:203;) accept:hook http2:request_complete any any -> any any (sid:204;) accept:hook http2:response_started any any -> any any (sid:301;) accept:hook http2:response_headers any any -> any any (sid:302;) accept:hook http2:response_body any any -> any any (sid:303;) accept:hook http2:response_complete any any -> any any (sid:304;)
On Suricata 8.0.4, the engine exits with errors:
Error: detect-parse: protocol "http2" does not support hook "request_headers" Error: detect-parse: protocol "http2" does not support hook "request_body" Error: detect-parse: protocol "http2" does not support hook "response_headers" Error: detect-parse: protocol "http2" does not support hook "response_body"
Expected behavior:
HTTP2 should register hook states that map to its frame-based protocol, at minimum covering HEADERS and DATA frames, so firewall rules can make per-frame accept/drop decisions on HTTP2 traffic. The test expects all http2:* rules to load and HTTP2 traffic to be processed through the hook chain rather than falling through to the default drop policy.
Files
VJ Updated by Victor Julien about 2 months ago
- Subject changed from Firewall mode: Register HTTP2 hook states for per-frame accept/drop decisions to firewall: supprt HTTP2 hook states for per-frame accept/drop decisions
VJ Updated by Victor Julien about 2 months ago
- Subject changed from firewall: supprt HTTP2 hook states for per-frame accept/drop decisions to firewall: support HTTP2 hook states for per-frame accept/drop decisions
- Target version changed from TBD to 9.0.0-beta1
VJ Updated by Victor Julien about 2 months ago
- Parent task set to #8388
JI Updated by Jason Ish about 1 month ago
- Related to Bug #8451: http2: http.host does not match as soon as possible added
VJ Updated by Victor Julien 5 days ago
- Related to Optimization #8518: http2: for stream based tx, split progress handling per direction added
VJ Updated by Victor Julien 5 days ago ยท Edited
We discussed this today at our team meeting, and it seems there is some unexpected complexity. In our HTTP/2 implementation there are essentially 3 different transaction types that all share a single state machine. This won't translate very well to our hook based model.
The transaction types are: stream (http like request/responses), control (settings, ping, etc), push (server initiated comms).
One idea is that we would need to split these tx types to have their own state machines and hook names.
Something like
http2:control:client_in_progress http2:control:client_complete http2:stream:request_data http2:push:server_in_progress
This will require some more thought and discussion.