diff --git a/doc/userguide/rules/http2-keywords.rst b/doc/userguide/rules/http2-keywords.rst index e9319111a9..548f298cad 100644 --- a/doc/userguide/rules/http2-keywords.rst +++ b/doc/userguide/rules/http2-keywords.rst @@ -20,6 +20,12 @@ http2.frametype Match on the frame type present in a transaction. +http2.frametype uses an :ref:`unsigned 8-bit integer `. + +http2.frametype is also a :ref:`multi-integer `. + +http2.frametype does not have any corresponding log output. + Examples:: http2.frametype:GOAWAY; @@ -67,6 +73,8 @@ http2.window uses an :ref:`unsigned 32-bit integer `. http2.window is also a :ref:`multi-integer `. +http2.window does not have any corresponding log output. + This keyword takes a numeric argument after a colon and supports additional qualifiers, such as: * ``>`` (greater than) diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index f4c1dfda2d..305e76ec44 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -20,7 +20,8 @@ use super::http2::{ }; use super::parser; use crate::detect::uint::{ - detect_match_uint, detect_uint_match_at_index, DetectUintArrayData, DetectUintData, + detect_match_uint, detect_parse_array_uint_enum, detect_uint_match_at_index, + DetectUintArrayData, DetectUintData, }; use crate::direction::Direction; use base64::{engine::general_purpose::STANDARD, Engine}; @@ -30,44 +31,38 @@ use std::rc::Rc; use std::str::FromStr; use suricata_sys::sys::DetectEngineThreadCtx; -fn http2_tx_has_frametype( - tx: &HTTP2Transaction, direction: Direction, value: u8, -) -> std::os::raw::c_int { - if direction == Direction::ToServer { - for i in 0..tx.frames_ts.len() { - if tx.frames_ts[i].header.ftype == value { - return 1; - } - } - } else { - for i in 0..tx.frames_tc.len() { - if tx.frames_tc[i].header.ftype == value { - return 1; - } - } - } - return 0; -} - #[no_mangle] pub unsafe extern "C" fn SCHttp2TxHasFrametype( - tx: *mut std::os::raw::c_void, direction: u8, value: u8, + tx: *mut std::os::raw::c_void, direction: u8, ctx: *const std::os::raw::c_void, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, HTTP2Transaction); - return http2_tx_has_frametype(tx, direction.into(), value); + let ctx = cast_pointer!(ctx, DetectUintArrayData); + let frames = if direction & Direction::ToServer as u8 != 0 { + &tx.frames_ts + } else { + &tx.frames_tc + }; + return detect_uint_match_at_index::( + frames, + ctx, + |f| Some(f.header.ftype), + tx.state >= HTTP2TransactionState::HTTP2StateClosed, + ); } #[no_mangle] pub unsafe extern "C" fn SCHttp2ParseFrametype( str: *const std::os::raw::c_char, -) -> std::os::raw::c_int { +) -> *mut std::os::raw::c_void { let ft_name: &CStr = CStr::from_ptr(str); //unsafe if let Ok(s) = ft_name.to_str() { - if let Ok(x) = parser::HTTP2FrameType::from_str(s) { - return x as i32; + if let Some(ctx) = detect_parse_array_uint_enum::(s) { + let boxed = Box::new(ctx); + // DetectUintArrayData cannot be cbindgend + return Box::into_raw(boxed) as *mut c_void; } } - return -1; + return std::ptr::null_mut(); } fn http2_tx_has_errorcode( diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs index 239d4e942a..0291a75214 100644 --- a/rust/src/http2/parser.rs +++ b/rust/src/http2/parser.rs @@ -35,7 +35,10 @@ use std::rc::Rc; use base64::{Engine, engine::general_purpose::STANDARD_NO_PAD}; #[repr(u8)] +#[derive(EnumStringU8)] #[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)] +// parse GOAWAY, not GO_AWAY +#[suricata(enum_string_style = "UPPERCASE")] pub enum HTTP2FrameType { Data = 0, Headers = 1, @@ -49,34 +52,6 @@ pub enum HTTP2FrameType { Continuation = 9, } -impl fmt::Display for HTTP2FrameType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::str::FromStr for HTTP2FrameType { - type Err = String; - - fn from_str(s: &str) -> Result { - let su = s.to_uppercase(); - let su_slice: &str = &su; - match su_slice { - "DATA" => Ok(HTTP2FrameType::Data), - "HEADERS" => Ok(HTTP2FrameType::Headers), - "PRIORITY" => Ok(HTTP2FrameType::Priority), - "RSTSTREAM" => Ok(HTTP2FrameType::RstStream), - "SETTINGS" => Ok(HTTP2FrameType::Settings), - "PUSHPROMISE" => Ok(HTTP2FrameType::PushPromise), - "PING" => Ok(HTTP2FrameType::Ping), - "GOAWAY" => Ok(HTTP2FrameType::GoAway), - "WINDOWUPDATE" => Ok(HTTP2FrameType::WindowUpdate), - "CONTINUATION" => Ok(HTTP2FrameType::Continuation), - _ => Err(format!("'{}' is not a valid value for HTTP2FrameType", s)), - } - } -} - #[derive(PartialEq, Eq, Debug)] pub struct HTTP2FrameHeader { //we could add detection on (GOAWAY) additional data diff --git a/src/detect-http2.c b/src/detect-http2.c index ae577dd4d6..1b0a3ae125 100644 --- a/src/detect-http2.c +++ b/src/detect-http2.c @@ -110,6 +110,8 @@ void DetectHttp2Register(void) sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch; sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup; sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].flags = + SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_ENUM_UINT; #ifdef UNITTESTS sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests; #endif @@ -132,8 +134,7 @@ void DetectHttp2Register(void) sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch; sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup; sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree; - sigmatch_table[DETECT_HTTP2_PRIORITY].flags = - SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_MULTI_UINT; + sigmatch_table[DETECT_HTTP2_PRIORITY].flags = SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT; #ifdef UNITTESTS sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests; #endif @@ -216,26 +217,7 @@ static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx, const SigMatchCtx *ctx) { - uint8_t *detect = (uint8_t *)ctx; - - return SCHttp2TxHasFrametype(txv, flags, *detect); -} - -static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft) -{ - // first parse numeric value - if (ByteExtractStringUint8(ft, 10, (uint16_t)strlen(str), str) > 0) { - return 1; - } - - // it it failed so far, parse string value from enumeration - int r = SCHttp2ParseFrametype(str); - if (r >= 0 && r <= UINT8_MAX) { - *ft = (uint8_t)r; - return 1; - } - - return 0; + return SCHttp2TxHasFrametype(txv, flags, ctx); } /** @@ -250,24 +232,16 @@ static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft) */ static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) { - uint8_t frame_type; - if (SCDetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) return -1; - if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) { - SCLogError("Invalid argument \"%s\" supplied to http2.frametype keyword.", str); + void *dua8 = SCHttp2ParseFrametype(str); + if (dua8 == NULL) return -1; - } - uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t)); - if (http2ft == NULL) - return -1; - *http2ft = frame_type; - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)http2ft, + if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)dua8, g_http2_match_buffer_id) == NULL) { - DetectHTTP2frametypeFree(NULL, http2ft); + DetectHTTP2frametypeFree(NULL, dua8); return -1; } @@ -281,7 +255,7 @@ static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, con */ void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr) { - SCFree(ptr); + SCDetectU8ArrayFree(ptr); } /**