To be blunt: The current Divert Mode implementation in SSLproxy is a dead end for H2 and H3. While it works for H1, it will never enable Suricata to inspect H2/H3 traffic from SSLproxy without a massive, fragile protocol-translation layer that doesn’t scale.
I’m elevating the urgency of my ICAP proposal from the PreSuriCon webinar. And I suggest another solution to pass decrypted packets to Suricata, instead of my previous suggestion (a new DAQ module with ICAP server support + packet emulation), which had an unnecessary emulation overhead just to satisfy Suricata’s reassembly needs, as I hinted at the webinar.
The new proposal: Once I implement ICAP client support in SSLproxy, we should develop a standalone ICAP server that integrates Suricata as a library.
This avoids the “packet emulation” mess entirely. Instead of pretending to be a network interface to feed Suricata, we use Suricata’s inspection power directly on the stream buffers provided by the ICAP lifecycle.
I realize that Library Mode isn’t fully mature yet (per recent forum discussions like this), but I believe it is the best path forward if we want to support H2/H3 and finally unblock UDP 443.
In summary, I think ICAP and Library Mode seem to be the missing links for modern protocol inspection. What do you think?
For those interested, I have just pushed the h2-divert branch to the GitHub repo of SSLproxy, which contains the PoC code I mention in my LinkedIn article above.
I think the translation to HTTP/1 is an unfortunate design goal, that is not needed for a tool like Suricata to get a lot of value out of H2 support. Suricata supports parsing and tracking HTTP/2 fully (and at high speeds too), so as long as we get the decrypted stream we’re pretty happy. Guess we’d only need some way to get the magic header for the original tuple.
I understand sslproxy has some other goals, esp around the support of the filtering “listening programs”. I think this is why prefixing the http streams with the magic header (as opposed to an inserted http header) was rejected. So I guess there is just a mismatch in use cases.
Wrt the ICAP idea: I would certainly be interested in this. Would this be limited to the HTTP family or also support other TLS based protocols like POP3s and IMAP. I’m currently seeing a lot of value in having decrypt support for generic TLS for the Suricata use case.
Thanks for the feedback. I’d like to clarify a few points from the perspective of an inline IPS deployment:
The h2c vs. h2 Reality: While Suricata can handle h2c, in the wild, virtually all H2 is encrypted (h2). Since IDPS engines cannot inspect the encrypted cipher, we must use a proxy.
Loss of Network Context: Once SSLproxy (or for that matter Blue Coat) decrypts H2, we lose the ability to imitate low-level TCP/TLS anomalies in the diverted path. We are left only with the payload. As I argued in my webinar, content inspection becomes the primary goal once the encryption is stripped.
Inline IPS vs. IDS: My focus is on active inline IPS mode. For simple IDS/logging in split mode, mirroring decrypted H2 from SSLproxy is fine (and it seems like a basic ALPN support to allow for H2 upgrade may be sufficient in Split mode). But for real-time blocking, we need a synchronous path.
The Divert Mode “Dead End” for IPS: Currently, the only way for Suricata to be an active inline IPS for SSLproxy’s diverted H2 traffic is a chain like: Client → SSLproxy → [Divert Socket] → Suricata → Listening Program (lp) → SSLproxy → Server. This is highly inefficient. Using a listening program just to “catch” packets so Suricata can inspect them creates the same overhead/packet-emulation issues I raised in my previous DAQ proposal.
ICAP + Library Mode: This is why I believe the ICAP path is superior for the IPS use case. It allows SSLproxy to hand off the decrypted stream directly to a Suricata-powered service without the “kernel-to-user-to-kernel” bounce of divert sockets.
Regarding other protocols: While ICAP was born for HTTP, it is essentially a “Content Adaptation” framework. I absolutely intend to add ICAP support to POP3s and IMAPs, and in fact to all protocols for content inspection. If we build a Suricata ICAP server (using Library-mode), we could encapsulate any decrypted stream into an ICAP-like PDU (extended ICAP) for inspection.
I’m glad to hear you’re interested in the ICAP/Library mode path—I think it’s the most sustainable way to handle H2 and H3 (QUIC) (H3 in bold, because this solution targets H3 and beyond as well).
[Updated with further improvements and explanations]
The ssl-alpn-h2 branch at the GitHub repo of SSLproxy implements basic ALPN support for HTTP/2 upgrade.
The changes support both Divert and Split modes, so Suricata can run as active inline IPS and just IDS, respectively.
Both https and ssl proxyspecs can be used. The https proxyspec can filter and verify decrypted H1 traffic, but directly passes decrypted H2 traffic.
The verify_h2_gateway.sh script uses divert mode to demonstrate how Suricata IPS can inspect h2 traffic inline with lp. It can be edited to use split mode just by removing the up:9080 specification.
The script records decrypted h2 traffic into h2.pcap, which can be fed into Suricata. Wireshark does not recognize the TCP flow as h2, unless forced to with the Decode As option.
The mirroring option should work as well, but not tested.
The following is copy-pasted directly from the Follow HTTP2 Stream window of Wireshark, showing decrypted h2 contents recorded into h2.pcap in split mode:
:method: GET
:scheme: https
:authority: 127.0.0.1:8080
:path: /
user-agent: curl/8.5.0
accept: */*
:status: 404
server: nghttpd nghttp2/1.59.0
date: Sat, 14 Feb 2026 15:18:16 GMT
content-type: text/html; charset=UTF-8
content-length: 148
<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1><hr><address>nghttpd nghttp2/1.59.0 at port 10443</address></body></html>
Thanks Victor for testing. I’m glad it works with Suricata too. It would be great if you could try active inline IPS mode too, if you can.
I am working on how to match protocols selected by ALPN negotiation on both sides of SSLproxy (client ↔ SSLproxy and SSLproxy ↔ server), and what to do if they don’t match. It’s still PoC level code, hence currently does not support auto protocol selection between h2 and http1.1, even if so advertised during ALPN negotiation.
My tests are with inline mode. Sslproxy uses the lp test program and Suricata sits between them using NFQ. This is my concept of active inline IPS mode. If you mean something different by it, please let me know.
I’m seeing some connections not working, but I can’t say yet if that is a SSLproxy issue or a Suricata issue. Will try to dig into that.
I’d suggest enabling the DEBUG_PROXY switch in Mk/main.mk, which should be already enabled in the ssl-alpn-h2 branch, and then starting sslproxy with the -D4 option, as in the verify_h2_gateway.sh script. sslproxy produces very verbose debug logs with -D4.
I’m just guessing that the ubuntu update servers do not support h2, but sslproxy cannot enable http1.1. I think that the ssl-alpn-h2 branch works properly with h2 only (well, properly for a PoC code).
I am working exactly on how to manage this alpn negotiation on both sides (my current target is to update the ClientHello parser to return the ALPN protocols too).
Can you test the latest commit on the ssl-alpn-h2 branch please? I think these changes fix the issues you are seeing.
I have implemented proper ALPN negotiation on both sides, which tries to match client’s protocols with server’s, if there is no overlap, the connection is closed by server. See the commit message for details.
It seems to work better, but I’m still seeing quite a few timeouts/stalls in various places. But should run master for a bit as well to see if it is related to the h2 branch or something else.
Ah, that’s good news, because the issues in those logs are related with certificate verification, not with the ssl-alpn-h2 branch (which I have updated recently again btw).
Those SSL errors mean that you have not installed the CA certificate you use with SSLproxy into all of the trusted cert stores on the system or the web browsers or perhaps other software. Note that they may all be using different cert stores, in fact Firefox and Chrome/Brave do use different cert stores. If those errors are due to apt, that’s probably the system cert store.
In short, you need to install the CA cert of SSLproxy into all such cert stores.