#include "util-profiling.h"
/**
- * dsize:[<>]<0-65535>[<><0-65535>];
+ * dsize:[<>!]<0-65535>[<><0-65535>];
*/
-#define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$"
+#define PARSE_REGEX "^\\s*(<|>|!)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$"
static DetectParseRegex parse_regex;
static int DetectDsizeMatch (DetectEngineThreadCtx *, Packet *,
return 1;
else if (mode == DETECTDSIZE_RA && psize > dsize && psize < dsize2)
return 1;
+ else if (mode == DETECTDSIZE_NE && dsize != psize)
+ return 1;
return 0;
}
goto error;
dd->dsize = 0;
dd->dsize2 = 0;
- dd->mode = DETECTDSIZE_EQ; // default
-
- if (strlen(mode) > 0) {
- if (mode[0] == '<')
- dd->mode = DETECTDSIZE_LT;
- else if (mode[0] == '>')
- dd->mode = DETECTDSIZE_GT;
- else
- dd->mode = DETECTDSIZE_EQ;
- }
+ dd->mode = 0;
if (strcmp("<>", range) == 0) {
if (strlen(mode) != 0) {
goto error;
}
dd->mode = DETECTDSIZE_RA;
+ } else if (strlen(mode) > 0) {
+ if (mode[0] == '<')
+ dd->mode = DETECTDSIZE_LT;
+ else if (mode[0] == '>')
+ dd->mode = DETECTDSIZE_GT;
+ else if (mode[0] == '!')
+ dd->mode = DETECTDSIZE_NE;
+ else
+ dd->mode = DETECTDSIZE_EQ;
+ } else {
+ dd->mode = DETECTDSIZE_EQ; // default
}
/** set the first dsize value */
switch (dd->mode) {
case DETECTDSIZE_LT:
case DETECTDSIZE_EQ:
+ case DETECTDSIZE_NE:
return dd->dsize;
case DETECTDSIZE_RA:
return dd->dsize2;
high = dd->dsize;
break;
case DETECTDSIZE_EQ:
+ case DETECTDSIZE_NE:
low = dd->dsize;
high = dd->dsize;
break;
high = 65535;
break;
}
+ s->dsize_mode = dd->mode;
s->dsize_low = low;
s->dsize_high = high;
- SCLogDebug("low %u, high %u", low, high);
+ SCLogDebug("low %u, high %u, mode %u", low, high, dd->mode);
}
}
return result;
}
+/**
+ * \test this is a test for a valid dsize value !1
+ *
+ * \retval 1 on success
+ * \retval 0 on failure
+ */
+static int DsizeTestParse21(void)
+{
+ DetectDsizeData *dd = NULL;
+ dd = DetectDsizeParse("!1");
+ FAIL_IF_NULL(dd);
+ DetectDsizeFree(NULL, dd);
+ PASS;
+}
+
+/**
+ * \test this is a test for a valid dsize value ! 1
+ *
+ * \retval 1 on success
+ * \retval 0 on failure
+ */
+static int DsizeTestParse22(void)
+{
+ DetectDsizeData *dd = NULL;
+ dd = DetectDsizeParse("! 1");
+ FAIL_IF_NULL(dd);
+ DetectDsizeFree(NULL, dd);
+ PASS;
+}
+
+/**
+ * \test this is a test for a invalid dsize value 1!
+ *
+ * \retval 1 on success
+ * \retval 0 on failure
+ */
+static int DsizeTestParse23(void)
+{
+ DetectDsizeData *dd = NULL;
+ dd = DetectDsizeParse("1!");
+ if (dd) {
+ DetectDsizeFree(NULL, dd);
+ FAIL;
+ }
+ PASS;
+}
+
+/**
+ * \test this is a test for positive ! dsize matching
+ *
+ * \retval 1 on success
+ * \retval 0 on failure
+ */
+static int DsizeTestMatch01(void)
+{
+ uint16_t psize = 1;
+ uint16_t dsizelow = 2;
+ uint16_t dsizehigh = 0;
+ int result = 0;
+
+ result = DsizeMatch(psize, DETECTDSIZE_NE, dsizelow, dsizehigh);
+
+ PASS_IF(result);
+}
+
+/**
+ * \test this is a test for negative ! dsize matching
+ *
+ * \retval 1 on success
+ * \retval 0 on failure
+ */
+static int DsizeTestMatch02(void)
+{
+ uint16_t psize = 1;
+ uint16_t dsizelow = 1;
+ uint16_t dsizehigh = 0;
+ int result = 0;
+
+ result = !DsizeMatch(psize, DETECTDSIZE_NE, dsizelow, dsizehigh);
+
+ PASS_IF(result);
+}
+
/**
* \test DetectDsizeIcmpv6Test01 is a test for checking the working of
* dsize keyword by creating 2 rules and matching a crafted packet
UtRegisterTest("DsizeTestParse18", DsizeTestParse18);
UtRegisterTest("DsizeTestParse19", DsizeTestParse19);
UtRegisterTest("DsizeTestParse20", DsizeTestParse20);
+ UtRegisterTest("DsizeTestParse21", DsizeTestParse21);
+ UtRegisterTest("DsizeTestParse22", DsizeTestParse22);
+ UtRegisterTest("DsizeTestParse23", DsizeTestParse23);
+ UtRegisterTest("DsizeTestMatch01", DsizeTestMatch01);
+ UtRegisterTest("DsizeTestMatch02", DsizeTestMatch02);
UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01);
}
#define DETECTDSIZE_EQ 1
#define DETECTDSIZE_GT 2
#define DETECTDSIZE_RA 3
+#define DETECTDSIZE_NE 4
typedef struct DetectDsizeData_ {
uint16_t dsize;
void SigParseSetDsizePair(Signature *s);
void SigParseApplyDsizeToContent(Signature *s);
+/** Determine if a packet p should be kicked out during prefilter due
+ * to dsize outside the range specified in signature s */
+static inline bool SigDsizePrefilter(const Packet *p, const Signature *s, uint32_t sflags)
+{
+ if (unlikely(sflags & SIG_FLAG_DSIZE)) {
+ if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) {
+ if (!(s->dsize_mode == DETECTDSIZE_NE)) {
+ SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", p->payload_len,
+ s->dsize_low, s->dsize_high);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
#endif /* __DETECT_DSIZE_H__ */
case DETECT_DSIZE:
{
DetectDsizeData *ds = (DetectDsizeData *)sm->ctx;
- switch (ds->mode) {
- case DETECTDSIZE_LT:
- /* LT will include 0, so no payload.
- * if GT is used in the same rule the
- * flag will be set anyway. */
- break;
- case DETECTDSIZE_RA:
- case DETECTDSIZE_GT:
+ /* LT will include 0, so no payload.
+ * if GT is used in the same rule the
+ * flag will be set anyway. */
+ if (ds->mode == DETECTDSIZE_RA || ds->mode == DETECTDSIZE_GT ||
+ ds->mode == DETECTDSIZE_NE) {
+
+ s->mask |= SIG_MASK_REQUIRE_PAYLOAD;
+ SCLogDebug("sig requires payload");
+
+ } else if (ds->mode == DETECTDSIZE_EQ) {
+ if (ds->dsize > 0) {
s->mask |= SIG_MASK_REQUIRE_PAYLOAD;
SCLogDebug("sig requires payload");
- break;
- case DETECTDSIZE_EQ:
- if (ds->dsize > 0) {
- s->mask |= SIG_MASK_REQUIRE_PAYLOAD;
- SCLogDebug("sig requires payload");
- } else if (ds->dsize == 0) {
- s->mask |= SIG_MASK_REQUIRE_NO_PAYLOAD;
- SCLogDebug("sig requires no payload");
- }
- break;
+ } else {
+ s->mask |= SIG_MASK_REQUIRE_NO_PAYLOAD;
+ SCLogDebug("sig requires no payload");
+ }
}
break;
}