}
}
+/// value matching is done use `DetectUintData` logic.
+/// isset matching is done using special `DetectUintData` value ">= 0"
+/// isnotset matching bypasses `DetectUintData` and is handled directly
+/// in the match function (in C).
#[derive(Debug)]
#[repr(C)]
pub struct DetectIPRepData {
pub du8: DetectUintData<u8>,
pub cat: u8,
pub cmd: DetectIPRepDataCmd,
+ pub isnotset: bool, // if true, ignores `du8`
}
pub fn is_alphanumeric_or_slash(chr: char) -> bool {
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 args = values.len();
+ if args == 4 || args == 3 {
+ let cmd = if let Ok(cmd) = DetectIPRepDataCmd::from_str(values[0].trim()) {
+ cmd
+ } else {
+ 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 namez = if let Ok(name) = CString::new(name) {
+ name
+ } else {
+ return Err(make_error("invalid name".to_string()));
};
-
- 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 {
+
+ if args == 4 {
+ let mode = match detect_parse_uint_mode(values[2].trim()) {
+ Ok(val) => val.1,
+ Err(_) => return Err(make_error("invalid mode".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, isnotset: false, }));
+ } else {
+ let (isnotset, mode, arg1) = match values[2].trim() {
+ "isset" => { (false, DetectUintMode::DetectUintModeGte, 0) },
+ "isnotset" => { (true, DetectUintMode::DetectUintModeEqual, 0) },
+ _ => { return Err(make_error("invalid mode".to_string())); },
+ };
+ let du8 = DetectUintData::<u8> {
+ arg1,
+ arg2: 0,
+ mode,
+ };
+ return Ok((i, DetectIPRepData { du8, cat, cmd, isnotset, }));
+ }
+ } else if args < 3 {
+ return Err(make_error("too few arguments".to_string()));
+ } else {
return Err(make_error("too many arguments".to_string()));
}
SCLogDebug("rd->cmd %u", rd->cmd);
switch (rd->cmd) {
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 (DetectU8Match((uint8_t)val, &rd->du8))
+ if (!rd->isnotset) {
+ 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 (DetectU8Match((uint8_t)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 DetectU8Match((uint8_t)val, &rd->du8);
+ }
+ } else {
+ /* isnotset for any */
+
+ val = GetHostRepSrc(p, rd->cat, version);
+ if (val < 0)
+ val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
+ if (val < 0) {
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 DetectU8Match((uint8_t)val, &rd->du8);
+ }
+ 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 1;
+ }
+ /* both have a value, so none 'isnotset' */
+ return 0;
}
break;
if (val >= 0) {
return DetectU8Match((uint8_t)val, &rd->du8);
}
+ /* implied: no value found */
+ if (rd->isnotset) {
+ return 1;
+ }
break;
case IPRepCmdDst:
if (val >= 0) {
return DetectU8Match((uint8_t)val, &rd->du8);
}
+ /* implied: no value found */
+ if (rd->isnotset) {
+ return 1;
+ }
break;
case IPRepCmdBoth:
- val = GetHostRepSrc(p, rd->cat, version);
- if (val < 0)
+ if (!rd->isnotset) {
+ val = GetHostRepSrc(p, rd->cat, version);
+ if (val < 0)
+ val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
+ if (val < 0 || DetectU8Match((uint8_t)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 DetectU8Match((uint8_t)val, &rd->du8);
+ }
+ } else {
+ val = GetHostRepSrc(p, rd->cat, version);
+ if (val >= 0)
+ return 0;
val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
- if (val < 0 || DetectU8Match((uint8_t)val, &rd->du8) == 0)
- return 0;
- val = GetHostRepDst(p, rd->cat, version);
- if (val < 0)
+ if (val >= 0)
+ return 0;
+ val = GetHostRepDst(p, rd->cat, version);
+ if (val >= 0)
+ return 0;
val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version);
- if (val >= 0) {
- return DetectU8Match((uint8_t)val, &rd->du8);
+ if (val >= 0)
+ return 0;
+ return 1;
}
break;
}
PASS;
}
+static FILE *DetectIPRepGenerateNetworksDummy3(void)
+{
+ FILE *fd = NULL;
+ const char *buffer = "192.168.0.0/16,1,127"; // BadHosts
+
+ fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
+ if (fd == NULL)
+ SCLogDebug("Error with SCFmemopen()");
+
+ return fd;
+}
+
+static int DetectIPRepTest10(void)
+{
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Signature *sig = NULL;
+ FILE *fd = NULL;
+ int r = 0;
+ Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP);
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+
+ HostInitConfig(HOST_QUIET);
+ memset(&th_v, 0, sizeof(th_v));
+
+ FAIL_IF_NULL(de_ctx);
+ FAIL_IF_NULL(p);
+
+ p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1");
+ p->dst.addr_data32[0] = UTHSetIPv4Address("192.168.0.2");
+ de_ctx->flags |= DE_QUIET;
+
+ SRepInit(de_ctx);
+ SRepResetVersion();
+
+ fd = DetectIPRepGenerateCategoriesDummy2();
+ r = SRepLoadCatFileFromFD(fd);
+ FAIL_IF(r < 0);
+
+ fd = DetectIPRepGenerateNetworksDummy3();
+ r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd);
+ FAIL_IF(r < 0);
+
+ sig = DetectEngineAppendSig(de_ctx,
+ "alert tcp any any -> any any (msg:\"test\"; iprep:src,BadHosts,isset; sid:1; rev:1;)");
+ FAIL_IF_NULL(sig);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+ FAIL_IF_NOT(p->alerts.cnt == 1);
+
+ UTHFreePacket(p);
+
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ HostShutdown();
+ PASS;
+}
+
+static int DetectIPRepTest11(void)
+{
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Signature *sig = NULL;
+ FILE *fd = NULL;
+ int r = 0;
+ Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP);
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+
+ HostInitConfig(HOST_QUIET);
+ memset(&th_v, 0, sizeof(th_v));
+
+ FAIL_IF_NULL(de_ctx);
+ FAIL_IF_NULL(p);
+
+ p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1");
+ p->dst.addr_data32[0] = UTHSetIPv4Address("10.0.0.2");
+ de_ctx->flags |= DE_QUIET;
+
+ SRepInit(de_ctx);
+ SRepResetVersion();
+
+ fd = DetectIPRepGenerateCategoriesDummy2();
+ r = SRepLoadCatFileFromFD(fd);
+ FAIL_IF(r < 0);
+
+ fd = DetectIPRepGenerateNetworksDummy3();
+ r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd);
+ FAIL_IF(r < 0);
+
+ sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"test\"; "
+ "iprep:src,BadHosts,isnotset; sid:1; rev:1;)");
+ FAIL_IF_NULL(sig);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+ FAIL_IF_NOT(p->alerts.cnt == 1);
+
+ UTHFreePacket(p);
+
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ HostShutdown();
+ PASS;
+}
+
/**
* \brief this function registers unit tests for IPRep
*/
UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07);
UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08);
UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09);
+ UtRegisterTest("DetectIPRepTest10 -- isset", DetectIPRepTest10);
+ UtRegisterTest("DetectIPRepTest11 -- isnotset", DetectIPRepTest11);
}
#endif /* UNITTESTS */