From 029cc968c8c78b4e8c2d6cc3596fb06004c4d447 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 18 Feb 2026 21:22:01 +0100 Subject: [PATCH] detect/http2: use ThreadCtx for http.request_header And also for http.response_header Instead of custom inefficient "escaped" Vec Ticket: 8291 (cherry picked from commit 4e538dfa3baa06456365ce53109c03ef6a6ab798) --- rust/src/http2/detect.rs | 43 ++++++++++++++++++++++++++++++---------- src/detect-http-header.c | 26 ++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index d24d0c490b..e242f38462 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -763,7 +763,8 @@ pub unsafe extern "C" fn SCHttp2TxGetHeaderNames( tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, Http2ThreadBuf); - tbuf.data = vec![b'\r', b'\n']; + tbuf.data.clear(); + tbuf.data.extend_from_slice(b"\r\n"); let frames = if direction & Direction::ToServer as u8 != 0 { &tx.frames_ts } else { @@ -826,7 +827,7 @@ pub unsafe extern "C" fn SCHttp2TxGetHeaders( tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, Http2ThreadBuf); - tbuf.data = Vec::new(); + tbuf.data.clear(); let frames = if direction & Direction::ToServer as u8 != 0 { &tx.frames_ts } else { @@ -860,7 +861,7 @@ pub unsafe extern "C" fn SCHttp2TxGetHeadersRaw( tbuf: *mut c_void, ) -> u8 { let tbuf = cast_pointer!(tbuf, Http2ThreadBuf); - tbuf.data = Vec::new(); + tbuf.data.clear(); let frames = if direction & Direction::ToServer as u8 != 0 { &tx.frames_ts } else { @@ -885,22 +886,42 @@ pub unsafe extern "C" fn SCHttp2TxGetHeadersRaw( return 0; } +#[derive(Default)] +struct Http2ThreadMultiBuf { + data: Vec>, +} + +#[no_mangle] +pub unsafe extern "C" fn SCHttp2ThreadMultiBufDataInit(_cfg: *mut c_void) -> *mut c_void { + let boxed = Box::new(Http2ThreadMultiBuf::default()); + return Box::into_raw(boxed) as *mut c_void; +} + +#[no_mangle] +pub unsafe extern "C" fn SCHttp2ThreadMultiBufDataFree(ctx: *mut c_void) { + std::mem::drop(Box::from_raw(ctx as *mut Http2ThreadMultiBuf)); +} + #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeader( - _de: *mut DetectEngineThreadCtx, tx: *const c_void, direction: u8, nb: u32, - buffer: *mut *const u8, buffer_len: *mut u32, + tbuf: *mut c_void, tx: *const c_void, direction: u8, nb: u32, buffer: *mut *const u8, + buffer_len: *mut u32, ) -> bool { + let tbuf = cast_pointer!(tbuf, Http2ThreadMultiBuf); let tx = cast_pointer!(tx, HTTP2Transaction); let mut pos = 0_u32; + if nb == 0 { + tbuf.data.clear(); + } match direction.into() { Direction::ToServer => { for i in 0..tx.frames_ts.len() { if let Some(blocks) = http2_header_blocks(&tx.frames_ts[i]) { if nb < pos + blocks.len() as u32 { let ehdr = http2_escape_header(blocks, nb - pos); - tx.escaped.push(ehdr); - let idx = tx.escaped.len() - 1; - let value = &tx.escaped[idx]; + tbuf.data.push(ehdr); + let idx = tbuf.data.len() - 1; + let value = &tbuf.data[idx]; *buffer = value.as_ptr(); //unsafe *buffer_len = value.len() as u32; return true; @@ -915,9 +936,9 @@ pub unsafe extern "C" fn SCHttp2TxGetHeader( if let Some(blocks) = http2_header_blocks(&tx.frames_tc[i]) { if nb < pos + blocks.len() as u32 { let ehdr = http2_escape_header(blocks, nb - pos); - tx.escaped.push(ehdr); - let idx = tx.escaped.len() - 1; - let value = &tx.escaped[idx]; + tbuf.data.push(ehdr); + let idx = tbuf.data.len() - 1; + let value = &tbuf.data[idx]; *buffer = value.as_ptr(); //unsafe *buffer_len = value.len() as u32; return true; diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 54d27b58cc..c1a41dae57 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -465,6 +465,8 @@ static int g_http_request_header_buffer_id = 0; static int g_http_response_header_buffer_id = 0; static int g_request_header_thread_id = 0; static int g_response_header_thread_id = 0; +static int g_h2_request_header_thread_id = 0; +static int g_h2_response_header_thread_id = 0; typedef struct HttpMultiBufItem { uint8_t *buffer; @@ -503,6 +505,22 @@ static void HttpMultiBufHeaderThreadDataFree(void *data) SCFree(td); } +static bool GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx, const void *txv, const uint8_t flags, + uint32_t local_id, const uint8_t **buf, uint32_t *buf_len) +{ + int kw_thread_id; + if (flags & STREAM_TOSERVER) { + kw_thread_id = g_h2_request_header_thread_id; + } else { + kw_thread_id = g_h2_response_header_thread_id; + } + void *hdr_td = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, kw_thread_id); + if (unlikely(hdr_td == NULL)) { + return false; + } + return SCHttp2TxGetHeader(hdr_td, txv, flags, local_id, buf, buf_len); +} + static bool GetHttp1HeaderData(DetectEngineThreadCtx *det_ctx, const void *txv, const uint8_t flags, uint32_t local_id, const uint8_t **buf, uint32_t *buf_len) { @@ -598,7 +616,7 @@ void DetectHttpRequestHeaderRegister(void) SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; DetectAppLayerMultiRegister("http_request_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateOpen, SCHttp2TxGetHeader, 2); + HTTP2StateOpen, GetHttp2HeaderData, 2); DetectAppLayerMultiRegister("http_request_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, HTP_REQUEST_PROGRESS_HEADERS, GetHttp1HeaderData, 2); @@ -607,6 +625,8 @@ void DetectHttpRequestHeaderRegister(void) DetectBufferTypeSupportsMultiInstance("http_request_header"); g_request_header_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_request_header", HttpMultiBufHeaderThreadDataInit, NULL, HttpMultiBufHeaderThreadDataFree); + g_h2_request_header_thread_id = DetectRegisterThreadCtxGlobalFuncs("http2_request_header", + SCHttp2ThreadMultiBufDataInit, NULL, SCHttp2ThreadMultiBufDataFree); } static int DetectHTTPResponseHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) @@ -631,7 +651,7 @@ void DetectHttpResponseHeaderRegister(void) SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; DetectAppLayerMultiRegister("http_response_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateOpen, SCHttp2TxGetHeader, 2); + HTTP2StateOpen, GetHttp2HeaderData, 2); DetectAppLayerMultiRegister("http_response_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, HTP_RESPONSE_PROGRESS_HEADERS, GetHttp1HeaderData, 2); @@ -640,6 +660,8 @@ void DetectHttpResponseHeaderRegister(void) DetectBufferTypeSupportsMultiInstance("http_response_header"); g_response_header_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_response_header", HttpMultiBufHeaderThreadDataInit, NULL, HttpMultiBufHeaderThreadDataFree); + g_h2_response_header_thread_id = DetectRegisterThreadCtxGlobalFuncs("http2_response_header", + SCHttp2ThreadMultiBufDataInit, NULL, SCHttp2ThreadMultiBufDataFree); } /************************************Unittests*********************************/