From c9ca1a4fbaf3349c766829f322b7f8baf11bb1da Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Sun, 30 Aug 2026 22:29:52 +0200 Subject: [PATCH] doh2: handle http1->http2->doh2 upgrade in one packet Ticket: 8973 Before that, the update to DoH2 happened before http1 state was freed, leading to a type confusion. In case of a HTTP1->HTTP2 upgrade, if the client sends a DOH2 request, Suricata went to change again the flow's alproto with SCAppLayerForceProtocolChange But SCAppLayerForceProtocolChange did not take into account the fact that we were doing a HTTP1->HTTP2 upgrade, and the previous HTTP1 state was not freed yet. Now SCAppLayerForceProtocolChange checks FlowChangeProto and update alproto_orig only if we were not doing a proto change already, as alproto_orig is used to know which type of state to free. --- src/app-layer-detect-proto.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 3f8cfb231b..30031f694b 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1884,7 +1884,14 @@ bool SCAppLayerRequestProtocolTLSUpgrade(Flow *f) void SCAppLayerForceProtocolChange(Flow *f, AppProto new_proto) { if (new_proto != f->alproto) { - f->alproto_orig = f->alproto; + if (!FlowChangeProto(f)) { + // may happen when changing protocol from http1 to http2, then doh2 + // We need to keep the original alproto, as HTTP1 state was not freed yet + f->alproto_orig = f->alproto; + } else if (f->alproto == f->alproto_expect) { + // First change went as expected + f->alproto_expect = new_proto; + } f->alproto = new_proto; f->alproto_ts = f->alproto; f->alproto_tc = f->alproto;