Replace GeoIP Legacy DB support with MaxMind DB support

This updates the "lookup_location" and "lookup_asn" BIFs to use
libmaxminddb.  The motivation for this is that MaxMind is discontinuing
GeoLite Legacy databases: no updates after April 1, 2018, no downloads
after January 2, 2019.  It's also noted that all GeoIP Legacy databases
may be discontinued as they are superseded by GeoIP2.
This commit is contained in:
Jonathan Perkins 2018-04-27 00:38:53 +02:00 committed by Jon Siwek
parent 2502e48a01
commit 1ae7d3b349
7 changed files with 363 additions and 228 deletions

View file

@ -140,11 +140,11 @@ include_directories(BEFORE
# Optional Dependencies # Optional Dependencies
set(USE_GEOIP false) set(USE_GEOIP false)
find_package(LibGeoIP) find_package(LibMMDB)
if (LIBGEOIP_FOUND) if (LibMMDB_FOUND)
set(USE_GEOIP true) set(USE_GEOIP true)
include_directories(BEFORE ${LibGeoIP_INCLUDE_DIR}) include_directories(BEFORE ${LibMMDB_INCLUDE_DIR})
list(APPEND OPTLIBS ${LibGeoIP_LIBRARY}) list(APPEND OPTLIBS ${LibMMDB_LIBRARY})
endif () endif ()
set(USE_KRB5 false) set(USE_KRB5 false)
@ -323,7 +323,7 @@ message(
"\nBroctl: ${INSTALL_BROCTL}" "\nBroctl: ${INSTALL_BROCTL}"
"\nAux. Tools: ${INSTALL_AUX_TOOLS}" "\nAux. Tools: ${INSTALL_AUX_TOOLS}"
"\n" "\n"
"\nGeoIP: ${USE_GEOIP}" "\nlibmaxminddb: ${USE_GEOIP}"
"\nKerberos: ${USE_KRB5}" "\nKerberos: ${USE_KRB5}"
"\ngperftools found: ${HAVE_PERFTOOLS}" "\ngperftools found: ${HAVE_PERFTOOLS}"
"\n tcmalloc: ${USE_PERFTOOLS_TCMALLOC}" "\n tcmalloc: ${USE_PERFTOOLS_TCMALLOC}"

9
NEWS
View file

@ -356,6 +356,15 @@ Changed Functionality
- The string_to_pattern() built-in (and the now-deprecated merge_pattern() - The string_to_pattern() built-in (and the now-deprecated merge_pattern()
built-in) is no longer restricted to only be called at initialization time. built-in) is no longer restricted to only be called at initialization time.
- GeoIP Legacy Database support has been replaced with GeoIP2 MaxMind DB
format support.
- This updates the "lookup_location" and "lookup_asn" BIFs to use
libmaxminddb. The motivation for this is that MaxMind is discontinuing
GeoLite Legacy databases: no updates after April 1, 2018, no downloads
after January 2, 2019. It's also noted that all GeoIP Legacy databases
may be discontinued as they are superseded by GeoIP2.
Removed Functionality Removed Functionality
--------------------- ---------------------

View file

@ -111,12 +111,6 @@
/* Define if KRB5 is available */ /* Define if KRB5 is available */
#cmakedefine USE_KRB5 #cmakedefine USE_KRB5
/* Whether the found GeoIP API supports IPv6 Country Edition */
#cmakedefine HAVE_GEOIP_COUNTRY_EDITION_V6
/* Whether the found GeoIP API supports IPv6 City Edition */
#cmakedefine HAVE_GEOIP_CITY_EDITION_REV0_V6
/* Use Google's perftools */ /* Use Google's perftools */
#cmakedefine USE_PERFTOOLS_DEBUG #cmakedefine USE_PERFTOOLS_DEBUG

4
configure vendored
View file

@ -72,7 +72,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
(a required Broker dependency) (a required Broker dependency)
Optional Packages in Non-Standard Locations: Optional Packages in Non-Standard Locations:
--with-geoip=PATH path to the libGeoIP install root --with-geoip=PATH path to the libmaxminddb install root
--with-krb5=PATH path to krb5 install root --with-krb5=PATH path to krb5 install root
--with-perftools=PATH path to Google Perftools install root --with-perftools=PATH path to Google Perftools install root
--with-jemalloc=PATH path to jemalloc install root --with-jemalloc=PATH path to jemalloc install root
@ -252,7 +252,7 @@ while [ $# -ne 0 ]; do
append_cache_entry BISON_EXECUTABLE PATH $optarg append_cache_entry BISON_EXECUTABLE PATH $optarg
;; ;;
--with-geoip=*) --with-geoip=*)
append_cache_entry LibGeoIP_ROOT_DIR PATH $optarg append_cache_entry LibMMDB_ROOT_DIR PATH $optarg
;; ;;
--with-krb5=*) --with-krb5=*)
append_cache_entry LibKrb5_ROOT_DIR PATH $optarg append_cache_entry LibKrb5_ROOT_DIR PATH $optarg

View file

@ -8,11 +8,13 @@ GeoLocation
.. rst-class:: opening .. rst-class:: opening
During the process of creating policy scripts the need may arise During the process of creating policy scripts the need may arise
to find the geographic location for an IP address. Bro has support to find the geographic location for an IP address. Bro had support
for the `GeoIP library <http://www.maxmind.com/app/c>`__ at the for the `GeoIP library <http://www.maxmind.com/app/c>`__ at the
policy script level beginning with release 1.3 to account for this policy script level from release 1.3 to 2.5.X to account for this
need. To use this functionality, you need to first install the libGeoIP need. Starting with release 2.6 GeoIP support requires `libmaxminddb
software, and then install the GeoLite city database before building <https://github.com/maxmind/libmaxminddb/releases>`__.
To use this functionality, you need to first install the libmaxminddb
software, and then install the GeoLite2 city database before building
Bro. Bro.
.. contents:: .. contents::
@ -20,85 +22,91 @@ GeoLocation
Install libGeoIP Install libGeoIP
---------------- ----------------
Before building Bro, you need to install libGeoIP. Before building Bro, you need to install libmaxminddb.
* FreeBSD: * FreeBSD:
.. console:: .. console::
sudo pkg install GeoIP sudo pkg install libmaxminddb
* RPM/RedHat-based Linux: * RPM/RedHat-based Linux:
.. console:: .. console::
sudo yum install GeoIP-devel sudo yum install libmaxminddb-devel
* DEB/Debian-based Linux: * DEB/Debian-based Linux:
.. console:: .. console::
sudo apt-get install libgeoip-dev sudo apt-get install libmaxminddb-dev
* Mac OS X: * Mac OS X:
You need to install from your preferred package management system You need to install from your preferred package management system
(e.g. MacPorts, Fink, or Homebrew). The name of the package that you need (e.g. MacPorts, Fink, or Homebrew). The name of the package that you need
may be libgeoip, geoip, or geoip-dev, depending on which package management may be libmaxminddb, maxminddb, or libmaxminddb-dev, depending on which
system you are using. package management system you are using.
GeoIPLite Database Installation GeoLite2-City Database Installation
------------------------------- -----------------------------------
A country database for GeoIPLite is included when you do the C API Bro can use the city or country database. The city database includes cities
install, but for Bro, we are using the city database which includes and regions in addition to countries.
cities and regions in addition to countries.
`Download <http://www.maxmind.com/app/geolitecity>`__ the GeoLite city `Download <http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz>`__
binary database: the GeoLite2 city binary database:
.. console:: .. console::
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz
gunzip GeoLiteCity.dat.gz tar zxf GeoLite2-City.tar.gz
Next, the file needs to be renamed and put in the GeoIP database directory. Next, the file "GeoLite2-City_YYYYMMDD/GeoLite2-City.mmdb" needs to be renamed
This directory should already exist and will vary depending on which platform and put in the GeoIP database directory. This directory should already exist
and package you are using. For FreeBSD, use ``/usr/local/share/GeoIP``. For and will vary depending on which platform and package you are using. For
Linux, use ``/usr/share/GeoIP`` or ``/var/lib/GeoIP`` (choose whichever one FreeBSD, use ``/usr/local/share/GeoIP``. For Linux, use ``/usr/share/GeoIP``
already exists). or ``/var/lib/GeoIP`` (choose whichever one already exists).
.. console:: .. console::
mv GeoLiteCity.dat <path_to_database_dir>/GeoIPCity.dat mv <extracted subdir>/GeoLite2-City.mmdb <path_to_database_dir>/GeoLite2-City.mmdb
Note that there is a separate database for IPv6 addresses, which can also
be installed if you want GeoIP functionality for IPv6.
Testing Testing
------- -------
Before using the GeoIP functionality, it is a good idea to verify that Before using the GeoIP functionality, it is a good idea to verify that
everything is setup correctly. After installing libGeoIP and the GeoIP city everything is setup correctly. After installing libmaxminddb and the GeoIP
database, and building Bro, you can quickly check if the GeoIP functionality city database, and building Bro, you can quickly check if the GeoIP
works by running a command like this: functionality works by running a command like this:
.. console:: .. console::
bro -e "print lookup_location(8.8.8.8);" bro -e "print lookup_location(8.8.8.8);"
If you see an error message similar to "Failed to open GeoIP City database", If you see an error message similar to "Failed to open GeoIP location
then you may need to either rename or move your GeoIP city database file (the database", then you may need to either rename or move your GeoIP
error message should give you the full pathname of the database file that location database file. Bro looks for location database files in the
Bro is looking for). following order by default:
/usr/share/GeoIP/GeoLite2-City.mmdb
/var/lib/GeoIP/GeoLite2-City.mmdb
/usr/local/share/GeoIP/GeoLite2-City.mmdb
/usr/local/var/GeoIP/GeoLite2-City.mmdb
/usr/share/GeoIP/GeoLite2-Country.mmdb
/var/lib/GeoIP/GeoLite2-Country.mmdb
/usr/local/share/GeoIP/GeoLite2-Country.mmdb
/usr/local/var/GeoIP/GeoLite2-Country.mmdb
If you see an error message similar to "Bro was not configured for GeoIP If you see an error message similar to "Bro was not configured for GeoIP
support", then you need to rebuild Bro and make sure it is linked against support", then you either need to rebuild Bro and make sure it is linked
libGeoIP. Normally, if libGeoIP is installed correctly then it should against libmaxminddb or else set the :bro:see:`mmdb_dir`` value
automatically be found when building Bro. If this doesn't happen, then correctly. Normally, if libmaxminddb is installed correctly then it
you may need to specify the path to the libGeoIP installation should automatically be found when building Bro. If this doesn't
(e.g. ``./configure --with-geoip=<path>``). happen, then you may need to specify the path to the libmaxminddb
installation (e.g. ``./configure --with-geoip=<path>``).
Usage Usage
----- -----

View file

@ -872,6 +872,9 @@ type geo_location: record {
longitude: double &optional; ##< Longitude. longitude: double &optional; ##< Longitude.
} &log; } &log;
## The directory containing MaxMind DB (*.mmdb) files to use for GeoIP support.
const mmdb_dir: string = "" &redef;
## Computed entropy values. The record captures a number of measures that are ## Computed entropy values. The record captures a number of measures that are
## computed in parallel. See `A Pseudorandom Number Sequence Test Program ## computed in parallel. See `A Pseudorandom Number Sequence Test Program
## <http://www.fourmilab.ch/random>`_ for more information, Bro uses the same ## <http://www.fourmilab.ch/random>`_ for more information, Bro uses the same

View file

@ -3599,77 +3599,269 @@ function lookup_hostname%(host: string%) : addr_set
%%{ %%{
#ifdef USE_GEOIP #ifdef USE_GEOIP
extern "C" { extern "C" {
#include <GeoIPCity.h> #include <maxminddb.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
} }
static GeoIP* open_geoip_db(GeoIPDBTypes type) class MMDB {
public:
MMDB(const char* filename);
~MMDB();
MMDB_lookup_result_s Lookup(const struct sockaddr* const sa);
private:
MMDB_s mmdb;
};
MMDB::MMDB(const char *filename)
{ {
GeoIP* geoip = 0; int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
if ( GeoIP_db_avail(type) ) if ( MMDB_SUCCESS != status )
geoip = GeoIP_open_type(type, GEOIP_MEMORY_CACHE); {
throw std::runtime_error(MMDB_strerror(status));
return geoip; }
} }
static GeoIP* open_geoip_city_db() MMDB::~MMDB()
{ {
GeoIP* geoip = open_geoip_db(GEOIP_CITY_EDITION_REV0); MMDB_close(&mmdb);
if ( ! geoip )
geoip = open_geoip_db(GEOIP_CITY_EDITION_REV1);
if ( ! geoip )
{
string rev0_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV0];
string rev1_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV1];
string db_path = rev0_path;
// Maybe in the future the revisions won't share a common default path.
if ( rev0_path != rev1_path )
db_path = rev0_path + " or " + rev1_path;
reporter->Info("Failed to open GeoIP City database: %s",
db_path.c_str());
}
return geoip;
} }
static GeoIP* open_geoip_city_db_v6() MMDB_lookup_result_s MMDB::Lookup(const struct sockaddr* const sa)
{ {
GeoIP* geoip = 0; int mmdb_error;
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdb, sa, &mmdb_error);
// Both city edition revisions for IPv6 show up in libGeoIP 1.4.7. if ( MMDB_SUCCESS != mmdb_error )
#ifdef HAVE_GEOIP_CITY_EDITION_REV0_V6
geoip = open_geoip_db(GEOIP_CITY_EDITION_REV0_V6);
if ( ! geoip )
geoip = open_geoip_db(GEOIP_CITY_EDITION_REV1_V6);
if ( ! geoip )
{ {
string rev0_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV0_V6]; throw std::runtime_error(MMDB_strerror(mmdb_error));
string rev1_path = GeoIPDBFileName[GEOIP_CITY_EDITION_REV1_V6];
string db_path = rev0_path;
// Maybe in the future the revisions won't share a common default path.
if ( rev0_path != rev1_path )
db_path = rev0_path + " or " + rev1_path;
reporter->Info("Failed to open GeoIP Cityv6 database: %s",
db_path.c_str());
} }
#endif
return geoip; return result;
}
std::unique_ptr<MMDB> mmdb_loc;
std::unique_ptr<MMDB> mmdb_asn;
static bool mmdb_open(const char* filename, bool asn)
{
struct stat buf;
if ( 0 != stat(filename, &buf) )
{
return false;
}
try
{
if ( asn )
{
mmdb_asn.reset(new MMDB(filename));
}
else
{
mmdb_loc.reset(new MMDB(filename));
}
}
catch ( const std::exception& e )
{
reporter->Info("Failed to open MaxMind DB: %s [%s]", filename,
e.what());
return false;
}
return true;
}
static bool mmdb_open_loc(const char* filename)
{
return mmdb_open(filename, false);
}
static bool mmdb_open_asn(const char* filename)
{
return mmdb_open(filename, true);
}
static bool mmdb_lookup(const IPAddr& addr, MMDB_lookup_result_s& result,
bool asn)
{
struct sockaddr_storage ss = {0};
if ( IPv4 == addr.GetFamily() )
{
struct sockaddr_in* sa = (struct sockaddr_in*)&ss;
sa->sin_family = AF_INET;
addr.CopyIPv4(&sa->sin_addr);
}
else
{
struct sockaddr_in6* sa = (struct sockaddr_in6*)&ss;
sa->sin6_family = AF_INET6;
addr.CopyIPv6(&sa->sin6_addr);
}
try
{
result = asn ? mmdb_asn->Lookup((struct sockaddr*)&ss)
: mmdb_loc->Lookup((struct sockaddr*)&ss);
}
catch ( const std::exception& e )
{
reporter->Info("MaxMind DB lookup location error [%s]",
e.what());
return false;
}
return result.found_entry;
}
static bool mmdb_lookup_loc(const IPAddr& addr, MMDB_lookup_result_s& result)
{
return mmdb_lookup(addr, result, false);
}
static bool mmdb_lookup_asn(const IPAddr& addr, MMDB_lookup_result_s& result)
{
return mmdb_lookup(addr, result, true);
}
static Val* mmdb_getvalue(MMDB_entry_data_s* entry_data, int status,
int data_type )
{
switch (status)
{
case MMDB_SUCCESS:
if ( entry_data->has_data )
{
switch (data_type)
{
case MMDB_DATA_TYPE_UTF8_STRING:
return new StringVal(entry_data->data_size,
entry_data->utf8_string);
break;
case MMDB_DATA_TYPE_DOUBLE:
return new Val(entry_data->double_value, TYPE_DOUBLE);
break;
case MMDB_DATA_TYPE_UINT32:
return new Val(entry_data->uint32, TYPE_COUNT);
default:
break;
}
}
break;
case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR:
// key doesn't exist, nothing to do
break;
default:
reporter->Info("MaxMind DB error [%s]", MMDB_strerror(status));
break;
}
return nullptr;
}
static bool mmdb_try_open_loc ()
{
// City database is always preferred over Country database.
auto mmdb_dir_val = global_scope()->Lookup("mmdb_dir")->ID_Val();
std::string mmdb_dir = mmdb_dir_val->AsString()->CheckString();
if ( ! mmdb_dir.empty() )
{
auto d = mmdb_dir + "/GeoLite2-City.mmdb";
if ( mmdb_open_loc(d.data()) )
return true;
d = mmdb_dir + "/GeoLite2-Country.mmdb";
if ( mmdb_open_loc(d.data()) )
return true;;
}
return mmdb_open_loc("/usr/share/GeoIP/GeoLite2-City.mmdb")
|| mmdb_open_loc("/var/lib/GeoIP/GeoLite2-City.mmdb")
|| mmdb_open_loc("/usr/local/share/GeoIP/GeoLite2-City.mmdb")
|| mmdb_open_loc("/usr/local/var/GeoIP/GeoLite2-City.mmdb")
|| mmdb_open_loc("/usr/share/GeoIP/GeoLite2-Country.mmdb")
|| mmdb_open_loc("/var/lib/GeoIP/GeoLite2-Country.mmdb")
|| mmdb_open_loc("/usr/local/share/GeoIP/GeoLite2-Country.mmdb")
|| mmdb_open_loc("/usr/local/var/GeoIP/GeoLite2-Country.mmdb");
}
static bool mmdb_try_open_asn ()
{
auto mmdb_dir_val = global_scope()->Lookup("mmdb_dir")->ID_Val();
std::string mmdb_dir = mmdb_dir_val->AsString()->CheckString();
if ( ! mmdb_dir.empty() )
{
auto d = mmdb_dir + "/GeoLite2-ASN.mmdb";
if ( mmdb_open_asn(d.data()) )
return true;
}
return mmdb_open_asn("/usr/share/GeoIP/GeoLite2-ASN.mmdb")
|| mmdb_open_asn("/var/lib/GeoIP/GeoLite2-ASN.mmdb")
|| mmdb_open_asn("/usr/local/share/GeoIP/GeoLite2-ASN.mmdb")
|| mmdb_open_asn("/usr/local/var/GeoIP/GeoLite2-ASN.mmdb");
} }
#endif #endif
%%} %%}
## Initializes MMDB for later use of lookup_location.
## Requires Bro to be built with ``libmaxminddb``.
##
## f: The filename of the MaxMind City or Country DB.
##
## Returns: A boolean indicating whether the db was successfully opened.
##
## .. bro:see:: lookup_asn
function mmdb_open_location_db%(f: string%) : bool
%{
#ifdef USE_GEOIP
return new Val(mmdb_open_loc(f->CheckString()), TYPE_BOOL);
#else
return new Val(0, TYPE_BOOL);
#endif
%}
## Initializes MMDB for later use of lookup_asn.
## Requires Bro to be built with ``libmaxminddb``.
##
## f: The filename of the MaxMind ASN DB.
##
## Returns: A boolean indicating whether the db was successfully opened.
##
## .. bro:see:: lookup_asn
function mmdb_open_asn_db%(f: string%) : bool
%{
#ifdef USE_GEOIP
return new Val(mmdb_open_asn(f->CheckString()), TYPE_BOOL);
#else
return new Val(0, TYPE_BOOL);
#endif
%}
## Performs a geo-lookup of an IP address. ## Performs a geo-lookup of an IP address.
## Requires Bro to be built with ``libgeoip``. ## Requires Bro to be built with ``libmaxminddb``.
## ##
## a: The IP address to lookup. ## a: The IP address to lookup.
## ##
@ -3681,104 +3873,52 @@ function lookup_location%(a: addr%) : geo_location
RecordVal* location = new RecordVal(geo_location); RecordVal* location = new RecordVal(geo_location);
#ifdef USE_GEOIP #ifdef USE_GEOIP
static bool geoip_initialized = false; if ( ! mmdb_loc )
static GeoIP* geoip = 0;
static GeoIP* geoip_v6 = 0;
static bool have_city_db = false;
static bool have_cityv6_db = false;
GeoIPRecord* gir = 0;
const char* cc = 0;
if ( ! geoip_initialized )
{ {
geoip_initialized = true; if ( ! mmdb_try_open_loc() )
geoip = open_geoip_city_db();
if ( ! geoip )
{ {
geoip = open_geoip_db(GEOIP_COUNTRY_EDITION); builtin_error("Failed to open GeoIP location database");
string db_path = GeoIPDBFileName[GEOIP_COUNTRY_EDITION]; return location;
if ( ! geoip )
builtin_error(fmt("Failed fall back to GeoIP Country "
"database: %s",
GeoIPDBFileName[GEOIP_COUNTRY_EDITION]));
else
reporter->Info("Fell back to GeoIP Country database");
} }
else
have_city_db = true;
geoip_v6 = open_geoip_city_db_v6();
if ( geoip_v6 )
have_cityv6_db = true;
#ifdef HAVE_GEOIP_COUNTRY_EDITION_V6
if ( ! geoip_v6 )
{
geoip_v6 = open_geoip_db(GEOIP_COUNTRY_EDITION_V6);
if ( ! geoip_v6 )
reporter->Info("Failed to open GeoIPv6 Country database: %s",
GeoIPDBFileName[GEOIP_COUNTRY_EDITION_V6]);
}
#endif
if ( ! geoip_v6 )
builtin_error("Can't open GeoIPv6 City/Country database");
} }
#ifdef HAVE_GEOIP_COUNTRY_EDITION_V6 MMDB_lookup_result_s result;
if ( geoip_v6 && a->AsAddr().GetFamily() == IPv6 )
if ( mmdb_lookup_loc(a->AsAddr(), result) )
{ {
geoipv6_t ga; MMDB_entry_data_s entry_data;
a->AsAddr().CopyIPv6(&ga); int status;
if ( have_cityv6_db )
gir = GeoIP_record_by_ipnum_v6(geoip_v6, ga);
else
cc = GeoIP_country_code_by_ipnum_v6(geoip_v6, ga);
}
else
#endif
if ( geoip && a->AsAddr().GetFamily() == IPv4 ) // Get Country ISO Code
{ status = MMDB_get_value(&result.entry, &entry_data,
const uint32* bytes; "country", "iso_code", nullptr);
a->AsAddr().GetBytes(&bytes); location->Assign(0, mmdb_getvalue(&entry_data, status,
if ( have_city_db ) MMDB_DATA_TYPE_UTF8_STRING));
gir = GeoIP_record_by_ipnum(geoip, ntohl(*bytes));
else
cc = GeoIP_country_code_by_ipnum(geoip, ntohl(*bytes));
}
if ( gir ) // Get Major Subdivision ISO Code
{ status = MMDB_get_value(&result.entry, &entry_data,
if ( gir->country_code ) "subdivisions", "0", "iso_code", nullptr);
location->Assign(0, new StringVal(gir->country_code)); location->Assign(1, mmdb_getvalue(&entry_data, status,
MMDB_DATA_TYPE_UTF8_STRING));
if ( gir->region ) // Get City English Name
location->Assign(1, new StringVal(gir->region)); status = MMDB_get_value(&result.entry, &entry_data,
"city", "names", "en", nullptr);
location->Assign(2, mmdb_getvalue(&entry_data, status,
MMDB_DATA_TYPE_UTF8_STRING));
if ( gir->city ) // Get Location Latitude
location->Assign(2, new StringVal(gir->city)); status = MMDB_get_value(&result.entry, &entry_data,
"location", "latitude", nullptr);
location->Assign(3, mmdb_getvalue(&entry_data, status,
MMDB_DATA_TYPE_DOUBLE));
if ( gir->latitude ) // Get Location Longitude
location->Assign(3, new Val(gir->latitude, status = MMDB_get_value(&result.entry, &entry_data,
TYPE_DOUBLE)); "location", "longitude", nullptr);
location->Assign(4, mmdb_getvalue(&entry_data, status,
MMDB_DATA_TYPE_DOUBLE));
if ( gir->longitude )
location->Assign(4, new Val(gir->longitude,
TYPE_DOUBLE));
GeoIPRecord_delete(gir);
return location;
}
else if ( cc )
{
location->Assign(0, new StringVal(cc));
return location; return location;
} }
@ -3792,64 +3932,45 @@ function lookup_location%(a: addr%) : geo_location
} }
#endif #endif
// We can get here even if we have GeoIP support if we weren't // We can get here even if we have MMDB support if we weren't
// able to initialize it or it didn't return any information for // able to initialize it or it didn't return any information for
// the address. // the address.
return location; return location;
%} %}
## Performs an AS lookup of an IP address. ## Performs an ASN lookup of an IP address.
## Requires Bro to be built with ``libgeoip``. ## Requires Bro to be built with ``libmaxminddb``.
## ##
## a: The IP address to lookup. ## a: The IP address to lookup.
## ##
## Returns: The number of the AS that contains *a*. ## Returns: The number of the ASN that contains *a*.
## ##
## .. bro:see:: lookup_location ## .. bro:see:: lookup_location
function lookup_asn%(a: addr%) : count function lookup_asn%(a: addr%) : count
%{ %{
#ifdef USE_GEOIP #ifdef USE_GEOIP
static GeoIP* geoip_asn = 0; if ( ! mmdb_asn )
static bool geoip_asn_initialized = false;
char* gir = 0;
if ( ! geoip_asn_initialized )
{ {
geoip_asn_initialized = true; if ( ! mmdb_try_open_asn() )
geoip_asn = open_geoip_db(GEOIP_ASNUM_EDITION);
if ( ! geoip_asn )
builtin_error(fmt("Can't open GeoIP ASNUM database: %s",
GeoIPDBFileName[GEOIP_ASNUM_EDITION]));
}
if ( geoip_asn )
{
// IPv6 support showed up in 1.4.5.
#ifdef HAVE_GEOIP_COUNTRY_EDITION_V6
if ( a->AsAddr().GetFamily() == IPv6 )
{ {
geoipv6_t ga; builtin_error("No open GeoIP ASN database");
a->AsAddr().CopyIPv6(&ga); return new Val(0, TYPE_COUNT);
gir = GeoIP_name_by_ipnum_v6(geoip_asn, ga);
}
else
#endif
if ( a->AsAddr().GetFamily() == IPv4 )
{
const uint32* bytes;
a->AsAddr().GetBytes(&bytes);
gir = GeoIP_name_by_ipnum(geoip_asn, ntohl(*bytes));
} }
} }
if ( gir ) MMDB_lookup_result_s result;
if ( mmdb_lookup_asn(a->AsAddr(), result) )
{ {
// Move the pointer +2 so we don't return MMDB_entry_data_s entry_data;
// the first two characters: "AS". int status;
return new Val(atoi(gir+2), TYPE_COUNT);
// Get Autonomous System Number
status = MMDB_get_value(&result.entry, &entry_data,
"autonomous_system_number", nullptr);
Val* asn = mmdb_getvalue(&entry_data, status, MMDB_DATA_TYPE_UINT32);
return asn == nullptr ? new Val(0, TYPE_COUNT) : asn;
} }
#else // not USE_GEOIP #else // not USE_GEOIP