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
15 changes: 14 additions & 1 deletion doc/userguide/rules/integer-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,17 @@ For the array [1,2,3,4,5,6], here are some examples:
* 3:-1 will have subslice [4,5]
* -4:4 will have subslice [3,4]

If one index is out of bounds, an empty subslice is used.
If one index is out of bounds, an empty subslice is used.

Count
-----

Multi-integer can also just count the number of occurences
without matching to a specific value.

The syntax is::
keyword: count [mode] value;
Copy link
Member

Choose a reason for hiding this comment

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

should this be extended (separately) to multi-buffer? dns.query: count >1;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes ! that is done in #13902 which builds on top of that PR ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ping @victorjulien ;-)


Examples::

http2.window:count >5;
4 changes: 2 additions & 2 deletions etc/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,7 @@
"type": "string",
"suricata": {
"keywords": [
"enip.command"
"enip_command"
]
}
},
Expand Down Expand Up @@ -1692,7 +1692,7 @@
"type": "string",
"suricata": {
"keywords": [
"enip.command"
"enip_command"
]
}
},
Expand Down
56 changes: 56 additions & 0 deletions rust/src/detect/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub enum DetectUintIndex {
OrAbsent,
Index((bool, i32)),
NumberMatches(DetectUintData<u32>),
Count(DetectUintData<u32>),
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -109,6 +110,13 @@ fn parse_uint_subslice(parts: &[&str]) -> Option<(i32, i32)> {
return Some((start, end));
}

fn parse_uint_count(s: &str) -> IResult<&str, DetectUintData<u32>> {
let (s, _) = tag("count")(s)?;
let (s, _) = opt(is_a(" "))(s)?;
let (s, du32) = detect_parse_uint::<u32>(s)?;
Ok((s, du32))
}

fn parse_uint_index(parts: &[&str]) -> Option<DetectUintIndex> {
let index = if parts.len() >= 2 {
match parts[1] {
Expand All @@ -119,6 +127,8 @@ 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]) {
DetectUintIndex::Count(du)
} else {
DetectUintIndex::Any
};
Expand All @@ -132,6 +142,19 @@ pub(crate) fn detect_parse_array_uint<T: DetectIntType>(s: &str) -> Option<Detec
}

let index = parse_uint_index(&parts)?;
if let DetectUintIndex::Count(_) = &index {
return Some(DetectUintArrayData {
du: DetectUintData::<T> {
arg1: T::min_value(),
arg2: T::min_value(),
mode: DetectUintMode::DetectUintModeEqual,
},
index,
start: 0,
end: 0,
});
}

let (_, du) = detect_parse_uint::<T>(parts[0]).ok()?;
let (start, end) = parse_uint_subslice(&parts)?;

Expand All @@ -152,6 +175,19 @@ pub(crate) fn detect_parse_array_uint_enum<T1: DetectIntType, T2: EnumString<T1>
}

let index = parse_uint_index(&parts)?;
if let DetectUintIndex::Count(_) = &index {
return Some(DetectUintArrayData {
du: DetectUintData::<T1> {
arg1: T1::min_value(),
arg2: T1::min_value(),
mode: DetectUintMode::DetectUintModeEqual,
},
index,
start: 0,
end: 0,
});
}

let du = detect_parse_uint_enum::<T1, T2>(parts[0])?;
let (start, end) = parse_uint_subslice(&parts)?;

Expand Down Expand Up @@ -229,6 +265,26 @@ pub(crate) fn detect_uint_match_at_index<T, U: DetectIntType>(
}
return 0;
}
DetectUintIndex::Count(du32) => {
if !eof {
match du32.mode {
DetectUintMode::DetectUintModeGt | DetectUintMode::DetectUintModeGte => {}
_ => {
return 0;
}
}
}
let mut nb = 0u32;
for response in subslice {
if get_value(response).is_some() {
nb += 1;
}
}
if detect_match_uint(du32, nb) {
return 1;
}
return 0;
}
DetectUintIndex::All => {
if !eof {
return 0;
Expand Down
Loading