]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
iprep: extends cidr support
authorGiuseppe Longo <giuseppelng@gmail.com>
Fri, 29 Aug 2014 12:22:09 +0000 (14:22 +0200)
committerVictor Julien <victor@inliniac.net>
Sat, 25 Oct 2014 18:26:53 +0000 (20:26 +0200)
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.

src/detect.h
src/reputation.c
src/reputation.h

index a3a7d4a7defcb9f8adab1d65e97e7f59d2641602..cc23fe3028d4d53a899611b0fcda6a91fddc2e3e 100644 (file)
@@ -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 */
index f84c1a8808f91c6b1285e3776671cf0ebb34d39c..f8f4c620538bfe6dcba94b7ac1a20f880343c163 100644 (file)
@@ -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);
index 4e35830d82ffb82e75cf4fe0cc0689eaded2ea5d..d489b1ff807c2b2b009a024d3f230c0b104385ad 100644 (file)
 #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_ {