diff options
Diffstat (limited to 'framework/src/suricata/src/detect-geoip.c')
-rw-r--r-- | framework/src/suricata/src/detect-geoip.c | 618 |
1 files changed, 0 insertions, 618 deletions
diff --git a/framework/src/suricata/src/detect-geoip.c b/framework/src/suricata/src/detect-geoip.c deleted file mode 100644 index 53c950f8..00000000 --- a/framework/src/suricata/src/detect-geoip.c +++ /dev/null @@ -1,618 +0,0 @@ -/* Copyright (C) 2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Ignacio Sanchez <sanchezmartin.ji@gmail.com> - * - * Implements the geoip keyword. - */ - -#include "suricata-common.h" -#include "debug.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" - -#include "detect-geoip.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#ifndef HAVE_GEOIP - -static int DetectGeoipSetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) -{ - SCLogError(SC_ERR_NO_GEOIP_SUPPORT, "no GeoIP support built in, needed for geoip keyword"); - return -1; -} - -/** - * \brief Registration function for geoip keyword (no libgeoip support) - * \todo add support for src_only and dst_only - */ -void DetectGeoipRegister(void) -{ - sigmatch_table[DETECT_GEOIP].name = "geoip"; - sigmatch_table[DETECT_GEOIP].Setup = DetectGeoipSetupNoSupport; - sigmatch_table[DETECT_GEOIP].Free = NULL; - sigmatch_table[DETECT_GEOIP].RegisterTests = NULL; -} - -#else /* HAVE_GEOIP */ - -#include <GeoIP.h> - - -static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, const SigMatchCtx *); -static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); -static void DetectGeoipRegisterTests(void); -static void DetectGeoipDataFree(void *); - -/** - * \brief Registration function for geoip keyword - * \todo add support for src_only and dst_only - */ -void DetectGeoipRegister(void) -{ - sigmatch_table[DETECT_GEOIP].name = "geoip"; - sigmatch_table[DETECT_GEOIP].Match = DetectGeoipMatch; - sigmatch_table[DETECT_GEOIP].Setup = DetectGeoipSetup; - sigmatch_table[DETECT_GEOIP].Free = DetectGeoipDataFree; - sigmatch_table[DETECT_GEOIP].RegisterTests = DetectGeoipRegisterTests; -} - -/** - * \internal - * \brief This function is used to initialize the geolocation MaxMind engine - * - * \retval NULL if the engine couldn't be initialized - * \retval (GeoIP *) to the geolocation engine - */ -static GeoIP *InitGeolocationEngine(void) -{ - return GeoIP_new(GEOIP_MEMORY_CACHE); -} - -/** - * \internal - * \brief This function is used to geolocate the IP using the MaxMind libraries - * - * \param ip IP to geolocate (uint32_t ip) - * - * \retval NULL if it couldn't be geolocated - * \retval ptr (const char *) to the country code string - */ -static const char *GeolocateIPv4(GeoIP *geoengine, uint32_t ip) -{ - if (geoengine != NULL) - return GeoIP_country_code_by_ipnum(geoengine, ntohl(ip)); - return NULL; -} - -/* Match-on conditions supported */ -#define GEOIP_MATCH_SRC_STR "src" -#define GEOIP_MATCH_DST_STR "dst" -#define GEOIP_MATCH_BOTH_STR "both" -#define GEOIP_MATCH_ANY_STR "any" - -#define GEOIP_MATCH_NO_FLAG 0 -#define GEOIP_MATCH_SRC_FLAG 1 -#define GEOIP_MATCH_DST_FLAG 2 -#define GEOIP_MATCH_ANY_FLAG 3 /* default src and dst*/ -#define GEOIP_MATCH_BOTH_FLAG 4 -#define GEOIP_MATCH_NEGATED 8 - -/** - * \internal - * \brief This function is used to geolocate the IP using the MaxMind libraries - * - * \param ip IP to geolocate (uint32_t ip) - * - * \retval 0 no match - * \retval 1 match - */ -static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) -{ - const char *country; - int i; - country = GeolocateIPv4(geoipdata->geoengine, ip); - /* Check if NOT NEGATED match-on condition */ - if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0) - { - for (i = 0; i < geoipdata->nlocations; i++) - if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) - return 1; - } else { - /* Check if NEGATED match-on condition */ - for (i = 0; i < geoipdata->nlocations; i++) - if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) - return 0; /* if one matches, rule does NOT match (negated) */ - return 1; /* returns 1 if no location matches (negated) */ - } - return 0; -} - -/** - * \internal - * \brief This function is used to match packets with a IPs in an specified country - * - * \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 DetectGeoipData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, const SigMatchCtx *ctx) -{ - const DetectGeoipData *geoipdata = (const DetectGeoipData *)ctx; - int matches = 0; - - if (PKT_IS_PSEUDOPKT(p)) - return 0; - - if (PKT_IS_IPV4(p)) - { - if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG )) - { - if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_SRC_ADDR_U32(p))) - { - if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) - matches++; - else - return 1; - } - } - if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG )) - { - if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_DST_ADDR_U32(p))) - { - if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) - matches++; - else - return 1; - } - } - /* if matches == 2 is because match-on is "both" */ - if (matches == 2) - return 1; - } - - return 0; -} - -/** - * \brief This function is used to parse geoipdata - * - * \param str Pointer to the geoipdata value string - * - * \retval pointer to DetectGeoipData on success - * \retval NULL on failure - */ -static DetectGeoipData *DetectGeoipDataParse (char *str) -{ - DetectGeoipData *geoipdata = NULL; - uint16_t pos = 0; - uint16_t prevpos = 0; - uint16_t slen = 0; - int skiplocationparsing = 0; - - slen = strlen(str); - if (slen == 0) - goto error; - - /* We have a correct geoip options string */ - geoipdata = SCMalloc(sizeof(DetectGeoipData)); - if (unlikely(geoipdata == NULL)) - goto error; - - memset(geoipdata, 0x00, sizeof(DetectGeoipData)); - - /* Parse the geoip option string */ - while (pos <= slen) - { - /* search for ',' or end of string */ - if (str[pos] == ',' || pos == slen) - { - if (geoipdata->flags == GEOIP_MATCH_NO_FLAG) - { - /* Parse match-on condition */ - if (pos == slen) /* if end of option str then there are no match-on cond. */ - { - /* There was NO match-on condition! we default to ANY*/ - skiplocationparsing = 0; - geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; - } else { - skiplocationparsing = 1; - if (strncmp(&str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0) - geoipdata->flags |= GEOIP_MATCH_SRC_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0) - geoipdata->flags |= GEOIP_MATCH_DST_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0) - geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0) - geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; - else { - /* There was NO match-on condition! we default to ANY*/ - skiplocationparsing = 0; - geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; - } - } - } - if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0) - { - /* Parse location string: for now just the country code(s) */ - if (str[prevpos] == '!') - { - geoipdata->flags |= GEOIP_MATCH_NEGATED; - prevpos++; /* dot not copy the ! */ - } - - if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "too many arguements for geoip keyword"); - goto error; - } - - if (pos-prevpos > GEOOPTION_MAXSIZE) - strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], - GEOOPTION_MAXSIZE); - else - strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], - pos-prevpos+1); - - if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS) - geoipdata->nlocations++; - } - prevpos = pos+1; - skiplocationparsing = 0; /* match-on condition for sure has been parsed already */ - } - pos++; - } - - SCLogDebug("GeoIP: %"PRIu32" countries loaded", geoipdata->nlocations); - for (int i=0; i<geoipdata->nlocations; i++) - SCLogDebug("GeoIP country code: %s", geoipdata->location[i]); - - SCLogDebug("flags %02X", geoipdata->flags); - if (geoipdata->flags & GEOIP_MATCH_NEGATED) { - SCLogDebug("negated geoip"); - } - - /* Initialize the geolocation engine */ - geoipdata->geoengine = InitGeolocationEngine(); - if (geoipdata->geoengine == NULL) - goto error; - - return geoipdata; - -error: - if (geoipdata != NULL) - DetectGeoipDataFree(geoipdata); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the geoip option into the signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param optstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectGeoipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) -{ - DetectGeoipData *geoipdata = NULL; - SigMatch *sm = NULL; - - geoipdata = DetectGeoipDataParse(optstr); - if (geoipdata == NULL) - goto error; - - /* Get this into a SigMatch and put it in the Signature. */ - sm = SigMatchAlloc(); - if (sm == NULL) - goto error; - - sm->type = DETECT_GEOIP; - sm->ctx = (SigMatchCtx *)geoipdata; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); - s->flags |= SIG_FLAG_REQUIRE_PACKET; - - return 0; - -error: - if (geoipdata != NULL) - DetectGeoipDataFree(geoipdata); - if (sm != NULL) - SCFree(sm); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectGeoipData - * - * \param geoipdata pointer to DetectGeoipData - */ -static void DetectGeoipDataFree(void *ptr) -{ - if (ptr != NULL) { - DetectGeoipData *geoipdata = (DetectGeoipData *)ptr; - SCFree(geoipdata); - } -} - -#ifdef UNITTESTS - -static int GeoipParseTest(char *rule, int ncountries, char **countries, uint32_t flags) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectGeoipData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, rule); - - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_MATCH] == NULL) { - printf("empty server body list: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_MATCH]->type != DETECT_GEOIP) { - printf("last sm not geoip: "); - goto end; - } - - data = (DetectGeoipData *)s->sm_lists_tail[DETECT_SM_LIST_MATCH]->ctx; - if (data->flags != flags) { - printf("flags not right: (flags=%d)",data->flags); - goto end; - } - - if (data->nlocations!=ncountries) - { - printf("wrong number of parsed countries: "); - goto end; - } - - for (int i=0; i<ncountries; i++) - { - if (strcmp((char *)data->location[i],countries[i])!=0) - { - printf("wrong parsed country code: "); - goto end; - } - } - - result = 1; -end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -static int GeoipParseTest01(void) -{ - char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG); -} - -static int GeoipParseTest02(void) -{ - char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); -} - -static int GeoipParseTest03(void) -{ - char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); -} - -static int GeoipParseTest04(void) -{ - char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes, - GEOIP_MATCH_SRC_FLAG); -} - -static int GeoipParseTest05(void) -{ - char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED); -} - -static int GeoipParseTest06(void) -{ - char *ccodes[3] = {"US", "ES", "UK"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes, - GEOIP_MATCH_ANY_FLAG); -} - -static int GeoipParseTest07(void) -{ - char *ccodes[3] = {"US", "ES", "UK"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes, - GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED); -} - -/** - * \internal - * \brief This test tests geoip success and failure. - */ -static int GeoipMatchTest(char *rule, char *srcip, char *dstip) -{ - uint8_t *buf = (uint8_t *) "GET / HTTP/1.0\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p1 = UTHBuildPacketSrcDst(buf, buflen, IPPROTO_TCP, srcip, dstip); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, rule); - - if (de_ctx->sig_list == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - result = 2; - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1) == 0) { - goto cleanup; - } - - result = 1; - -cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - -end: - return result; -} - -static int GeoipMatchTest01(void) -{ - /* Tests with IP of google DNS as US for both src and dst IPs */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:US;sid:1;)", "8.8.8.8", "8.8.8.8"); - /* Expected result 1 = match */ -} - -static int GeoipMatchTest02(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:JP;sid:1;)", "8.8.8.8", - "202.12.27.33"); - /* Expected result 1 = match */ -} - -static int GeoipMatchTest03(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:dst,JP;sid:1;)", - "8.8.8.8", "202.12.27.33"); - /* Expected result 1 = match */ -} - -static int GeoipMatchTest04(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:src,JP;sid:1;)", - "8.8.8.8", "202.12.27.33"); - /* Expected result 2 = NO match */ -} - -static int GeoipMatchTest05(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:src,JP,US;sid:1;)", - "8.8.8.8", "202.12.27.33"); - /* Expected result 1 = match */ -} - -static int GeoipMatchTest06(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:src,ES,JP,US,UK,PT;sid:1;)", - "8.8.8.8", "202.12.27.33"); - /* Expected result 1 = match */ -} - -static int GeoipMatchTest07(void) -{ - /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ - return GeoipMatchTest("alert tcp any any -> any any (geoip:src,!ES,JP,US,UK,PT;sid:1;)", - "8.8.8.8", "202.12.27.33"); - /* Expected result 2 = NO match */ -} - - -#endif /* UNITTESTS */ - -/** - * \internal - * \brief This function registers unit tests for DetectGeoip - */ -static void DetectGeoipRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("GeoipParseTest01", GeoipParseTest01, 1); - UtRegisterTest("GeoipParseTest02", GeoipParseTest02, 1); - UtRegisterTest("GeoipParseTest03", GeoipParseTest03, 1); - UtRegisterTest("GeoipParseTest04", GeoipParseTest04, 1); - UtRegisterTest("GeoipParseTest05", GeoipParseTest05, 1); - UtRegisterTest("GeoipParseTest06", GeoipParseTest06, 1); - UtRegisterTest("GeoipParseTest07", GeoipParseTest07, 1); - - UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01, 1); - UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02, 1); - UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03, 1); - UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04, 2); - UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05, 1); - UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06, 1); - UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07, 2); -#endif /* UNITTESTS */ -} - -#endif /* HAVE_GEOIP */ |