2 * GeoIP database support
4 * Copyright 2008, Gerald Combs <gerald@wireshark.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * We currently return a single string for each database. Some databases,
27 * e.g. GeoIPCity, can return other info such as area codes.
34 #include <epan/wmem/wmem.h>
38 #include <GeoIPCity.h>
40 #include <epan/geoip_db.h>
42 #include <epan/prefs.h>
43 #include <epan/value_string.h>
45 #include <wsutil/report_err.h>
46 #include <wsutil/file_util.h>
48 /* This needs to match NUM_GEOIP_COLS in hostlist_table.h */
49 #define MAX_GEOIP_DBS 13
51 /* Column names for each database type */
52 value_string geoip_type_name_vals[] = {
53 { GEOIP_COUNTRY_EDITION, "Country" },
54 { GEOIP_REGION_EDITION_REV0, "Region" },
55 { GEOIP_CITY_EDITION_REV0, "City"},
56 { GEOIP_ORG_EDITION, "Organization" },
57 { GEOIP_ISP_EDITION, "ISP" },
58 { GEOIP_CITY_EDITION_REV1, "City" },
59 { GEOIP_REGION_EDITION_REV1, "Region" },
60 { GEOIP_PROXY_EDITION, "Proxy" },
61 { GEOIP_ASNUM_EDITION, "AS Number" },
62 { GEOIP_NETSPEED_EDITION, "Speed" },
63 { GEOIP_DOMAIN_EDITION, "Domain" },
65 { GEOIP_COUNTRY_EDITION_V6, "Country" },
66 /* This is the closest thing to a version that GeoIP.h seems to provide. */
67 #if NUM_DB_TYPES > 31 /* 1.4.7 */
68 { GEOIP_CITY_EDITION_REV0_V6, "City"},
69 { GEOIP_CITY_EDITION_REV1_V6, "City"},
70 { GEOIP_ASNUM_EDITION_V6, "AS Number" },
71 { GEOIP_ISP_EDITION_V6, "ISP" },
72 { GEOIP_ORG_EDITION_V6, "Organization" },
73 { GEOIP_DOMAIN_EDITION_V6, "Domain" },
74 #endif /* NUM_DB_TYPES > 31 */
75 #if NUM_DB_TYPES > 32 /* 1.4.8 */
76 { GEOIP_NETSPEED_EDITION_REV1_V6, "Speed" },
77 #endif /* NUM_DB_TYPES > 32 */
78 #endif /* HAVE_GEOIP_V6 */
79 { WS_LAT_FAKE_EDITION, "Latitude" }, /* fake database */
80 { WS_LON_FAKE_EDITION, "Longitude" }, /* fake database */
84 static GArray *geoip_dat_arr = NULL;
86 /* UAT definitions. Copied from oids.c */
87 typedef struct _geoip_db_path_t {
91 static geoip_db_path_t *geoip_db_paths = NULL;
92 static guint num_geoip_db_paths = 0;
93 static uat_t *geoip_db_paths_uat = NULL;
94 UAT_DIRECTORYNAME_CB_DEF(geoip_mod, path, geoip_db_path_t)
98 * Scan a directory for GeoIP databases and load them
101 geoip_dat_scan_dir(const char *dirname) {
108 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) {
109 while ((file = ws_dir_read_name(dir)) != NULL) {
110 name = ws_dir_get_name(file);
111 if (g_str_has_prefix(file, "Geo") && g_str_has_suffix(file, ".dat")) {
112 datname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name);
113 gi = GeoIP_open(datname, GEOIP_MEMORY_CACHE);
115 g_array_append_val(geoip_dat_arr, gi);
125 static void* geoip_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) {
126 const geoip_db_path_t *m = (const geoip_db_path_t *)orig;
127 geoip_db_path_t *d = (geoip_db_path_t *)dest;
129 d->path = g_strdup(m->path);
134 static void geoip_db_path_free_cb(void* p) {
135 geoip_db_path_t *m = (geoip_db_path_t *)p;
139 /* called every time the user presses "Apply" or "OK in the list of
140 * GeoIP directories, and also once on startup */
141 static void geoip_db_post_update_cb(void) {
145 /* If we have old data, clear out the whole thing
146 * and start again. TODO: Just update the ones that
147 * have changed for efficiency's sake. */
149 /* skip the last two, as they are fake */
150 for (i = 0; i < geoip_db_num_dbs() - 2; i++) {
151 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
156 /* don't use GeoIP_delete() on the two fake
157 * databases as they weren't created by GeoIP_new()
159 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
163 gi = g_array_index(geoip_dat_arr, GeoIP *, i+1);
167 /* finally, free the array itself */
168 g_array_free(geoip_dat_arr, TRUE);
171 /* allocate the array */
172 geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
174 /* Walk all the directories */
175 for (i = 0; i < num_geoip_db_paths; i++) {
176 if (geoip_db_paths[i].path) {
177 geoip_dat_scan_dir(geoip_db_paths[i].path);
181 /* add fake databases for latitude and longitude
182 * (using "City" in reality) */
185 gi = (GeoIP *)g_malloc(sizeof (GeoIP));
186 gi->databaseType = WS_LAT_FAKE_EDITION;
187 g_array_append_val(geoip_dat_arr, gi);
190 gi = (GeoIP *)g_malloc(sizeof (GeoIP));
191 gi->databaseType = WS_LON_FAKE_EDITION;
192 g_array_append_val(geoip_dat_arr, gi);
196 * Initialize GeoIP lookups
199 geoip_db_pref_init(module_t *nameres)
201 static uat_field_t geoip_db_paths_fields[] = {
202 UAT_FLD_DIRECTORYNAME(geoip_mod, path, "GeoIP Database Directory", "The GeoIP database directory path"),
206 geoip_db_paths_uat = uat_new("GeoIP Database Paths",
207 sizeof(geoip_db_path_t),
210 (void**)&geoip_db_paths,
212 /* affects dissection of packets (as the GeoIP database is
213 used when dissecting), but not set of named fields */
214 UAT_AFFECTS_DISSECTION,
216 geoip_db_path_copy_cb,
218 geoip_db_path_free_cb,
219 geoip_db_post_update_cb,
220 geoip_db_paths_fields);
222 prefs_register_uat_preference(nameres,
224 "GeoIP database directories",
225 "Search paths for GeoIP address mapping databases.\n"
226 "Wireshark will look in each directory for files beginning\n"
227 "with \"Geo\" and ending with \".dat\".",
232 geoip_db_num_dbs(void) {
233 return geoip_dat_arr->len;
237 geoip_db_name(guint dbnum) {
240 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
242 return (val_to_str_const(gi->databaseType, geoip_type_name_vals, "Unknown database"));
244 return "Invalid database";
248 geoip_db_type(guint dbnum) {
251 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
253 return (gi->databaseType);
259 geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) {
264 for (i = 0; i < geoip_db_num_dbs(); i++) {
265 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
267 switch (gi->databaseType) {
268 case GEOIP_CITY_EDITION_REV0:
269 case GEOIP_CITY_EDITION_REV1:
270 gir = GeoIP_record_by_ipnum(gi, addr);
272 *lat = gir->latitude;
273 *lon = gir->longitude;
288 * GeoIP 1.4.3 and later provide GeoIP_set_charset(), but in versions
289 * 1.4.3 to 1.4.6 that only applies to the City databases. I.e., it's
290 * possible to produce invalid UTF-8 sequences even if GeoIP_set_charset()
294 /* Ensure that a given db value is UTF-8 */
296 db_val_to_utf_8(const char *val, GeoIP *gi) {
298 if (GeoIP_charset(gi) == GEOIP_CHARSET_ISO_8859_1) {
300 utf8_val = g_convert(val, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
302 char *ret_val = wmem_strdup(NULL, utf8_val);
307 return wmem_strdup(NULL, val);
311 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
315 char *val, *ret = NULL;
317 if (dbnum > geoip_db_num_dbs()) {
318 if (not_found == NULL)
321 return wmem_strdup(NULL, not_found);
323 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
325 switch (gi->databaseType) {
326 case GEOIP_COUNTRY_EDITION:
327 raw_val = GeoIP_country_name_by_ipnum(gi, addr);
329 ret = db_val_to_utf_8(raw_val, gi);
333 case GEOIP_CITY_EDITION_REV0:
334 case GEOIP_CITY_EDITION_REV1:
335 gir = GeoIP_record_by_ipnum(gi, addr);
336 if (gir && gir->city && gir->region) {
337 val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region);
338 ret = db_val_to_utf_8(val, gi);
339 wmem_free(NULL, val);
340 } else if (gir && gir->city) {
341 ret = db_val_to_utf_8(gir->city, gi);
345 case GEOIP_ORG_EDITION:
346 case GEOIP_ISP_EDITION:
347 case GEOIP_ASNUM_EDITION:
348 raw_val = GeoIP_name_by_ipnum(gi, addr);
350 ret = db_val_to_utf_8(raw_val, gi);
354 case WS_LAT_FAKE_EDITION:
359 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
360 val = wmem_strdup_printf(NULL, "%f", lat);
361 c = strchr(val, ',');
362 if (c != NULL) *c = '.';
368 case WS_LON_FAKE_EDITION:
373 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
374 val = wmem_strdup_printf(NULL, "%f", lon);
375 c = strchr(val, ',');
376 if (c != NULL) *c = '.';
388 if (not_found == NULL)
391 return wmem_strdup(NULL, not_found);
400 #if NUM_DB_TYPES > 31 /* 1.4.7 */
401 geoip_db_lookup_latlon6(geoipv6_t addr, float *lat, float *lon) {
406 for (i = 0; i < geoip_db_num_dbs(); i++) {
407 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
409 switch (gi->databaseType) {
410 case GEOIP_CITY_EDITION_REV0_V6:
411 case GEOIP_CITY_EDITION_REV1_V6:
412 gir = GeoIP_record_by_ipnum_v6(gi, addr);
414 *lat = gir->latitude;
415 *lon = gir->longitude;
428 #else /* NUM_DB_TYPES */
429 geoip_db_lookup_latlon6(geoipv6_t addr _U_, float *lat _U_, float *lon _U_) {
432 #endif /* NUM_DB_TYPES */
435 geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found) {
439 char *val, *ret = NULL;
440 #if NUM_DB_TYPES > 31
443 if (dbnum > geoip_db_num_dbs()) {
444 if (not_found == NULL)
447 return wmem_strdup(NULL, not_found);
450 memcpy(&gaddr, &addr, sizeof(addr));
452 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
454 switch (gi->databaseType) {
455 case GEOIP_COUNTRY_EDITION_V6:
456 raw_val = GeoIP_country_name_by_ipnum_v6(gi, gaddr);
458 ret = db_val_to_utf_8(raw_val, gi);
462 #if NUM_DB_TYPES > 31
463 case GEOIP_CITY_EDITION_REV0_V6:
464 case GEOIP_CITY_EDITION_REV1_V6:
465 gir = GeoIP_record_by_ipnum_v6(gi, gaddr);
466 if (gir && gir->city && gir->region) {
467 val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region);
468 ret = db_val_to_utf_8(val, gi);
469 wmem_free(NULL, val);
470 } else if (gir && gir->city) {
471 ret = db_val_to_utf_8(gir->city, gi);
475 case GEOIP_ORG_EDITION_V6:
476 case GEOIP_ISP_EDITION_V6:
477 case GEOIP_ASNUM_EDITION_V6:
478 raw_val = GeoIP_name_by_ipnum_v6(gi, gaddr);
480 ret = db_val_to_utf_8(raw_val, gi);
483 #endif /* NUM_DB_TYPES */
485 case WS_LAT_FAKE_EDITION:
490 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
491 val = wmem_strdup_printf(NULL, "%f", lat);
492 c = strchr(val, ',');
493 if (c != NULL) *c = '.';
499 case WS_LON_FAKE_EDITION:
504 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
505 val = wmem_strdup_printf(NULL, "%f", lon);
506 c = strchr(val, ',');
507 if (c != NULL) *c = '.';
519 if (not_found == NULL)
522 return wmem_strdup(NULL, not_found);
528 #else /* HAVE_GEOIP_V6 */
531 geoip_db_lookup_ipv6(guint dbnum _U_, struct e_in6_addr addr _U_, const char *not_found) {
532 if (not_found == NULL)
535 return wmem_strdup(NULL, not_found);
538 #endif /* HAVE_GEOIP_V6 */
541 geoip_db_get_paths(void) {
542 GString* path_str = NULL;
546 path_str = g_string_new("");
548 path_separator = ';';
550 path_separator = ':';
553 for (i = 0; i < num_geoip_db_paths; i++) {
554 if (geoip_db_paths[i].path) {
555 g_string_append_printf(path_str, "%s%c", geoip_db_paths[i].path, path_separator);
559 g_string_truncate(path_str, path_str->len-1);
561 return g_string_free(path_str, FALSE);
564 #else /* HAVE_GEOIP */
566 geoip_db_num_dbs(void) {
571 geoip_db_name(guint dbnum _U_) {
572 return "Unsupported";
576 geoip_db_type(guint dbnum _U_) {
581 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
582 if (not_found == NULL)
585 return (char *)wmem_strdup(NULL, not_found);
589 geoip_db_lookup_ipv6(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
590 if (not_found == NULL)
593 return (char *)wmem_strdup(NULL, not_found);
597 geoip_db_get_paths(void) {
601 #endif /* HAVE_GEOIP */
609 * indent-tabs-mode: nil
612 * ex: set shiftwidth=4 tabstop=8 expandtab:
613 * :indentSize=4:tabSize=8:noTabs=true: