diff --git a/appveyor.yml b/appveyor.yml index 3419d1c98e09..9d6b25c46ade 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,7 +31,7 @@ init: install: - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' - '%CYG_SETUP% -gqnNdO --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" > NUL 2>&1' - - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libGeoIP-devel,libyaml-devel,luajit-devel,unzip,libiconv,libiconv-devel > NUL 2>&1' + - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libyaml-devel,luajit-devel,unzip,libiconv,libiconv-devel > NUL 2>&1' - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - '%CYG_BASH% -lc "wget https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip && ls && unzip WpdPack_4_1_2.zip"' - '%CYG_BASH% -lc "cp WpdPack/Lib/libpacket.a /usr/lib/"' @@ -47,7 +47,7 @@ build_script: - 'echo building...' - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; bash ./qa/travis-libhtp.sh"' - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh"' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./configure --enable-unittests --disable-shared --disable-gccmarch-native --enable-luajit --enable-geoip"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./configure --enable-unittests --disable-shared --disable-gccmarch-native --enable-luajit"' - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0mmdb_status = MMDB_FILE_OPEN_ERROR; + return FALSE; + } + + /* Attempt to open MaxMind DB and save file handle if successful */ + int status = MMDB_open(filename, MMDB_MODE_MMAP, &geoipdata->mmdb); + + if (status == MMDB_SUCCESS) { + geoipdata->mmdb_status = status; + return TRUE; + } + + SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Failed to open GeoIP2 database: %s. " + "Error was: %s. GeoIP rule matching is disabled.", filename, + MMDB_strerror(status)); + geoipdata->mmdb_status = status; + return FALSE; } /** * \internal * \brief This function is used to geolocate the IP using the MaxMind libraries * - * \param ip IP to geolocate (uint32_t ip) + * \param ip IPv4 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) +static const char *GeolocateIPv4(const DetectGeoipData *geoipdata, uint32_t ip) { - if (geoengine != NULL) - return GeoIP_country_code_by_ipnum(geoengine, SCNtohl(ip)); + int mmdb_error; + struct sockaddr_in sa; + sa.sin_family = AF_INET; + sa.sin_port = 0; + sa.sin_addr.s_addr = ip; + MMDB_lookup_result_s result; + MMDB_entry_data_s entry_data; + + /* Return if no GeoIP database access available */ + if (geoipdata->mmdb_status != MMDB_SUCCESS) + return NULL; + + /* Attempt to find the IPv4 address in the database */ + result = MMDB_lookup_sockaddr((MMDB_s *)&geoipdata->mmdb, + (struct sockaddr*)&sa, &mmdb_error); + if (mmdb_error != MMDB_SUCCESS) + return NULL; + + /* The IPv4 address was found, so grab ISO country code if available */ + if (result.found_entry) { + mmdb_error = MMDB_get_value(&result.entry, &entry_data, "country", + "iso_code", NULL); + if (mmdb_error != MMDB_SUCCESS) + return NULL; + + /* If ISO country code was found, then return it */ + if (entry_data.has_data) { + if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) { + char *country_code = strndup((char *)entry_data.utf8_string, + entry_data.data_size); + return country_code; + } + } + } + + /* The country code for the IP was not found */ return NULL; } @@ -125,29 +183,44 @@ static const char *GeolocateIPv4(GeoIP *geoengine, uint32_t ip) * \internal * \brief This function is used to geolocate the IP using the MaxMind libraries * - * \param ip IP to geolocate (uint32_t ip) + * \param ip IPv4 to geolocate (uint32_t ip) * * \retval 0 no match * \retval 1 match */ static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) { - const char *country; + const char *country = NULL; int i; - country = GeolocateIPv4(geoipdata->geoengine, ip); + + /* Attempt country code lookup for the IP address */ + country = GeolocateIPv4(geoipdata, ip); + + /* Skip further checks if did not find a country code */ + if (country == NULL) + return 0; + /* 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) + for (i = 0; i < geoipdata->nlocations; i++) { + if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) { + SCFree(country); 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) + for (i = 0; i < geoipdata->nlocations; i++) { + if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) { + SCFree(country); return 0; /* if one matches, rule does NOT match (negated) */ + } + } + SCFree(country); return 1; /* returns 1 if no location matches (negated) */ } + SCFree(country); return 0; } @@ -299,8 +372,7 @@ static DetectGeoipData *DetectGeoipDataParse (const char *str) } /* Initialize the geolocation engine */ - geoipdata->geoengine = InitGeolocationEngine(); - if (geoipdata->geoengine == NULL) + if (InitGeolocationEngine(geoipdata) == FALSE) goto error; return geoipdata; @@ -362,6 +434,8 @@ static void DetectGeoipDataFree(void *ptr) { if (ptr != NULL) { DetectGeoipData *geoipdata = (DetectGeoipData *)ptr; + if (geoipdata->mmdb_status == MMDB_SUCCESS) + MMDB_close(&geoipdata->mmdb); SCFree(geoipdata); } } diff --git a/src/detect-geoip.h b/src/detect-geoip.h index 1bfc7aff0d30..b648d5a56b0a 100644 --- a/src/detect-geoip.h +++ b/src/detect-geoip.h @@ -26,7 +26,7 @@ #ifdef HAVE_GEOIP -#include +#include #include "util-spm-bm.h" #define GEOOPTION_MAXSIZE 3 /* Country Code (2 chars) + NULL */ @@ -34,9 +34,10 @@ typedef struct DetectGeoipData_ { uint8_t location[GEOOPTION_MAXLOCATIONS][GEOOPTION_MAXSIZE]; /** country code for now, null term.*/ - int nlocations; /** number of location strings parsed */ + int nlocations; /** number of location strings parsed */ uint32_t flags; - GeoIP *geoengine; + int mmdb_status; /** Status of DB open call, MMDB_SUCCESS or error */ + MMDB_s mmdb; /** MaxMind DB file handle structure */ } DetectGeoipData; #endif diff --git a/suricata.yaml.in b/suricata.yaml.in index 3a4f147edbef..03e737484a63 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1122,6 +1122,10 @@ unix-command: #magic-file: /usr/share/file/magic @e_magic_file_comment@magic-file: @e_magic_file@ +# GeoIP2 database file. Specify path and filename of GeoIP2 database +# if using rules with "geoip" rule option. +#geoip-database: /usr/local/share/GeoLite2/GeoLite2-Country.mmdb + legacy: uricontent: enabled