]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: use generic integer functions for iprep
authorPhilippe Antoine <pantoine@oisf.net>
Thu, 9 Jun 2022 13:42:40 +0000 (15:42 +0200)
committerVictor Julien <vjulien@oisf.net>
Fri, 1 Jul 2022 15:04:08 +0000 (17:04 +0200)
Ticket: #4112

rust/cbindgen.toml
rust/src/detect.rs
src/detect-iprep.c
src/detect-iprep.h

index ac1b8ed1c2f86d2da949e5a934a397baa4d48136..bccb19fd193d760622189332f6b4f7f6d0abd7da 100644 (file)
@@ -109,6 +109,7 @@ exclude = [
     "free",
     "IPPROTO_TCP",
     "IPPROTO_UDP",
+    "SRepCatGetByShortname",
 ]
 
 # Types of items that we'll generate. If empty, then all types of item are emitted.
index b568214e74afcd4d0f9f66b4047cdbd918d229cf..7f2e04b72f3c0bc647f9a1aad89338a7ed51fe13 100644 (file)
@@ -23,7 +23,7 @@ use nom7::error::{make_error, ErrorKind};
 use nom7::Err;
 use nom7::IResult;
 
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 use std::str::FromStr;
 
 #[derive(PartialEq, Clone, Debug)]
@@ -444,3 +444,103 @@ pub unsafe extern "C" fn rs_detect_urilen_free(ctx: &mut DetectUrilenData) {
     // Just unbox...
     std::mem::drop(Box::from_raw(ctx));
 }
+
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, FromPrimitive, Debug)]
+pub enum DetectIPRepDataCmd {
+    IPRepCmdAny = 0,
+    IPRepCmdBoth = 1,
+    IPRepCmdSrc = 2,
+    IPRepCmdDst = 3,
+}
+
+impl std::str::FromStr for DetectIPRepDataCmd {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "any" => Ok(DetectIPRepDataCmd::IPRepCmdAny),
+            "both" => Ok(DetectIPRepDataCmd::IPRepCmdBoth),
+            "src" => Ok(DetectIPRepDataCmd::IPRepCmdSrc),
+            "dst" => Ok(DetectIPRepDataCmd::IPRepCmdDst),
+            _ => Err(format!(
+                "'{}' is not a valid value for DetectIPRepDataCmd",
+                s
+            )),
+        }
+    }
+}
+
+#[derive(Debug)]
+#[repr(C)]
+pub struct DetectIPRepData {
+    pub du8: DetectUintData<u8>,
+    pub cat: u8,
+    pub cmd: DetectIPRepDataCmd,
+}
+
+pub fn is_alphanumeric_or_slash(chr: char) -> bool {
+    if chr.is_ascii_alphanumeric() {
+        return true;
+    }
+    if chr == '_' || chr == '-' {
+        return true;
+    }
+    return false;
+}
+
+extern "C" {
+    pub fn SRepCatGetByShortname(name: *const i8) -> u8;
+}
+
+pub fn detect_parse_iprep(i: &str) -> IResult<&str, DetectIPRepData> {
+    let (i, _) = opt(is_a(" "))(i)?;
+    let (i, cmd) = map_res(alpha0, |s: &str| DetectIPRepDataCmd::from_str(s))(i)?;
+    let (i, _) = opt(is_a(" "))(i)?;
+    let (i, _) = char(',')(i)?;
+    let (i, _) = opt(is_a(" "))(i)?;
+
+    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() as *const i8) };
+    if cat == 0 {
+        return Err(Err::Error(make_error(i, ErrorKind::MapOpt)));
+    }
+
+    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: arg1,
+        arg2: 0,
+        mode: mode,
+    };
+    return Ok((i, DetectIPRepData { du8, cat, cmd }));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rs_detect_iprep_parse(
+    ustr: *const std::os::raw::c_char,
+) -> *mut DetectIPRepData {
+    let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe
+    if let Ok(s) = ft_name.to_str() {
+        if let Ok((_, ctx)) = detect_parse_iprep(s) {
+            let boxed = Box::new(ctx);
+            return Box::into_raw(boxed) as *mut _;
+        }
+    }
+    return std::ptr::null_mut();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rs_detect_iprep_free(ctx: &mut DetectIPRepData) {
+    // Just unbox...
+    std::mem::drop(Box::from_raw(ctx));
+}
index 752da0d342403019a45b68c1d4727913615f7a16..2474ff17d7aa400d17cdc3d7df62ac8736e04e21 100644 (file)
@@ -39,6 +39,7 @@
 #include "detect-engine.h"
 #include "detect-engine-mpm.h"
 #include "detect-engine-state.h"
+#include "detect-engine-uint.h"
 
 #include "util-debug.h"
 #include "util-byte.h"
@@ -50,9 +51,6 @@
 #include "reputation.h"
 #include "host.h"
 
-#define PARSE_REGEX         "\\s*(any|src|dst|both)\\s*,\\s*([A-Za-z0-9\\-\\_]+)\\s*,\\s*(\\<|\\>|\\=)\\s*,\\s*([0-9]+)\\s*"
-static DetectParseRegex parse_regex;
-
 static int DetectIPRepMatch (DetectEngineThreadCtx *, Packet *,
         const Signature *, const SigMatchCtx *);
 static int DetectIPRepSetup (DetectEngineCtx *, Signature *, const char *);
@@ -74,8 +72,6 @@ void DetectIPRepRegister (void)
 #endif
     /* this is compatible to ip-only signatures */
     sigmatch_table[DETECT_IPREP].flags |= SIGMATCH_IPONLY_COMPAT;
-
-    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
 }
 
 static inline uint8_t GetRep(const SReputation *r, const uint8_t cat, const uint32_t version)
@@ -142,18 +138,6 @@ static uint8_t GetHostRepDst(Packet *p, uint8_t cat, uint32_t version)
     }
 }
 
-static inline int RepMatch(uint8_t op, uint8_t val1, uint8_t val2)
-{
-    if (op == DETECT_IPREP_OP_GT && val1 > val2) {
-        return 1;
-    } else if (op == DETECT_IPREP_OP_LT && val1 < val2) {
-        return 1;
-    } else if (op == DETECT_IPREP_OP_EQ && val1 == val2) {
-        return 1;
-    }
-    return 0;
-}
-
 /*
  * returns 0: no match
  *         1: match
@@ -171,53 +155,54 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
 
     SCLogDebug("rd->cmd %u", rd->cmd);
     switch(rd->cmd) {
-        case DETECT_IPREP_CMD_ANY:
+        case IPRepCmdAny:
             val = GetHostRepSrc(p, rd->cat, version);
             if (val == 0)
                 val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
             if (val > 0) {
-                if (RepMatch(rd->op, val, rd->val) == 1)
+                if (DetectU8Match(val, &rd->du8))
                     return 1;
             }
             val = GetHostRepDst(p, rd->cat, version);
             if (val == 0)
                 val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
             if (val > 0) {
-                return RepMatch(rd->op, val, rd->val);
+                return DetectU8Match(val, &rd->du8);
             }
             break;
 
-        case DETECT_IPREP_CMD_SRC:
+        case IPRepCmdSrc:
             val = GetHostRepSrc(p, rd->cat, version);
-            SCLogDebug("checking src -- val %u (looking for cat %u, val %u)", val, rd->cat, rd->val);
+            SCLogDebug("checking src -- val %u (looking for cat %u, val %u)", val, rd->cat,
+                    rd->du8.arg1);
             if (val == 0)
                 val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
             if (val > 0) {
-                return RepMatch(rd->op, val, rd->val);
+                return DetectU8Match(val, &rd->du8);
             }
             break;
 
-        case DETECT_IPREP_CMD_DST:
+        case IPRepCmdDst:
             SCLogDebug("checking dst");
             val = GetHostRepDst(p, rd->cat, version);
             if (val == 0)
                 val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
             if (val > 0) {
-                return RepMatch(rd->op, val, rd->val);
+                return DetectU8Match(val, &rd->du8);
             }
             break;
 
-        case DETECT_IPREP_CMD_BOTH:
+        case IPRepCmdBoth:
             val = GetHostRepSrc(p, rd->cat, version);
             if (val == 0)
                 val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
-            if (val == 0 || RepMatch(rd->op, val, rd->val) == 0)
+            if (val == 0 || DetectU8Match(val, &rd->du8) == 0)
                 return 0;
             val = GetHostRepDst(p, rd->cat, version);
             if (val == 0)
                 val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
             if (val > 0) {
-                return RepMatch(rd->op, val, rd->val);
+                return DetectU8Match(val, &rd->du8);
             }
             break;
     }
@@ -227,113 +212,15 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
 
 int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
 {
-    DetectIPRepData *cd = NULL;
     SigMatch *sm = NULL;
-    char *cmd_str = NULL, *name = NULL, *op_str = NULL, *value = NULL;
-    uint8_t cmd = 0;
-    int ret = 0, res = 0;
-    size_t pcre2_len;
-
-    ret = DetectParsePcreExec(&parse_regex, rawstr, 0, 0);
-    if (ret != 5) {
-        SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for iprep", rawstr);
-        return -1;
-    }
-
-    const char *str_ptr;
-    res = pcre2_substring_get_bynumber(parse_regex.match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_get_bynumber failed");
-        return -1;
-    }
-    cmd_str = (char *)str_ptr;
 
-    res = pcre2_substring_get_bynumber(parse_regex.match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_get_bynumber failed");
-        goto error;
-    }
-    name = (char *)str_ptr;
-
-    res = pcre2_substring_get_bynumber(parse_regex.match, 3, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_get_bynumber failed");
-        goto error;
-    }
-    op_str = (char *)str_ptr;
-
-    res = pcre2_substring_get_bynumber(parse_regex.match, 4, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
-    if (res < 0) {
-        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_get_bynumber failed");
-        goto error;
-    }
-    value = (char *)str_ptr;
-
-    if (strcmp(cmd_str,"any") == 0) {
-        cmd = DETECT_IPREP_CMD_ANY;
-    } else if (strcmp(cmd_str,"both") == 0) {
-        cmd = DETECT_IPREP_CMD_BOTH;
-    } else if (strcmp(cmd_str,"src") == 0) {
-        cmd = DETECT_IPREP_CMD_SRC;
-    } else if (strcmp(cmd_str,"dst") == 0) {
-        cmd = DETECT_IPREP_CMD_DST;
-    } else {
-        SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: iprep \"%s\" is not supported.", cmd_str);
+    DetectIPRepData *cd = rs_detect_iprep_parse(rawstr);
+    if (cd == NULL) {
+        SCLogError(SC_ERR_UNKNOWN_VALUE, "\"%s\" is not a valid setting for iprep", rawstr);
         goto error;
     }
 
-    //SCLogInfo("category %s", name);
-    uint8_t cat = SRepCatGetByShortname(name);
-    if (cat == 0) {
-        SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown iprep category \"%s\"", name);
-        goto error;
-    }
-
-    uint8_t op = 0;
-    uint8_t val = 0;
-
-    if (op_str == NULL || strlen(op_str) != 1) {
-        goto error;
-    }
-
-    switch(op_str[0]) {
-        case '<':
-            op = DETECT_IPREP_OP_LT;
-            break;
-        case '>':
-            op = DETECT_IPREP_OP_GT;
-            break;
-        case '=':
-            op = DETECT_IPREP_OP_EQ;
-            break;
-        default:
-            goto error;
-            break;
-    }
-
-    if (value != NULL && strlen(value) > 0) {
-        if (StringParseU8RangeCheck(&val, 10, 0, (const char *)value, 0, 127) < 0)
-            goto error;
-    }
-
-    cd = SCMalloc(sizeof(DetectIPRepData));
-    if (unlikely(cd == NULL))
-        goto error;
-
-    cd->cmd = cmd;
-    cd->cat = cat;
-    cd->op = op;
-    cd->val = val;
-    SCLogDebug("cmd %u, cat %u, op %u, val %u", cd->cmd, cd->cat, cd->op, cd->val);
-
-    pcre2_substring_free((PCRE2_UCHAR *)name);
-    name = NULL;
-    pcre2_substring_free((PCRE2_UCHAR *)cmd_str);
-    cmd_str = NULL;
-    pcre2_substring_free((PCRE2_UCHAR *)op_str);
-    op_str = NULL;
-    pcre2_substring_free((PCRE2_UCHAR *)value);
-    value = NULL;
+    SCLogDebug("cmd %u, cat %u, op %u, val %u", cd->cmd, cd->cat, cd->du8.mode, cd->du8.arg1);
 
     /* Okay so far so good, lets get this into a SigMatch
      * and put it in the Signature. */
@@ -349,16 +236,8 @@ int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
     return 0;
 
 error:
-    if (name != NULL)
-        pcre2_substring_free((PCRE2_UCHAR *)name);
-    if (cmd_str != NULL)
-        pcre2_substring_free((PCRE2_UCHAR *)cmd_str);
-    if (op_str != NULL)
-        pcre2_substring_free((PCRE2_UCHAR *)op_str);
-    if (value != NULL)
-        pcre2_substring_free((PCRE2_UCHAR *)value);
     if (cd != NULL)
-        SCFree(cd);
+        DetectIPRepFree(de_ctx, cd);
     if (sm != NULL)
         SCFree(sm);
     return -1;
@@ -371,7 +250,7 @@ void DetectIPRepFree (DetectEngineCtx *de_ctx, void *ptr)
     if (fd == NULL)
         return;
 
-    SCFree(fd);
+    rs_detect_iprep_free(fd);
 }
 
 #ifdef UNITTESTS
index 129851b9009fd3a5b551ea304a176c2f293c5f86..07cd5c7f606fbebcdec746fc5575822d2bc26944 100644 (file)
 #ifndef __DETECT_IPREP_H__
 #define __DETECT_IPREP_H__
 
-#define DETECT_IPREP_CMD_ANY      0
-#define DETECT_IPREP_CMD_BOTH     1
-#define DETECT_IPREP_CMD_SRC      2
-#define DETECT_IPREP_CMD_DST      3
-
-#define DETECT_IPREP_OP_LT        0
-#define DETECT_IPREP_OP_GT        1
-#define DETECT_IPREP_OP_EQ        2
-
-typedef struct DetectIPRepData_ {
-    uint8_t cmd;
-    int8_t cat;
-    int8_t op;
-    uint8_t val;
-} DetectIPRepData;
-
 /* prototypes */
 void DetectIPRepRegister (void);