geoip2.c (goaccess-1.6.5) | : | geoip2.c (goaccess-1.7) | ||
---|---|---|---|---|
skipping to change at line 51 | skipping to change at line 51 | |||
#endif | #endif | |||
#include "geoip1.h" | #include "geoip1.h" | |||
#include "error.h" | #include "error.h" | |||
#include "labels.h" | #include "labels.h" | |||
#include "util.h" | #include "util.h" | |||
#include "xmalloc.h" | #include "xmalloc.h" | |||
/* should be reused across lookups */ | /* should be reused across lookups */ | |||
static int geoip_asn_type = 0; | ||||
static int geoip_city_type = 0; | static int geoip_city_type = 0; | |||
static MMDB_s *mmdb = NULL; | static int geoip_country_type = 0; | |||
static int mmdb_cnt = 0; | ||||
static MMDB_s *mmdbs = NULL; | ||||
/* Determine if we have a valid geoip resource. | /* Determine if we have a valid geoip resource. | |||
* | * | |||
* If the geoip resource is NULL, 0 is returned. | * If the geoip resource is NULL, 0 is returned. | |||
* If the geoip resource is valid and malloc'd, 1 is returned. */ | * If the geoip resource is valid and malloc'd, 1 is returned. */ | |||
int | int | |||
is_geoip_resource (void) { | is_geoip_resource (void) { | |||
return mmdb != NULL ? 1 : 0; | return mmdbs && mmdb_cnt; | |||
} | } | |||
/* Free up GeoIP resources */ | /* Free up GeoIP resources */ | |||
void | void | |||
geoip_free (void) { | geoip_free (void) { | |||
int idx = 0; | ||||
if (!is_geoip_resource ()) | if (!is_geoip_resource ()) | |||
return; | return; | |||
MMDB_close (mmdb); | for (idx = 0; idx < mmdb_cnt; idx++) | |||
free (mmdb); | MMDB_close (&mmdbs[idx]); | |||
mmdb = NULL; | free (mmdbs); | |||
mmdbs = NULL; | ||||
} | ||||
static void | ||||
set_geoip (const char *db) { | ||||
int status = 0; | ||||
MMDB_s *new_mmdbs = NULL, mmdb; | ||||
if (db == NULL || *db == '\0') | ||||
return; | ||||
if ((status = MMDB_open (db, MMDB_MODE_MMAP, &mmdb)) != MMDB_SUCCESS) | ||||
FATAL ("Unable to open GeoIP2 database %s: %s\n", db, MMDB_strerror (status) | ||||
); | ||||
mmdb_cnt++; | ||||
new_mmdbs = realloc (mmdbs, sizeof (*mmdbs) * mmdb_cnt); | ||||
if (new_mmdbs == NULL) | ||||
FATAL ("Unable to realloc GeoIP2 database %s\n", db); | ||||
mmdbs = new_mmdbs; | ||||
mmdbs[mmdb_cnt - 1] = mmdb; | ||||
if (strstr (mmdb.metadata.database_type, "-City") != NULL) | ||||
conf.has_geocountry = conf.has_geocity = geoip_country_type = geoip_city_typ | ||||
e = 1; | ||||
if (strstr (mmdb.metadata.database_type, "-ASN") != NULL) | ||||
conf.has_geoasn = geoip_asn_type = 1; | ||||
if (strstr (mmdb.metadata.database_type, "-Country") != NULL) | ||||
conf.has_geocountry = geoip_country_type = 1; | ||||
} | } | |||
/* Open the given GeoIP2 database. | /* Open the given GeoIP2 database. | |||
* | * | |||
* On error, it aborts. | * On error, it aborts. | |||
* On success, a new geolocation structure is set. */ | * On success, a new geolocation structure is set. */ | |||
void | void | |||
init_geoip (void) { | init_geoip (void) { | |||
const char *fn = conf.geoip_database; | int i; | |||
int status = 0; | ||||
if (fn == NULL) | ||||
return; | ||||
/* open custom city GeoIP database */ | ||||
mmdb = xcalloc (1, sizeof (MMDB_s)); | ||||
if ((status = MMDB_open (fn, MMDB_MODE_MMAP, mmdb)) != MMDB_SUCCESS) { | ||||
free (mmdb); | ||||
FATAL ("Unable to open GeoIP2 database %s: %s\n", fn, MMDB_strerror (status) | ||||
); | ||||
} | ||||
if (strstr (mmdb->metadata.database_type, "-City") != NULL) | for (i = 0; i < conf.geoip_db_idx; ++i) | |||
geoip_city_type = 1; | set_geoip (conf.geoip_databases[i]); | |||
} | } | |||
/* Look up an IP address that is passed in as a null-terminated string. | /* Look up an IP address that is passed in as a null-terminated string. | |||
* | * | |||
* On error, it aborts. | * On error, it aborts. | |||
* If no entry is found, 1 is returned. | * If no entry is found, 1 is returned. | |||
* On success, MMDB_lookup_result_s struct is set and 0 is returned. */ | * On success, MMDB_lookup_result_s struct is set and 0 is returned. */ | |||
static int | static int | |||
geoip_lookup (MMDB_lookup_result_s * res, const char *ip) { | geoip_lookup (MMDB_lookup_result_s * res, const char *ip, int is_asn) { | |||
int gai_err, mmdb_err; | int gai_err, mmdb_err, idx = 0; | |||
MMDB_s *mmdb = NULL; | ||||
*res = MMDB_lookup_string (mmdb, ip, &gai_err, &mmdb_err); | ||||
if (0 != gai_err) | for (idx = 0; idx < mmdb_cnt; idx++) { | |||
return 1; | if (is_asn && (!strstr (mmdbs[idx].metadata.database_type, "ASN"))) | |||
continue; | ||||
if (MMDB_SUCCESS != mmdb_err) | if (!is_asn && (strstr (mmdbs[idx].metadata.database_type, "ASN"))) | |||
FATAL ("Error from libmaxminddb: %s\n", MMDB_strerror (mmdb_err)); | continue; | |||
if (!(*res).found_entry) | mmdb = &mmdbs[idx]; | |||
return 1; | ||||
*res = MMDB_lookup_string (mmdb, ip, &gai_err, &mmdb_err); | ||||
if (0 != gai_err) | ||||
return 1; | ||||
if (MMDB_SUCCESS != mmdb_err) | ||||
FATAL ("Error from libmaxminddb: %s\n", MMDB_strerror (mmdb_err)); | ||||
if (!(*res).found_entry) | ||||
return 1; | ||||
break; | ||||
} | ||||
return 0; | return 0; | |||
} | } | |||
/* Get continent name concatenated with code. | /* Get continent name concatenated with code. | |||
* | * | |||
* If continent not found, "Unknown" is returned. | * If continent not found, "Unknown" is returned. | |||
* On success, the continent code & name is returned . */ | * On success, the continent code & name is returned . */ | |||
static const char * | static const char * | |||
get_continent_name_and_code (const char *continentid) { | get_continent_name_and_code (const char *continentid) { | |||
skipping to change at line 153 | skipping to change at line 183 | |||
/* Compose a string with the country name and code and store it in the | /* Compose a string with the country name and code and store it in the | |||
* given buffer. */ | * given buffer. */ | |||
static void | static void | |||
geoip_set_country (const char *country, const char *code, char *loc) { | geoip_set_country (const char *country, const char *code, char *loc) { | |||
if (country && code) | if (country && code) | |||
snprintf (loc, COUNTRY_LEN, "%s %s", code, country); | snprintf (loc, COUNTRY_LEN, "%s %s", code, country); | |||
else | else | |||
snprintf (loc, COUNTRY_LEN, "%s", "Unknown"); | snprintf (loc, COUNTRY_LEN, "%s", "Unknown"); | |||
} | } | |||
/* Compose a string with the ASN name and code and store it in the | ||||
* given buffer. */ | ||||
static void | ||||
geoip_set_asn (MMDB_entry_data_s name, MMDB_entry_data_s code, char *asn, int st | ||||
atus) { | ||||
if (status == 0) | ||||
snprintf (asn, ASN_LEN, "%05u: %.*s", code.uint32, name.data_size, name.utf8 | ||||
_string); | ||||
else | ||||
snprintf (asn, ASN_LEN, "%s", "00000: Unknown"); | ||||
} | ||||
/* Compose a string with the city name and state/region and store it | /* Compose a string with the city name and state/region and store it | |||
* in the given buffer. */ | * in the given buffer. */ | |||
static void | static void | |||
geoip_set_city (const char *city, const char *region, char *loc) { | geoip_set_city (const char *city, const char *region, char *loc) { | |||
snprintf (loc, CITY_LEN, "%s, %s", city ? city : "N/A City", region ? region : "N/A Region"); | snprintf (loc, CITY_LEN, "%s, %s", city ? city : "N/A City", region ? region : "N/A Region"); | |||
} | } | |||
/* Compose a string with the continent name and store it in the given | /* Compose a string with the continent name and store it in the given | |||
* buffer. */ | * buffer. */ | |||
static void | static void | |||
skipping to change at line 244 | skipping to change at line 284 | |||
code = get_value (res, "country", "iso_code", NULL); | code = get_value (res, "country", "iso_code", NULL); | |||
if (!country) { | if (!country) { | |||
country = get_value (res, "country", "names", "en", NULL); | country = get_value (res, "country", "names", "en", NULL); | |||
} | } | |||
} | } | |||
geoip_set_country (country, code, location); | geoip_set_country (country, code, location); | |||
free (code); | free (code); | |||
free (country); | free (country); | |||
} | } | |||
/* Sets the value for the given array of strings as the lookup path. | ||||
* | ||||
* On error or not found, 1 is returned. | ||||
* On success, 0 is returned and the entry data is set. */ | ||||
static int | ||||
geoip_query_asn_code (MMDB_lookup_result_s res, MMDB_entry_data_s * code) { | ||||
int status; | ||||
const char *key[] = { "autonomous_system_number", NULL }; | ||||
if (res.found_entry) { | ||||
status = MMDB_aget_value (&res.entry, code, key); | ||||
if (status != MMDB_SUCCESS || !code->has_data) | ||||
return 1; | ||||
} | ||||
return 0; | ||||
} | ||||
/* Sets the value for the given array of strings as the lookup path. | ||||
* | ||||
* On error or not found, 1 is returned. | ||||
* On success, 0 is returned and the entry data is set. */ | ||||
static int | ||||
geoip_query_asn_name (MMDB_lookup_result_s res, MMDB_entry_data_s * name) { | ||||
int status; | ||||
const char *key[] = { "autonomous_system_organization", NULL }; | ||||
if (res.found_entry) { | ||||
status = MMDB_aget_value (&res.entry, name, key); | ||||
if (status != MMDB_SUCCESS || !name->has_data) | ||||
return 1; | ||||
} | ||||
return 0; | ||||
} | ||||
/* A wrapper to fetch the looked up result and set the ASN organization & code. | ||||
* | ||||
* If no data is found, "Uknown" is set. | ||||
* On success, the fetched value is set. */ | ||||
void | ||||
geoip_asn (char *host, char *asn) { | ||||
MMDB_lookup_result_s res = { 0 }; | ||||
MMDB_entry_data_s name = { 0 }; | ||||
MMDB_entry_data_s code = { 0 }; | ||||
int status = 1; | ||||
geoip_lookup (&res, host, 1); | ||||
if (!res.found_entry) | ||||
goto out; | ||||
if ((status &= geoip_query_asn_name (res, &name))) | ||||
goto out; | ||||
if ((status |= geoip_query_asn_code (res, &code))) | ||||
goto out; | ||||
out: | ||||
geoip_set_asn (name, code, asn, status); | ||||
} | ||||
/* A wrapper to fetch the looked up result and set the continent code. | /* A wrapper to fetch the looked up result and set the continent code. | |||
* | * | |||
* If no data is found, NULL is set. | * If no data is found, NULL is set. | |||
* On success, the fetched value is set. */ | * On success, the fetched value is set. */ | |||
static void | static void | |||
geoip_query_continent (MMDB_lookup_result_s res, char *location) { | geoip_query_continent (MMDB_lookup_result_s res, char *location) { | |||
char *code = NULL; | char *code = NULL; | |||
if (res.found_entry) | if (res.found_entry) | |||
code = get_value (res, "continent", "code", NULL); | code = get_value (res, "continent", "code", NULL); | |||
geoip_set_continent (code, location); | geoip_set_continent (code, location); | |||
free (code); | free (code); | |||
} | } | |||
/* Set country data by record into the given `location` buffer */ | /* Set country data by record into the given `location` buffer */ | |||
void | void | |||
geoip_get_country (const char *ip, char *location, GO_UNUSED GTypeIP type_ip) { | geoip_get_country (const char *ip, char *location, GO_UNUSED GTypeIP type_ip) { | |||
MMDB_lookup_result_s res; | MMDB_lookup_result_s res = { 0 }; | |||
geoip_lookup (&res, ip); | geoip_lookup (&res, ip, 0); | |||
geoip_query_country (res, location); | geoip_query_country (res, location); | |||
} | } | |||
/* A wrapper to fetch the looked up result and set the continent. */ | /* A wrapper to fetch the looked up result and set the continent. */ | |||
void | void | |||
geoip_get_continent (const char *ip, char *location, GO_UNUSED GTypeIP type_ip) { | geoip_get_continent (const char *ip, char *location, GO_UNUSED GTypeIP type_ip) { | |||
MMDB_lookup_result_s res; | MMDB_lookup_result_s res = { 0 }; | |||
geoip_lookup (&res, ip); | geoip_lookup (&res, ip, 0); | |||
geoip_query_continent (res, location); | geoip_query_continent (res, location); | |||
} | } | |||
/* Entry point to set GeoIP location into the corresponding buffers, | /* Entry point to set GeoIP location into the corresponding buffers, | |||
* (continent, country, city). | * (continent, country, city). | |||
* | * | |||
* On error, 1 is returned | * On error, 1 is returned | |||
* On success, buffers are set and 0 is returned */ | * On success, buffers are set and 0 is returned */ | |||
int | int | |||
set_geolocation (char *host, char *continent, char *country, char *city) { | set_geolocation (char *host, char *continent, char *country, char *city, char *a | |||
MMDB_lookup_result_s res; | sn) { | |||
MMDB_lookup_result_s res = { 0 }; | ||||
if (!is_geoip_resource ()) | if (!is_geoip_resource ()) | |||
return 1; | return 1; | |||
geoip_lookup (&res, host); | /* set ASN data */ | |||
if (geoip_asn_type) | ||||
geoip_asn (host, asn); | ||||
if (!geoip_city_type && !geoip_country_type) | ||||
return 0; | ||||
/* set Country/City data */ | ||||
geoip_lookup (&res, host, 0); | ||||
geoip_query_country (res, country); | geoip_query_country (res, country); | |||
geoip_query_continent (res, continent); | geoip_query_continent (res, continent); | |||
if (geoip_city_type) | if (geoip_city_type) | |||
geoip_query_city (res, city); | geoip_query_city (res, city); | |||
return 0; | return 0; | |||
} | } | |||
End of changes. 17 change blocks. | ||||
39 lines changed or deleted | 152 lines changed or added |