Add ip_proto support.

remotes/origin/master-1.0.x
Brian Rectanus 16 years ago committed by Victor Julien
parent f70c026340
commit e28647032d

@ -53,6 +53,7 @@ detect-recursive.c detect-recursive.h \
detect-rawbytes.c detect-rawbytes.h \
detect-bytetest.c detect-bytetest.h \
detect-bytejump.c detect-bytejump.h \
detect-ipproto.c detect-ipproto.h \
detect-within.c detect-within.h \
detect-distance.c detect-distance.h \
detect-offset.c detect-offset.h \

@ -11,6 +11,7 @@
#include "flow-var.h"
#include "util-cidr.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "detect-engine-siggroup.h"
@ -69,15 +70,31 @@ int DetectProtoParse(DetectProto *dp, char *str) {
} else if (strcasecmp(str, "icmp") == 0) {
proto = IPPROTO_ICMP;
dp->proto[proto / 8] |= 1 << (proto % 8);
} else if (strcasecmp(str, "ip") == 0) {
} else if (strcasecmp(str,"ip") == 0) {
/* Proto "ip" is treated as an "any" */
dp->flags |= DETECT_PROTO_ANY;
memset(&dp->proto, 0xFF, sizeof(dp->proto));
} else {
proto = atoi(str);
dp->proto[proto / 8] |= 1 << (proto % 8);
uint8_t proto_u8; /* Used to avoid sign extension */
/* Extract out a 0-256 value with validation checks */
if (ByteExtractStringUint8(&proto_u8, 10, 0, str) == -1) {
// XXX
goto error;
}
proto = (int)proto_u8;
/* Proto 0 is the same as "ip" above */
if (proto == IPPROTO_IP) {
dp->flags |= DETECT_PROTO_ANY;
} else {
dp->proto[proto / 8] |= 1<<(proto % 8);
}
}
return 0;
error:
return -1;
}
/* XXX remove */
@ -124,6 +141,19 @@ static int ProtoTestParse03 (void) {
return 0;
}
static int ProtoTestParse04 (void) {
DetectProto dp;
memset(&dp,0,sizeof(DetectProto));
/* Check for a bad number */
int r = DetectProtoParse(&dp, "4242");
if (r == -1) {
return 1;
}
return 0;
}
#endif /* UNITTESTS */
@ -132,6 +162,7 @@ void DetectProtoTests(void) {
UtRegisterTest("ProtoTestParse01", ProtoTestParse01, 1);
UtRegisterTest("ProtoTestParse02", ProtoTestParse02, 1);
UtRegisterTest("ProtoTestParse03", ProtoTestParse03, 1);
UtRegisterTest("ProtoTestParse04", ProtoTestParse04, 1);
#endif /* UNITTESTS */
}

@ -0,0 +1,513 @@
/* Copyright (c) 2009 Open Information Security Foundation */
/**
* \file
* \author Brian Rectanus <brectanu@gmail.com>
*/
#include <netdb.h>
#include "eidps-common.h"
#include "debug.h"
#include "decode.h"
#include "detect.h"
#include "detect-ipproto.h"
#include "util-byte.h"
#include "util-unittest.h"
/**
* \brief Regex for parsing our options
*/
#define PARSE_REGEX "^\\s*" \
"([!<>]?)" \
"\\s*([^\\s]+)" \
"\\s*$"
static pcre *parse_regex;
static pcre_extra *parse_regex_study;
int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s,
SigMatch *m, char *optstr);
DetectIPProtoData *DetectIPProtoParse(const char *optstr);
void DetectIPProtoRegisterTests(void);
void DetectIPProtoRegister (void) {
const char *eb;
int eo;
int opts = 0;
sigmatch_table[DETECT_IPPROTO].name = "ip_proto";
sigmatch_table[DETECT_IPPROTO].Match = NULL;
sigmatch_table[DETECT_IPPROTO].Setup = DetectIPProtoSetup;
sigmatch_table[DETECT_IPPROTO].Free = NULL;
sigmatch_table[DETECT_IPPROTO].RegisterTests = DetectIPProtoRegisterTests;
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
if(parse_regex == NULL)
{
printf("DetectIPProtoRegister: pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", PARSE_REGEX, eo, eb);
goto error;
}
parse_regex_study = pcre_study(parse_regex, 0, &eb);
if(eb != NULL)
{
printf("DetectIPProtoRegister: pcre study failed: %s\n", eb);
goto error;
}
return;
error:
/* XXX */
return;
}
/**
* \internal
* \brief Parse ip_proto options string.
*
* \param optstr Options string to parse
*
* \return New ip_proto data structure
*/
DetectIPProtoData *DetectIPProtoParse(const char *optstr)
{
DetectIPProtoData *data = NULL;
char *args[9] = { NULL, NULL };
#define MAX_SUBSTRINGS 30
int ret = 0, res = 0;
int ov[MAX_SUBSTRINGS];
int i;
const char *str_ptr;
/* Execute the regex and populate args with captures. */
ret = pcre_exec(parse_regex, parse_regex_study, optstr,
strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS);
if (ret != 3) {
printf("DetectIPProtoParse: parse error, ret %" PRId32
", string %s\n", ret, optstr);
goto error;
}
for (i = 0; i < (ret - 1); i++) {
res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS,
i + 1, &str_ptr);
if (res < 0) {
printf("DetectIPProtoParse: pcre_get_substring failed "
"for arg %d\n", i + 1);
goto error;
}
args[i] = (char *)str_ptr;
}
/* Initialize the data */
data = malloc(sizeof(DetectIPProtoData));
if (data == NULL) {
printf("DetectIPProtoParse: malloc failed\n");
goto error;
}
data->op = DETECT_IPPROTO_OP_EQ;
data->proto = 0;
/* Operator */
if (*(args[0]) != '\0') {
data->op = *(args[0]);
}
/* Protocol name/number */
if (!isdigit(*(args[1]))) {
struct protoent *pent = getprotobyname(args[1]);
if (pent == NULL) {
printf("DetectIPProtoParse: Malformed protocol name: %s\n", str_ptr);
goto error;
}
data->proto = (uint8_t)pent->p_proto;
}
else {
if (ByteExtractStringUint8(&data->proto, 10, 0, args[1]) <= 0) {
printf("DetectIPProtoParse: Malformed protocol number: %s\n", str_ptr);
goto error;
}
}
for (i = 0; i < (ret - 1); i++){
if (args[i] != NULL) free(args[i]);
}
return data;
error:
for (i = 0; i < (ret - 1); i++){
if (args[i] != NULL) free(args[i]);
}
if (data != NULL) free(data);
return NULL;
}
/**
* \internal
* \brief Setup ip_proto keyword.
*
* \param de_ctx Detection engine context
* \param s Signature
* \param m Signature match
* \param optstr Options string
*
* \return Non-zero on error
*/
int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s,
SigMatch *m, char *optstr)
{
DetectIPProtoData *data = NULL;
int i;
//printf("DetectIPProtoSetup: \'%s\'\n", optstr);
data = DetectIPProtoParse((const char *)optstr);
if (data == NULL) goto error;
s->proto.flags &= ~DETECT_PROTO_ANY;
switch (data->op) {
case DETECT_IPPROTO_OP_EQ:
s->proto.proto[data->proto/8] |= 1 << (data->proto%8);
break;
case DETECT_IPPROTO_OP_GT:
s->proto.proto[data->proto/8] |= 0xff << (data->proto%8);
for (i = (data->proto/8) + 1; i < (256/8); i++) {
s->proto.proto[i] = 0xff;
}
break;
case DETECT_IPPROTO_OP_LT:
for (i = 0; i < (data->proto/8); i++) {
s->proto.proto[i] = 0xff;
}
s->proto.proto[data->proto/8] |= ~(0xff << (data->proto%8));
break;
case DETECT_IPPROTO_OP_NOT:
s->proto.proto[data->proto/8] &= ~(1 << (data->proto%8));
break;
}
#if DEBUG
printf("op='%c' bits=\"", data->op);
for (i = 0; i < (256/8); i++) {
printf("%02x", s->proto.proto[i]);
}
printf("\"\n");
#endif
return 0;
error:
if (data != NULL) free(data);
return -1;
}
/* UNITTESTS */
#ifdef UNITTESTS
#include "detect-engine.h"
#include "detect-parse.h"
static int DetectIPProtoInitTest(DetectEngineCtx **de_ctx, Signature **sig, DetectIPProtoData **data, const char *str) {
char fullstr[1024];
int result = 0;
*de_ctx = NULL;
*sig = NULL;
if (snprintf(fullstr, 1024, "alert ip any any -> any any (msg:\"IPProto test\"; ip_proto:%s; sid:1;)", str) >= 1024) {
goto end;
}
*de_ctx = DetectEngineCtxInit();
if (*de_ctx == NULL) {
goto end;
}
(*de_ctx)->flags |= DE_QUIET;
(*de_ctx)->sig_list = SigInit(*de_ctx, fullstr);
if ((*de_ctx)->sig_list == NULL) {
goto end;
}
*sig = (*de_ctx)->sig_list;
if ((*sig)->proto.flags & DETECT_PROTO_ANY) {
goto end;
}
*data = DetectIPProtoParse(str);
result = 1;
end:
return result;
}
/**
* \test DetectIPProtoTestParse01 is a test for an invalid proto number
*/
int DetectIPProtoTestParse01(void) {
int result = 0;
DetectIPProtoData *data = NULL;
data = DetectIPProtoParse("999");
if (data == NULL) {
result = 1;
}
return result;
}
/**
* \test DetectIPProtoTestParse02 is a test for an invalid proto name
*/
int DetectIPProtoTestParse02(void) {
int result = 0;
DetectIPProtoData *data = NULL;
data = DetectIPProtoParse("foobarbooeek");
if (data == NULL) {
result = 1;
}
return result;
}
/**
* \test DetectIPProtoTestSetup01 is a test for a protocol number
*/
int DetectIPProtoTestSetup01(void) {
DetectIPProtoData *data = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = NULL;
int result = 0;
int i;
result = DetectIPProtoInitTest(&de_ctx, &sig, &data, "14");
if (result == 0) {
goto end;
}
result = 0;
if (data == NULL) {
goto cleanup;
}
if ( (data->op != DETECT_IPPROTO_OP_EQ)
|| (data->proto != 14))
{
goto cleanup;
}
/* The 6th bit is the only one that should be set */
if (sig->proto.proto[1] != 0x40) {
goto cleanup;
}
for (i = 2; i < 256/8; i++) {
if (sig->proto.proto[i] != 0) {
goto cleanup;
}
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test DetectIPProtoTestSetup02 is a test for a protocol name
*/
int DetectIPProtoTestSetup02(void) {
DetectIPProtoData *data = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = NULL;
int result = 0;
result = DetectIPProtoInitTest(&de_ctx, &sig, &data, "tcp");
if (result == 0) {
goto end;
}
result = 0;
if (data == NULL) {
goto cleanup;
}
if ( (data->op != DETECT_IPPROTO_OP_EQ)
|| (data->proto != 6))
{
goto cleanup;
}
/* The 6th bit is the only one that should be set */
if (sig->proto.proto[0] != 0x40) {
goto cleanup;
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test DetectIPProtoTestSetup03 is a test for a < operator
*/
int DetectIPProtoTestSetup03(void) {
DetectIPProtoData *data = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = NULL;
int result = 0;
result = DetectIPProtoInitTest(&de_ctx, &sig, &data, "<14");
if (result == 0) {
printf("ERR1\n");
goto end;
}
result = 0;
if (data == NULL) {
goto cleanup;
}
if ( (data->op != DETECT_IPPROTO_OP_LT)
|| (data->proto != 14))
{
goto cleanup;
}
if ( (sig->proto.proto[0] != 0xff)
|| (sig->proto.proto[1] != 0x3f))
{
goto cleanup;
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test DetectIPProtoTestSetup04 is a test for a > operator
*/
int DetectIPProtoTestSetup04(void) {
DetectIPProtoData *data = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = NULL;
int result = 0;
int i;
result = DetectIPProtoInitTest(&de_ctx, &sig, &data, ">14");
if (result == 0) {
goto end;
}
result = 0;
if (data == NULL) {
goto cleanup;
}
if ( (data->op != DETECT_IPPROTO_OP_GT)
|| (data->proto != 14))
{
goto cleanup;
}
if (sig->proto.proto[1] != 0xc0) {
goto cleanup;
}
for (i = 2; i < 256/8; i++) {
if (sig->proto.proto[i] != 0xff) {
goto cleanup;
}
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test DetectIPProtoTestSetup05 is a test for a ! operator
*/
int DetectIPProtoTestSetup05(void) {
DetectIPProtoData *data = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = NULL;
int result = 0;
int i;
result = DetectIPProtoInitTest(&de_ctx, &sig, &data, "!14");
if (result == 0) {
goto end;
}
result = 0;
if (data == NULL) {
goto cleanup;
}
if ( (data->op != DETECT_IPPROTO_OP_NOT)
|| (data->proto != 14))
{
goto cleanup;
}
for (i = 1; i < 256/8; i++) {
if (sig->proto.proto[i] != 0) {
goto cleanup;
}
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
#endif /* UNITTESTS */
/**
* \internal
* \brief Register ip_proto tests.
*/
void DetectIPProtoRegisterTests(void) {
#ifdef UNITTESTS
UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01, 1);
UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02, 1);
UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01, 1);
UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02, 1);
UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03, 1);
UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04, 1);
UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05, 1);
#endif /* UNITTESTS */
}

@ -0,0 +1,31 @@
/* Copyright (c) 2009 Open Information Security Foundation */
/**
* \file
* \author Brian Rectanus <brectanu@gmail.com>
*/
#ifndef __DETECT_IPPROTO_H__
#define __DETECT_IPPROTO_H__
/** IPProto Operators */
#define DETECT_IPPROTO_OP_EQ '=' /**< "equals" operator (default) */
#define DETECT_IPPROTO_OP_NOT '!' /**< "not" operator */
#define DETECT_IPPROTO_OP_LT '<' /**< "less than" operator */
#define DETECT_IPPROTO_OP_GT '>' /**< "greater than" operator */
/** ip_proto data */
typedef struct DetectIPProtoData_ {
uint8_t op; /**< Operator used to compare */
uint8_t proto; /**< Protocol used to compare */
} DetectIPProtoData;
/* prototypes */
/**
* \brief Registration function for ip_proto keyword.
*/
void DetectIPProtoRegister (void);
#endif /* __DETECT_IPPROTO_H__ */

@ -28,6 +28,7 @@
#include "detect-rawbytes.h"
#include "detect-bytetest.h"
#include "detect-bytejump.h"
#include "detect-ipproto.h"
#include "detect-within.h"
#include "detect-distance.h"
#include "detect-offset.h"
@ -2550,6 +2551,7 @@ void SigTableSetup(void) {
DetectRawbytesRegister();
DetectBytetestRegister();
DetectBytejumpRegister();
DetectIPProtoRegister();
DetectWithinRegister();
DetectDistanceRegister();
DetectOffsetRegister();
@ -6403,6 +6405,96 @@ end:
return result;
}
static int SigTest41Real (int mpm_type) {
uint8_t *buf = (uint8_t *)
"GET /one/ HTTP/1.1\r\n"
"Host: one.example.org\r\n"
"\r\n";
uint16_t buflen = strlen((char *)buf);
Packet p;
Signature *s = NULL;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
int result = 0;
memset(&th_v, 0, sizeof(th_v));
memset(&p, 0, sizeof(p));
p.src.family = AF_INET;
p.dst.family = AF_INET;
p.payload = buf;
p.payload_len = buflen;
p.proto = IPPROTO_TCP;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
//de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
PatternMatchPrepare(mpm_ctx, mpm_type);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
if (PacketAlertCheck(&p, 1)) {
printf("sid 1 alerted, but should not have: ");
goto cleanup;
} else if (PacketAlertCheck(&p, 2) == 0) {
printf("sid 2 did not alert, but should have: ");
goto cleanup;
} else if (PacketAlertCheck(&p, 3) == 0) {
printf("sid 3 did not alert, but should have: ");
goto cleanup;
} else if (PacketAlertCheck(&p, 4) == 0) {
printf("sid 4 did not alert, but should have: ");
goto cleanup;
}
result = 1;
cleanup:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
static int SigTest41B2g (void) {
return SigTest41Real(MPM_B2G);
}
static int SigTest41B3g (void) {
return SigTest41Real(MPM_B3G);
}
static int SigTest41Wm (void) {
return SigTest41Real(MPM_WUMANBER);
}
#endif /* UNITTESTS */
void SigRegisterTests(void) {
@ -6554,6 +6646,9 @@ void SigRegisterTests(void) {
UtRegisterTest("SigTest40SignatureIsIPOnly02", SigTest40IPOnly02, 1);
UtRegisterTest("SigTest40SignatureIsIPOnly03", SigTest40IPOnly03, 1);
UtRegisterTest("SigTest41B2g -- ip_proto test", SigTest41B2g, 1);
UtRegisterTest("SigTest41B3g -- ip_proto test", SigTest41B3g, 1);
UtRegisterTest("SigTest41Wm -- ip_proto test", SigTest41Wm, 1);
#endif /* UNITTESTS */
}

@ -410,6 +410,7 @@ enum {
DETECT_RAWBYTES,
DETECT_BYTETEST,
DETECT_BYTEJUMP,
DETECT_IPPROTO,
DETECT_FLOW,
DETECT_WINDOW,
DETECT_ISDATAAT,

Loading…
Cancel
Save