detect/integers: nb index to match a specific number of times

For example
dns.rrtype: !A,nb>3
will match if we have more than 3 dns records which are not A
pull/13878/head
Philippe Antoine 2 months ago committed by Victor Julien
parent 6f848eeaaf
commit 1480cf47ab

@ -109,6 +109,7 @@ They expand the syntax of a single integer::
any Match with any index
all Match only if all indexes match
all1 Match only if all and at least one indexes match
nb Matches a number of times
0>= Match specific index
0< Match specific index with back to front indexing
========= ================================================
@ -116,3 +117,9 @@ They expand the syntax of a single integer::
The index ``all`` will match if there is no value.
The index ``all1`` will not match if there is no value and behaves
like ``all`` if there is at least one value.
These keywords will wait for transaction completion to run, to
be sure to have the final number of elements.
The index ``nb`` accepts all comparison modes as integer keywords.
For example ``nb>3`` will match only if more than 3 integers in the
array match the value.

@ -17,7 +17,7 @@
use nom7::branch::alt;
use nom7::bytes::complete::{is_a, tag, tag_no_case, take_while};
use nom7::character::complete::{char, digit1, hex_digit1};
use nom7::character::complete::{char, digit1, hex_digit1, i32 as nom_i32};
use nom7::combinator::{all_consuming, map_opt, opt, value, verify};
use nom7::error::{make_error, Error, ErrorKind};
use nom7::Err;
@ -26,7 +26,6 @@ use nom7::IResult;
use super::EnumString;
use std::ffi::{c_int, c_void, CStr};
use std::str::FromStr;
#[derive(PartialEq, Eq, Clone, Debug)]
#[repr(u8)]
@ -57,6 +56,7 @@ pub enum DetectUintIndex {
All,
All1,
Index(i32),
NumberMatches(DetectUintData<u32>),
}
#[derive(Debug, PartialEq)]
@ -65,16 +65,30 @@ pub struct DetectUintArrayData<T> {
pub index: DetectUintIndex,
}
fn parse_uint_index_precise(s: &str) -> IResult<&str, DetectUintIndex> {
let (s, i32_index) = nom_i32(s)?;
Ok((s, DetectUintIndex::Index(i32_index)))
}
fn parse_uint_index_nb(s: &str) -> IResult<&str, DetectUintIndex> {
let (s, _) = tag("nb")(s)?;
let (s, du32) = detect_parse_uint::<u32>(s)?;
Ok((s, DetectUintIndex::NumberMatches(du32)))
}
fn parse_uint_index_val(s: &str) -> Option<DetectUintIndex> {
let (_s, arg1) = alt((parse_uint_index_precise, parse_uint_index_nb))(s).ok()?;
Some(arg1)
}
fn parse_uint_index(parts: &[&str]) -> Option<DetectUintIndex> {
let index = if parts.len() == 2 {
match parts[1] {
"all" => DetectUintIndex::All,
"all1" => DetectUintIndex::All1,
"any" => DetectUintIndex::Any,
_ => {
let i32_index = i32::from_str(parts[1]).ok()?;
DetectUintIndex::Index(i32_index)
}
// not only a literal, but some numeric value
_ => return parse_uint_index_val(parts[1]),
}
} else {
DetectUintIndex::Any
@ -111,7 +125,7 @@ pub(crate) fn detect_parse_array_uint_enum<T1: DetectIntType, T2: EnumString<T1>
pub(crate) fn detect_uint_match_at_index<T, U: DetectIntType>(
array: &[T], ctx: &DetectUintArrayData<U>, get_value: impl Fn(&T) -> Option<U>, eof: bool,
) -> c_int {
match ctx.index {
match &ctx.index {
DetectUintIndex::Any => {
for response in array {
if let Some(code) = get_value(response) {
@ -122,6 +136,28 @@ pub(crate) fn detect_uint_match_at_index<T, U: DetectIntType>(
}
return 0;
}
DetectUintIndex::NumberMatches(du32) => {
if !eof {
match du32.mode {
DetectUintMode::DetectUintModeGt | DetectUintMode::DetectUintModeGte => {}
_ => {
return 0;
}
}
}
let mut nb = 0u32;
for response in array {
if let Some(code) = get_value(response) {
if detect_match_uint::<U>(&ctx.du, code) {
nb += 1;
}
}
}
if detect_match_uint(du32, nb) {
return 1;
}
return 0;
}
DetectUintIndex::All => {
if !eof {
return 0;
@ -154,11 +190,11 @@ pub(crate) fn detect_uint_match_at_index<T, U: DetectIntType>(
return 0;
}
DetectUintIndex::Index(idx) => {
let index = if idx < 0 {
let index = if *idx < 0 {
// negative values for backward indexing.
((array.len() as i32) + idx) as usize
} else {
idx as usize
*idx as usize
};
if array.len() <= index {
return 0;

Loading…
Cancel
Save