]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
location: Add support for the anycast keyword
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 1 Oct 2021 15:18:31 +0000 (15:18 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Dec 2021 12:44:16 +0000 (12:44 +0000)
This allows matching for source, destination or both for anycast
networks.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/detect-engine-register.h
src/detect-location.c

index ab77074d44c1cf4f56df0cbf5e56c36819ecd290..df6c10533e98c75539adb8f5cc30dcc7469eadf9 100644 (file)
@@ -98,6 +98,7 @@ enum DetectKeywordId {
     DETECT_DETECTION_FILTER,
     DETECT_DATASET,
     DETECT_DATAREP,
+    DETECT_ANYCAST,
 
     DETECT_DECODE_EVENT,
     DETECT_GID,
index f126266bc8cf431261d75b425ebe676345230376..9b2bdd8de014517775ee6a15efa5a4b9549f2975 100644 (file)
@@ -49,6 +49,7 @@ struct DetectLocationData {
     struct loc_ctx* ctx;
     struct loc_database* db;
     char** countries;
+    int anycast:1;
     int flags;
 };
 
@@ -247,6 +248,59 @@ ERROR:
     return NULL;
 }
 
+static const struct direction {
+    const char* keyword;
+    int flags;
+} directions[] = {
+    { "src", LOCATION_FLAG_SRC },
+    { "dst", LOCATION_FLAG_DST },
+    { "both", LOCATION_FLAG_SRC|LOCATION_FLAG_DST },
+    { NULL, 0 },
+};
+
+static int DetectLocationParseDirection(const char* string) {
+    for (const struct direction* direction = directions; direction->keyword; direction++) {
+        if (strcmp(direction->keyword, string) == 0)
+            return direction->flags;
+    }
+
+    SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid direction: %s", string);
+
+    return 0;
+}
+
+static struct DetectLocationData* DetectLocationParseAnycast(DetectEngineCtx* ctx,
+        const char* string) {
+    // Check for valid input
+    if (!string || !*string)
+        return NULL;
+
+    // Allocate DetectLocationData
+    struct DetectLocationData* data = SCCalloc(1, sizeof(*data));
+    if (!data)
+        return NULL;
+
+    // Match anycast
+    data->anycast = 1;
+
+    // Which direction?
+    data->flags = DetectLocationParseDirection(string);
+    if (!data->flags)
+        goto ERROR;
+
+    // Open location database
+    int r = DetectLocationOpenDatabase(data);
+    if (r)
+        goto ERROR;
+
+    return data;
+
+ERROR:
+    DetectLocationFree(ctx, data);
+
+    return NULL;
+}
+
 static int DetectLocationCreateMatch(Signature* signature, const enum DetectKeywordId type,
         SigMatchCtx* ctx) {
     // Allocate a new SigMatch structure
@@ -296,15 +350,32 @@ static int DetectLocationSetupGeoIP(DetectEngineCtx* ctx, Signature* signature,
     return 0;
 }
 
+static int DetectLocationSetupAnycast(DetectEngineCtx* ctx, Signature* signature,
+        const char* optstring) {
+    int r;
+
+    // Parse the option string
+    struct DetectLocationData* data = DetectLocationParseAnycast(ctx, optstring);
+    if (!data)
+        return -1;
+
+    // Create a match
+    r = DetectLocationCreateMatch(signature, DETECT_ANYCAST, (SigMatchCtx*)data);
+    if (r) {
+        DetectLocationFree(ctx, data);
+        return r;
+    }
+
+    return 0;
+}
+
 static int DetectLocationMatchCountryCode(const struct DetectLocationData* data, struct loc_network* network) {
     int found = 0;
 
-    if (data->countries) {
-        for (char** country = data->countries; *country; country++) {
-            if (loc_network_matches_country_code(network, *country)) {
-                found = 1;
-                break;
-            }
+    for (char** country = data->countries; *country; country++) {
+        if (loc_network_matches_country_code(network, *country)) {
+            found = 1;
+            break;
         }
     }
 
@@ -323,8 +394,12 @@ static int DetectLocationMatchAddress(const struct DetectLocationData* data, con
 
     // If we found a network, let's check whether the country matches
     if (network) {
-        if (DetectLocationMatchCountryCode(data, network))
-            r = 1;
+        if (data->countries) {
+            if (DetectLocationMatchCountryCode(data, network))
+                r = 1;
+
+        } else if (data->anycast)
+            r = loc_network_has_flag(network, LOC_NETWORK_FLAG_ANYCAST);
 
         loc_network_unref(network);
     }
@@ -438,6 +513,12 @@ static int DetectLocationSetupGeoIP(DetectEngineCtx* ctx, Signature* signature,
     return -1;
 }
 
+static int DetectLocationSetupAnycast(DetectEngineCtx* ctx, Signature* signature, const char* optstring) {
+    SCLogError(SC_ERR_NO_LOCATION_SUPPORT,
+        "Support for IPFire Location is not built in (needed for anycast keyword)");
+    return -1;
+}
+
 #endif /* HAVE_LIBLOC */
 
 /**
@@ -452,4 +533,13 @@ void DetectLocationRegister(void) {
     sigmatch_table[DETECT_GEOIP].Match = DetectLocationMatch;
     sigmatch_table[DETECT_GEOIP].Free = DetectLocationFree;
 #endif /* HAVE_LIBLOC */
+
+    sigmatch_table[DETECT_ANYCAST].name = "anycast";
+    sigmatch_table[DETECT_ANYCAST].desc = "match on the source, destination or source and destination IP addresses and check if they belong to an anycast network";
+    sigmatch_table[DETECT_ANYCAST].url = "/rules/header-keywords.html#anycast";
+    sigmatch_table[DETECT_ANYCAST].Setup = DetectLocationSetupAnycast;
+#ifdef HAVE_LIBLOC
+    sigmatch_table[DETECT_ANYCAST].Match = DetectLocationMatch;
+    sigmatch_table[DETECT_ANYCAST].Free = DetectLocationFree;
+#endif /* HAVE_LIBLOC */
 }