diff --git a/doc/userguide/rules/mqtt-keywords.rst b/doc/userguide/rules/mqtt-keywords.rst index 36133b20840b..211ccf75d90a 100644 --- a/doc/userguide/rules/mqtt-keywords.rst +++ b/doc/userguide/rules/mqtt-keywords.rst @@ -46,10 +46,13 @@ Valid values are : where ``UNASSIGNED`` refers to message type code 0. +mqtt.type uses an :ref:`unsigned 8-bits integer `. + Examples:: mqtt.type:CONNECT; mqtt.type:PUBLISH; + mqtt.type:2; mqtt.flags @@ -57,6 +60,8 @@ mqtt.flags Match on a combination of MQTT header flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match. +mqtt.flags uses an :ref:`unsigned 8-bits integer ` + Valid flags are: * ``dup`` (duplicate message) @@ -89,6 +94,8 @@ mqtt.reason_code Match on the numeric value of the reason code that is used in MQTT 5.0 for some message types. Please refer to the specification for the meaning of these values, which are often specific to the message type in question. +mqtt.reason_code uses an :ref:`unsigned 8-bits integer `. + Examples:: # match on attempts to unsubscribe from a non-subscribed topic @@ -137,6 +144,8 @@ mqtt.connect.flags Match on a combination of MQTT CONNECT flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match. +mqtt.connect.flags uses an :ref:`unsigned 8-bits integer ` + Valid flags are: * ``username`` (message contains a username) diff --git a/rust/cbindgen.toml b/rust/cbindgen.toml index b277e00506d8..939b21a24c3e 100644 --- a/rust/cbindgen.toml +++ b/rust/cbindgen.toml @@ -109,6 +109,7 @@ exclude = [ "IPPROTO_TCP", "IPPROTO_UDP", "SRepCatGetByShortname", + "SIG_FLAG_TOSERVER", ] # Types of items that we'll generate. If empty, then all types of item are emitted. diff --git a/rust/derive/src/applayerevent.rs b/rust/derive/src/applayerevent.rs index 29475fa2d51b..c4402381120a 100644 --- a/rust/derive/src/applayerevent.rs +++ b/rust/derive/src/applayerevent.rs @@ -110,6 +110,9 @@ pub fn derive_app_layer_event(input: TokenStream) -> TokenStream { /// Transform names such as "OneTwoThree" to "one_two_three". pub fn transform_name(in_name: &str) -> String { + if in_name.to_uppercase() == in_name { + return in_name.to_lowercase(); + } let mut out = String::new(); for (i, c) in in_name.chars().enumerate() { if i == 0 { @@ -159,5 +162,7 @@ mod test { transform_name("UnassignedMsgType"), "unassigned_msg_type".to_string() ); + assert_eq!(transform_name("SAMECASE"), "samecase".to_string()); + assert_eq!(transform_name("ZFlagSet"), "z_flag_set".to_string()); } } diff --git a/rust/derive/src/stringenum.rs b/rust/derive/src/stringenum.rs index 5344b934cde6..8eb33e43e6b1 100644 --- a/rust/derive/src/stringenum.rs +++ b/rust/derive/src/stringenum.rs @@ -27,13 +27,16 @@ pub fn derive_enum_string(input: TokenSt let name = input.ident; let mut values = Vec::new(); let mut names = Vec::new(); + let mut names_upper = Vec::new(); let mut fields = Vec::new(); if let syn::Data::Enum(ref data) = input.data { for v in (&data.variants).into_iter() { if let Some((_, val)) = &v.discriminant { let fname = transform_name(&v.ident.to_string()); + let fnameu = fname.to_ascii_uppercase(); names.push(fname); + names_upper.push(fnameu); fields.push(v.ident.clone()); if let syn::Expr::Lit(l) = val { if let syn::Lit::Int(li) = &l.lit { @@ -84,8 +87,8 @@ pub fn derive_enum_string(input: TokenSt } } fn from_str(s: &str) -> Option { - match s { - #( #names => Some(#name::#fields) ,)* + match s.to_ascii_uppercase().as_str() { + #( #names_upper => Some(#name::#fields) ,)* _ => None } } diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index bb2441798edb..4b481c975474 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -28,7 +28,7 @@ pub mod requires; pub mod tojson; use crate::core::AppProto; -use std::os::raw::{c_int, c_void}; +use std::os::raw::{c_char, c_int, c_void}; /// EnumString trait that will be implemented on enums that /// derive StringEnum. @@ -104,6 +104,44 @@ extern { ) -> *mut c_void; } +// needed for calls to DetectAppLayerMultiRegister +pub const SIG_FLAG_TOSERVER: u32 = 0x80000; // BIT_U32(19) + +extern { + // in detect-engine-helper.h + pub fn DetectHelperGetMultiData( + de: *mut c_void, + transforms: *const c_void, + flow: *const c_void, + flow_flags: u8, + tx: *const c_void, + list_id: c_int, + local_id: u32, + get_buf: unsafe extern "C" fn(*const c_void, u8, u32, *mut *const u8, *mut u32) -> bool, + ) -> *mut c_void; + // in detect-engine.h + pub fn DetectAppLayerMultiRegister( + name: *const c_char, + alproto: AppProto, + dir: u32, + progress: c_int, + get_data: unsafe extern "C" fn( + *mut c_void, + *const c_void, + *const c_void, + u8, + *const c_void, + i32, + u32, + ) -> *mut c_void, + priority: c_int, + tx_min_progress: c_int, + ); + pub fn DetectBufferTypeSetDescriptionByName(name: *const c_char, desc: *const c_char); + pub fn DetectBufferTypeSupportsMultiInstance(name: *const c_char); + pub fn DetectBufferTypeGetByName(name: *const c_char) -> c_int; +} + #[cfg(test)] mod test { use super::*; diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index 67933b6c2446..6ebdd17c4286 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -359,7 +359,7 @@ pub unsafe extern "C" fn rs_http2_detect_sizeupdatectx_match( #[no_mangle] pub unsafe extern "C" fn rs_http2_tx_get_header_name( tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +) -> bool { let mut pos = 0_u32; match direction.into() { Direction::ToServer => { @@ -369,7 +369,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_header_name( let value = &blocks[(nb - pos) as usize].name; *buffer = value.as_ptr(); //unsafe *buffer_len = value.len() as u32; - return 1; + return true; } else { pos += blocks.len() as u32; } @@ -383,7 +383,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_header_name( let value = &blocks[(nb - pos) as usize].name; *buffer = value.as_ptr(); //unsafe *buffer_len = value.len() as u32; - return 1; + return true; } else { pos += blocks.len() as u32; } @@ -391,7 +391,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_header_name( } } } - return 0; + return false; } fn http2_frames_get_header_firstvalue<'a>( diff --git a/rust/src/mqtt/detect.rs b/rust/src/mqtt/detect.rs index df0c78e8497f..77432761bd9c 100644 --- a/rust/src/mqtt/detect.rs +++ b/rust/src/mqtt/detect.rs @@ -17,144 +17,73 @@ // written by Sascha Steinbiss -use crate::mqtt::mqtt::{MQTTState, MQTTTransaction}; +use crate::detect::uint::{ + detect_match_uint, detect_parse_uint, detect_parse_uint_enum, rs_detect_u8_free, + rs_detect_u8_parse, DetectUintData, DetectUintMode, +}; +use crate::detect::{ + DetectAppLayerMultiRegister, DetectBufferSetActiveList, DetectBufferTypeGetByName, + DetectBufferTypeSetDescriptionByName, DetectBufferTypeSupportsMultiInstance, + DetectHelperBufferMpmRegister, DetectHelperBufferRegister, DetectHelperGetData, + DetectHelperGetMultiData, DetectHelperKeywordRegister, DetectSignatureSetAppProto, + SCSigTableElmt, SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT, + SIG_FLAG_TOSERVER, +}; + +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::{MQTTOperation, MQTTTypeCode}; use std::ffi::CStr; +use std::os::raw::{c_int, c_void}; use std::ptr; use std::str::FromStr; -#[derive(FromPrimitive, Debug, Copy, Clone, PartialOrd, PartialEq, Eq)] -#[allow(non_camel_case_types)] -#[repr(u8)] -pub enum MQTTFlagState { - MQTT_DONT_CARE = 0, - MQTT_MUST_BE_SET = 1, - MQTT_CANT_BE_SET = 2, -} - -#[inline] -fn check_flag_state(flag_state: MQTTFlagState, flag_value: bool, ok: &mut bool) { - match flag_state { - MQTTFlagState::MQTT_MUST_BE_SET => { - if !flag_value { - *ok = false; - } - } - MQTTFlagState::MQTT_CANT_BE_SET => { - if flag_value { - *ok = false; - } - } - _ => {} - } -} - -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_type(tx: &MQTTTransaction, mtype: u8) -> u8 { - for msg in tx.msg.iter() { - if mtype == msg.header.message_type as u8 { - return 1; - } - } - return 0; -} - -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_cstr_message_code( - str: *const std::os::raw::c_char, -) -> std::os::raw::c_int { - let msgtype: &CStr = CStr::from_ptr(str); - if let Ok(s) = msgtype.to_str() { - if let Ok(x) = MQTTTypeCode::from_str(s) { - return x as i32; - } - } - return -1; -} - -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_flags( - tx: &MQTTTransaction, qretain: MQTTFlagState, qdup: MQTTFlagState, -) -> u8 { - for msg in tx.msg.iter() { - let mut ok = true; - check_flag_state(qretain, msg.header.retain, &mut ok); - check_flag_state(qdup, msg.header.dup_flag, &mut ok); - if ok { - return 1; - } - } - - return 0; -} - -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_qos(tx: &MQTTTransaction, qos: u8) -> u8 { +fn mqtt_tx_has_type(tx: &MQTTTransaction, mtype: &DetectUintData) -> c_int { for msg in tx.msg.iter() { - if qos == msg.header.qos_level { + if detect_match_uint(mtype, msg.header.message_type as u8) { return 1; } } return 0; } -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_get_protocol_version(state: &MQTTState) -> u8 { - return state.protocol_version; -} - -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_connect_flags( - tx: &MQTTTransaction, username: MQTTFlagState, password: MQTTFlagState, will: MQTTFlagState, - will_retain: MQTTFlagState, clean_session: MQTTFlagState, -) -> u8 { - for msg in tx.msg.iter() { - if let MQTTOperation::CONNECT(ref cv) = msg.op { - let mut ok = true; - check_flag_state(username, cv.username_flag, &mut ok); - check_flag_state(password, cv.password_flag, &mut ok); - check_flag_state(will, cv.will_flag, &mut ok); - check_flag_state(will_retain, cv.will_retain, &mut ok); - check_flag_state(clean_session, cv.clean_session, &mut ok); - if ok { - return 1; - } - } - } - return 0; -} - -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_clientid( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_clientid( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { let p = &cv.client_id; if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } *buffer = ptr::null(); *buffer_len = 0; - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_username( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_username( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { if let Some(p) = &cv.username { if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } @@ -162,21 +91,20 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_username( *buffer = ptr::null(); *buffer_len = 0; - - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_password( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_password( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { if let Some(p) = &cv.password { if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } @@ -184,20 +112,20 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_password( *buffer = ptr::null(); *buffer_len = 0; - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willtopic( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_willtopic( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { if let Some(p) = &cv.will_topic { if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } @@ -205,21 +133,20 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willtopic( *buffer = ptr::null(); *buffer_len = 0; - - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willmessage( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_willmessage( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { if let Some(p) = &cv.will_message { if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } @@ -227,211 +154,1395 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willmessage( *buffer = ptr::null(); *buffer_len = 0; - - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_protocol_string( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_connect_protocol_string( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::CONNECT(ref cv) = msg.op { let p = &cv.protocol_string; if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } *buffer = ptr::null(); *buffer_len = 0; - return 0; -} - -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connack_sessionpresent( - tx: &MQTTTransaction, session_present: *mut bool, -) -> u8 { - for msg in tx.msg.iter() { - if let MQTTOperation::CONNACK(ref ca) = msg.op { - *session_present = ca.session_present; - return 1; - } - } - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_publish_topic( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_publish_topic( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::PUBLISH(ref pubv) = msg.op { let p = &pubv.topic; if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } *buffer = ptr::null(); *buffer_len = 0; - - return 0; + return false; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_publish_message( - tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { +unsafe extern "C" fn mqtt_tx_get_publish_message( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { if let MQTTOperation::PUBLISH(ref pubv) = msg.op { let p = &pubv.message; if !p.is_empty() { *buffer = p.as_ptr(); *buffer_len = p.len() as u32; - return 1; + return true; } } } *buffer = ptr::null(); *buffer_len = 0; + return false; +} +fn mqtt_tx_get_reason_code(tx: &MQTTTransaction) -> Option { + for msg in tx.msg.iter() { + match msg.op { + MQTTOperation::PUBACK(ref v) + | MQTTOperation::PUBREL(ref v) + | MQTTOperation::PUBREC(ref v) + | MQTTOperation::PUBCOMP(ref v) => { + if let Some(rcode) = v.reason_code { + return Some(rcode); + } + } + MQTTOperation::AUTH(ref v) => { + return Some(v.reason_code); + } + MQTTOperation::CONNACK(ref v) => { + return Some(v.return_code); + } + MQTTOperation::DISCONNECT(ref v) => { + if let Some(rcode) = v.reason_code { + return Some(rcode); + } + } + _ => return None, + } + } + return None; +} + +fn mqtt_tx_unsuback_has_reason_code(tx: &MQTTTransaction, code: &DetectUintData) -> c_int { + for msg in tx.msg.iter() { + if let MQTTOperation::UNSUBACK(ref unsuback) = msg.op { + if let Some(ref reason_codes) = unsuback.reason_codes { + for rc in reason_codes.iter() { + if detect_match_uint(code, *rc) { + return 1; + } + } + } + } + } return 0; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_subscribe_topic( - tx: &MQTTTransaction, i: u32, buf: *mut *const u8, len: *mut u32, -) -> u8 { +static mut UNSUB_TOPIC_MATCH_LIMIT: isize = 100; +static mut G_MQTT_UNSUB_TOPIC_BUFFER_ID: c_int = 0; +static mut G_MQTT_TYPE_KW_ID: c_int = 0; +static mut G_MQTT_TYPE_BUFFER_ID: c_int = 0; +static mut SUB_TOPIC_MATCH_LIMIT: isize = 100; +static mut G_MQTT_SUB_TOPIC_BUFFER_ID: c_int = 0; +static mut G_MQTT_REASON_CODE_KW_ID: c_int = 0; +static mut G_MQTT_REASON_CODE_BUFFER_ID: c_int = 0; +static mut G_MQTT_QOS_KW_ID: c_int = 0; +static mut G_MQTT_QOS_BUFFER_ID: c_int = 0; +static mut G_MQTT_PUB_TOPIC_BUFFER_ID: c_int = 0; +static mut G_MQTT_PUB_MSG_BUFFER_ID: c_int = 0; +static mut G_MQTT_PROTOCOL_VERSION_KW_ID: c_int = 0; +static mut G_MQTT_PROTOCOL_VERSION_BUFFER_ID: c_int = 0; +static mut G_MQTT_FLAGS_KW_ID: c_int = 0; +static mut G_MQTT_FLAGS_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_WILLTOPIC_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_WILLMSG_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_USERNAME_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_PROTOCOLSTRING_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_PASSWORD_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_CLIENTID_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONNACK_SESSIONPRESENT_KW_ID: c_int = 0; +static mut G_MQTT_CONNACK_SESSIONPRESENT_BUFFER_ID: c_int = 0; +static mut G_MQTT_CONN_FLAGS_KW_ID: c_int = 0; +static mut G_MQTT_CONN_FLAGS_BUFFER_ID: c_int = 0; + +unsafe extern "C" fn unsub_topic_get_data( + tx: *const c_void, _flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let ml = unsafe { UNSUB_TOPIC_MATCH_LIMIT }; + if ml > 0 && local_id >= ml as u32 { + return false; + } let mut offset = 0; + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { - if let MQTTOperation::SUBSCRIBE(ref subv) = msg.op { - if (i as usize) < subv.topics.len() + offset { - let topic = &subv.topics[(i as usize) - offset]; - if !topic.topic_name.is_empty() { - *len = topic.topic_name.len() as u32; - *buf = topic.topic_name.as_ptr(); - return 1; + if let MQTTOperation::UNSUBSCRIBE(ref unsubv) = msg.op { + if (local_id as usize) < unsubv.topics.len() + offset { + let topic = &unsubv.topics[(local_id as usize) - offset]; + if !topic.is_empty() { + *buffer_len = topic.len() as u32; + *buffer = topic.as_ptr(); + return true; } } else { - offset += subv.topics.len(); + offset += unsubv.topics.len(); } } } - *buf = ptr::null(); - *len = 0; + *buffer = ptr::null(); + *buffer_len = 0; + return false; +} + +unsafe extern "C" fn unsub_topic_get_data_wrapper( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + unsub_topic_get_data, + ); +} + +unsafe extern "C" fn unsub_topic_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_UNSUB_TOPIC_BUFFER_ID) < 0 { + return -1; + } return 0; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_unsubscribe_topic( - tx: &MQTTTransaction, i: u32, buf: *mut *const u8, len: *mut u32, -) -> u8 { +unsafe extern "C" fn sub_topic_get_data( + tx: *const c_void, _flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let ml = unsafe { SUB_TOPIC_MATCH_LIMIT }; + if ml > 0 && local_id >= ml as u32 { + return false; + } let mut offset = 0; + let tx = cast_pointer!(tx, MQTTTransaction); for msg in tx.msg.iter() { - if let MQTTOperation::UNSUBSCRIBE(ref unsubv) = msg.op { - if (i as usize) < unsubv.topics.len() + offset { - let topic = &unsubv.topics[(i as usize) - offset]; - if !topic.is_empty() { - *len = topic.len() as u32; - *buf = topic.as_ptr(); - return 1; + if let MQTTOperation::SUBSCRIBE(ref subv) = msg.op { + if (local_id as usize) < subv.topics.len() + offset { + let topic = &subv.topics[(local_id as usize) - offset]; + if !topic.topic_name.is_empty() { + *buffer_len = topic.topic_name.len() as u32; + *buffer = topic.topic_name.as_ptr(); + return true; } } else { - offset += unsubv.topics.len(); + offset += subv.topics.len(); } } } - *buf = ptr::null(); - *len = 0; + *buffer = ptr::null(); + *buffer_len = 0; + return false; +} + +unsafe extern "C" fn sub_topic_get_data_wrapper( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sub_topic_get_data, + ); +} + +unsafe extern "C" fn sub_topic_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_SUB_TOPIC_BUFFER_ID) < 0 { + return -1; + } + + return 0; +} +unsafe extern "C" fn mqtt_parse_type(ustr: *const std::os::raw::c_char) -> *mut DetectUintData { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Some(ctx) = detect_parse_uint_enum::(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn mqtt_type_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = mqtt_parse_type(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_MQTT_TYPE_KW_ID, ctx, G_MQTT_TYPE_BUFFER_ID).is_null() { + mqtt_type_free(std::ptr::null_mut(), ctx); + return -1; + } return 0; } -#[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_reason_code(tx: &MQTTTransaction, result: *mut u8) -> u8 { +unsafe extern "C" fn mqtt_type_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + return mqtt_tx_has_type(tx, ctx); +} + +unsafe extern "C" fn mqtt_type_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(ctx); +} + +unsafe extern "C" fn mqtt_reason_code_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = rs_detect_u8_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList( + de, + s, + G_MQTT_REASON_CODE_KW_ID, + ctx, + G_MQTT_REASON_CODE_BUFFER_ID, + ) + .is_null() + { + mqtt_reason_code_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn mqtt_reason_code_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + if let Some(v) = mqtt_tx_get_reason_code(tx) { + if detect_match_uint(ctx, v) { + return 1; + } + } + return mqtt_tx_unsuback_has_reason_code(tx, ctx); +} + +unsafe extern "C" fn mqtt_reason_code_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(ctx); +} + +unsafe extern "C" fn mqtt_parse_qos(ustr: *const std::os::raw::c_char) -> *mut u8 { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Ok(ctx) = u8::from_str(s.trim()) { + if ctx <= 2 { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn mqtt_qos_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = mqtt_parse_qos(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_MQTT_QOS_KW_ID, ctx, G_MQTT_QOS_BUFFER_ID).is_null() { + mqtt_qos_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +fn mqtt_tx_has_qos(tx: &MQTTTransaction, qos: u8) -> c_int { for msg in tx.msg.iter() { - match msg.op { - MQTTOperation::PUBACK(ref v) - | MQTTOperation::PUBREL(ref v) - | MQTTOperation::PUBREC(ref v) - | MQTTOperation::PUBCOMP(ref v) => { - if let Some(rcode) = v.reason_code { - *result = rcode; - return 1; - } + if qos == msg.header.qos_level { + return 1; + } + } + return 0; +} + +unsafe extern "C" fn mqtt_qos_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, u8); + return mqtt_tx_has_qos(tx, *ctx); +} + +unsafe extern "C" fn mqtt_qos_free(_de: *mut c_void, ctx: *mut c_void) { + std::mem::drop(Box::from_raw(ctx as *mut u8)); +} + +unsafe extern "C" fn mqtt_parse_bool(ustr: *const std::os::raw::c_char) -> *mut bool { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Ok(ctx) = u8::from_str(s.trim()) { + if ctx <= 2 { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; } - MQTTOperation::AUTH(ref v) => { - *result = v.reason_code; + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn mqtt_connack_sessionpresent_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = mqtt_parse_bool(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList( + de, + s, + G_MQTT_CONNACK_SESSIONPRESENT_KW_ID, + ctx, + G_MQTT_CONNACK_SESSIONPRESENT_BUFFER_ID, + ) + .is_null() + { + mqtt_connack_sessionpresent_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +fn mqtt_tx_get_connack_sessionpresent(tx: &MQTTTransaction, session_present: bool) -> c_int { + for msg in tx.msg.iter() { + if let MQTTOperation::CONNACK(ref ca) = msg.op { + if session_present == ca.session_present { return 1; } - MQTTOperation::CONNACK(ref v) => { - *result = v.return_code; - return 1; + } + } + return 0; +} + +unsafe extern "C" fn mqtt_connack_sessionpresent_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, bool); + return mqtt_tx_get_connack_sessionpresent(tx, *ctx); +} + +unsafe extern "C" fn mqtt_connack_sessionpresent_free(_de: *mut c_void, ctx: *mut c_void) { + std::mem::drop(Box::from_raw(ctx as *mut bool)); +} + +pub unsafe extern "C" fn mqtt_pub_topic_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_PUB_TOPIC_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_pub_topic_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_publish_topic, + ); +} + +pub unsafe extern "C" fn mqtt_pub_msg_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_PUB_MSG_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_pub_msg_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_publish_message, + ); +} + +unsafe extern "C" fn mqtt_protocol_version_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = rs_detect_u8_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList( + de, + s, + G_MQTT_PROTOCOL_VERSION_KW_ID, + ctx, + G_MQTT_PROTOCOL_VERSION_BUFFER_ID, + ) + .is_null() + { + mqtt_protocol_version_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn mqtt_protocol_version_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, state: *mut c_void, _tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let state = cast_pointer!(state, MQTTState); + let ctx = cast_pointer!(ctx, DetectUintData); + if detect_match_uint(ctx, state.protocol_version) { + return 1; + } + return 0; +} + +unsafe extern "C" fn mqtt_protocol_version_free(_de: *mut c_void, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(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; } - MQTTOperation::DISCONNECT(ref v) => { - if let Some(rcode) = v.reason_code { - *result = rcode; - return 1; - } + arg1 |= elem.value; + if !elem.neg { + arg2 |= elem.value; } - _ => return 0, + } + let ctx = DetectUintData:: { + arg1, + arg2, + mode: DetectUintMode::DetectUintModeBitmask, + }; + return Some(ctx); + } + return None; +} + +unsafe extern "C" fn mqtt_parse_flags( + ustr: *const std::os::raw::c_char, +) -> *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) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; } } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn mqtt_flags_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = mqtt_parse_flags(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_MQTT_FLAGS_KW_ID, ctx, G_MQTT_FLAGS_BUFFER_ID).is_null() { + mqtt_flags_free(std::ptr::null_mut(), ctx); + return -1; + } return 0; } -#[no_mangle] -pub extern "C" fn rs_mqtt_tx_unsuback_has_reason_code(tx: &MQTTTransaction, code: u8) -> u8 { +extern "C" fn rs_mqtt_tx_has_flags(tx: &MQTTTransaction, ctx: &DetectUintData) -> c_int { for msg in tx.msg.iter() { - if let MQTTOperation::UNSUBACK(ref unsuback) = msg.op { - if let Some(ref reason_codes) = unsuback.reason_codes { - for rc in reason_codes.iter() { - if *rc == code { - return 1; - } - } + let mut v = 0; + if msg.header.retain { + v |= 1; + } + if msg.header.dup_flag { + v |= 0x8; + } + if detect_match_uint(ctx, v) { + return 1; + } + } + return 0; +} + +unsafe extern "C" fn mqtt_flags_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + return rs_mqtt_tx_has_flags(tx, ctx); +} + +unsafe extern "C" fn mqtt_flags_free(_de: *mut c_void, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(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; +} + +unsafe extern "C" fn mqtt_parse_conn_flags( + ustr: *const std::os::raw::c_char, +) -> *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) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn mqtt_conn_flags_setup( + de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + let ctx = mqtt_parse_conn_flags(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList( + de, + s, + G_MQTT_CONN_FLAGS_KW_ID, + ctx, + G_MQTT_CONN_FLAGS_BUFFER_ID, + ) + .is_null() + { + mqtt_conn_flags_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +fn rs_mqtt_tx_has_conn_flags(tx: &MQTTTransaction, ctx: &DetectUintData) -> c_int { + for msg in tx.msg.iter() { + if let MQTTOperation::CONNECT(ref cv) = msg.op { + if detect_match_uint(ctx, cv.rawflags) { + return 1; } } } return 0; } +unsafe extern "C" fn mqtt_conn_flags_match( + _de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, MQTTTransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + return rs_mqtt_tx_has_conn_flags(tx, ctx); +} + +unsafe extern "C" fn mqtt_conn_flags_free(_de: *mut c_void, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(ctx); +} + +pub unsafe extern "C" fn mqtt_conn_willtopic_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_WILLTOPIC_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_willtopic_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_willtopic, + ); +} + +pub unsafe extern "C" fn mqtt_conn_willmsg_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_WILLMSG_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_willmsg_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_willmessage, + ); +} + +pub unsafe extern "C" fn mqtt_conn_username_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_USERNAME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_username_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_username, + ); +} + +pub unsafe extern "C" fn mqtt_conn_protocolstring_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_PROTOCOLSTRING_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_protocolstring_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_protocol_string, + ); +} + +pub unsafe extern "C" fn mqtt_conn_password_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_PASSWORD_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_password_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_password, + ); +} + +pub unsafe extern "C" fn mqtt_conn_clientid_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_MQTT) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_MQTT_CONN_CLIENTID_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +pub unsafe extern "C" fn mqtt_conn_clientid_get_data( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + mqtt_tx_get_connect_clientid, + ); +} + +#[no_mangle] +pub unsafe extern "C" fn ScDetectMqttRegister() { + let keyword_name = b"mqtt.unsubscribe.topic\0".as_ptr() as *const libc::c_char; + let kw = SCSigTableElmt { + name: keyword_name, + desc: b"sticky buffer to match MQTT UNSUBSCRIBE topic\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-unsubscribe-topic\0".as_ptr() as *const libc::c_char, + Setup: unsub_topic_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + if let Some(val) = conf_get("app-layer.protocols.mqtt.unsubscribe-topic-match-limit") { + if let Ok(v) = val.parse::() { + UNSUB_TOPIC_MATCH_LIMIT = v; + } else { + SCLogError!("Invalid value for app-layer.protocols.mqtt.unsubscribe-topic-match-limit"); + } + } + let _g_mqtt_unsub_topic_kw_id = DetectHelperKeywordRegister(&kw); + DetectAppLayerMultiRegister( + keyword_name, + ALPROTO_MQTT, + SIG_FLAG_TOSERVER, + 0, + unsub_topic_get_data_wrapper, + 2, + 0, + ); + DetectBufferTypeSetDescriptionByName( + keyword_name, + b"unsubscribe topic query\0".as_ptr() as *const libc::c_char, + ); + DetectBufferTypeSupportsMultiInstance(keyword_name); + G_MQTT_UNSUB_TOPIC_BUFFER_ID = DetectBufferTypeGetByName(keyword_name); + + let kw = SCSigTableElmt { + name: b"mqtt.type\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT control packet type\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-type\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_type_match), + Setup: mqtt_type_setup, + Free: Some(mqtt_type_free), + flags: 0, + }; + G_MQTT_TYPE_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_TYPE_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.type\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + + let keyword_name = b"mqtt.subscribe.topic\0".as_ptr() as *const libc::c_char; + let kw = SCSigTableElmt { + name: keyword_name, + desc: b"sticky buffer to match MQTT SUBSCRIBE topic\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-subscribe-topic\0".as_ptr() as *const libc::c_char, + Setup: sub_topic_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + if let Some(val) = conf_get("app-layer.protocols.mqtt.subscribe-topic-match-limit") { + if let Ok(v) = val.parse::() { + SUB_TOPIC_MATCH_LIMIT = v; + } else { + SCLogError!("Invalid value for app-layer.protocols.mqtt.subscribe-topic-match-limit"); + } + } + let _g_mqtt_sub_topic_kw_id = DetectHelperKeywordRegister(&kw); + DetectAppLayerMultiRegister( + keyword_name, + ALPROTO_MQTT, + SIG_FLAG_TOSERVER, + 0, + sub_topic_get_data_wrapper, + 2, + 0, + ); + DetectBufferTypeSetDescriptionByName( + keyword_name, + b"subscribe topic query\0".as_ptr() as *const libc::c_char, + ); + DetectBufferTypeSupportsMultiInstance(keyword_name); + G_MQTT_SUB_TOPIC_BUFFER_ID = DetectBufferTypeGetByName(keyword_name); + + let kw = SCSigTableElmt { + name: b"mqtt.reason_code\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT 5.0+ reason code\0".as_ptr() as *const libc::c_char, + //TODO alias "mqtt.connack.return_code" + url: b"/rules/mqtt-keywords.html#mqtt-reason-code\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_reason_code_match), + Setup: mqtt_reason_code_setup, + Free: Some(mqtt_reason_code_free), + flags: 0, + }; + G_MQTT_REASON_CODE_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_REASON_CODE_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.reason_code\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connack.session_present\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT CONNACK session present flag\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-connack-session-present\0".as_ptr() + as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_connack_sessionpresent_match), + Setup: mqtt_connack_sessionpresent_setup, + Free: Some(mqtt_connack_sessionpresent_free), + flags: 0, + }; + G_MQTT_CONNACK_SESSIONPRESENT_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_CONNACK_SESSIONPRESENT_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.connack.session_present\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.qos\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT fixed header QOS level\0".as_ptr() as *const libc::c_char, + //TODO alias "mqtt.connack.return_code" + url: b"/rules/mqtt-keywords.html#mqtt-qos\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_qos_match), + Setup: mqtt_qos_setup, + Free: Some(mqtt_qos_free), + flags: 0, + }; + G_MQTT_QOS_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_QOS_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.qos\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.publish.topic\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT PUBLISH topic\0".as_ptr() as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-publish-topic\0".as_ptr() as *const libc::c_char, + Setup: mqtt_pub_topic_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_pub_topic_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_PUB_TOPIC_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.publish.topic\0".as_ptr() as *const libc::c_char, + b"MQTT PUBLISH topic\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_pub_topic_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.publish.message\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT PUBLISH message\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-publish-message\0".as_ptr() as *const libc::c_char, + Setup: mqtt_pub_msg_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_pub_msg_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_PUB_MSG_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.publish.message\0".as_ptr() as *const libc::c_char, + b"MQTT PUBLISH message\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_pub_msg_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.protocol_version\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT protocol version\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-protocol-version\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_protocol_version_match), + Setup: mqtt_protocol_version_setup, + Free: Some(mqtt_protocol_version_free), + flags: 0, + }; + G_MQTT_PROTOCOL_VERSION_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_PROTOCOL_VERSION_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.protocol_version\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.flags\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT fixed header flags\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-flags\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_flags_match), + Setup: mqtt_flags_setup, + Free: Some(mqtt_flags_free), + flags: 0, + }; + G_MQTT_FLAGS_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_FLAGS_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.flags\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.flags\0".as_ptr() as *const libc::c_char, + desc: b"match MQTT CONNECT variable header flags\0".as_ptr() as *const libc::c_char, + url: b"/rules/mqtt-keywords.html#mqtt-connect-flags\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(mqtt_conn_flags_match), + Setup: mqtt_conn_flags_setup, + Free: Some(mqtt_conn_flags_free), + flags: 0, + }; + G_MQTT_CONN_FLAGS_KW_ID = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_FLAGS_BUFFER_ID = DetectHelperBufferRegister( + b"mqtt.connect.flags\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, // only to server + true, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.willtopic\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT will topic\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-willtopic\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_willtopic_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_willtopic_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_WILLTOPIC_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.willtopic\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT will topic\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_willtopic_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.willmessage\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT will message\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-willmessage\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_willmsg_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_willmsg_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_WILLMSG_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.willmessage\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT will message\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_willtopic_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.username\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT username\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-username\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_username_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_username_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_USERNAME_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.username\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT username\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_username_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.protocol_string\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT protocol string\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-protocol_string\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_protocolstring_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_protostr_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_PROTOCOLSTRING_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.protocol_string\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT protocol string\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_protocolstring_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.password\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT password\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-password\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_password_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_password_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_PASSWORD_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.password\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT password\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_password_get_data, + ); + let kw = SCSigTableElmt { + name: b"mqtt.connect.clientid\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the MQTT CONNECT clientid\0".as_ptr() + as *const libc::c_char, + url: b"mqtt-keywords.html#mqtt-connect-clientid\0".as_ptr() as *const libc::c_char, + Setup: mqtt_conn_clientid_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_mqtt_conn_password_kw_id = DetectHelperKeywordRegister(&kw); + G_MQTT_CONN_CLIENTID_BUFFER_ID = DetectHelperBufferMpmRegister( + b"mqtt.connect.clientid\0".as_ptr() as *const libc::c_char, + b"MQTT CONNECT clientid\0".as_ptr() as *const libc::c_char, + ALPROTO_MQTT, + false, + true, + mqtt_conn_clientid_get_data, + ); +} + #[cfg(test)] mod test { use super::*; + use crate::core::Direction; + use crate::detect::uint::DetectUintMode; use crate::mqtt::mqtt::MQTTTransaction; use crate::mqtt::mqtt_message::*; use crate::mqtt::parser::FixedHeader; - use crate::core::Direction; use std; + #[test] + fn mqtt_type_test_qos() { + let ctx = unsafe { mqtt_parse_qos("0\0".as_ptr() as *const libc::c_char) }; + assert!(!ctx.is_null()); + assert_eq!(unsafe { *ctx }, 0); + let ctx = unsafe { mqtt_parse_qos(" 0\0".as_ptr() as *const libc::c_char) }; + assert!(!ctx.is_null()); + assert_eq!(unsafe { *ctx }, 0); + let ctx = unsafe { mqtt_parse_qos("1\0".as_ptr() as *const libc::c_char) }; + assert!(!ctx.is_null()); + assert_eq!(unsafe { *ctx }, 1); + let ctx = unsafe { mqtt_parse_qos("2\0".as_ptr() as *const libc::c_char) }; + assert!(!ctx.is_null()); + assert_eq!(unsafe { *ctx }, 2); + let ctx = unsafe { mqtt_parse_qos("3\0".as_ptr() as *const libc::c_char) }; + assert!(ctx.is_null()); + let ctx = unsafe { mqtt_parse_qos("12\0".as_ptr() as *const libc::c_char) }; + assert!(ctx.is_null()); + } + + #[test] + fn mqtt_parse_flags() { + let ctx = parse_flags("retain").unwrap(); + assert_eq!(ctx.arg1, 1); + assert_eq!(ctx.arg2, 1); + let ctx = parse_flags("dup").unwrap(); + assert_eq!(ctx.arg1, 8); + assert_eq!(ctx.arg2, 8); + let ctx = parse_flags("retain,dup").unwrap(); + assert_eq!(ctx.arg1, 8 | 1); + assert_eq!(ctx.arg2, 8 | 1); + let ctx = parse_flags("dup, retain").unwrap(); + assert_eq!(ctx.arg1, 8 | 1); + assert_eq!(ctx.arg2, 8 | 1); + let ctx = parse_flags("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()); + } + + #[test] + fn mqtt_parse_conn_flags() { + let ctx = parse_conn_flags("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(); + assert_eq!(ctx.arg1, 0xE6); + assert_eq!(ctx.arg2, 0xE6); + let ctx = + parse_conn_flags("!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(); + 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()); + } + + #[test] + fn mqtt_type_test_parse() { + let ctx = detect_parse_uint_enum::("CONNECT").unwrap(); + assert_eq!(ctx.arg1, 1); + assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual); + let ctx = detect_parse_uint_enum::("PINGRESP").unwrap(); + assert_eq!(ctx.arg1, 13); + assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual); + let ctx = detect_parse_uint_enum::("auth").unwrap(); + assert_eq!(ctx.arg1, 15); + assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual); + assert!(detect_parse_uint_enum::("invalidopt").is_none()); + let ctx = detect_parse_uint_enum::("unassigned").unwrap(); + assert_eq!(ctx.arg1, 0); + assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual); + } + #[test] fn test_multi_unsubscribe() { - let mut t = MQTTTransaction::new(MQTTMessage { - header: FixedHeader { - message_type: MQTTTypeCode::UNSUBSCRIBE, - dup_flag: false, - qos_level: 0, - retain: false, - remaining_length: 0, + let mut t = MQTTTransaction::new( + MQTTMessage { + header: FixedHeader { + message_type: MQTTTypeCode::UNSUBSCRIBE, + dup_flag: false, + qos_level: 0, + retain: false, + remaining_length: 0, + }, + op: MQTTOperation::UNSUBSCRIBE(MQTTUnsubscribeData { + message_id: 1, + topics: vec!["foo".to_string(), "baar".to_string()], + properties: None, + }), }, - op: MQTTOperation::UNSUBSCRIBE(MQTTUnsubscribeData { - message_id: 1, - topics: vec!["foo".to_string(), "baar".to_string()], - properties: None, - }), - }, Direction::ToServer); + Direction::ToServer, + ); t.msg.push(MQTTMessage { header: FixedHeader { message_type: MQTTTypeCode::UNSUBSCRIBE, @@ -448,51 +1559,55 @@ mod test { }); let mut s: *const u8 = std::ptr::null_mut(); let mut slen: u32 = 0; - let mut r = unsafe { rs_mqtt_tx_get_unsubscribe_topic(&t, 0, &mut s, &mut slen) }; - assert_eq!(r, 1); + let tx = &t as *const _ as *mut _; + let mut r = unsafe { unsub_topic_get_data(tx, 0, 0, &mut s, &mut slen) }; + assert!(r); let mut topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "foo"); - r = unsafe { rs_mqtt_tx_get_unsubscribe_topic(&t, 1, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { unsub_topic_get_data(tx, 0, 1, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "baar"); - r = unsafe { rs_mqtt_tx_get_unsubscribe_topic(&t, 2, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { unsub_topic_get_data(tx, 0, 2, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "fieee"); - r = unsafe { rs_mqtt_tx_get_unsubscribe_topic(&t, 3, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { unsub_topic_get_data(tx, 0, 3, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "baaaaz"); - r = unsafe { rs_mqtt_tx_get_unsubscribe_topic(&t, 4, &mut s, &mut slen) }; - assert_eq!(r, 0); + r = unsafe { unsub_topic_get_data(tx, 0, 4, &mut s, &mut slen) }; + assert!(!r); } #[test] fn test_multi_subscribe() { - let mut t = MQTTTransaction::new(MQTTMessage { - header: FixedHeader { - message_type: MQTTTypeCode::SUBSCRIBE, - dup_flag: false, - qos_level: 0, - retain: false, - remaining_length: 0, + let mut t = MQTTTransaction::new( + MQTTMessage { + header: FixedHeader { + message_type: MQTTTypeCode::SUBSCRIBE, + dup_flag: false, + qos_level: 0, + retain: false, + remaining_length: 0, + }, + op: MQTTOperation::SUBSCRIBE(MQTTSubscribeData { + message_id: 1, + topics: vec![ + MQTTSubscribeTopicData { + topic_name: "foo".to_string(), + qos: 0, + }, + MQTTSubscribeTopicData { + topic_name: "baar".to_string(), + qos: 1, + }, + ], + properties: None, + }), }, - op: MQTTOperation::SUBSCRIBE(MQTTSubscribeData { - message_id: 1, - topics: vec![ - MQTTSubscribeTopicData { - topic_name: "foo".to_string(), - qos: 0, - }, - MQTTSubscribeTopicData { - topic_name: "baar".to_string(), - qos: 1, - }, - ], - properties: None, - }), - }, Direction::ToServer); + Direction::ToServer, + ); t.msg.push(MQTTMessage { header: FixedHeader { message_type: MQTTTypeCode::SUBSCRIBE, @@ -518,23 +1633,24 @@ mod test { }); let mut s: *const u8 = std::ptr::null_mut(); let mut slen: u32 = 0; - let mut r = unsafe { rs_mqtt_tx_get_subscribe_topic(&t, 0, &mut s, &mut slen) }; - assert_eq!(r, 1); + let tx = &t as *const _ as *mut _; + let mut r = unsafe { sub_topic_get_data(tx, 0, 0, &mut s, &mut slen) }; + assert!(r); let mut topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "foo"); - r = unsafe { rs_mqtt_tx_get_subscribe_topic(&t, 1, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { sub_topic_get_data(tx, 0, 1, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "baar"); - r = unsafe { rs_mqtt_tx_get_subscribe_topic(&t, 2, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { sub_topic_get_data(tx, 0, 2, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "fieee"); - r = unsafe { rs_mqtt_tx_get_subscribe_topic(&t, 3, &mut s, &mut slen) }; - assert_eq!(r, 1); + r = unsafe { sub_topic_get_data(tx, 0, 3, &mut s, &mut slen) }; + assert!(r); topic = String::from_utf8_lossy(unsafe { build_slice!(s, slen as usize) }); assert_eq!(topic, "baaaaz"); - r = unsafe { rs_mqtt_tx_get_subscribe_topic(&t, 4, &mut s, &mut slen) }; - assert_eq!(r, 0); + r = unsafe { sub_topic_get_data(tx, 0, 4, &mut s, &mut slen) }; + assert!(!r); } } diff --git a/rust/src/mqtt/mqtt.rs b/rust/src/mqtt/mqtt.rs index b33069f7094c..f938f2539a62 100644 --- a/rust/src/mqtt/mqtt.rs +++ b/rust/src/mqtt/mqtt.rs @@ -40,7 +40,7 @@ static mut MAX_MSG_LEN: u32 = 1048576; static mut MQTT_MAX_TX: usize = 1024; -static mut ALPROTO_MQTT: AppProto = ALPROTO_UNKNOWN; +pub(super) static mut ALPROTO_MQTT: AppProto = ALPROTO_UNKNOWN; #[derive(AppLayerFrameType)] pub enum MQTTFrameType { @@ -701,9 +701,8 @@ pub unsafe extern "C" fn rs_mqtt_state_get_tx_count(state: *mut std::os::raw::c_ #[no_mangle] pub unsafe extern "C" fn rs_mqtt_tx_is_toclient( - tx: *const std::os::raw::c_void, + tx: &MQTTTransaction, ) -> std::os::raw::c_int { - let tx = cast_pointer!(tx, MQTTTransaction); if tx.toclient { return 1; } diff --git a/rust/src/mqtt/mqtt_message.rs b/rust/src/mqtt/mqtt_message.rs index 390fc9e85a19..2ba42273ecc3 100644 --- a/rust/src/mqtt/mqtt_message.rs +++ b/rust/src/mqtt/mqtt_message.rs @@ -20,6 +20,7 @@ use crate::mqtt::mqtt_property::*; use crate::mqtt::parser::*; use std::fmt; +use suricata_derive::EnumStringU8; #[derive(Debug)] pub struct MQTTMessage { @@ -52,7 +53,7 @@ pub enum MQTTOperation { } #[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, FromPrimitive, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, FromPrimitive, Debug, EnumStringU8)] pub enum MQTTTypeCode { UNASSIGNED = 0, CONNECT = 1, @@ -84,36 +85,11 @@ impl fmt::Display for MQTTTypeCode { } } -impl std::str::FromStr for MQTTTypeCode { - type Err = String; - fn from_str(s: &str) -> Result { - let su = s.to_uppercase(); - let su_slice: &str = &su; - match su_slice { - "CONNECT" => Ok(MQTTTypeCode::CONNECT), - "CONNACK" => Ok(MQTTTypeCode::CONNACK), - "PUBLISH" => Ok(MQTTTypeCode::PUBLISH), - "PUBACK" => Ok(MQTTTypeCode::PUBACK), - "PUBREC" => Ok(MQTTTypeCode::PUBREC), - "PUBREL" => Ok(MQTTTypeCode::PUBREL), - "PUBCOMP" => Ok(MQTTTypeCode::PUBCOMP), - "SUBSCRIBE" => Ok(MQTTTypeCode::SUBSCRIBE), - "SUBACK" => Ok(MQTTTypeCode::SUBACK), - "UNSUBSCRIBE" => Ok(MQTTTypeCode::UNSUBSCRIBE), - "UNSUBACK" => Ok(MQTTTypeCode::UNSUBACK), - "PINGREQ" => Ok(MQTTTypeCode::PINGREQ), - "PINGRESP" => Ok(MQTTTypeCode::PINGRESP), - "DISCONNECT" => Ok(MQTTTypeCode::DISCONNECT), - "AUTH" => Ok(MQTTTypeCode::AUTH), - _ => Err(format!("'{}' is not a valid value for MQTTTypeCode", s)), - } - } -} - #[derive(Debug)] pub struct MQTTConnectData { pub protocol_string: String, pub protocol_version: u8, + pub rawflags: u8, pub username_flag: bool, pub password_flag: bool, pub will_retain: bool, diff --git a/rust/src/mqtt/parser.rs b/rust/src/mqtt/parser.rs index eb1de176f44f..3fd3b5cc4c9c 100644 --- a/rust/src/mqtt/parser.rs +++ b/rust/src/mqtt/parser.rs @@ -173,44 +173,31 @@ pub fn parse_fixed_header(i: &[u8]) -> IResult<&[u8], FixedHeader> { )) } -#[inline] -#[allow(clippy::type_complexity)] -fn parse_connect_variable_flags(i: &[u8]) -> IResult<&[u8], (u8, u8, u8, u8, u8, u8, u8)> { - bits(tuple(( - take_bits(1u8), - take_bits(1u8), - take_bits(1u8), - take_bits(2u8), - take_bits(1u8), - take_bits(1u8), - take_bits(1u8), - )))(i) -} - #[inline] fn parse_connect(i: &[u8]) -> IResult<&[u8], MQTTConnectData> { let (i, protocol_string) = parse_mqtt_string(i)?; let (i, protocol_version) = be_u8(i)?; - let (i, flags) = parse_connect_variable_flags(i)?; + let (i, rawflags) = be_u8(i)?; let (i, keepalive) = be_u16(i)?; let (i, properties) = parse_properties(i, protocol_version == 5)?; let (i, client_id) = parse_mqtt_string(i)?; - let (i, will_properties) = parse_properties(i, protocol_version == 5 && flags.4 != 0)?; - let (i, will_topic) = cond(flags.4 != 0, parse_mqtt_string)(i)?; - let (i, will_message) = cond(flags.4 != 0, parse_mqtt_binary_data)(i)?; - let (i, username) = cond(flags.0 != 0, parse_mqtt_string)(i)?; - let (i, password) = cond(flags.1 != 0, parse_mqtt_binary_data)(i)?; + let (i, will_properties) = parse_properties(i, protocol_version == 5 && rawflags & 0x4 != 0)?; + let (i, will_topic) = cond(rawflags & 0x4 != 0, parse_mqtt_string)(i)?; + let (i, will_message) = cond(rawflags & 0x4 != 0, parse_mqtt_binary_data)(i)?; + let (i, username) = cond(rawflags & 0x80 != 0, parse_mqtt_string)(i)?; + let (i, password) = cond(rawflags & 0x40 != 0, parse_mqtt_binary_data)(i)?; Ok(( i, MQTTConnectData { protocol_string, protocol_version, - username_flag: flags.0 != 0, - password_flag: flags.1 != 0, - will_retain: flags.2 != 0, - will_qos: flags.3, - will_flag: flags.4 != 0, - clean_session: flags.5 != 0, + rawflags, + username_flag: rawflags & 0x80 != 0, + password_flag: rawflags & 0x40 != 0, + will_retain: rawflags & 0x20 != 0, + will_qos: (rawflags & 0x18) >> 3, + will_flag: rawflags & 0x4 != 0, + clean_session: rawflags & 0x2 != 0, keepalive, client_id, will_topic, diff --git a/src/Makefile.am b/src/Makefile.am index 5b83d60cfd42..f406beed4c2e 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -241,23 +241,6 @@ noinst_HEADERS = \ detect-quic-version.h \ detect-quic-cyu-hash.h \ detect-quic-cyu-string.h \ - detect-mqtt-connack-sessionpresent.h \ - detect-mqtt-connect-clientid.h \ - detect-mqtt-connect-flags.h \ - detect-mqtt-connect-password.h \ - detect-mqtt-connect-protocol-string.h \ - detect-mqtt-connect-username.h \ - detect-mqtt-connect-willmessage.h \ - detect-mqtt-connect-willtopic.h \ - detect-mqtt-flags.h \ - detect-mqtt-protocol-version.h \ - detect-mqtt-publish-message.h \ - detect-mqtt-publish-topic.h \ - detect-mqtt-qos.h \ - detect-mqtt-reason-code.h \ - detect-mqtt-subscribe-topic.h \ - detect-mqtt-type.h \ - detect-mqtt-unsubscribe-topic.h \ detect-msg.h \ detect-nfs-procedure.h \ detect-nfs-version.h \ @@ -840,23 +823,6 @@ libsuricata_c_a_SOURCES = \ detect-quic-version.c \ detect-quic-cyu-hash.c \ detect-quic-cyu-string.c \ - detect-mqtt-connack-sessionpresent.c \ - detect-mqtt-connect-clientid.c \ - detect-mqtt-connect-flags.c \ - detect-mqtt-connect-password.c \ - detect-mqtt-connect-protocol-string.c \ - detect-mqtt-connect-username.c \ - detect-mqtt-connect-willmessage.c \ - detect-mqtt-connect-willtopic.c \ - detect-mqtt-flags.c \ - detect-mqtt-protocol-version.c \ - detect-mqtt-publish-message.c \ - detect-mqtt-publish-topic.c \ - detect-mqtt-qos.c \ - detect-mqtt-reason-code.c \ - detect-mqtt-subscribe-topic.c \ - detect-mqtt-type.c \ - detect-mqtt-unsubscribe-topic.c \ detect-msg.c \ detect-nfs-procedure.c \ detect-nfs-version.c \ @@ -1209,6 +1175,7 @@ EXTRA_DIST = \ tests/detect-http2.c \ tests/detect-icmpv6-mtu.c \ tests/detect-icmpv6hdr.c \ + tests/detect-mqtt.c \ tests/detect-template.c \ tests/detect-transform-pcrexform.c \ tests/detect-transform-xor.c \ diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 0b7c9ccb2077..9b5886488166 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -28,6 +28,7 @@ #include "detect-engine-mpm.h" #include "detect-engine-prefilter.h" #include "detect-parse.h" +#include "detect-engine-content-inspection.h" int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver) { @@ -105,3 +106,27 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw) DETECT_TBLSIZE_IDX++; return DETECT_TBLSIZE_IDX - 1; } + +InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, uint32_t index, MultiGetTxBuffer GetBuf) +{ + InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index); + if (buffer == NULL) { + return NULL; + } + if (buffer->initialized) { + return buffer; + } + + const uint8_t *data = NULL; + uint32_t data_len = 0; + + if (!GetBuf(txv, flow_flags, index, &data, &data_len)) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + buffer->flags = DETECT_CI_FLAGS_SINGLE; + return buffer; +} diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index bd8fe6cce5a6..4328def5fc73 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -32,10 +32,14 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw); int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver); typedef bool (*SimpleGetTxBuffer)(void *, uint8_t, const uint8_t **, uint32_t *); +typedef bool (*MultiGetTxBuffer)(void *, uint8_t, uint32_t, const uint8_t **, uint32_t *); InspectionBuffer *DetectHelperGetData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, SimpleGetTxBuffer GetBuf); int DetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, bool toclient, bool toserver, InspectionBufferGetDataPtr GetData); +InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, uint32_t index, MultiGetTxBuffer GetBuf); #endif /* SURICATA_DETECT_ENGINE_HELPER_H */ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 5d4438485811..908e59401ef1 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -212,23 +212,6 @@ #include "detect-rfb-name.h" #include "detect-target.h" #include "detect-template-rust-buffer.h" -#include "detect-mqtt-type.h" -#include "detect-mqtt-flags.h" -#include "detect-mqtt-qos.h" -#include "detect-mqtt-protocol-version.h" -#include "detect-mqtt-reason-code.h" -#include "detect-mqtt-connect-flags.h" -#include "detect-mqtt-connect-clientid.h" -#include "detect-mqtt-connect-username.h" -#include "detect-mqtt-connect-password.h" -#include "detect-mqtt-connect-protocol-string.h" -#include "detect-mqtt-connect-willtopic.h" -#include "detect-mqtt-connect-willmessage.h" -#include "detect-mqtt-connack-sessionpresent.h" -#include "detect-mqtt-publish-topic.h" -#include "detect-mqtt-publish-message.h" -#include "detect-mqtt-subscribe-topic.h" -#include "detect-mqtt-unsubscribe-topic.h" #include "detect-quic-sni.h" #include "detect-quic-ua.h" #include "detect-quic-version.h" @@ -691,23 +674,6 @@ void SigTableSetup(void) DetectRfbNameRegister(); DetectTargetRegister(); DetectTemplateRustBufferRegister(); - DetectMQTTTypeRegister(); - DetectMQTTFlagsRegister(); - DetectMQTTQosRegister(); - DetectMQTTProtocolVersionRegister(); - DetectMQTTReasonCodeRegister(); - DetectMQTTConnectFlagsRegister(); - DetectMQTTConnectClientIDRegister(); - DetectMQTTConnectUsernameRegister(); - DetectMQTTConnectPasswordRegister(); - DetectMQTTConnectProtocolStringRegister(); - DetectMQTTConnectWillTopicRegister(); - DetectMQTTConnectWillMessageRegister(); - DetectMQTTConnackSessionPresentRegister(); - DetectMQTTPublishTopicRegister(); - DetectMQTTPublishMessageRegister(); - DetectMQTTSubscribeTopicRegister(); - DetectMQTTUnsubscribeTopicRegister(); DetectQuicSniRegister(); DetectQuicUaRegister(); DetectQuicVersionRegister(); @@ -738,12 +704,15 @@ void SigTableSetup(void) ScDetectDHCPRegister(); ScDetectWebsocketRegister(); ScDetectEnipRegister(); + ScDetectMqttRegister(); /* close keyword registration */ DetectBufferTypeCloseRegistration(); } #ifdef UNITTESTS +#include "tests/detect-mqtt.c" + void SigTableRegisterTests(void) { /* register the tests */ @@ -762,5 +731,7 @@ void SigTableRegisterTests(void) sigmatch_table[i].name); } } + // Tests with whole mqtt signature and not just unit testing the keyword + MQTTProtocolVersionRegisterTests(); } #endif diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 71af4c3a1659..58234e75c6ab 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -290,23 +290,6 @@ enum DetectKeywordId { DETECT_FTPDATA, DETECT_TARGET, DETECT_AL_TEMPLATE_BUFFER, - DETECT_AL_MQTT_TYPE, - DETECT_AL_MQTT_FLAGS, - DETECT_AL_MQTT_QOS, - DETECT_AL_MQTT_PROTOCOL_VERSION, - DETECT_AL_MQTT_REASON_CODE, - DETECT_AL_MQTT_CONNECT_FLAGS, - DETECT_AL_MQTT_CONNECT_CLIENTID, - DETECT_AL_MQTT_CONNECT_USERNAME, - DETECT_AL_MQTT_CONNECT_PASSWORD, - DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING, - DETECT_AL_MQTT_CONNECT_WILLTOPIC, - DETECT_AL_MQTT_CONNECT_WILLMESSAGE, - DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, - DETECT_AL_MQTT_PUBLISH_TOPIC, - DETECT_AL_MQTT_PUBLISH_MESSAGE, - DETECT_AL_MQTT_SUBSCRIBE_TOPIC, - DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC, DETECT_AL_QUIC_VERSION, DETECT_AL_QUIC_SNI, DETECT_AL_QUIC_UA, diff --git a/src/detect-http2.c b/src/detect-http2.c index 113fb1af3f06..4d954a5ac96a 100644 --- a/src/detect-http2.c +++ b/src/detect-http2.c @@ -33,6 +33,7 @@ #include "detect-engine-mpm.h" #include "detect-engine-prefilter.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-helper.h" #include "detect-http2.h" #include "util-byte.h" @@ -102,30 +103,8 @@ static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flags, void *txv, int list_id, uint32_t local_id) { - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_name(txv, flags, local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - - SCReturnPtr(buffer, "InspectionBuffer"); + return DetectHelperGetMultiData(det_ctx, transforms, _f, flags, txv, list_id, local_id, + (MultiGetTxBuffer)rs_http2_tx_get_header_name); } void DetectHttp2Register(void) diff --git a/src/detect-mqtt-connack-sessionpresent.c b/src/detect-mqtt-connack-sessionpresent.c deleted file mode 100644 index 4bb10eacacd2..000000000000 --- a/src/detect-mqtt-connack-sessionpresent.c +++ /dev/null @@ -1,294 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-connack-sessionpresent.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "^true|false|yes|no$" -static DetectParseRegex parse_regex; - -static int mqtt_connack_session_present_id = 0; - -static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTConnackSessionPresentRegisterTests(void); -void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.connack.session_present: keyword - */ -void DetectMQTTConnackSessionPresentRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = "match MQTT CONNACK session present flag"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = "/rules/mqtt-keywords.html#mqtt-connack-session-present"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = DetectMQTTConnackSessionPresentMatch; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = DetectMQTTConnackSessionPresentSetup; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free = DetectMQTTConnackSessionPresentFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = MQTTConnackSessionPresentRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister("mqtt.connack.session_present", ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present"); -} - -/** - * \internal - * \brief Function to match session_present flag of an MQTT CONNACK message - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnackSessionPresentData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const bool *de = (const bool *)ctx; - bool value = false; - - if (!de) - return 0; - - if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) ==0 ) { - return 0; - } - if (value != *de) { - return 0; - } - - return 1; -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.connack.session_present: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTConnackSessionPresentData on success - * \retval NULL on failure - */ -static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr) -{ - bool *de = NULL; - de = SCMalloc(sizeof(bool)); - if (unlikely(de == NULL)) - return NULL; - *de = false; - - if (strcmp(rawstr, "yes") == 0) { - *de = true; - } else if (strcmp(rawstr, "true") == 0) { - *de = true; - } else if (strcmp(rawstr, "no") == 0) { - *de = false; - } else if (strcmp(rawstr, "false") == 0) { - *de = false; - } else { - SCLogError("invalid session_present flag definition: %s", rawstr); - goto error; - } - - return de; - -error: - /* de can't be NULL here */ - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - bool *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTConnackSessionPresentParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, (SigMatchCtx *)de, - mqtt_connack_session_present_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTConnackSessionPresentData - * - * \param de pointer to DetectMQTTConnackSessionPresentData - */ -void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTConnackSessionPresentTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse01 (void) -{ - bool *de = NULL; - - de = DetectMQTTConnackSessionPresentParse("yes"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("true"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("false"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("no"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse02 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse("nix"); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse03 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse(""); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse04 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse(","); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTConnackSessionPresent - */ -void MQTTConnackSessionPresentRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01); - UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02); - UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03); - UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-connack-sessionpresent.h b/src/detect-mqtt-connack-sessionpresent.h deleted file mode 100644 index 42a7887b27f7..000000000000 --- a/src/detect-mqtt-connack-sessionpresent.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H -#define SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H - -void DetectMQTTConnackSessionPresentRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H */ diff --git a/src/detect-mqtt-connect-clientid.c b/src/detect-mqtt-connect-clientid.c deleted file mode 100644 index c3bc31474342..000000000000 --- a/src/detect-mqtt-connect-clientid.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.clientid sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-clientid.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.clientid" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-clientid" -#define BUFFER_NAME "mqtt.connect.clientid" -#define BUFFER_DESC "MQTT CONNECT client ID" -static int g_buffer_id = 0; - -static int DetectMQTTConnectClientIDSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_clientid(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectClientIDRegister(void) -{ - /* mqtt.connect.clientid sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].desc = "sticky buffer to match on the MQTT CONNECT client ID"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].Setup = DetectMQTTConnectClientIDSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-clientid.h b/src/detect-mqtt-connect-clientid.h deleted file mode 100644 index 691573c8d21a..000000000000 --- a/src/detect-mqtt-connect-clientid.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H -#define SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H - -void DetectMQTTConnectClientIDRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H */ diff --git a/src/detect-mqtt-connect-flags.c b/src/detect-mqtt-connect-flags.c deleted file mode 100644 index fa44af9ee042..000000000000 --- a/src/detect-mqtt-connect-flags.c +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-connect-flags.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "(?: *,?!?(?:username|password|will|will_retain|clean_session))+" -static DetectParseRegex parse_regex; - -static int mqtt_connect_flags_id = 0; - -static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTConnectFlagsSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTConnectFlagsRegisterTests(void); -void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *); - -typedef struct DetectMQTTConnectFlagsData_ { - MQTTFlagState username, - password, - will, - will_retain, - clean_session; -} DetectMQTTConnectFlagsData; - -/** - * \brief Registration function for mqtt.connect.flags: keyword - */ -void DetectMQTTConnectFlagsRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].name = "mqtt.connect.flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].desc = "match MQTT CONNECT variable header flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-connect-flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].AppLayerTxMatch = DetectMQTTConnectFlagsMatch; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Setup = DetectMQTTConnectFlagsSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Free = DetectMQTTConnectFlagsFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].RegisterTests = MQTTConnectFlagsRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister("mqtt.connect.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - mqtt_connect_flags_id = DetectBufferTypeGetByName("mqtt.connect.flags"); -} - -/** - * \internal - * \brief Function to match variable header flags of an MQTT CONNECT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnectFlagsData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectMQTTConnectFlagsData *de = (const DetectMQTTConnectFlagsData *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_connect_flags(txv, de->username, de->password, de->will, - de->will_retain, de->clean_session); - } - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.connect.flags: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTConnectFlagsData on success - * \retval NULL on failure - */ -static DetectMQTTConnectFlagsData *DetectMQTTConnectFlagsParse(const char *rawstr) -{ - char copy[strlen(rawstr) + 1]; - - DetectMQTTConnectFlagsData *de = SCCalloc(1, sizeof(DetectMQTTConnectFlagsData)); - if (unlikely(de == NULL)) - return NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 1) { - SCLogError("invalid flag definition: %s", rawstr); - goto error; - } - - de->username = de->password = de->will = MQTT_DONT_CARE; - de->will_retain = de->clean_session = MQTT_DONT_CARE; - - strlcpy(copy, rawstr, sizeof(copy)); - char *xsaveptr = NULL; - char *flagv = strtok_r(copy, ",", &xsaveptr); - while (flagv != NULL) { - while (*flagv != '\0' && isblank(*flagv)) { - flagv++; - } - if (strlen(flagv) < 2) { - SCLogError("malformed flag value: %s", flagv); - goto error; - } else { - int offset = 0; - MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; - if (flagv[0] == '!') { - /* negated flag */ - offset = 1; /* skip negation operator during comparison */ - fs_to_set = MQTT_CANT_BE_SET; - } - if (strcmp(flagv+offset, "username") == 0) { - if (de->username != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->username = fs_to_set; - } else if (strcmp(flagv+offset, "password") == 0) { - if (de->password != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->password = fs_to_set; - } else if (strcmp(flagv+offset, "will") == 0) { - if (de->will != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->will = fs_to_set; - } else if (strcmp(flagv+offset, "will_retain") == 0) { - if (de->will_retain != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->will_retain = fs_to_set; - } else if (strcmp(flagv+offset, "clean_session") == 0) { - if (de->clean_session != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->clean_session = fs_to_set; - } else { - SCLogError("invalid flag definition: %s", flagv); - goto error; - } - } - flagv = strtok_r(NULL, ",", &xsaveptr); - } - - pcre2_match_data_free(match); - return de; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (de) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTConnectFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectMQTTConnectFlagsData *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTConnectFlagsParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNECT_FLAGS, (SigMatchCtx *)de, - mqtt_connect_flags_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTConnectFlagsData - * - * \param de pointer to DetectMQTTConnectFlagsData - */ -void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTConnectFlagsTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse01 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("username"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse("username,password,will,will_retain,clean_session"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse("!username,!password,!will,!will_retain,!clean_session"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse(" username,password"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse02 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("foobar"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse03 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("will,!"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse04 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse(""); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse05 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse05 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("username, username"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("!username, username"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("!username,password,!password"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("will, username,password, !will, will"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTConnectFlags - */ -void MQTTConnectFlagsRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTConnectFlagsTestParse01", MQTTConnectFlagsTestParse01); - UtRegisterTest("MQTTConnectFlagsTestParse02", MQTTConnectFlagsTestParse02); - UtRegisterTest("MQTTConnectFlagsTestParse03", MQTTConnectFlagsTestParse03); - UtRegisterTest("MQTTConnectFlagsTestParse04", MQTTConnectFlagsTestParse04); - UtRegisterTest("MQTTConnectFlagsTestParse05", MQTTConnectFlagsTestParse05); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-connect-flags.h b/src/detect-mqtt-connect-flags.h deleted file mode 100644 index 2c5588060412..000000000000 --- a/src/detect-mqtt-connect-flags.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_FLAGS_H -#define SURICATA_DETECT_MQTT_CONNECT_FLAGS_H - -void DetectMQTTConnectFlagsRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_FLAGS_H */ diff --git a/src/detect-mqtt-connect-password.c b/src/detect-mqtt-connect-password.c deleted file mode 100644 index 57ec1ba24ff9..000000000000 --- a/src/detect-mqtt-connect-password.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.password sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-password.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.password" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-password" -#define BUFFER_NAME "mqtt.connect.password" -#define BUFFER_DESC "MQTT CONNECT password" -static int g_buffer_id = 0; - -static int DetectMQTTConnectPasswordSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_password(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectPasswordRegister(void) -{ - /* mqtt.connect.password sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].desc = "sticky buffer to match on the MQTT CONNECT password"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].Setup = DetectMQTTConnectPasswordSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-password.h b/src/detect-mqtt-connect-password.h deleted file mode 100644 index c4b12d946255..000000000000 --- a/src/detect-mqtt-connect-password.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H -#define SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H - -void DetectMQTTConnectPasswordRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H */ diff --git a/src/detect-mqtt-connect-protocol-string.c b/src/detect-mqtt-connect-protocol-string.c deleted file mode 100644 index 254cc3e2d24d..000000000000 --- a/src/detect-mqtt-connect-protocol-string.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.protocolstring sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-protocol-string.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.protocol_string" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-protocol_string" -#define BUFFER_NAME "mqtt.connect.protocol_string" -#define BUFFER_DESC "MQTT CONNECT protocol string" -static int g_buffer_id = 0; - -static int DetectMQTTConnectProtocolStringSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_protocol_string(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectProtocolStringRegister(void) -{ - /* mqtt.connect.protocol_string sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].desc = - "sticky buffer to match on the MQTT CONNECT protocol string"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].Setup = - DetectMQTTConnectProtocolStringSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-protocol-string.h b/src/detect-mqtt-connect-protocol-string.h deleted file mode 100644 index 0ab324db583f..000000000000 --- a/src/detect-mqtt-connect-protocol-string.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H -#define SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H - -void DetectMQTTConnectProtocolStringRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H */ diff --git a/src/detect-mqtt-connect-username.c b/src/detect-mqtt-connect-username.c deleted file mode 100644 index 607a35685493..000000000000 --- a/src/detect-mqtt-connect-username.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.username sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-username.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.username" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-username" -#define BUFFER_NAME "mqtt.connect.username" -#define BUFFER_DESC "MQTT CONNECT username" -static int g_buffer_id = 0; - -static int DetectMQTTConnectUsernameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_username(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectUsernameRegister(void) -{ - /* mqtt.connect.username sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].desc = "sticky buffer to match on the MQTT CONNECT username"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].Setup = DetectMQTTConnectUsernameSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-username.h b/src/detect-mqtt-connect-username.h deleted file mode 100644 index 9ae55277d718..000000000000 --- a/src/detect-mqtt-connect-username.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_USERNAME_H -#define SURICATA_DETECT_MQTT_CONNECT_USERNAME_H - -void DetectMQTTConnectUsernameRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_USERNAME_H */ diff --git a/src/detect-mqtt-connect-willmessage.c b/src/detect-mqtt-connect-willmessage.c deleted file mode 100644 index 8ff68a6594e3..000000000000 --- a/src/detect-mqtt-connect-willmessage.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.willmessage sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-willmessage.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.willmessage" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willmessage" -#define BUFFER_NAME "mqtt.connect.willmessage" -#define BUFFER_DESC "MQTT CONNECT will message" -static int g_buffer_id = 0; - -static int DetectMQTTConnectWillMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_willmessage(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectWillMessageRegister(void) -{ - /* mqtt.connect.willmessage sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].desc = "sticky buffer to match on the MQTT CONNECT will message"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].Setup = DetectMQTTConnectWillMessageSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-willmessage.h b/src/detect-mqtt-connect-willmessage.h deleted file mode 100644 index 4f62f33712bf..000000000000 --- a/src/detect-mqtt-connect-willmessage.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H -#define SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H - -void DetectMQTTConnectWillMessageRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H */ diff --git a/src/detect-mqtt-connect-willtopic.c b/src/detect-mqtt-connect-willtopic.c deleted file mode 100644 index 55efe93122eb..000000000000 --- a/src/detect-mqtt-connect-willtopic.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.willtopic sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-willtopic.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.willtopic" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willtopic" -#define BUFFER_NAME "mqtt.connect.willtopic" -#define BUFFER_DESC "MQTT CONNECT will topic" -static int g_buffer_id = 0; - -static int DetectMQTTConnectWillTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_willtopic(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectWillTopicRegister(void) -{ - /* mqtt.connect.willtopic sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].desc = "sticky buffer to match on the MQTT CONNECT will topic"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].Setup = DetectMQTTConnectWillTopicSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-willtopic.h b/src/detect-mqtt-connect-willtopic.h deleted file mode 100644 index fa571c1a1c48..000000000000 --- a/src/detect-mqtt-connect-willtopic.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H -#define SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H - -void DetectMQTTConnectWillTopicRegister(void); - -#endif /* SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H */ diff --git a/src/detect-mqtt-flags.c b/src/detect-mqtt-flags.c deleted file mode 100644 index ad2fed2a0ab3..000000000000 --- a/src/detect-mqtt-flags.c +++ /dev/null @@ -1,359 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-flags.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "(?: *,?!?(?:retain|dup))+" -static DetectParseRegex parse_regex; - -static int mqtt_flags_id = 0; - -static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTFlagsSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTFlagsRegisterTests(void); -void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *); - -typedef struct DetectMQTTFlagsData_ { - MQTTFlagState retain, dup; -} DetectMQTTFlagsData; - -/** - * \brief Registration function for mqtt.flags: keyword - */ -void DetectMQTTFlagsRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_FLAGS].name = "mqtt.flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].desc = "match MQTT fixed header flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].AppLayerTxMatch = DetectMQTTFlagsMatch; - sigmatch_table[DETECT_AL_MQTT_FLAGS].Setup = DetectMQTTFlagsSetup; - sigmatch_table[DETECT_AL_MQTT_FLAGS].Free = DetectMQTTFlagsFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_FLAGS].RegisterTests = MQTTFlagsRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister( - "mqtt.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_flags_id = DetectBufferTypeGetByName("mqtt.flags"); -} - -/** - * \internal - * \brief Function to match fixed header flags of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTFlagsData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectMQTTFlagsData *de = (const DetectMQTTFlagsData *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_flags(txv, de->retain, de->dup); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.flags: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTFlagsData on success - * \retval NULL on failure - */ -static DetectMQTTFlagsData *DetectMQTTFlagsParse(const char *rawstr) -{ - - DetectMQTTFlagsData *de = SCCalloc(1, sizeof(DetectMQTTFlagsData)); - if (unlikely(de == NULL)) - return NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 1) { - SCLogError("invalid flag definition: %s", rawstr); - if (match) { - pcre2_match_data_free(match); - } - SCFree(de); - return NULL; - } - - de->retain = de->dup = MQTT_DONT_CARE; - - char copy[strlen(rawstr)+1]; - strlcpy(copy, rawstr, sizeof(copy)); - char *xsaveptr = NULL; - - /* Iterate through comma-separated string... */ - char *flagv = strtok_r(copy, ",", &xsaveptr); - while (flagv != NULL) { - /* skip blanks */ - while (*flagv != '\0' && isblank(*flagv)) { - flagv++; - } - if (strlen(flagv) < 2) { - /* flags have a minimum length */ - SCLogError("malformed flag value: %s", flagv); - goto error; - } else { - int offset = 0; - MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; - if (flagv[0] == '!') { - /* negated flag */ - offset = 1; /* skip negation operator during comparison */ - fs_to_set = MQTT_CANT_BE_SET; - } - if (strcmp(flagv+offset, "dup") == 0) { - if (de->dup != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->dup = fs_to_set; - } else if (strcmp(flagv+offset, "retain") == 0) { - if (de->retain != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->retain = fs_to_set; - } else { - SCLogError("invalid flag definition: %s", flagv); - goto error; - } - } - flagv = strtok_r(NULL, ",", &xsaveptr); - } - - pcre2_match_data_free(match); - return de; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (de) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectMQTTFlagsData *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTFlagsParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_FLAGS, (SigMatchCtx *)de, mqtt_flags_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTFlagsData - * - * \param de pointer to DetectMQTTFlagsData - */ -void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTFlagsTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse01 (void) -{ - DetectMQTTFlagsData *de = NULL; - - de = DetectMQTTFlagsParse("retain"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("retain,dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("dup, retain"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTFlagsTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse02 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("retain,!dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTFlagsTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse03 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("ref"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTFlagsTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse04 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("dup,!"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTFlagsTestParse05 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse05 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("dup,!dup"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - de = DetectMQTTFlagsParse("!retain,retain"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTFlags - */ -void MQTTFlagsRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTFlagsTestParse01", MQTTFlagsTestParse01); - UtRegisterTest("MQTTFlagsTestParse02", MQTTFlagsTestParse02); - UtRegisterTest("MQTTFlagsTestParse03", MQTTFlagsTestParse03); - UtRegisterTest("MQTTFlagsTestParse04", MQTTFlagsTestParse04); - UtRegisterTest("MQTTFlagsTestParse05", MQTTFlagsTestParse05); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-flags.h b/src/detect-mqtt-flags.h deleted file mode 100644 index 1f792b36e98f..000000000000 --- a/src/detect-mqtt-flags.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_FLAGS_H -#define SURICATA_DETECT_MQTT_FLAGS_H - -void DetectMQTTFlagsRegister(void); - -#endif /* SURICATA_DETECT_MQTT_FLAGS_H */ diff --git a/src/detect-mqtt-protocol-version.c b/src/detect-mqtt-protocol-version.c deleted file mode 100644 index 8368d49580e3..000000000000 --- a/src/detect-mqtt-protocol-version.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-uint.h" -#include "detect-mqtt-protocol-version.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_protocol_version_id = 0; - -static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTProtocolVersionSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTProtocolVersionRegisterTests(void); -void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.protocol_version: keyword - */ -void DetectMQTTProtocolVersionRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].name = "mqtt.protocol_version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].desc = "match MQTT protocol version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].url = "/rules/mqtt-keywords.html#mqtt-protocol-version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].AppLayerTxMatch = DetectMQTTProtocolVersionMatch; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Setup = DetectMQTTProtocolVersionSetup; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Free = DetectMQTTProtocolVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].RegisterTests = MQTTProtocolVersionRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister("mqtt.protocol_version", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - mqtt_protocol_version_id = DetectBufferTypeGetByName("mqtt.protocol_version"); -} - -/** - * \internal - * \brief Function to match protocol version of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTProtocolVersionData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectU8Data *de = (const DetectU8Data *)ctx; - uint8_t version; - - version = rs_mqtt_tx_get_protocol_version(state); - - return DetectU8Match(version, de); -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTProtocolVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectU8Data *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectU8Parse(rawstr); - if (de == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_PROTOCOL_VERSION, (SigMatchCtx *)de, - mqtt_protocol_version_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - rs_detect_u8_free(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTProtocolVersionData - * - * \param de pointer to DetectMQTTProtocolVersionData - */ -void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - rs_detect_u8_free(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTProtocolVersionTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse01 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:3; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:3; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse02 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:>3; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:<44; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse03 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse04 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:<444; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTProtocolVersion - */ -void MQTTProtocolVersionRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTProtocolVersionTestParse01", MQTTProtocolVersionTestParse01); - UtRegisterTest("MQTTProtocolVersionTestParse02", MQTTProtocolVersionTestParse02); - UtRegisterTest("MQTTProtocolVersionTestParse03", MQTTProtocolVersionTestParse03); - UtRegisterTest("MQTTProtocolVersionTestParse04", MQTTProtocolVersionTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-protocol-version.h b/src/detect-mqtt-protocol-version.h deleted file mode 100644 index 7f8cac288358..000000000000 --- a/src/detect-mqtt-protocol-version.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H -#define SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H - -void DetectMQTTProtocolVersionRegister(void); - -#endif /* SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H */ diff --git a/src/detect-mqtt-publish-message.c b/src/detect-mqtt-publish-message.c deleted file mode 100644 index 02595737271c..000000000000 --- a/src/detect-mqtt-publish-message.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.publish.message sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-publish-message.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.publish.message" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-message" -#define BUFFER_NAME "mqtt.publish.message" -#define BUFFER_DESC "MQTT PUBLISH message" -static int g_buffer_id = 0; - -static int DetectMQTTPublishMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_publish_message(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTPublishMessageRegister(void) -{ - /* mqtt.publish.message sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].desc = "sticky buffer to match on the MQTT PUBLISH message"; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].Setup = DetectMQTTPublishMessageSetup; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-publish-message.h b/src/detect-mqtt-publish-message.h deleted file mode 100644 index e5b5f0db3554..000000000000 --- a/src/detect-mqtt-publish-message.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H -#define SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H - -void DetectMQTTPublishMessageRegister(void); - -#endif /* SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H */ diff --git a/src/detect-mqtt-publish-topic.c b/src/detect-mqtt-publish-topic.c deleted file mode 100644 index 6538857e8c2b..000000000000 --- a/src/detect-mqtt-publish-topic.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.publish.topic sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-publish-topic.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.publish.topic" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-topic" -#define BUFFER_NAME "mqtt.publish.topic" -#define BUFFER_DESC "MQTT PUBLISH topic" -static int g_buffer_id = 0; - -static int DetectMQTTPublishTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_publish_topic(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTPublishTopicRegister(void) -{ - /* mqtt.publish.topic sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].desc = "sticky buffer to match on the MQTT PUBLISH topic"; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].Setup = DetectMQTTPublishTopicSetup; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-publish-topic.h b/src/detect-mqtt-publish-topic.h deleted file mode 100644 index aa8225c92233..000000000000 --- a/src/detect-mqtt-publish-topic.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H -#define SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H - -void DetectMQTTPublishTopicRegister(void); - -#endif /* SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H */ diff --git a/src/detect-mqtt-qos.c b/src/detect-mqtt-qos.c deleted file mode 100644 index a94530a2957b..000000000000 --- a/src/detect-mqtt-qos.c +++ /dev/null @@ -1,258 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-qos.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_qos_id = 0; - -static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTQosSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTQosRegisterTests(void); -void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.qos: keyword - */ -void DetectMQTTQosRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_QOS].name = "mqtt.qos"; - sigmatch_table[DETECT_AL_MQTT_QOS].desc = "match MQTT fixed header QOS level"; - sigmatch_table[DETECT_AL_MQTT_QOS].url = "/rules/mqtt-keywords.html#mqtt-qos"; - sigmatch_table[DETECT_AL_MQTT_QOS].AppLayerTxMatch = DetectMQTTQosMatch; - sigmatch_table[DETECT_AL_MQTT_QOS].Setup = DetectMQTTQosSetup; - sigmatch_table[DETECT_AL_MQTT_QOS].Free = DetectMQTTQosFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_QOS].RegisterTests = MQTTQosRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister( - "mqtt.qos", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_qos_id = DetectBufferTypeGetByName("mqtt.qos"); -} - -/** - * \internal - * \brief Function to match fixed header QOS field of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into uint8_t. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_qos(txv, *de); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.qos: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTQosData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTQosParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - uint8_t val; - - ret = StringParseU8RangeCheck(&val, 10, 0, rawstr, 0, 2); - if (ret < 0) { - SCLogError("invalid MQTT QOS level: %s", rawstr); - return NULL; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - return NULL; - *de = val; - - return de; -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTQosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTQosParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_QOS, (SigMatchCtx *)de, mqtt_qos_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTQosData - * - * \param de pointer to DetectMQTTQosData - */ -void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTQosTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse01 (void) -{ - uint8_t *de = NULL; - - de = DetectMQTTQosParse("0"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 0); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse(" 0"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 0); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse("1"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 1); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse("2"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 2); - DetectMQTTQosFree(NULL, de); - - PASS; -} - -/** - * \test MQTTQosTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTQosParse("3"); - if (de) { - DetectMQTTQosFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTQosTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTQosParse("12"); - if (de) { - DetectMQTTQosFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTQos - */ -void MQTTQosRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTQosTestParse01", MQTTQosTestParse01); - UtRegisterTest("MQTTQosTestParse02", MQTTQosTestParse02); - UtRegisterTest("MQTTQosTestParse03", MQTTQosTestParse03); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-qos.h b/src/detect-mqtt-qos.h deleted file mode 100644 index b96f630ebbdf..000000000000 --- a/src/detect-mqtt-qos.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_QOS_H -#define SURICATA_DETECT_MQTT_QOS_H - -void DetectMQTTQosRegister(void); - -#endif /* SURICATA_DETECT_MQTT_QOS_H */ diff --git a/src/detect-mqtt-reason-code.c b/src/detect-mqtt-reason-code.c deleted file mode 100644 index 1c60b371919c..000000000000 --- a/src/detect-mqtt-reason-code.c +++ /dev/null @@ -1,294 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-reason-code.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "^\\s*\\d+\\s*$" -static DetectParseRegex parse_regex; - -static int mqtt_reason_code_id = 0; - -static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTReasonCodeSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTReasonCodeRegisterTests(void); -void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.reason_code: keyword - */ -void DetectMQTTReasonCodeRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].name = "mqtt.reason_code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].alias = "mqtt.connack.return_code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].desc = "match MQTT 5.0+ reason code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].url = "/rules/mqtt-keywords.html#mqtt-reason-code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].AppLayerTxMatch = DetectMQTTReasonCodeMatch; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Setup = DetectMQTTReasonCodeSetup; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Free = DetectMQTTReasonCodeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].RegisterTests = MQTTReasonCodeRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister("mqtt.reason_code", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - mqtt_reason_code_id = DetectBufferTypeGetByName("mqtt.reason_code"); -} - -/** - * \internal - * \brief Function to match reason code of an MQTT 5.0 Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTReasonCodeData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - uint8_t code; - - if (!de) - return 0; - - if (rs_mqtt_tx_get_reason_code(txv, &code) == 0) { - /* this function does not return a code that needs to be compared, - so we can just return the result of the check implemented in - Rust */ - return rs_mqtt_tx_unsuback_has_reason_code(txv, *de); - } else { - if (code == *de) - return 1; - } - return 0; -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.reason_code: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTReasonCodeData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTReasonCodeParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - uint8_t val; - - ret = StringParseUint8(&val, 10, 0, rawstr); - if (ret < 0) { - SCLogError("invalid MQTT reason code: %s", rawstr); - return NULL; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - return NULL; - *de = (uint8_t) val; - - return de; -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTReasonCodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTReasonCodeParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_REASON_CODE, (SigMatchCtx *)de, - mqtt_reason_code_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTReasonCodeData - * - * \param de pointer to DetectMQTTReasonCodeData - */ -void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTReasonCodeTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse01 (void) -{ - uint8_t *de = NULL; - - de = DetectMQTTReasonCodeParse("3"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 3); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse(" 4"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 4); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse(" 5"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 5); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse("255"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 255); - DetectMQTTReasonCodeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse("6X"); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse(""); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse04 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse("256"); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTReasonCode - */ -void MQTTReasonCodeRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTReasonCodeTestParse01", MQTTReasonCodeTestParse01); - UtRegisterTest("MQTTReasonCodeTestParse02", MQTTReasonCodeTestParse02); - UtRegisterTest("MQTTReasonCodeTestParse03", MQTTReasonCodeTestParse03); - UtRegisterTest("MQTTReasonCodeTestParse04", MQTTReasonCodeTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-reason-code.h b/src/detect-mqtt-reason-code.h deleted file mode 100644 index ba7f0146bdb1..000000000000 --- a/src/detect-mqtt-reason-code.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_REASON_CODE_H -#define SURICATA_DETECT_MQTT_REASON_CODE_H - -void DetectMQTTReasonCodeRegister(void); - -#endif /* SURICATA_DETECT_MQTT_REASON_CODE_H */ diff --git a/src/detect-mqtt-subscribe-topic.c b/src/detect-mqtt-subscribe-topic.c deleted file mode 100644 index 12e882aed063..000000000000 --- a/src/detect-mqtt-subscribe-topic.c +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "conf.h" -#include "decode.h" -#include "detect.h" -#include "detect-content.h" -#include "detect-parse.h" -#include "detect-pcre.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-subscribe-topic.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "rust-bindings.h" - -#include "threads.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-profiling.h" - -static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); - -static int g_mqtt_subscribe_topic_buffer_id = 0; - -static uint32_t subscribe_topic_match_limit = 100; - -static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv, - int list_id, uint32_t local_id) -{ - SCEnter(); - - if (subscribe_topic_match_limit > 0 && local_id >= subscribe_topic_match_limit) - return NULL; - - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_mqtt_tx_get_subscribe_topic(txv, local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -/** - * \brief Registration function for keyword: mqtt.subscribe.topic - */ -void DetectMQTTSubscribeTopicRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].name = "mqtt.subscribe.topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT SUBSCRIBE topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-subscribe-topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].Setup = DetectMQTTSubscribeTopicSetup; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - intmax_t val = 0; - if (ConfGetInt("app-layer.protocols.mqtt.subscribe-topic-match-limit", &val)) { - subscribe_topic_match_limit = val; - } - if (subscribe_topic_match_limit <= 0) { - SCLogDebug("Using unrestricted MQTT SUBSCRIBE topic matching"); - } else { - SCLogDebug("Using MQTT SUBSCRIBE topic match-limit setting of: %u", - subscribe_topic_match_limit); - } - - DetectAppLayerMultiRegister("mqtt.subscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - MQTTSubscribeTopicGetData, 1, 1); - - DetectBufferTypeSetDescriptionByName("mqtt.subscribe.topic", - "subscribe topic query"); - - g_mqtt_subscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.subscribe.topic"); - - DetectBufferTypeSupportsMultiInstance("mqtt.subscribe.topic"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_subscribe_topic_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - return 0; -} diff --git a/src/detect-mqtt-subscribe-topic.h b/src/detect-mqtt-subscribe-topic.h deleted file mode 100644 index 868188af4716..000000000000 --- a/src/detect-mqtt-subscribe-topic.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H -#define SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H - -void DetectMQTTSubscribeTopicRegister(void); - -#endif /* SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H */ diff --git a/src/detect-mqtt-type.c b/src/detect-mqtt-type.c deleted file mode 100644 index 60b5386de838..000000000000 --- a/src/detect-mqtt-type.c +++ /dev/null @@ -1,256 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-type.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_type_id = 0; - -static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTTypeSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTTypeRegisterTests(void); -void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.type: keyword - */ -void DetectMQTTTypeRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_TYPE].name = "mqtt.type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].desc = "match MQTT control packet type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].url = "/rules/mqtt-keywords.html#mqtt-type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].AppLayerTxMatch = DetectMQTTTypeMatch; - sigmatch_table[DETECT_AL_MQTT_TYPE].Setup = DetectMQTTTypeSetup; - sigmatch_table[DETECT_AL_MQTT_TYPE].Free = DetectMQTTTypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_TYPE].RegisterTests = MQTTTypeRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister( - "mqtt.type", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_type_id = DetectBufferTypeGetByName("mqtt.type"); -} - -/** - * \internal - * \brief Function to match control packet type of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTTypeData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_type(txv, *de); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.type: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTTypeData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTTypeParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - - ret = rs_mqtt_cstr_message_code(rawstr); - // negative value denotes invalid input - if(ret < 0) { - SCLogError("unknown mqtt.type value %s", rawstr); - goto error; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - goto error; - - *de = (uint8_t) ret; - - return de; - -error: - if (de != NULL) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTTypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTTypeParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_TYPE, (SigMatchCtx *)de, mqtt_type_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTTypeData - * - * \param de pointer to DetectMQTTTypeData - */ -void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTTypeTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse01 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("CONNECT"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 1); - DetectMQTTTypeFree(NULL, de); - - de = DetectMQTTTypeParse("PINGRESP"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 13); - DetectMQTTTypeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTTypeTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("auth"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 15); - DetectMQTTTypeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTTypeTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("invalidopt"); - if (de) { - DetectMQTTTypeFree(NULL, de); - FAIL; - } - - de = DetectMQTTTypeParse("unassigned"); - if (de) { - DetectMQTTTypeFree(NULL, de); - FAIL; - } - - PASS; -} - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTType - */ -void MQTTTypeRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTTypeTestParse01", MQTTTypeTestParse01); - UtRegisterTest("MQTTTypeTestParse02", MQTTTypeTestParse02); - UtRegisterTest("MQTTTypeTestParse03", MQTTTypeTestParse03); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-type.h b/src/detect-mqtt-type.h deleted file mode 100644 index 7139e183deba..000000000000 --- a/src/detect-mqtt-type.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_TYPE_H -#define SURICATA_DETECT_MQTT_TYPE_H - -void DetectMQTTTypeRegister(void); - -#endif /* SURICATA_DETECT_MQTT_TYPE_H */ diff --git a/src/detect-mqtt-unsubscribe-topic.c b/src/detect-mqtt-unsubscribe-topic.c deleted file mode 100644 index 7b4b8a00f493..000000000000 --- a/src/detect-mqtt-unsubscribe-topic.c +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "conf.h" -#include "decode.h" -#include "detect.h" -#include "detect-content.h" -#include "detect-parse.h" -#include "detect-pcre.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-unsubscribe-topic.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "rust-bindings.h" - -#include "threads.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-profiling.h" - -static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); - -static int g_mqtt_unsubscribe_topic_buffer_id = 0; - -static uint32_t unsubscribe_topic_match_limit = 100; - -static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv, - int list_id, uint32_t local_id) -{ - SCEnter(); - - if (unsubscribe_topic_match_limit > 0 && local_id >= unsubscribe_topic_match_limit) - return NULL; - - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_mqtt_tx_get_unsubscribe_topic(txv, local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -/** - * \brief Registration function for keyword: mqtt.unsubscribe.topic - */ -void DetectMQTTUnsubscribeTopicRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].name = "mqtt.unsubscribe.topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT UNSUBSCRIBE topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-unsubscribe-topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].Setup = DetectMQTTUnsubscribeTopicSetup; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - intmax_t val = 0; - if (ConfGetInt("app-layer.protocols.mqtt.unsubscribe-topic-match-limit", &val)) { - unsubscribe_topic_match_limit = val; - } - if (unsubscribe_topic_match_limit <= 0) { - SCLogDebug("Using unrestricted MQTT UNSUBSCRIBE topic matching"); - } else { - SCLogDebug("Using MQTT UNSUBSCRIBE topic match-limit setting of: %i", - unsubscribe_topic_match_limit); - } - - DetectAppLayerMultiRegister("mqtt.unsubscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - MQTTUnsubscribeTopicGetData, 1, 1); - - DetectBufferTypeSetDescriptionByName("mqtt.unsubscribe.topic", - "unsubscribe topic query"); - - g_mqtt_unsubscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.unsubscribe.topic"); - - DetectBufferTypeSupportsMultiInstance("mqtt.unsubscribe.topic"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_unsubscribe_topic_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - return 0; -} diff --git a/src/detect-mqtt-unsubscribe-topic.h b/src/detect-mqtt-unsubscribe-topic.h deleted file mode 100644 index 18e51c33c435..000000000000 --- a/src/detect-mqtt-unsubscribe-topic.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H -#define SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H - -void DetectMQTTUnsubscribeTopicRegister(void); - -#endif /* SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H */ diff --git a/src/tests/detect-mqtt.c b/src/tests/detect-mqtt.c new file mode 100644 index 000000000000..3a24dc4b321a --- /dev/null +++ b/src/tests/detect-mqtt.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "util-unittest.h" + +#include "rust.h" + +/** + * \test MQTTProtocolVersionTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:3; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:3; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse02 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:>3; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:<44; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse04(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:<444; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \brief this function registers unit tests for MQTTProtocolVersion + */ +static void MQTTProtocolVersionRegisterTests(void) +{ + UtRegisterTest("MQTTProtocolVersionTestParse01", MQTTProtocolVersionTestParse01); + UtRegisterTest("MQTTProtocolVersionTestParse02", MQTTProtocolVersionTestParse02); + UtRegisterTest("MQTTProtocolVersionTestParse03", MQTTProtocolVersionTestParse03); + UtRegisterTest("MQTTProtocolVersionTestParse04", MQTTProtocolVersionTestParse04); +}