]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/iprep: update keyword parser for extendibility
authorVictor Julien <vjulien@oisf.net>
Mon, 13 May 2024 10:33:57 +0000 (12:33 +0200)
committerVictor Julien <victor@inliniac.net>
Sat, 15 Jun 2024 13:43:28 +0000 (15:43 +0200)
rust/src/detect/error.rs
rust/src/detect/iprep.rs

index 4959e2c883a408ff385f3180ee2e29d72b528d05..211c5afceb33859d2df19d52e7765acbe3151495 100644 (file)
@@ -23,6 +23,7 @@ use nom7::error::{ErrorKind, ParseError};
 #[derive(Debug, PartialEq, Eq)]
 pub enum RuleParseError<I> {
     InvalidByteMath(String),
+    InvalidIPRep(String),
 
     Nom(I, ErrorKind),
 }
index 16f5d9d5d15eaed5ba2a6a79a110f09904f08454..09df0b2bcd4004a04e5381512ad7c370f77bac0e 100644 (file)
  */
 
 use super::uint::*;
-use nom7::bytes::complete::{is_a, take_while};
-use nom7::character::complete::{alpha0, char, digit1};
-use nom7::combinator::{all_consuming, map_opt, map_res, opt};
-use nom7::error::{make_error, ErrorKind};
+use crate::detect::error::RuleParseError;
+use nom7::bytes::complete::tag;
+use nom7::character::complete::multispace0;
+use nom7::sequence::preceded;
+
 use nom7::Err;
 use nom7::IResult;
 
@@ -75,36 +76,46 @@ extern "C" {
     pub fn SRepCatGetByShortname(name: *const c_char) -> u8;
 }
 
-pub fn detect_parse_iprep(i: &str) -> IResult<&str, DetectIPRepData> {
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, cmd) = map_res(alpha0, DetectIPRepDataCmd::from_str)(i)?;
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, _) = char(',')(i)?;
-    let (i, _) = opt(is_a(" "))(i)?;
+pub fn detect_parse_iprep(i: &str) -> IResult<&str, DetectIPRepData, RuleParseError<&str>> {
+    // Inner utility function for easy error creation.
+    fn make_error(reason: String) -> nom7::Err<RuleParseError<&'static str>> {
+        Err::Error(RuleParseError::InvalidIPRep(reason))
+    }
+    let (_, values) = nom7::multi::separated_list1(
+        tag(","),
+        preceded(multispace0, nom7::bytes::complete::is_not(",")),
+    )(i)?;
+
+    if values.len() == 4 {
+        let cmd = match DetectIPRepDataCmd::from_str(values[0].trim()) {
+            Ok(val) => val,
+            Err(_) => return Err(make_error("invalid command".to_string())),
+        };
+        let name = values[1].trim();
+        let mode = match detect_parse_uint_mode(values[2].trim()) {
+            Ok(val) => val.1,
+            Err(_) => return Err(make_error("invalid mode".to_string())),
+        };
 
-    let (i, name) = take_while(is_alphanumeric_or_slash)(i)?;
-    // copy as to have final zero
-    let namez = CString::new(name).unwrap();
-    let cat = unsafe { SRepCatGetByShortname(namez.as_ptr()) };
-    if cat == 0 {
-        return Err(Err::Error(make_error(i, ErrorKind::MapOpt)));
+        let namez = CString::new(name).unwrap();
+        let cat = unsafe { SRepCatGetByShortname(namez.as_ptr()) };
+        if cat == 0 {
+            return Err(make_error("unknown category".to_string()));
+        }
+        let arg1 = match values[3].trim().parse::<u8>() {
+            Ok(val) => val,
+            Err(_) => return Err(make_error("invalid value".to_string())),
+        };
+        let du8 = DetectUintData::<u8> {
+            arg1,
+            arg2: 0,
+            mode,
+        };
+        return Ok((i, DetectIPRepData { du8, cat, cmd }));
+    } else {
+        return Err(make_error("too many arguments".to_string()));
     }
 
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, _) = char(',')(i)?;
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, mode) = detect_parse_uint_mode(i)?;
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, _) = char(',')(i)?;
-    let (i, _) = opt(is_a(" "))(i)?;
-    let (i, arg1) = map_opt(digit1, |s: &str| s.parse::<u8>().ok())(i)?;
-    let (i, _) = all_consuming(take_while(|c| c == ' '))(i)?;
-    let du8 = DetectUintData::<u8> {
-        arg1,
-        arg2: 0,
-        mode,
-    };
-    return Ok((i, DetectIPRepData { du8, cat, cmd }));
 }
 
 #[no_mangle]