Adds support for libMaxMind

This commit is contained in:
Felipe Zimmerle
2018-03-21 19:48:52 -03:00
parent 7bff76d794
commit df169ea108
20 changed files with 845 additions and 115 deletions

View File

@@ -304,6 +304,7 @@ libmodsecurity_la_CPPFLAGS = \
$(LMDB_CFLAGS) \
$(PCRE_CFLAGS) \
$(SSDEEP_CFLAGS) \
$(MAXMIND_CFLAGS) \
$(LUA_CFLAGS) \
$(LIBXML2_CFLAGS)
@@ -318,6 +319,7 @@ libmodsecurity_la_LDFLAGS = \
$(LUA_LDFLAGS) \
$(PCRE_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(MAXMIND_LDFLAGS) \
$(YAJL_LDFLAGS) \
-version-info @MSC_VERSION_INFO@
@@ -332,6 +334,7 @@ libmodsecurity_la_LIBADD = \
../others/libinjection.la \
../others/libmbedtls.la \
$(PCRE_LDADD) \
$(MAXMIND_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)

View File

@@ -15,7 +15,11 @@
#include "src/operators/geo_lookup.h"
#ifdef WITH_GEOIP
#if WITH_MAXMIND
#include <maxminddb.h>
#endif
#if WITH_GEOIP
#include <GeoIPCity.h>
#endif
@@ -35,65 +39,13 @@ bool GeoLookup::evaluate(Transaction *trans, const std::string &exp) {
using std::placeholders::_2;
bool ret = true;
#ifdef WITH_GEOIP
GeoIPRecord *gir;
if (trans) {
ret = Utils::GeoLookup::getInstance().lookup(exp, &gir,
ret = Utils::GeoLookup::getInstance().lookup(exp, trans,
std::bind(&GeoLookup::debug, this, trans, _1, _2));
} else {
ret = Utils::GeoLookup::getInstance().lookup(exp, &gir,
ret = Utils::GeoLookup::getInstance().lookup(exp, NULL,
nullptr);
}
if (ret && gir) {
if (gir->country_code) {
trans->m_variableGeo.set("COUNTRY_CODE",
std::string(gir->country_code), 0);
}
if (gir->country_code3) {
trans->m_variableGeo.set("COUNTRY_CODE3",
std::string(gir->country_code3), 0);
}
if (gir->country_name) {
trans->m_variableGeo.set("COUNTRY_NAME",
std::string(gir->country_name), 0);
}
if (gir->continent_code) {
trans->m_variableGeo.set("COUNTRY_CONTINENT",
std::string(gir->continent_code), 0);
}
if (gir->country_code && gir->region) {
trans->m_variableGeo.set("REGION",
std::string(GeoIP_region_name_by_code(gir->country_code,
gir->region)), 0);
}
if (gir->city) {
trans->m_variableGeo.set("CITY", std::string(gir->city), 0);
}
if (gir->postal_code) {
trans->m_variableGeo.set("POSTAL_CODE",
std::string(gir->postal_code), 0);
}
if (gir->latitude) {
trans->m_variableGeo.set("LATITUDE",
std::to_string(gir->latitude), 0);
}
if (gir->longitude) {
trans->m_variableGeo.set("LONGITUDE",
std::to_string(gir->longitude), 0);
}
if (gir->metro_code) {
trans->m_variableGeo.set("DMA_CODE",
std::to_string(gir->metro_code), 0);
}
if (gir->area_code) {
trans->m_variableGeo.set("AREA_CODE",
std::to_string(gir->area_code), 0);
}
GeoIPRecord_delete(gir);
}
#endif // WITH_GEOIP
return ret;
}

View File

@@ -2438,10 +2438,10 @@ namespace yy {
driver.error(yystack_[1].location, ss.str());
YYERROR;
}
if (GeoLookup::getInstance().setDataBase(file) == false) {
if (GeoLookup::getInstance().setDataBase(file, &err) == false) {
std::stringstream ss;
ss << "Failed to load the GeoDB from: ";
ss << file;
ss << file << ". " << err;
driver.error(yystack_[1].location, ss.str());
YYERROR;
}

View File

@@ -1557,10 +1557,10 @@ expression:
driver.error(@0, ss.str());
YYERROR;
}
if (GeoLookup::getInstance().setDataBase(file) == false) {
if (GeoLookup::getInstance().setDataBase(file, &err) == false) {
std::stringstream ss;
ss << "Failed to load the GeoDB from: ";
ss << file;
ss << file << ". " << err;
driver.error(@0, ss.str());
YYERROR;
}

View File

@@ -23,33 +23,81 @@
#include <iostream>
#include "src/utils/geo_lookup.h"
#ifdef WITH_GEOIP
#if WITH_MAXMIND
#include <maxminddb.h>
#elif WITH_GEOIP
#include <GeoIPCity.h>
#endif // WITH_GEOIP
#endif
namespace modsecurity {
namespace Utils {
GeoLookup::~GeoLookup() {
#ifdef WITH_GEOIP
cleanUp();
#endif // WITH_GEOIP
}
#ifdef WITH_GEOIP
void GeoLookup::cleanUp() {
if (m_gi != NULL) {
#ifdef WITH_MAXMIND
if (m_version == VERSION_MAXMIND) {
MMDB_close(&mmdb);
}
#endif
#ifdef WITH_GEOIP
if (m_version == VERSION_GEOIP && m_gi != NULL) {
GeoIP_delete(m_gi);
m_gi = NULL;
}
#endif
m_version = NOT_LOADED;
}
bool GeoLookup::setDataBase(const std::string& filePath) {
m_gi = GeoIP_open(filePath.c_str(), GEOIP_INDEX_CACHE);
if (m_gi == NULL) {
bool GeoLookup::setDataBase(const std::string& filePath,
std::string *err) {
std::string intMax;
std::string intGeo;
#ifdef WITH_MAXMIND
int status = MMDB_open(filePath.c_str(), MMDB_MODE_MMAP, &mmdb);
if (status != MMDB_SUCCESS) {
intMax.assign("libMaxMind: Can't open: " + std::string(MMDB_strerror(status)) + ".");
} else {
m_version = VERSION_MAXMIND;
}
#endif
#ifdef WITH_GEOIP
if (m_version == NOT_LOADED) {
m_gi = GeoIP_open(filePath.c_str(), GEOIP_INDEX_CACHE);
if (m_gi == NULL) {
intGeo.append("GeoIP: Can't open: " + filePath + ".");
} else {
m_version = VERSION_GEOIP;
}
}
#endif
if (m_version == NOT_LOADED) {
err->assign("Can't open: " + filePath + ". ");
err->append("Support enabled for:");
#ifdef WITH_MAXMIND
err->append(" libMaxMind");
#endif
#ifdef WITH_GEOIP
err->append(" GeoIP");
#endif
err->append(".");
if (intMax.size() > 0) {
err->append(" " + intMax);
}
if (intGeo.size() > 0) {
err->append(" " + intGeo);
}
return false;
}
@@ -57,25 +105,195 @@ bool GeoLookup::setDataBase(const std::string& filePath) {
}
bool GeoLookup::lookup(const std::string& target, GeoIPRecord **gir,
bool GeoLookup::lookup(const std::string& target, Transaction *trans,
std::function<bool(int, std::string)> debug) {
if (m_gi == NULL) {
if (m_version == NOT_LOADED) {
if (debug) {
debug(4, "GeoIP: Database is not open. " \
debug(4, "Database is not open. " \
"Use: SecGeoLookupDb directive.");
}
return false;
}
*gir = GeoIP_record_by_name(m_gi, target.c_str());
if (*gir == NULL) {
return false;
#ifdef WITH_MAXMIND
if (m_version == VERSION_MAXMIND) {
int gai_error, mmdb_error;
MMDB_lookup_result_s r;
int status;
r = MMDB_lookup_string(&mmdb, target.c_str(), &gai_error, &mmdb_error);
if (gai_error) {
if (debug) {
debug(4, "MaxMind: Error from getaddrinfo for: " +
target + ". " + gai_strerror(gai_error));
}
return false;
}
if (mmdb_error != MMDB_SUCCESS) {
if (debug) {
debug(4, "MaxMind: Got an error from libmaxminddb: " +
std::string(MMDB_strerror(mmdb_error)));
}
return false;
}
if (!r.found_entry) {
return false;
} else {
MMDB_entry_data_s entry_data;
status = MMDB_get_value(&r.entry, &entry_data,
"country", "iso_code", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("COUNTRY_CODE",
std::string(entry_data.utf8_string,
entry_data.data_size), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"country", "names", "en", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("COUNTRY_NAME",
std::string(entry_data.utf8_string,
entry_data.data_size), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"continent", "names", "en", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("COUNTRY_CONTINENT",
std::string(entry_data.utf8_string,
entry_data.data_size), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"city", "names", "en", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("CITY",
std::string(entry_data.utf8_string,
entry_data.data_size), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"postal", "code", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("POSTAL_CODE",
std::string(entry_data.utf8_string,
entry_data.data_size), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"location", "latitude", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("LATITUDE",
std::to_string(entry_data.double_value), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
"location", "longitude", NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("LONGITUDE",
std::to_string(entry_data.double_value), 0);
}
/*
status = MMDB_get_value(&r.entry, &entry_data,
NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("COUNTRY_CODE3",
std::string(entry_data.utf8_string), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("REGION",
std::string(entry_data.utf8_string), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("DMA_CODE",
std::string(entry_data.utf8_string), 0);
}
status = MMDB_get_value(&r.entry, &entry_data,
NULL);
if (status == MMDB_SUCCESS && entry_data.has_data) {
trans->m_variableGeo.set("AREA_CODE",
std::string(entry_data.utf8_string), 0);
}
*/
}
}
#endif
#ifdef WITH_GEOIP
if (m_version == VERSION_GEOIP) {
GeoIPRecord *gir;
gir = GeoIP_record_by_name(m_gi, target.c_str());
if (gir == NULL) {
return false;
}
if (trans) {
if (gir->country_code) {
trans->m_variableGeo.set("COUNTRY_CODE",
std::string(gir->country_code), 0);
}
if (gir->country_code3) {
trans->m_variableGeo.set("COUNTRY_CODE3",
std::string(gir->country_code3), 0);
}
if (gir->country_name) {
trans->m_variableGeo.set("COUNTRY_NAME",
std::string(gir->country_name), 0);
}
if (gir->continent_code) {
trans->m_variableGeo.set("COUNTRY_CONTINENT",
std::string(gir->continent_code), 0);
}
if (gir->country_code && gir->region) {
trans->m_variableGeo.set("REGION",
std::string(GeoIP_region_name_by_code(gir->country_code,
gir->region)), 0);
}
if (gir->city) {
trans->m_variableGeo.set("CITY", std::string(gir->city), 0);
}
if (gir->postal_code) {
trans->m_variableGeo.set("POSTAL_CODE",
std::string(gir->postal_code), 0);
}
if (gir->latitude) {
trans->m_variableGeo.set("LATITUDE",
std::to_string(gir->latitude), 0);
}
if (gir->longitude) {
trans->m_variableGeo.set("LONGITUDE",
std::to_string(gir->longitude), 0);
}
if (gir->metro_code) {
trans->m_variableGeo.set("DMA_CODE",
std::to_string(gir->metro_code), 0);
}
if (gir->area_code) {
trans->m_variableGeo.set("AREA_CODE",
std::to_string(gir->area_code), 0);
}
}
GeoIPRecord_delete(gir);
}
#endif
return true;
}
#endif // WITH_GEOIP
} // namespace Utils

View File

@@ -18,7 +18,10 @@
#include <string>
#include <functional>
#ifdef WITH_GEOIP // WITH_GEOIP
#if WITH_MAXMIND
#include <maxminddb.h>
#endif
#if WITH_GEOIP
#include <GeoIPCity.h>
#endif
@@ -30,6 +33,11 @@
namespace modsecurity {
namespace Utils {
enum GeoLookupVersion {
NOT_LOADED,
VERSION_MAXMIND,
VERSION_GEOIP,
};
class GeoLookup {
public:
@@ -37,24 +45,31 @@ class GeoLookup {
static GeoLookup instance;
return instance;
}
#ifdef WITH_GEOIP
bool setDataBase(const std::string& filePath);
bool lookup(const std::string& target, GeoIPRecord **georec,
std::function<bool(int, std::string)> callback);
bool setDataBase(const std::string& filePath, std::string *err);
void cleanUp();
#endif // WITH_GEOIP
bool lookup(const std::string& target, Transaction *t,
std::function<bool(int, std::string)> callback);
private:
GeoLookup()
: m_gi(NULL) { }
GeoLookup() :
#if WITH_GEOIP
m_gi(NULL),
#endif
m_version(NOT_LOADED) { }
~GeoLookup();
GeoLookup(GeoLookup const&);
void operator=(GeoLookup const&);
#ifdef WITH_GEOIP
GeoLookupVersion m_version;
#if WITH_MAXMIND
MMDB_s mmdb;
#endif
#if WITH_GEOIP
GeoIP *m_gi;
#else // WITH_GEOIP
void *m_gi;
#endif // WITH_GEOIP
#endif
};