Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mqtt rust keywords 4863 v1 #11316

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/userguide/rules/mqtt-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,22 @@ Valid values are :

where ``UNASSIGNED`` refers to message type code 0.

mqtt.type uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`.

Examples::

mqtt.type:CONNECT;
mqtt.type:PUBLISH;
mqtt.type:2;


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 <rules-integer-keywords>`

Valid flags are:

* ``dup`` (duplicate message)
Expand Down Expand Up @@ -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 <rules-integer-keywords>`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now use all the operators


Examples::

# match on attempts to unsubscribe from a non-subscribed topic
Expand Down Expand Up @@ -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 <rules-integer-keywords>`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now match on the unassigned bit and the qos 2 bits if we want


Valid flags are:

* ``username`` (message contains a username)
Expand Down
1 change: 1 addition & 0 deletions rust/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ exclude = [
"IPPROTO_TCP",
"IPPROTO_UDP",
"SRepCatGetByShortname",
"SIG_FLAG_TOSERVER",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@satta why is MQTT detection only to server ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I just grepped through detect-mqtt-* and saw many instances of SIG_FLAG_TOSERVER... well, not all of the things that are alerted on in the detection keywords are sent to the broker, but most are (e.g. anything with CONNECT or PUBLISH, but not CONNACK, the reason code, etc.).
Could be a copy-paste artifact; interesting that these keywords still seem to work though.

Maybe I should also revisit the code and check if maybe the transactions the parser produces are deliberately registered as being toserver because I didn't know an alternative (even though they likely contain messages in various directions) and that's why we want to apply the keywords to toserver.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there is no SIG_FLAG_TOCLIENT

]

# Types of items that we'll generate. If empty, then all types of item are emitted.
Expand Down
5 changes: 5 additions & 0 deletions rust/derive/src/applayerevent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -159,5 +162,7 @@ mod test {
transform_name("UnassignedMsgType"),
"unassigned_msg_type".to_string()
);
assert_eq!(transform_name("SAMECASE"), "samecase".to_string());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine in a test.

assert_eq!(transform_name("ZFlagSet"), "z_flag_set".to_string());
}
}
7 changes: 5 additions & 2 deletions rust/derive/src/stringenum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ pub fn derive_enum_string<T: std::str::FromStr + quote::ToTokens>(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 {
Expand Down Expand Up @@ -84,8 +87,8 @@ pub fn derive_enum_string<T: std::str::FromStr + quote::ToTokens>(input: TokenSt
}
}
fn from_str(s: &str) -> Option<Self> {
match s {
#( #names => Some(#name::#fields) ,)*
match s.to_ascii_uppercase().as_str() {
#( #names_upper => Some(#name::#fields) ,)*
_ => None
}
}
Expand Down
40 changes: 39 additions & 1 deletion rust/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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::*;
Expand Down
8 changes: 4 additions & 4 deletions rust/src/http2/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand All @@ -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;
}
Expand All @@ -383,15 +383,15 @@ 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;
}
}
}
}
}
return 0;
return false;
}

fn http2_frames_get_header_firstvalue<'a>(
Expand Down
Loading
Loading