detect/iprep: implement isset and isnotset

Implement special "isset" and "isnotset" modes.

"isset" matches if an IP address is part of an iprep category with any
value.

It is internally implemented as ">=,0", which should always be true if
there is a value to evaluate, as valid reputation values are 0-127.

"isnotset" matches if an IP address is not part of an iprep category.

Internally it is implemented outside the uint support.

Ticket: #6857.
pull/11309/head
Victor Julien 2 years ago committed by Victor Julien
parent 3e46c51651
commit 83976a4cd4

@ -54,12 +54,17 @@ impl std::str::FromStr for DetectIPRepDataCmd {
}
}
/// 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 {
@ -86,33 +91,56 @@ pub fn detect_parse_iprep(i: &str) -> IResult<&str, DetectIPRepData, RuleParseEr
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()));
}

@ -158,18 +158,37 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
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;
@ -182,6 +201,10 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
if (val >= 0) {
return DetectU8Match((uint8_t)val, &rd->du8);
}
/* implied: no value found */
if (rd->isnotset) {
return 1;
}
break;
case IPRepCmdDst:
@ -192,19 +215,39 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
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;
}
@ -775,6 +818,118 @@ static int DetectIPRepTest09(void)
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
*/
@ -789,5 +944,7 @@ void IPRepRegisterTests(void)
UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07);
UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08);
UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09);
UtRegisterTest("DetectIPRepTest10 -- isset", DetectIPRepTest10);
UtRegisterTest("DetectIPRepTest11 -- isnotset", DetectIPRepTest11);
}
#endif /* UNITTESTS */

Loading…
Cancel
Save