mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Move MaxMind/GeoIP BiF functionality into separate file
This commit is contained in:
parent
06642d185b
commit
8406959ae2
5 changed files with 523 additions and 519 deletions
|
@ -2113,6 +2113,7 @@ type gtp_delete_pdp_ctx_response_elements: record {
|
||||||
@load base/bif/supervisor.bif
|
@load base/bif/supervisor.bif
|
||||||
@load base/bif/packet_analysis.bif
|
@load base/bif/packet_analysis.bif
|
||||||
@load base/bif/CPP-load.bif
|
@load base/bif/CPP-load.bif
|
||||||
|
@load base/bif/mmdb.bif
|
||||||
|
|
||||||
## Internal function.
|
## Internal function.
|
||||||
function add_interface(iold: string, inew: string): string
|
function add_interface(iold: string, inew: string): string
|
||||||
|
|
|
@ -114,6 +114,7 @@ set(BIF_SRCS
|
||||||
communityid.bif
|
communityid.bif
|
||||||
const.bif
|
const.bif
|
||||||
event.bif
|
event.bif
|
||||||
|
mmdb.bif
|
||||||
option.bif
|
option.bif
|
||||||
reporter.bif
|
reporter.bif
|
||||||
stats.bif
|
stats.bif
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "supervisor.bif.func_h"
|
#include "supervisor.bif.func_h"
|
||||||
#include "packet_analysis.bif.func_h"
|
#include "packet_analysis.bif.func_h"
|
||||||
#include "CPP-load.bif.func_h"
|
#include "CPP-load.bif.func_h"
|
||||||
|
#include "mmdb.bif.func_h"
|
||||||
|
|
||||||
#include "zeek.bif.func_def"
|
#include "zeek.bif.func_def"
|
||||||
#include "communityid.bif.func_def"
|
#include "communityid.bif.func_def"
|
||||||
|
@ -62,6 +63,7 @@
|
||||||
#include "supervisor.bif.func_def"
|
#include "supervisor.bif.func_def"
|
||||||
#include "packet_analysis.bif.func_def"
|
#include "packet_analysis.bif.func_def"
|
||||||
#include "CPP-load.bif.func_def"
|
#include "CPP-load.bif.func_def"
|
||||||
|
#include "mmdb.bif.func_def"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
extern RETSIGTYPE sig_handler(int signo);
|
extern RETSIGTYPE sig_handler(int signo);
|
||||||
|
@ -1049,6 +1051,7 @@ void init_primary_bifs() {
|
||||||
|
|
||||||
#include "CPP-load.bif.func_init"
|
#include "CPP-load.bif.func_init"
|
||||||
#include "communityid.bif.func_init"
|
#include "communityid.bif.func_init"
|
||||||
|
#include "mmdb.bif.func_init"
|
||||||
#include "option.bif.func_init"
|
#include "option.bif.func_init"
|
||||||
#include "packet_analysis.bif.func_init"
|
#include "packet_analysis.bif.func_init"
|
||||||
#include "reporter.bif.func_init"
|
#include "reporter.bif.func_init"
|
||||||
|
|
518
src/mmdb.bif
Normal file
518
src/mmdb.bif
Normal file
|
@ -0,0 +1,518 @@
|
||||||
|
%%{
|
||||||
|
#ifdef USE_GEOIP
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <maxminddb.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmdb_msg_count = 0;
|
||||||
|
static constexpr int mmdb_msg_limit = 20;
|
||||||
|
static double mmdb_msg_suppression_time = 0;
|
||||||
|
static constexpr double mmdb_msg_suppression_duration = 300;
|
||||||
|
|
||||||
|
static void report_mmdb_msg(const char* format, ...)
|
||||||
|
{
|
||||||
|
if ( zeek::run_state::network_time > mmdb_msg_suppression_time + mmdb_msg_suppression_duration )
|
||||||
|
{
|
||||||
|
mmdb_msg_count = 0;
|
||||||
|
mmdb_msg_suppression_time = zeek::run_state::network_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mmdb_msg_count >= mmdb_msg_limit )
|
||||||
|
return;
|
||||||
|
|
||||||
|
++mmdb_msg_count;
|
||||||
|
|
||||||
|
va_list al;
|
||||||
|
va_start(al, format);
|
||||||
|
std::string msg = zeek::util::vfmt(format, al);
|
||||||
|
va_end(al);
|
||||||
|
|
||||||
|
zeek::reporter->Info("%s", msg.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MMDB {
|
||||||
|
public:
|
||||||
|
MMDB(const char* filename, struct stat info);
|
||||||
|
|
||||||
|
~MMDB();
|
||||||
|
|
||||||
|
MMDB_lookup_result_s Lookup(const struct sockaddr* const sa);
|
||||||
|
bool StaleDB();
|
||||||
|
const char* Filename();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MMDB_s mmdb;
|
||||||
|
struct stat file_info;
|
||||||
|
bool lookup_error;
|
||||||
|
double last_check;
|
||||||
|
};
|
||||||
|
|
||||||
|
MMDB::MMDB(const char* filename, struct stat info)
|
||||||
|
: file_info(info), lookup_error{false},
|
||||||
|
last_check{zeek::run_state::network_time}
|
||||||
|
{
|
||||||
|
int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
|
||||||
|
|
||||||
|
if ( MMDB_SUCCESS != status )
|
||||||
|
{
|
||||||
|
throw std::runtime_error(MMDB_strerror(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MMDB::~MMDB()
|
||||||
|
{
|
||||||
|
MMDB_close(&mmdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMDB_lookup_result_s MMDB::Lookup(const struct sockaddr* const sa)
|
||||||
|
{
|
||||||
|
int mmdb_error;
|
||||||
|
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdb, sa, &mmdb_error);
|
||||||
|
|
||||||
|
if ( MMDB_SUCCESS != mmdb_error )
|
||||||
|
{
|
||||||
|
lookup_error = true;
|
||||||
|
throw std::runtime_error(MMDB_strerror(mmdb_error));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the Maxmind DB should be closed and reopened. This will
|
||||||
|
// happen if there was a lookup error or if the mmap'd file has been replaced
|
||||||
|
// by an external process.
|
||||||
|
bool MMDB::StaleDB()
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
if ( lookup_error )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
static double mmdb_stale_check_interval = zeek::id::find_val("mmdb_stale_check_interval")->AsInterval();
|
||||||
|
|
||||||
|
if ( mmdb_stale_check_interval < 0.0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( zeek::run_state::network_time - last_check < mmdb_stale_check_interval )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
last_check = zeek::run_state::network_time;
|
||||||
|
|
||||||
|
if ( 0 != stat(mmdb.filename, &buf) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ( buf.st_ino != file_info.st_ino || buf.st_mtime != file_info.st_mtime )
|
||||||
|
{
|
||||||
|
report_mmdb_msg("%s change detected for MaxMind DB [%s]",
|
||||||
|
buf.st_ino != file_info.st_ino ? "Inode" : "Modification time",
|
||||||
|
mmdb.filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* MMDB::Filename()
|
||||||
|
{
|
||||||
|
return mmdb.filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<MMDB> mmdb_loc;
|
||||||
|
std::unique_ptr<MMDB> mmdb_asn;
|
||||||
|
static bool did_mmdb_loc_db_error = false;
|
||||||
|
static bool did_mmdb_asn_db_error = false;
|
||||||
|
|
||||||
|
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, buf));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mmdb_loc.reset(new MMDB(filename, buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch ( const std::exception& e )
|
||||||
|
{
|
||||||
|
if ( asn )
|
||||||
|
did_mmdb_asn_db_error = false;
|
||||||
|
else
|
||||||
|
did_mmdb_loc_db_error = false;
|
||||||
|
|
||||||
|
report_mmdb_msg("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 void mmdb_check_loc()
|
||||||
|
{
|
||||||
|
if ( mmdb_loc && mmdb_loc->StaleDB() )
|
||||||
|
{
|
||||||
|
report_mmdb_msg("Closing stale MaxMind DB [%s]", mmdb_loc->Filename());
|
||||||
|
did_mmdb_loc_db_error = false;
|
||||||
|
mmdb_loc.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mmdb_check_asn()
|
||||||
|
{
|
||||||
|
if ( mmdb_asn && mmdb_asn->StaleDB() )
|
||||||
|
{
|
||||||
|
report_mmdb_msg("Closing stale MaxMind DB [%s]", mmdb_asn->Filename());
|
||||||
|
did_mmdb_asn_db_error = false;
|
||||||
|
mmdb_asn.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mmdb_lookup(const zeek::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 )
|
||||||
|
{
|
||||||
|
report_mmdb_msg("MaxMind DB lookup location error [%s]", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.found_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mmdb_lookup_loc(const zeek::IPAddr& addr, MMDB_lookup_result_s& result)
|
||||||
|
{
|
||||||
|
return mmdb_lookup(addr, result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mmdb_lookup_asn(const zeek::IPAddr& addr, MMDB_lookup_result_s& result)
|
||||||
|
{
|
||||||
|
return mmdb_lookup(addr, result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static zeek::ValPtr 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 zeek::make_intrusive<zeek::StringVal>(
|
||||||
|
entry_data->data_size, entry_data->utf8_string);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDB_DATA_TYPE_DOUBLE:
|
||||||
|
return zeek::make_intrusive<zeek::DoubleVal>(entry_data->double_value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDB_DATA_TYPE_UINT32:
|
||||||
|
return zeek::val_mgr->Count(entry_data->uint32);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR:
|
||||||
|
// key doesn't exist, nothing to do
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
report_mmdb_msg("MaxMind DB error [%s]", MMDB_strerror(status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mmdb_try_open_loc ()
|
||||||
|
{
|
||||||
|
// City database is always preferred over Country database.
|
||||||
|
const auto& mmdb_dir_val = zeek::detail::global_scope()->Find("mmdb_dir")->GetVal();
|
||||||
|
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 ()
|
||||||
|
{
|
||||||
|
const auto& mmdb_dir_val = zeek::detail::global_scope()->Find("mmdb_dir")->GetVal();
|
||||||
|
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
|
||||||
|
%%}
|
||||||
|
|
||||||
|
## Initializes MMDB for later use of lookup_location.
|
||||||
|
## Requires Zeek 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.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: lookup_autonomous_system
|
||||||
|
function mmdb_open_location_db%(f: string%) : bool
|
||||||
|
%{
|
||||||
|
#ifdef USE_GEOIP
|
||||||
|
return zeek::val_mgr->Bool(mmdb_open_loc(f->CheckString()));
|
||||||
|
#else
|
||||||
|
return zeek::val_mgr->False();
|
||||||
|
#endif
|
||||||
|
%}
|
||||||
|
|
||||||
|
## Initializes MMDB for later use of lookup_autonomous_system.
|
||||||
|
## Requires Zeek to be built with ``libmaxminddb``.
|
||||||
|
##
|
||||||
|
## f: The filename of the MaxMind ASN DB.
|
||||||
|
##
|
||||||
|
## Returns: A boolean indicating whether the db was successfully opened.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: lookup_autonomous_system
|
||||||
|
function mmdb_open_asn_db%(f: string%) : bool
|
||||||
|
%{
|
||||||
|
#ifdef USE_GEOIP
|
||||||
|
return zeek::val_mgr->Bool(mmdb_open_asn(f->CheckString()));
|
||||||
|
#else
|
||||||
|
return zeek::val_mgr->False();
|
||||||
|
#endif
|
||||||
|
%}
|
||||||
|
|
||||||
|
## Performs a geo-lookup of an IP address.
|
||||||
|
## Requires Zeek to be built with ``libmaxminddb``.
|
||||||
|
##
|
||||||
|
## a: The IP address to lookup.
|
||||||
|
##
|
||||||
|
## Returns: A record with country, region, city, latitude, and longitude.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: lookup_autonomous_system
|
||||||
|
function lookup_location%(a: addr%) : geo_location
|
||||||
|
%{
|
||||||
|
static auto geo_location = zeek::id::find_type<zeek::RecordType>("geo_location");
|
||||||
|
auto location = zeek::make_intrusive<zeek::RecordVal>(geo_location);
|
||||||
|
|
||||||
|
#ifdef USE_GEOIP
|
||||||
|
mmdb_check_loc();
|
||||||
|
if ( ! mmdb_loc )
|
||||||
|
{
|
||||||
|
if ( ! mmdb_try_open_loc() )
|
||||||
|
{
|
||||||
|
if ( ! did_mmdb_loc_db_error )
|
||||||
|
{
|
||||||
|
did_mmdb_loc_db_error = true;
|
||||||
|
zeek::emit_builtin_error("Failed to open GeoIP location database");
|
||||||
|
}
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MMDB_lookup_result_s result;
|
||||||
|
|
||||||
|
if ( mmdb_lookup_loc(a->AsAddr(), result) )
|
||||||
|
{
|
||||||
|
MMDB_entry_data_s entry_data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
// Get Country ISO Code
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"country", "iso_code", nullptr);
|
||||||
|
location->Assign(0, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_UTF8_STRING));
|
||||||
|
|
||||||
|
// Get Major Subdivision ISO Code
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"subdivisions", "0", "iso_code", nullptr);
|
||||||
|
location->Assign(1, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_UTF8_STRING));
|
||||||
|
|
||||||
|
// Get City English Name
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Get Location Latitude
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"location", "latitude", nullptr);
|
||||||
|
location->Assign(3, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_DOUBLE));
|
||||||
|
|
||||||
|
// Get Location Longitude
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"location", "longitude", nullptr);
|
||||||
|
location->Assign(4, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_DOUBLE));
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // not USE_GEOIP
|
||||||
|
static int missing_geoip_reported = 0;
|
||||||
|
|
||||||
|
if ( ! missing_geoip_reported )
|
||||||
|
{
|
||||||
|
zeek::emit_builtin_error("Zeek was not configured for GeoIP support");
|
||||||
|
missing_geoip_reported = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// the address.
|
||||||
|
|
||||||
|
return std::move(location);
|
||||||
|
%}
|
||||||
|
|
||||||
|
## Performs an lookup of AS number & organization of an IP address.
|
||||||
|
## Requires Zeek to be built with ``libmaxminddb``.
|
||||||
|
##
|
||||||
|
## a: The IP address to lookup.
|
||||||
|
##
|
||||||
|
## Returns: A record with autonomous system number and organization that contains *a*.
|
||||||
|
##
|
||||||
|
## .. zeek:see:: lookup_location
|
||||||
|
function lookup_autonomous_system%(a: addr%) : geo_autonomous_system
|
||||||
|
%{
|
||||||
|
static auto geo_autonomous_system = zeek::id::find_type<zeek::RecordType>("geo_autonomous_system");
|
||||||
|
auto autonomous_system = zeek::make_intrusive<zeek::RecordVal>(geo_autonomous_system);
|
||||||
|
|
||||||
|
#ifdef USE_GEOIP
|
||||||
|
mmdb_check_asn();
|
||||||
|
if ( ! mmdb_asn )
|
||||||
|
{
|
||||||
|
if ( ! mmdb_try_open_asn() )
|
||||||
|
{
|
||||||
|
if ( ! did_mmdb_asn_db_error )
|
||||||
|
{
|
||||||
|
did_mmdb_asn_db_error = true;
|
||||||
|
zeek::emit_builtin_error("Failed to open GeoIP ASN database");
|
||||||
|
}
|
||||||
|
|
||||||
|
return autonomous_system;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MMDB_lookup_result_s result;
|
||||||
|
|
||||||
|
if ( mmdb_lookup_asn(a->AsAddr(), result) )
|
||||||
|
{
|
||||||
|
MMDB_entry_data_s entry_data;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
// Get Autonomous System Number
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"autonomous_system_number", nullptr);
|
||||||
|
autonomous_system->Assign(0, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_UINT32));
|
||||||
|
|
||||||
|
// Get Autonomous System Organization
|
||||||
|
status = MMDB_get_value(&result.entry, &entry_data,
|
||||||
|
"autonomous_system_organization", nullptr);
|
||||||
|
autonomous_system->Assign(1, mmdb_getvalue(&entry_data, status,
|
||||||
|
MMDB_DATA_TYPE_UTF8_STRING));
|
||||||
|
|
||||||
|
return autonomous_system;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // not USE_GEOIP
|
||||||
|
static int missing_geoip_reported = 0;
|
||||||
|
|
||||||
|
if ( ! missing_geoip_reported )
|
||||||
|
{
|
||||||
|
zeek::emit_builtin_error("Zeek was not configured for GeoIP ASN support");
|
||||||
|
missing_geoip_reported = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We can get here even if we have GeoIP support, if we weren't
|
||||||
|
// able to initialize it or it didn't return any information for
|
||||||
|
// the address.
|
||||||
|
return std::move(autonomous_system);
|
||||||
|
%}
|
519
src/zeek.bif
519
src/zeek.bif
|
@ -3980,525 +3980,6 @@ function lookup_hostname%(host: string%) : addr_set
|
||||||
return nullptr;
|
return nullptr;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%%{
|
|
||||||
#ifdef USE_GEOIP
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <maxminddb.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/ip.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmdb_msg_count = 0;
|
|
||||||
static constexpr int mmdb_msg_limit = 20;
|
|
||||||
static double mmdb_msg_suppression_time = 0;
|
|
||||||
static constexpr double mmdb_msg_suppression_duration = 300;
|
|
||||||
|
|
||||||
static void report_mmdb_msg(const char* format, ...)
|
|
||||||
{
|
|
||||||
if ( zeek::run_state::network_time > mmdb_msg_suppression_time + mmdb_msg_suppression_duration )
|
|
||||||
{
|
|
||||||
mmdb_msg_count = 0;
|
|
||||||
mmdb_msg_suppression_time = zeek::run_state::network_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mmdb_msg_count >= mmdb_msg_limit )
|
|
||||||
return;
|
|
||||||
|
|
||||||
++mmdb_msg_count;
|
|
||||||
|
|
||||||
va_list al;
|
|
||||||
va_start(al, format);
|
|
||||||
std::string msg = zeek::util::vfmt(format, al);
|
|
||||||
va_end(al);
|
|
||||||
|
|
||||||
zeek::reporter->Info("%s", msg.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
class MMDB {
|
|
||||||
public:
|
|
||||||
MMDB(const char* filename, struct stat info);
|
|
||||||
|
|
||||||
~MMDB();
|
|
||||||
|
|
||||||
MMDB_lookup_result_s Lookup(const struct sockaddr* const sa);
|
|
||||||
bool StaleDB();
|
|
||||||
const char* Filename();
|
|
||||||
|
|
||||||
private:
|
|
||||||
MMDB_s mmdb;
|
|
||||||
struct stat file_info;
|
|
||||||
bool lookup_error;
|
|
||||||
double last_check;
|
|
||||||
};
|
|
||||||
|
|
||||||
MMDB::MMDB(const char* filename, struct stat info)
|
|
||||||
: file_info(info), lookup_error{false},
|
|
||||||
last_check{zeek::run_state::network_time}
|
|
||||||
{
|
|
||||||
int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
|
|
||||||
|
|
||||||
if ( MMDB_SUCCESS != status )
|
|
||||||
{
|
|
||||||
throw std::runtime_error(MMDB_strerror(status));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MMDB::~MMDB()
|
|
||||||
{
|
|
||||||
MMDB_close(&mmdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
MMDB_lookup_result_s MMDB::Lookup(const struct sockaddr* const sa)
|
|
||||||
{
|
|
||||||
int mmdb_error;
|
|
||||||
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdb, sa, &mmdb_error);
|
|
||||||
|
|
||||||
if ( MMDB_SUCCESS != mmdb_error )
|
|
||||||
{
|
|
||||||
lookup_error = true;
|
|
||||||
throw std::runtime_error(MMDB_strerror(mmdb_error));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if the Maxmind DB should be closed and reopened. This will
|
|
||||||
// happen if there was a lookup error or if the mmap'd file has been replaced
|
|
||||||
// by an external process.
|
|
||||||
bool MMDB::StaleDB()
|
|
||||||
{
|
|
||||||
struct stat buf;
|
|
||||||
|
|
||||||
if ( lookup_error )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
static double mmdb_stale_check_interval = zeek::id::find_val("mmdb_stale_check_interval")->AsInterval();
|
|
||||||
|
|
||||||
if ( mmdb_stale_check_interval < 0.0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( zeek::run_state::network_time - last_check < mmdb_stale_check_interval )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
last_check = zeek::run_state::network_time;
|
|
||||||
|
|
||||||
if ( 0 != stat(mmdb.filename, &buf) )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( buf.st_ino != file_info.st_ino || buf.st_mtime != file_info.st_mtime )
|
|
||||||
{
|
|
||||||
report_mmdb_msg("%s change detected for MaxMind DB [%s]",
|
|
||||||
buf.st_ino != file_info.st_ino ? "Inode" : "Modification time",
|
|
||||||
mmdb.filename);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* MMDB::Filename()
|
|
||||||
{
|
|
||||||
return mmdb.filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<MMDB> mmdb_loc;
|
|
||||||
std::unique_ptr<MMDB> mmdb_asn;
|
|
||||||
static bool did_mmdb_loc_db_error = false;
|
|
||||||
static bool did_mmdb_asn_db_error = false;
|
|
||||||
|
|
||||||
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, buf));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mmdb_loc.reset(new MMDB(filename, buf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
catch ( const std::exception& e )
|
|
||||||
{
|
|
||||||
if ( asn )
|
|
||||||
did_mmdb_asn_db_error = false;
|
|
||||||
else
|
|
||||||
did_mmdb_loc_db_error = false;
|
|
||||||
|
|
||||||
report_mmdb_msg("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 void mmdb_check_loc()
|
|
||||||
{
|
|
||||||
if ( mmdb_loc && mmdb_loc->StaleDB() )
|
|
||||||
{
|
|
||||||
report_mmdb_msg("Closing stale MaxMind DB [%s]", mmdb_loc->Filename());
|
|
||||||
did_mmdb_loc_db_error = false;
|
|
||||||
mmdb_loc.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mmdb_check_asn()
|
|
||||||
{
|
|
||||||
if ( mmdb_asn && mmdb_asn->StaleDB() )
|
|
||||||
{
|
|
||||||
report_mmdb_msg("Closing stale MaxMind DB [%s]", mmdb_asn->Filename());
|
|
||||||
did_mmdb_asn_db_error = false;
|
|
||||||
mmdb_asn.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool mmdb_lookup(const zeek::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 )
|
|
||||||
{
|
|
||||||
report_mmdb_msg("MaxMind DB lookup location error [%s]", e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.found_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool mmdb_lookup_loc(const zeek::IPAddr& addr, MMDB_lookup_result_s& result)
|
|
||||||
{
|
|
||||||
return mmdb_lookup(addr, result, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool mmdb_lookup_asn(const zeek::IPAddr& addr, MMDB_lookup_result_s& result)
|
|
||||||
{
|
|
||||||
return mmdb_lookup(addr, result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeek::ValPtr 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 zeek::make_intrusive<zeek::StringVal>(
|
|
||||||
entry_data->data_size, entry_data->utf8_string);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDB_DATA_TYPE_DOUBLE:
|
|
||||||
return zeek::make_intrusive<zeek::DoubleVal>(entry_data->double_value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDB_DATA_TYPE_UINT32:
|
|
||||||
return zeek::val_mgr->Count(entry_data->uint32);
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR:
|
|
||||||
// key doesn't exist, nothing to do
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
report_mmdb_msg("MaxMind DB error [%s]", MMDB_strerror(status));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool mmdb_try_open_loc ()
|
|
||||||
{
|
|
||||||
// City database is always preferred over Country database.
|
|
||||||
const auto& mmdb_dir_val = zeek::detail::global_scope()->Find("mmdb_dir")->GetVal();
|
|
||||||
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 ()
|
|
||||||
{
|
|
||||||
const auto& mmdb_dir_val = zeek::detail::global_scope()->Find("mmdb_dir")->GetVal();
|
|
||||||
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
|
|
||||||
%%}
|
|
||||||
|
|
||||||
## Initializes MMDB for later use of lookup_location.
|
|
||||||
## Requires Zeek 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.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: lookup_autonomous_system
|
|
||||||
function mmdb_open_location_db%(f: string%) : bool
|
|
||||||
%{
|
|
||||||
#ifdef USE_GEOIP
|
|
||||||
return zeek::val_mgr->Bool(mmdb_open_loc(f->CheckString()));
|
|
||||||
#else
|
|
||||||
return zeek::val_mgr->False();
|
|
||||||
#endif
|
|
||||||
%}
|
|
||||||
|
|
||||||
## Initializes MMDB for later use of lookup_autonomous_system.
|
|
||||||
## Requires Zeek to be built with ``libmaxminddb``.
|
|
||||||
##
|
|
||||||
## f: The filename of the MaxMind ASN DB.
|
|
||||||
##
|
|
||||||
## Returns: A boolean indicating whether the db was successfully opened.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: lookup_autonomous_system
|
|
||||||
function mmdb_open_asn_db%(f: string%) : bool
|
|
||||||
%{
|
|
||||||
#ifdef USE_GEOIP
|
|
||||||
return zeek::val_mgr->Bool(mmdb_open_asn(f->CheckString()));
|
|
||||||
#else
|
|
||||||
return zeek::val_mgr->False();
|
|
||||||
#endif
|
|
||||||
%}
|
|
||||||
|
|
||||||
## Performs a geo-lookup of an IP address.
|
|
||||||
## Requires Zeek to be built with ``libmaxminddb``.
|
|
||||||
##
|
|
||||||
## a: The IP address to lookup.
|
|
||||||
##
|
|
||||||
## Returns: A record with country, region, city, latitude, and longitude.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: lookup_autonomous_system
|
|
||||||
function lookup_location%(a: addr%) : geo_location
|
|
||||||
%{
|
|
||||||
static auto geo_location = zeek::id::find_type<zeek::RecordType>("geo_location");
|
|
||||||
auto location = zeek::make_intrusive<zeek::RecordVal>(geo_location);
|
|
||||||
|
|
||||||
#ifdef USE_GEOIP
|
|
||||||
mmdb_check_loc();
|
|
||||||
if ( ! mmdb_loc )
|
|
||||||
{
|
|
||||||
if ( ! mmdb_try_open_loc() )
|
|
||||||
{
|
|
||||||
if ( ! did_mmdb_loc_db_error )
|
|
||||||
{
|
|
||||||
did_mmdb_loc_db_error = true;
|
|
||||||
zeek::emit_builtin_error("Failed to open GeoIP location database");
|
|
||||||
}
|
|
||||||
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MMDB_lookup_result_s result;
|
|
||||||
|
|
||||||
if ( mmdb_lookup_loc(a->AsAddr(), result) )
|
|
||||||
{
|
|
||||||
MMDB_entry_data_s entry_data;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
// Get Country ISO Code
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"country", "iso_code", nullptr);
|
|
||||||
location->Assign(0, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_UTF8_STRING));
|
|
||||||
|
|
||||||
// Get Major Subdivision ISO Code
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"subdivisions", "0", "iso_code", nullptr);
|
|
||||||
location->Assign(1, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_UTF8_STRING));
|
|
||||||
|
|
||||||
// Get City English Name
|
|
||||||
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));
|
|
||||||
|
|
||||||
// Get Location Latitude
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"location", "latitude", nullptr);
|
|
||||||
location->Assign(3, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_DOUBLE));
|
|
||||||
|
|
||||||
// Get Location Longitude
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"location", "longitude", nullptr);
|
|
||||||
location->Assign(4, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_DOUBLE));
|
|
||||||
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // not USE_GEOIP
|
|
||||||
static int missing_geoip_reported = 0;
|
|
||||||
|
|
||||||
if ( ! missing_geoip_reported )
|
|
||||||
{
|
|
||||||
zeek::emit_builtin_error("Zeek was not configured for GeoIP support");
|
|
||||||
missing_geoip_reported = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// the address.
|
|
||||||
|
|
||||||
return std::move(location);
|
|
||||||
%}
|
|
||||||
|
|
||||||
## Performs an lookup of AS number & organization of an IP address.
|
|
||||||
## Requires Zeek to be built with ``libmaxminddb``.
|
|
||||||
##
|
|
||||||
## a: The IP address to lookup.
|
|
||||||
##
|
|
||||||
## Returns: A record with autonomous system number and organization that contains *a*.
|
|
||||||
##
|
|
||||||
## .. zeek:see:: lookup_location
|
|
||||||
function lookup_autonomous_system%(a: addr%) : geo_autonomous_system
|
|
||||||
%{
|
|
||||||
static auto geo_autonomous_system = zeek::id::find_type<zeek::RecordType>("geo_autonomous_system");
|
|
||||||
auto autonomous_system = zeek::make_intrusive<zeek::RecordVal>(geo_autonomous_system);
|
|
||||||
|
|
||||||
#ifdef USE_GEOIP
|
|
||||||
mmdb_check_asn();
|
|
||||||
if ( ! mmdb_asn )
|
|
||||||
{
|
|
||||||
if ( ! mmdb_try_open_asn() )
|
|
||||||
{
|
|
||||||
if ( ! did_mmdb_asn_db_error )
|
|
||||||
{
|
|
||||||
did_mmdb_asn_db_error = true;
|
|
||||||
zeek::emit_builtin_error("Failed to open GeoIP ASN database");
|
|
||||||
}
|
|
||||||
|
|
||||||
return autonomous_system;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MMDB_lookup_result_s result;
|
|
||||||
|
|
||||||
if ( mmdb_lookup_asn(a->AsAddr(), result) )
|
|
||||||
{
|
|
||||||
MMDB_entry_data_s entry_data;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
// Get Autonomous System Number
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"autonomous_system_number", nullptr);
|
|
||||||
autonomous_system->Assign(0, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_UINT32));
|
|
||||||
|
|
||||||
// Get Autonomous System Organization
|
|
||||||
status = MMDB_get_value(&result.entry, &entry_data,
|
|
||||||
"autonomous_system_organization", nullptr);
|
|
||||||
autonomous_system->Assign(1, mmdb_getvalue(&entry_data, status,
|
|
||||||
MMDB_DATA_TYPE_UTF8_STRING));
|
|
||||||
|
|
||||||
return autonomous_system;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // not USE_GEOIP
|
|
||||||
static int missing_geoip_reported = 0;
|
|
||||||
|
|
||||||
if ( ! missing_geoip_reported )
|
|
||||||
{
|
|
||||||
zeek::emit_builtin_error("Zeek was not configured for GeoIP ASN support");
|
|
||||||
missing_geoip_reported = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// We can get here even if we have GeoIP support, if we weren't
|
|
||||||
// able to initialize it or it didn't return any information for
|
|
||||||
// the address.
|
|
||||||
return std::move(autonomous_system);
|
|
||||||
%}
|
|
||||||
|
|
||||||
## Calculates distance between two geographic locations using the haversine
|
## Calculates distance between two geographic locations using the haversine
|
||||||
## formula. Latitudes and longitudes must be given in degrees, where southern
|
## formula. Latitudes and longitudes must be given in degrees, where southern
|
||||||
## hemisphere latitudes are negative and western hemisphere longitudes are
|
## hemisphere latitudes are negative and western hemisphere longitudes are
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue