From: Philippe Antoine Date: Thu, 9 Jun 2022 13:42:40 +0000 (+0200) Subject: detect: use generic integer functions for iprep X-Git-Tag: suricata-7.0.0-beta1~393 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed6955ee988db1be2eafe64983e28a097dbacf35;p=thirdparty%2Fsuricata.git detect: use generic integer functions for iprep Ticket: #4112 --- diff --git a/rust/cbindgen.toml b/rust/cbindgen.toml index ac1b8ed1c2..bccb19fd19 100644 --- a/rust/cbindgen.toml +++ b/rust/cbindgen.toml @@ -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. diff --git a/rust/src/detect.rs b/rust/src/detect.rs index b568214e74..7f2e04b72f 100644 --- a/rust/src/detect.rs +++ b/rust/src/detect.rs @@ -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 { + 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, + 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::().ok())(i)?; + let (i, _) = all_consuming(take_while(|c| c == ' '))(i)?; + let du8 = DetectUintData:: { + 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)); +} diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 752da0d342..2474ff17d7 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -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 diff --git a/src/detect-iprep.h b/src/detect-iprep.h index 129851b900..07cd5c7f60 100644 --- a/src/detect-iprep.h +++ b/src/detect-iprep.h @@ -24,22 +24,6 @@ #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);