Skip to content
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
1 change: 1 addition & 0 deletions rust/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ include = [
"FtpDataStateValues",
"HTTP2TransactionState",
"DataRepType",
"DETECT_COUNT_INDEX",
]

# A list of items to not include in the generated bindings
Expand Down
2 changes: 2 additions & 0 deletions rust/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ pub const SIGMATCH_INFO_MULTI_UINT: u32 = 0x80000; // BIT_U32(19)
pub const SIGMATCH_INFO_ENUM_UINT: u32 = 0x100000; // BIT_U32(20)
pub const SIGMATCH_INFO_BITFLAGS_UINT: u32 = 0x200000; // BIT_U32(21)

pub const DETECT_COUNT_INDEX: u32 = 0xFFFFFFFF;

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
// endian <big|little|dce>
Expand Down
117 changes: 108 additions & 9 deletions rust/src/detect/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,20 @@ pub struct DetectUintData<T> {
pub mode: DetectUintMode,
}

#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct DetectUintIndexPrecise {
pub oob: bool,
pub pos: i32,
}

#[derive(Debug, PartialEq)]
pub enum DetectUintIndex {
Any,
AllOrAbsent,
All,
OrAbsent,
Index((bool, i32)),
Index(DetectUintIndexPrecise),
NumberMatches(DetectUintData<u32>),
Count(DetectUintData<u32>),
}
Expand All @@ -74,7 +81,13 @@ fn parse_uint_index_precise(s: &str) -> IResult<&str, DetectUintIndex> {
let (s, oob) = opt(tag("oob_or")).parse(s)?;
let (s, _) = opt(is_a(" ")).parse(s)?;
let (s, i32_index) = nom_i32.parse(s)?;
Ok((s, DetectUintIndex::Index((oob.is_some(), i32_index))))
Ok((
s,
DetectUintIndex::Index(DetectUintIndexPrecise {
oob: oob.is_some(),
pos: i32_index,
}),
))
}

fn parse_uint_index_nb(s: &str) -> IResult<&str, DetectUintIndex> {
Expand Down Expand Up @@ -112,7 +125,8 @@ fn parse_uint_subslice(parts: &[&str]) -> Option<(i32, i32)> {
return Some((start, end));
}

fn parse_uint_count(s: &str) -> IResult<&str, DetectUintData<u32>> {
fn parse_multi_count(s: &str) -> IResult<&str, DetectUintData<u32>> {
let (s, _) = opt(is_a(" ")).parse(s)?;
let (s, _) = tag("count").parse(s)?;
let (s, _) = opt(is_a(" ")).parse(s)?;
let (s, du32) = detect_parse_uint::<u32>(s)?;
Expand All @@ -129,7 +143,7 @@ fn parse_uint_index(parts: &[&str]) -> Option<DetectUintIndex> {
// not only a literal, but some numeric value
_ => return parse_uint_index_val(parts[1]),
}
} else if let Ok((_, du)) = parse_uint_count(parts[0]) {
} else if let Ok((_, du)) = parse_multi_count(parts[0]) {
DetectUintIndex::Count(du)
} else {
DetectUintIndex::Any
Expand Down Expand Up @@ -320,15 +334,15 @@ pub(crate) fn detect_uint_match_at_index<T, U: DetectIntType>(
}
return 0;
}
DetectUintIndex::Index((oob, idx)) => {
let index = if *idx < 0 {
DetectUintIndex::Index(prec) => {
let index = if prec.pos < 0 {
// negative values for backward indexing.
((subslice.len() as i32) + idx) as usize
((subslice.len() as i32) + prec.pos) as usize
} else {
*idx as usize
prec.pos as usize
};
if subslice.len() <= index {
if *oob && eof {
if prec.oob && eof {
return 1;
}
return 0;
Expand Down Expand Up @@ -988,6 +1002,91 @@ pub unsafe extern "C" fn SCDetectU16Free(ctx: &mut DetectUintData<u16>) {
std::mem::drop(Box::from_raw(ctx));
}

#[no_mangle]
pub unsafe extern "C" fn SCDetectMultiCountParse(ustr: *const std::os::raw::c_char) -> *mut c_void {
let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe
if let Ok(s) = ft_name.to_str() {
if let Ok((_, ctx)) = parse_multi_count(s) {
let boxed = Box::new(ctx);
return Box::into_raw(boxed) as *mut c_void;
}
}
return std::ptr::null_mut();
}

/// just a u8 for FFI
#[derive(PartialEq, Eq, Clone, Debug)]
#[repr(u8)]
pub enum DetectMultiIndex {
DetectMultiIndexAny,
DetectMultiIndexAbsentOr,
DetectMultiIndexAll,
DetectMultiIndexAllOrAbsent,
DetectMultiIndexNb,
DetectMultiIndexPrecise,
DetectMultiIndexError,
}

impl DetectUintIndex {
// just borrow
fn index(&self) -> DetectMultiIndex {
match self {
DetectUintIndex::All => DetectMultiIndex::DetectMultiIndexAll,
DetectUintIndex::AllOrAbsent => DetectMultiIndex::DetectMultiIndexAllOrAbsent,
DetectUintIndex::Any => DetectMultiIndex::DetectMultiIndexAny,
DetectUintIndex::OrAbsent => DetectMultiIndex::DetectMultiIndexAbsentOr,
DetectUintIndex::NumberMatches(_) => DetectMultiIndex::DetectMultiIndexNb,
DetectUintIndex::Index(_) => DetectMultiIndex::DetectMultiIndexPrecise,
DetectUintIndex::Count(_) => DetectMultiIndex::DetectMultiIndexError,
}
}

// take ownership and move
fn into_box(self) -> *mut c_void {
match self {
DetectUintIndex::NumberMatches(du32) => {
let boxed = Box::new(du32);
Box::into_raw(boxed) as *mut c_void
}
DetectUintIndex::Index(prec) => {
let boxed = Box::new(prec);
Box::into_raw(boxed) as *mut c_void
}
_ => std::ptr::null_mut(),
}
}
}

#[no_mangle]
pub unsafe extern "C" fn SCDetectMultiIndexFree(ctx: &mut DetectUintIndexPrecise) {
std::mem::drop(Box::from_raw(ctx));
}

fn parse_multi_index(s: &str) -> Option<DetectUintIndex> {
match s {
"all" => Some(DetectUintIndex::All),
"all_or_absent" => Some(DetectUintIndex::AllOrAbsent),
"any" => Some(DetectUintIndex::Any),
"absent_or" => Some(DetectUintIndex::OrAbsent),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

means any or absent

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added any_or_absent syntax sugar

// not only a literal, but some numeric value
_ => return parse_uint_index_val(s),
}
}

#[no_mangle]
pub unsafe extern "C" fn SCDetectMultiIndexParse(
ustr: *const std::os::raw::c_char, it: *mut DetectMultiIndex,
) -> *mut c_void {
let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe
if let Ok(s) = ft_name.to_str() {
if let Some(ctx) = parse_multi_index(s) {
*it = ctx.index();
return ctx.into_box();
}
}
return std::ptr::null_mut();
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
36 changes: 21 additions & 15 deletions rust/src/detect/vlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use super::uint::{
detect_parse_array_uint, detect_uint_match_at_index, DetectUintArrayData, DetectUintData,
DetectUintIndex,
DetectUintIndex, DetectUintIndexPrecise,
};
use std::ffi::{c_int, c_void, CStr};

Expand Down Expand Up @@ -49,7 +49,7 @@ pub fn detect_parse_vlan_id(s: &str) -> Option<DetectUintArrayData<u16>> {
SCLogError!("vlan id should be less than 4096");
return None;
}
match a.index {
match &a.index {
DetectUintIndex::All => {
// keep previous behavior that vlan.id: all matched only if there was vlan
return Some(DetectUintArrayData {
Expand All @@ -59,8 +59,8 @@ pub fn detect_parse_vlan_id(s: &str) -> Option<DetectUintArrayData<u16>> {
end: a.end,
});
}
DetectUintIndex::Index((_, i)) => {
if !(-VLAN_MAX_LAYERS..=VLAN_MAX_LAYERS - 1).contains(&i) {
DetectUintIndex::Index(prec) => {
if !(-VLAN_MAX_LAYERS..=VLAN_MAX_LAYERS - 1).contains(&prec.pos) {
SCLogError!(
"vlan id index should belong in range {:?}",
(-VLAN_MAX_LAYERS..=VLAN_MAX_LAYERS - 1)
Expand Down Expand Up @@ -110,7 +110,10 @@ pub unsafe extern "C" fn SCDetectVlanIdPrefilterMatch(
DETECT_VLAN_ID_ALL => DetectUintIndex::All,
DETECT_VLAN_ID_ALL_OR_ABSENT => DetectUintIndex::AllOrAbsent,
DETECT_VLAN_ID_OR_ABSENT => DetectUintIndex::OrAbsent,
i => DetectUintIndex::Index((false, i.into())),
i => DetectUintIndex::Index(DetectUintIndexPrecise {
oob: false,
pos: i.into(),
}),
};

let ctx = DetectUintArrayData {
Expand All @@ -127,12 +130,12 @@ pub unsafe extern "C" fn SCDetectVlanIdPrefilterMatch(
pub unsafe extern "C" fn SCDetectVlanIdPrefilter(
ctx: &DetectUintArrayData<u16>,
) -> DetectVlanIdDataPrefilter {
let layer = match ctx.index {
let layer = match &ctx.index {
DetectUintIndex::Any => DETECT_VLAN_ID_ANY,
DetectUintIndex::All => DETECT_VLAN_ID_ALL,
DetectUintIndex::AllOrAbsent => DETECT_VLAN_ID_ALL_OR_ABSENT,
DetectUintIndex::OrAbsent => DETECT_VLAN_ID_OR_ABSENT,
DetectUintIndex::Index((_, i)) => i as i8,
DetectUintIndex::Index(prec) => prec.pos as i8,
DetectUintIndex::NumberMatches(_) => DETECT_VLAN_ID_ERROR,
DetectUintIndex::Count(_) => DETECT_VLAN_ID_ERROR,
};
Expand All @@ -148,13 +151,13 @@ pub unsafe extern "C" fn SCDetectVlanIdPrefilterable(ctx: *const c_void) -> bool
if ctx.start != 0 || ctx.end != 0 {
return false;
}
match ctx.index {
match &ctx.index {
DetectUintIndex::Any => true,
DetectUintIndex::All => true,
DetectUintIndex::AllOrAbsent => true,
DetectUintIndex::OrAbsent => true,
// do not prefilter for precise index with "or out of bounds"
DetectUintIndex::Index((oob, _)) => !oob,
DetectUintIndex::Index(prec) => !prec.oob,
DetectUintIndex::NumberMatches(_) => false,
DetectUintIndex::Count(_) => false,
}
Expand Down Expand Up @@ -214,7 +217,7 @@ mod test {
arg2: 0,
mode: DetectUintMode::DetectUintModeEqual,
},
index: DetectUintIndex::Index((false, 1)),
index: DetectUintIndex::Index(DetectUintIndexPrecise { oob: false, pos: 1 }),
start: 0,
end: 0,
}
Expand All @@ -227,7 +230,10 @@ mod test {
arg2: 0,
mode: DetectUintMode::DetectUintModeEqual,
},
index: DetectUintIndex::Index((false, -1)),
index: DetectUintIndex::Index(DetectUintIndexPrecise {
oob: false,
pos: -1
}),
start: 0,
end: 0,
}
Expand All @@ -240,7 +246,7 @@ mod test {
arg2: 0,
mode: DetectUintMode::DetectUintModeNe,
},
index: DetectUintIndex::Index((false, 2)),
index: DetectUintIndex::Index(DetectUintIndexPrecise { oob: false, pos: 2 }),
start: 0,
end: 0,
}
Expand All @@ -253,7 +259,7 @@ mod test {
arg2: 0,
mode: DetectUintMode::DetectUintModeGt,
},
index: DetectUintIndex::Index((false, 2)),
index: DetectUintIndex::Index(DetectUintIndexPrecise { oob: false, pos: 2 }),
start: 0,
end: 0,
}
Expand All @@ -266,7 +272,7 @@ mod test {
arg2: 300,
mode: DetectUintMode::DetectUintModeRange,
},
index: DetectUintIndex::Index((false, 0)),
index: DetectUintIndex::Index(DetectUintIndexPrecise { oob: false, pos: 0 }),
start: 0,
end: 0,
}
Expand All @@ -279,7 +285,7 @@ mod test {
arg2: 0,
mode: DetectUintMode::DetectUintModeEqual,
},
index: DetectUintIndex::Index((false, 2)),
index: DetectUintIndex::Index(DetectUintIndexPrecise { oob: false, pos: 2 }),
start: 0,
end: 0,
}
Expand Down
20 changes: 20 additions & 0 deletions rust/src/mime/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ pub unsafe extern "C" fn SCDetectMimeEmailGetUrl(
return 0;
}

/// Intermediary function used in detect-email.c to access data from the MimeStateSMTP structure
/// for array header fields.
/// The hname parameter determines which data will be returned.
#[no_mangle]
pub unsafe extern "C" fn SCDetectMimeEmailGetCount(
ctx: &MimeStateSMTP, hname: *const std::os::raw::c_char,
) -> u32 {
let c_str = CStr::from_ptr(hname); //unsafe
let str = c_str.to_str().unwrap_or("");

let mut r = 0u32;
for h in &ctx.headers[..ctx.main_headers_nb] {
if mime::slice_equals_lowercase(&h.name, str.as_bytes()) {
r += 1;
}
}

return r;
}

/// Intermediary function used in detect-email.c to access data from the MimeStateSMTP structure
/// for array header fields.
/// The hname parameter determines which data will be returned.
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ noinst_HEADERS = \
detect-metadata.h \
detect-modbus.h \
detect-msg.h \
detect-multi.h \
detect-nfs-version.h \
detect-noalert.h \
detect-nocase.h \
Expand Down Expand Up @@ -830,6 +831,7 @@ libsuricata_c_a_SOURCES = \
detect-metadata.c \
detect-modbus.c \
detect-msg.c \
detect-multi.c \
detect-nfs-version.c \
detect-noalert.c \
detect-nocase.c \
Expand Down
12 changes: 11 additions & 1 deletion src/detect-email.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "detect-parse.h"
#include "app-layer-smtp.h"
#include "detect-email.h"
#include "detect-multi.h"
#include "rust.h"
#include "detect-engine-content-inspection.h"

Expand Down Expand Up @@ -205,6 +206,10 @@ static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, c
if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
return -1;

if (arg) {
return DetectMultiSetup(de_ctx, s, arg);
}

return 0;
}

Expand All @@ -217,6 +222,11 @@ static bool GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx, const void
return false;
}

if (idx == DETECT_COUNT_INDEX) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

as discussed in Salzburg, we want a form of a GetBufferCount callback instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, leaving that out to already get an approval for the rest

*buf_len = SCDetectMimeEmailGetCount(tx->mime_state, "received");
return true;
}

return SCDetectMimeEmailGetDataArray(tx->mime_state, buf, buf_len, "received", idx) == 1;
}

Expand Down Expand Up @@ -330,7 +340,7 @@ void DetectEmailRegister(void)
kw.desc = "'Received' field from an email";
kw.url = "/rules/email-keywords.html#email.received";
kw.Setup = DetectMimeEmailReceivedSetup;
kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_INFO_MULTI_BUFFER;
kw.flags = SIGMATCH_OPTIONAL_OPT | SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_INFO_MULTI_BUFFER;
SCDetectHelperKeywordRegister(&kw);
g_mime_email_received_buffer_id = SCDetectHelperMultiBufferMpmRegister("email.received",
"MIME EMAIL RECEIVED", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailReceivedData);
Expand Down
Loading
Loading