From: Giuseppe Longo Date: Fri, 29 Aug 2014 12:22:09 +0000 (+0200) Subject: iprep: extends cidr support X-Git-Tag: suricata-2.1beta2~54 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a1d8439b2537e366cdb308f7b14155a1b503ee26;p=thirdparty%2Fsuricata.git iprep: extends cidr support Implements new API to expand the IP reputation to netblocks with CIDR notation A new object 'srepCIDRTree' is kept in the DetectionEngineCtx, which contains two tree (one for ipv4 and one for ipv6) where the reputation values are stored. --- diff --git a/src/detect.h b/src/detect.h index a3a7d4a7de..cc23fe3028 100644 --- a/src/detect.h +++ b/src/detect.h @@ -39,6 +39,7 @@ #include "util-error.h" #include "util-radix-tree.h" #include "util-file.h" +#include "reputation.h" #include "detect-mark.h" @@ -586,6 +587,9 @@ typedef struct DetectEngineCtx_ { /* version of the srep data */ uint32_t srep_version; + /* reputation for netblocks */ + SRepCIDRTree *srepCIDR_ctx; + Signature **sig_array; uint32_t sig_array_size; /* size in bytes */ uint32_t sig_array_len; /* size in array members */ diff --git a/src/reputation.c b/src/reputation.c index f84c1a8808..f8f4c62053 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -57,11 +57,116 @@ static uint32_t SRepGetVersion(void) return srep_version; } +void SRepResetVersion(void) +{ + srep_version = 0; +} + static uint32_t SRepGetEffectiveVersion(void) { return SC_ATOMIC_GET(srep_eversion); } +static void SRepCIDRFreeUserData(void *data) +{ + if (data != NULL) + SCFree(data); + + return; +} + +static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, int value) +{ + SReputation *user_data = NULL; + if ((user_data = SCMalloc(sizeof(SReputation))) == NULL) { + SCLogError(SC_ERR_FATAL, "Error allocating memory. Exiting"); + exit(EXIT_FAILURE); + } + memset(user_data, 0x00, sizeof(SReputation)); + + user_data->version = SRepGetVersion(); + user_data->rep[cat] = value; + + if (strchr(ip, ':') != NULL) { + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + cidr_ctx->srepIPV6_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV6 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV6 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv6 host %s", ip); + if (SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv6 host %s", ip); + } + + } else { + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + cidr_ctx->srepIPV4_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV4 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV4 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv4 host %s", ip); + if (SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv4 host %s", ip); + } + } +} + +static uint8_t SRepCIDRGetIPv4IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv4_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, cidr_ctx->srepIPV4_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +static uint8_t SRepCIDRGetIPv6IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv6_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, cidr_ctx->srepIPV6_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_SRC_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_SRC_ADDR(p), cat); + + return rep; +} + +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_DST_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_DST_ADDR(p), cat); + + return rep; +} + /** \brief Increment effective reputation version after * a rule/reputatio reload is complete. */ void SRepReloadComplete(void) @@ -162,7 +267,7 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh * \retval 1 header * \retval -1 boo */ -static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) +static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); char *ptrs[3] = {NULL,NULL,NULL}; @@ -200,11 +305,6 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) if (strcmp(ptrs[0], "ip") == 0) return 1; - uint32_t addr; - if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { - return -1; - } - int c = atoi(ptrs[1]); if (c < 0 || c >= SREP_MAX_CATS) { return -1; @@ -215,9 +315,20 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) return -1; } - *ip = addr; - *cat = c; - *value = v; + if (strchr(ptrs[0], '/') != NULL) { + SRepCIDRAddNetblock(cidr_ctx, ptrs[0], c, v); + return 1; + } else { + uint32_t addr; + if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { + return -1; + } + + *ip = addr; + *cat = c; + *value = v; + } + return 0; } @@ -246,7 +357,24 @@ uint8_t SRepCatGetByShortname(char *shortname) return 0; } -int SRepLoadCatFile(char *filename) +static int SRepLoadCatFile(char *filename) +{ + int r = 0; + FILE *fp = fopen(filename, "r"); + + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); + return -1; + } + + r = SRepLoadCatFileFromFD(fp); + + fclose(fp); + fp = NULL; + return r; +} + +int SRepLoadCatFileFromFD(FILE *fp) { char line[8192] = ""; Address a; @@ -256,12 +384,6 @@ int SRepLoadCatFile(char *filename) BUG_ON(SRepGetVersion() > 0); - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); - return -1; - } - while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -290,8 +412,6 @@ int SRepLoadCatFile(char *filename) SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } } - fclose(fp); - fp = NULL; SCLogDebug("IP Rep categories:"); int i; @@ -303,19 +423,31 @@ int SRepLoadCatFile(char *filename) return 0; } -static int SRepLoadFile(char *filename) +static int SRepLoadFile(SRepCIDRTree *cidr_ctx, char *filename) { - char line[8192] = ""; - Address a; - memset(&a, 0x00, sizeof(a)); - a.family = AF_INET; - + int r = 0; FILE *fp = fopen(filename, "r"); + if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file \"%s\": %s", filename, strerror(errno)); + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); return -1; } + r = SRepLoadFileFromFD(cidr_ctx, fp); + + fclose(fp); + fp = NULL; + return r; + +} + +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) +{ + char line[8192] = ""; + Address a; + memset(&a, 0x00, sizeof(a)); + a.family = AF_INET; + while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -338,7 +470,7 @@ static int SRepLoadFile(char *filename) uint32_t ip = 0; uint8_t cat = 0, value = 0; - int r = SRepSplitLine(line, &ip, &cat, &value); + int r = SRepSplitLine(cidr_ctx, line, &ip, &cat, &value); if (r < 0) { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } else if (r == 0) { @@ -394,8 +526,6 @@ static int SRepLoadFile(char *filename) } } } - fclose(fp); - fp = NULL; return 0; } @@ -459,6 +589,18 @@ int SRepInit(DetectEngineCtx *de_ctx) char *sfile = NULL; char *filename = NULL; int init = 0; + int i = 0; + + de_ctx->srepCIDR_ctx = (SRepCIDRTree *)SCMalloc(sizeof(SRepCIDRTree)); + if (de_ctx->srepCIDR_ctx == NULL) + exit(EXIT_FAILURE); + memset(de_ctx->srepCIDR_ctx, 0, sizeof(SRepCIDRTree)); + SRepCIDRTree *cidr_ctx = de_ctx->srepCIDR_ctx; + + for (i = 0; i < SREP_MAX_CATS; i++) { + cidr_ctx->srepIPV4_tree[i] = NULL; + cidr_ctx->srepIPV6_tree[i] = NULL; + } if (SRepGetVersion() == 0) { SC_ATOMIC_INIT(srep_eversion); @@ -502,7 +644,7 @@ int SRepInit(DetectEngineCtx *de_ctx) sfile = SRepCompleteFilePath(file->val); SCLogInfo("Loading reputation file: %s", sfile); - r = SRepLoadFile(sfile); + r = SRepLoadFile(cidr_ctx, sfile); if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); diff --git a/src/reputation.h b/src/reputation.h index 4e35830d82..d489b1ff80 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -26,17 +26,22 @@ #ifndef __REPUTATION_H__ #define __REPUTATION_H__ -#include "detect.h" #include "host.h" #define SREP_MAX_CATS 60 + +typedef struct SRepCIDRTree_ { + SCRadixTree *srepIPV4_tree[SREP_MAX_CATS]; + SCRadixTree *srepIPV6_tree[SREP_MAX_CATS]; +} SRepCIDRTree; + typedef struct SReputation_ { uint32_t version; uint8_t rep[SREP_MAX_CATS]; } SReputation; uint8_t SRepCatGetByShortname(char *shortname); -int SRepInit(DetectEngineCtx *de_ctx); +int SRepInit(struct DetectEngineCtx_ *de_ctx); void SRepReloadComplete(void); int SRepHostTimedOut(Host *); @@ -76,6 +81,12 @@ typedef struct IPReputationCtx_ { SCMutex reputationIPV6_lock; }IPReputationCtx; +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +void SRepResetVersion(); +int SRepLoadCatFileFromFD(FILE *fp); +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp); + /** Reputation Data */ //TODO: Add a timestamp here to know the last update of this reputation. typedef struct Reputation_ {