|
|
|
@ -30,6 +30,7 @@
|
|
|
|
|
#include "detect.h"
|
|
|
|
|
#include "detect-parse.h"
|
|
|
|
|
#include "detect-engine-prefilter-common.h"
|
|
|
|
|
#include "detect-engine-uint.h"
|
|
|
|
|
|
|
|
|
|
#include "detect-icode.h"
|
|
|
|
|
|
|
|
|
@ -41,9 +42,6 @@
|
|
|
|
|
/**
|
|
|
|
|
*\brief Regex for parsing our icode options
|
|
|
|
|
*/
|
|
|
|
|
#define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]+)\\s*(?:<>\\s*([0-9]+))?\\s*$"
|
|
|
|
|
|
|
|
|
|
static DetectParseRegex parse_regex;
|
|
|
|
|
|
|
|
|
|
static int DetectICodeMatch(DetectEngineThreadCtx *, Packet *,
|
|
|
|
|
const Signature *, const SigMatchCtx *);
|
|
|
|
@ -72,48 +70,16 @@ void DetectICodeRegister (void)
|
|
|
|
|
#endif
|
|
|
|
|
sigmatch_table[DETECT_ICODE].SupportsPrefilter = PrefilterICodeIsPrefilterable;
|
|
|
|
|
sigmatch_table[DETECT_ICODE].SetupPrefilter = PrefilterSetupICode;
|
|
|
|
|
|
|
|
|
|
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DETECT_ICODE_EQ PREFILTER_U8HASH_MODE_EQ /**< "equal" operator */
|
|
|
|
|
#define DETECT_ICODE_LT PREFILTER_U8HASH_MODE_LT /**< "less than" operator */
|
|
|
|
|
#define DETECT_ICODE_GT PREFILTER_U8HASH_MODE_GT /**< "greater than" operator */
|
|
|
|
|
#define DETECT_ICODE_RN PREFILTER_U8HASH_MODE_RA /**< "range" operator */
|
|
|
|
|
|
|
|
|
|
typedef struct DetectICodeData_ {
|
|
|
|
|
uint8_t code1;
|
|
|
|
|
uint8_t code2;
|
|
|
|
|
|
|
|
|
|
uint8_t mode;
|
|
|
|
|
} DetectICodeData;
|
|
|
|
|
|
|
|
|
|
static inline int ICodeMatch(const uint8_t pcode, const uint8_t mode,
|
|
|
|
|
const uint8_t dcode1, const uint8_t dcode2)
|
|
|
|
|
{
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case DETECT_ICODE_EQ:
|
|
|
|
|
return (pcode == dcode1) ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
case DETECT_ICODE_LT:
|
|
|
|
|
return (pcode < dcode1) ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
case DETECT_ICODE_GT:
|
|
|
|
|
return (pcode > dcode1) ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
case DETECT_ICODE_RN:
|
|
|
|
|
return (pcode > dcode1 && pcode < dcode2) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief This function is used to match icode rule option set on a packet with those passed via icode:
|
|
|
|
|
* \brief This function is used to match icode rule option set on a packet with those passed via
|
|
|
|
|
* icode:
|
|
|
|
|
*
|
|
|
|
|
* \param t pointer to thread vars
|
|
|
|
|
* \param det_ctx pointer to the pattern matcher thread
|
|
|
|
|
* \param p pointer to the current packet
|
|
|
|
|
* \param m pointer to the sigmatch that we will cast into DetectICodeData
|
|
|
|
|
* \param ctx pointer to the sigmatch that we will cast into DetectU8Data
|
|
|
|
|
*
|
|
|
|
|
* \retval 0 no match
|
|
|
|
|
* \retval 1 match
|
|
|
|
@ -134,127 +100,8 @@ static int DetectICodeMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DetectICodeData *icd = (const DetectICodeData *)ctx;
|
|
|
|
|
return ICodeMatch(picode, icd->mode, icd->code1, icd->code2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief This function is used to parse icode options passed via icode: keyword
|
|
|
|
|
*
|
|
|
|
|
* \param de_ctx Pointer to the detection engine context
|
|
|
|
|
* \param icodestr Pointer to the user provided icode options
|
|
|
|
|
*
|
|
|
|
|
* \retval icd pointer to DetectICodeData on success
|
|
|
|
|
* \retval NULL on failure
|
|
|
|
|
*/
|
|
|
|
|
static DetectICodeData *DetectICodeParse(DetectEngineCtx *de_ctx, const char *icodestr)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = NULL;
|
|
|
|
|
char *args[3] = {NULL, NULL, NULL};
|
|
|
|
|
int ret = 0, res = 0;
|
|
|
|
|
size_t pcre2_len;
|
|
|
|
|
|
|
|
|
|
ret = DetectParsePcreExec(&parse_regex, icodestr, 0, 0);
|
|
|
|
|
if (ret < 1 || ret > 4) {
|
|
|
|
|
SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, icodestr);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
const char *str_ptr;
|
|
|
|
|
for (i = 1; i < ret; i++) {
|
|
|
|
|
res = SC_Pcre2SubstringGet(parse_regex.match, i, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
|
|
|
|
|
if (res < 0) {
|
|
|
|
|
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre2_substring_get_bynumber failed");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
args[i-1] = (char *)str_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
icd = SCMalloc(sizeof(DetectICodeData));
|
|
|
|
|
if (unlikely(icd == NULL))
|
|
|
|
|
goto error;
|
|
|
|
|
icd->code1 = 0;
|
|
|
|
|
icd->code2 = 0;
|
|
|
|
|
icd->mode = 0;
|
|
|
|
|
|
|
|
|
|
/* we have either "<" or ">" */
|
|
|
|
|
if (args[0] != NULL && strlen(args[0]) != 0) {
|
|
|
|
|
/* we have a third part ("<> y"), therefore it's invalid */
|
|
|
|
|
if (args[2] != NULL) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "icode: invalid value");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
/* we have only a comparison ("<", ">") */
|
|
|
|
|
if (StringParseUint8(&icd->code1, 10, 0, args[1]) < 0) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
|
|
|
|
|
"valid", args[1]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if ((strcmp(args[0], ">")) == 0) {
|
|
|
|
|
if (icd->code1 == 255) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
|
|
|
"specified icmp code >%s is not "
|
|
|
|
|
"valid",
|
|
|
|
|
args[1]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
icd->mode = DETECT_ICODE_GT;
|
|
|
|
|
} else {
|
|
|
|
|
if (icd->code1 == 0) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
|
|
|
"specified icmp code <%s is not "
|
|
|
|
|
"valid",
|
|
|
|
|
args[1]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
icd->mode = DETECT_ICODE_LT;
|
|
|
|
|
}
|
|
|
|
|
} else { /* no "<", ">" */
|
|
|
|
|
/* we have a range ("<>") */
|
|
|
|
|
if (args[2] != NULL) {
|
|
|
|
|
icd->mode = (uint8_t) DETECT_ICODE_RN;
|
|
|
|
|
if (StringParseUint8(&icd->code1, 10, 0, args[1]) < 0) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
|
|
|
|
|
"valid", args[1]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
if (StringParseUint8(&icd->code2, 10, 0, args[2]) < 0) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
|
|
|
|
|
"valid", args[2]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
/* we check that the first given value in the range is less than
|
|
|
|
|
the second, otherwise we swap them */
|
|
|
|
|
if (icd->code1 > icd->code2) {
|
|
|
|
|
uint8_t temp = icd->code1;
|
|
|
|
|
icd->code1 = icd->code2;
|
|
|
|
|
icd->code2 = temp;
|
|
|
|
|
}
|
|
|
|
|
} else { /* we have an equality */
|
|
|
|
|
icd->mode = DETECT_ICODE_EQ;
|
|
|
|
|
if (StringParseUint8(&icd->code1, 10, 0, args[1]) < 0) {
|
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
|
|
|
|
|
"valid", args[1]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < (ret-1); i++) {
|
|
|
|
|
if (args[i] != NULL)
|
|
|
|
|
pcre2_substring_free((PCRE2_UCHAR8 *)args[i]);
|
|
|
|
|
}
|
|
|
|
|
return icd;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
for (i = 0; i < (ret-1) && i < 3; i++) {
|
|
|
|
|
if (args[i] != NULL)
|
|
|
|
|
pcre2_substring_free((PCRE2_UCHAR8 *)args[i]);
|
|
|
|
|
}
|
|
|
|
|
if (icd != NULL)
|
|
|
|
|
DetectICodeFree(de_ctx, icd);
|
|
|
|
|
return NULL;
|
|
|
|
|
const DetectU8Data *icd = (const DetectU8Data *)ctx;
|
|
|
|
|
return DetectU8Match(picode, icd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -270,10 +117,10 @@ error:
|
|
|
|
|
static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *icodestr)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
DetectICodeData *icd = NULL;
|
|
|
|
|
DetectU8Data *icd = NULL;
|
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
|
|
|
|
|
|
icd = DetectICodeParse(NULL, icodestr);
|
|
|
|
|
icd = DetectU8Parse(icodestr);
|
|
|
|
|
if (icd == NULL) goto error;
|
|
|
|
|
|
|
|
|
|
sm = SigMatchAlloc();
|
|
|
|
@ -288,20 +135,20 @@ static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *i
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
if (icd != NULL) DetectICodeFree(de_ctx, icd);
|
|
|
|
|
if (icd != NULL)
|
|
|
|
|
SCFree(icd);
|
|
|
|
|
if (sm != NULL) SCFree(sm);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief this function will free memory associated with DetectICodeData
|
|
|
|
|
* \brief this function will free memory associated with DetectU8Data
|
|
|
|
|
*
|
|
|
|
|
* \param ptr pointer to DetectICodeData
|
|
|
|
|
* \param ptr pointer to DetectU8Data
|
|
|
|
|
*/
|
|
|
|
|
void DetectICodeFree(DetectEngineCtx *de_ctx, void *ptr)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = (DetectICodeData *)ptr;
|
|
|
|
|
SCFree(icd);
|
|
|
|
|
SCFree(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* prefilter code */
|
|
|
|
@ -333,19 +180,17 @@ static void PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx,
|
|
|
|
|
static void
|
|
|
|
|
PrefilterPacketICodeSet(PrefilterPacketHeaderValue *v, void *smctx)
|
|
|
|
|
{
|
|
|
|
|
const DetectICodeData *a = smctx;
|
|
|
|
|
const DetectU8Data *a = smctx;
|
|
|
|
|
v->u8[0] = a->mode;
|
|
|
|
|
v->u8[1] = a->code1;
|
|
|
|
|
v->u8[2] = a->code2;
|
|
|
|
|
v->u8[1] = a->arg1;
|
|
|
|
|
v->u8[2] = a->arg2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
PrefilterPacketICodeCompare(PrefilterPacketHeaderValue v, void *smctx)
|
|
|
|
|
{
|
|
|
|
|
const DetectICodeData *a = smctx;
|
|
|
|
|
if (v.u8[0] == a->mode &&
|
|
|
|
|
v.u8[1] == a->code1 &&
|
|
|
|
|
v.u8[2] == a->code2)
|
|
|
|
|
const DetectU8Data *a = smctx;
|
|
|
|
|
if (v.u8[0] == a->mode && v.u8[1] == a->arg1 && v.u8[2] == a->arg2)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -379,10 +224,10 @@ static bool PrefilterICodeIsPrefilterable(const Signature *s)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest01(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, "8");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse("8");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_EQ);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_EQ);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -394,10 +239,10 @@ static int DetectICodeParseTest01(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest02(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, ">8");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse(">8");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_GT);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_GT);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -409,10 +254,10 @@ static int DetectICodeParseTest02(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest03(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, "<8");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse("<8");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_LT);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_LT);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -424,11 +269,11 @@ static int DetectICodeParseTest03(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest04(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, "8<>20");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse("8<>20");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->code2 == 20);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_RN);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->arg2 == 20);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_RA);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -440,10 +285,10 @@ static int DetectICodeParseTest04(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest05(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, " 8 ");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse(" 8 ");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_EQ);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_EQ);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -455,10 +300,10 @@ static int DetectICodeParseTest05(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest06(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, " > 8 ");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse(" > 8 ");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_GT);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_GT);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -470,11 +315,11 @@ static int DetectICodeParseTest06(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest07(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, " 8 <> 20 ");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse(" 8 <> 20 ");
|
|
|
|
|
FAIL_IF_NULL(icd);
|
|
|
|
|
FAIL_IF_NOT(icd->code1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->code2 == 20);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_ICODE_RN);
|
|
|
|
|
FAIL_IF_NOT(icd->arg1 == 8);
|
|
|
|
|
FAIL_IF_NOT(icd->arg2 == 20);
|
|
|
|
|
FAIL_IF_NOT(icd->mode == DETECT_UINT_RA);
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
|
|
|
|
|
|
PASS;
|
|
|
|
@ -485,7 +330,7 @@ static int DetectICodeParseTest07(void)
|
|
|
|
|
*/
|
|
|
|
|
static int DetectICodeParseTest08(void)
|
|
|
|
|
{
|
|
|
|
|
DetectICodeData *icd = DetectICodeParse(NULL, "> 8 <> 20");
|
|
|
|
|
DetectU8Data *icd = DetectU8Parse("> 8 <> 20");
|
|
|
|
|
FAIL_IF_NOT_NULL(icd);
|
|
|
|
|
|
|
|
|
|
DetectICodeFree(NULL, icd);
|
|
|
|
@ -529,7 +374,7 @@ static int DetectICodeMatchTest01(void)
|
|
|
|
|
FAIL_IF_NULL(s);
|
|
|
|
|
|
|
|
|
|
s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any (icode:20<>8; sid:5;)");
|
|
|
|
|
FAIL_IF_NULL(s);
|
|
|
|
|
FAIL_IF_NOT_NULL(s);
|
|
|
|
|
|
|
|
|
|
SigGroupBuild(de_ctx);
|
|
|
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
@ -540,7 +385,6 @@ static int DetectICodeMatchTest01(void)
|
|
|
|
|
FAIL_IF(PacketAlertCheck(p, 2) == 0);
|
|
|
|
|
FAIL_IF(PacketAlertCheck(p, 3));
|
|
|
|
|
FAIL_IF(PacketAlertCheck(p, 4) == 0);
|
|
|
|
|
FAIL_IF(PacketAlertCheck(p, 5) == 0);
|
|
|
|
|
|
|
|
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
|
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
|