diff --git a/rust/src/mqtt/detect.rs b/rust/src/mqtt/detect.rs index 98d0d86131..6f773f1802 100644 --- a/rust/src/mqtt/detect.rs +++ b/rust/src/mqtt/detect.rs @@ -19,8 +19,9 @@ use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; use crate::detect::uint::{ - detect_match_uint, detect_parse_array_uint_enum, detect_parse_uint, detect_uint_match_at_index, - DetectUintArrayData, DetectUintData, DetectUintMode, SCDetectU8Free, SCDetectU8Parse, + detect_match_uint, detect_parse_array_uint_enum, detect_parse_uint_bitflags, + detect_uint_match_at_index, DetectUintArrayData, DetectUintData, SCDetectU8Free, + SCDetectU8Parse, }; use crate::detect::{ helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer, @@ -34,12 +35,6 @@ use suricata_sys::sys::{ SCSigTableAppLiteElmt, SigMatchCtx, Signature, }; -use nom7::branch::alt; -use nom7::bytes::complete::{is_a, tag}; -use nom7::combinator::{opt, value}; -use nom7::multi::many1; -use nom7::IResult; - use super::mqtt::{MQTTState, MQTTTransaction, ALPROTO_MQTT}; use crate::conf::conf_get; use crate::mqtt::mqtt_message::{MQTTMessage, MQTTOperation, MQTTTypeCode}; @@ -672,56 +667,11 @@ unsafe extern "C" fn mqtt_protocol_version_free(_de: *mut DetectEngineCtx, ctx: SCDetectU8Free(ctx); } -// maybe to factor with websocket.flags -struct MqttParsedFlagItem { - neg: bool, - value: u8, -} - -fn parse_flag_list_item(s: &str) -> IResult<&str, MqttParsedFlagItem> { - let (s, _) = opt(is_a(" "))(s)?; - let (s, neg) = opt(tag("!"))(s)?; - let neg = neg.is_some(); - let (s, value) = alt((value(0x8, tag("dup")), value(0x1, tag("retain"))))(s)?; - let (s, _) = opt(is_a(" ,"))(s)?; - Ok((s, MqttParsedFlagItem { neg, value })) -} - -fn parse_flag_list(s: &str) -> IResult<&str, Vec> { - return many1(parse_flag_list_item)(s); -} - -fn parse_flags(s: &str) -> Option> { - // try first numerical value - if let Ok((_, ctx)) = detect_parse_uint::(s) { - return Some(ctx); - } - // otherwise, try strings for bitmask - if let Ok((rem, l)) = parse_flag_list(s) { - if !rem.is_empty() { - SCLogWarning!("junk at the end of mqtt.flags"); - return None; - } - let mut arg1 = 0; - let mut arg2 = 0; - for elem in l.iter() { - if elem.value & arg1 != 0 { - SCLogWarning!("Repeated bitflag for mqtt.flags"); - return None; - } - arg1 |= elem.value; - if !elem.neg { - arg2 |= elem.value; - } - } - let ctx = DetectUintData:: { - arg1, - arg2, - mode: DetectUintMode::DetectUintModeBitmask, - }; - return Some(ctx); - } - return None; +#[repr(u8)] +#[derive(EnumStringU8)] +pub enum MqttFlag { + Dup = 0x8, + Retain = 0x1, } unsafe extern "C" fn mqtt_parse_flags( @@ -729,7 +679,7 @@ unsafe extern "C" fn mqtt_parse_flags( ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe if let Ok(s) = ft_name.to_str() { - if let Some(ctx) = parse_flags(s) { + if let Some(ctx) = detect_parse_uint_bitflags::(s) { let boxed = Box::new(ctx); return Box::into_raw(boxed) as *mut _; } @@ -792,57 +742,15 @@ unsafe extern "C" fn mqtt_flags_free(_de: *mut DetectEngineCtx, ctx: *mut c_void SCDetectU8Free(ctx); } -fn parse_conn_flag_list_item(s: &str) -> IResult<&str, MqttParsedFlagItem> { - let (s, _) = opt(is_a(" "))(s)?; - let (s, neg) = opt(tag("!"))(s)?; - let neg = neg.is_some(); - let (s, value) = alt(( - value(0x80, tag("username")), - value(0x40, tag("password")), - // longer version first - value(0x4, tag("will_retain")), - value(0x20, tag("will")), - value(0x2, tag("clean_session")), - ))(s)?; - let (s, _) = opt(is_a(" ,"))(s)?; - Ok((s, MqttParsedFlagItem { neg, value })) -} - -fn parse_conn_flag_list(s: &str) -> IResult<&str, Vec> { - return many1(parse_conn_flag_list_item)(s); -} - -fn parse_conn_flags(s: &str) -> Option> { - // try first numerical value - if let Ok((_, ctx)) = detect_parse_uint::(s) { - return Some(ctx); - } - // otherwise, try strings for bitmask - if let Ok((rem, l)) = parse_conn_flag_list(s) { - if !rem.is_empty() { - SCLogWarning!("junk at the end of mqtt.connect.flags"); - return None; - } - let mut arg1 = 0; - let mut arg2 = 0; - for elem in l.iter() { - if elem.value & arg1 != 0 { - SCLogWarning!("Repeated bitflag for mqtt.connect.flags"); - return None; - } - arg1 |= elem.value; - if !elem.neg { - arg2 |= elem.value; - } - } - let ctx = DetectUintData:: { - arg1, - arg2, - mode: DetectUintMode::DetectUintModeBitmask, - }; - return Some(ctx); - } - return None; +#[repr(u8)] +#[derive(EnumStringU8)] +#[allow(non_camel_case_types)] +pub enum MqttConnFlag { + Username = 0x80, + Password = 0x40, + Will = 0x20, + Will_retain = 0x4, + Clean_session = 0x2, } unsafe extern "C" fn mqtt_parse_conn_flags( @@ -850,7 +758,7 @@ unsafe extern "C" fn mqtt_parse_conn_flags( ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe if let Ok(s) = ft_name.to_str() { - if let Some(ctx) = parse_conn_flags(s) { + if let Some(ctx) = detect_parse_uint_bitflags::(s) { let boxed = Box::new(ctx); return Box::into_raw(boxed) as *mut _; } @@ -1283,49 +1191,60 @@ mod test { #[test] fn mqtt_parse_flags() { - let ctx = parse_flags("retain").unwrap(); + let ctx = detect_parse_uint_bitflags::("retain").unwrap(); assert_eq!(ctx.arg1, 1); assert_eq!(ctx.arg2, 1); - let ctx = parse_flags("dup").unwrap(); + let ctx = detect_parse_uint_bitflags::("dup").unwrap(); assert_eq!(ctx.arg1, 8); assert_eq!(ctx.arg2, 8); - let ctx = parse_flags("retain,dup").unwrap(); + let ctx = detect_parse_uint_bitflags::("retain,dup").unwrap(); assert_eq!(ctx.arg1, 8 | 1); assert_eq!(ctx.arg2, 8 | 1); - let ctx = parse_flags("dup, retain").unwrap(); + let ctx = detect_parse_uint_bitflags::("dup, retain").unwrap(); assert_eq!(ctx.arg1, 8 | 1); assert_eq!(ctx.arg2, 8 | 1); - let ctx = parse_flags("retain,!dup").unwrap(); + let ctx = detect_parse_uint_bitflags::("retain,!dup").unwrap(); assert_eq!(ctx.arg1, 1 | 8); assert_eq!(ctx.arg2, 1); - assert!(parse_flags("ref").is_none()); - assert!(parse_flags("dup,!").is_none()); - assert!(parse_flags("dup,!dup").is_none()); - assert!(parse_flags("!retain,retain").is_none()); + assert!(detect_parse_uint_bitflags::("ref").is_none()); + assert!(detect_parse_uint_bitflags::("dup,!").is_none()); + assert!(detect_parse_uint_bitflags::("dup,!dup").is_none()); + assert!(detect_parse_uint_bitflags::("!retain,retain").is_none()); } #[test] fn mqtt_parse_conn_flags() { - let ctx = parse_conn_flags("username").unwrap(); + let ctx = detect_parse_uint_bitflags::("username").unwrap(); assert_eq!(ctx.arg1, 0x80); assert_eq!(ctx.arg2, 0x80); - let ctx = parse_conn_flags("username,password,will,will_retain,clean_session").unwrap(); + let ctx = detect_parse_uint_bitflags::( + "username,password,will,will_retain,clean_session", + ) + .unwrap(); assert_eq!(ctx.arg1, 0xE6); assert_eq!(ctx.arg2, 0xE6); - let ctx = - parse_conn_flags("!username,!password,!will,!will_retain,!clean_session").unwrap(); + let ctx = detect_parse_uint_bitflags::( + "!username,!password,!will,!will_retain,!clean_session", + ) + .unwrap(); assert_eq!(ctx.arg1, 0xE6); assert_eq!(ctx.arg2, 0); - let ctx = parse_conn_flags(" username,password").unwrap(); + let ctx = detect_parse_uint_bitflags::(" username,password").unwrap(); assert_eq!(ctx.arg1, 0xC0); assert_eq!(ctx.arg2, 0xC0); - assert!(parse_conn_flags("foobar").is_none()); - assert!(parse_conn_flags("will,!").is_none()); - assert!(parse_conn_flags("").is_none()); - assert!(parse_conn_flags("username, username").is_none()); - assert!(parse_conn_flags("!username, username").is_none()); - assert!(parse_conn_flags("!username,password,!password").is_none()); - assert!(parse_conn_flags("will, username,password, !will, will").is_none()); + assert!(detect_parse_uint_bitflags::("foobar").is_none()); + assert!(detect_parse_uint_bitflags::("will,!").is_none()); + assert!(detect_parse_uint_bitflags::("").is_none()); + assert!(detect_parse_uint_bitflags::("username, username").is_none()); + assert!(detect_parse_uint_bitflags::("!username, username").is_none()); + assert!( + detect_parse_uint_bitflags::("!username,password,!password") + .is_none() + ); + assert!(detect_parse_uint_bitflags::( + "will, username,password, !will, will" + ) + .is_none()); } #[test]