2 * GeoIP database support
4 * Copyright 2008, Gerald Combs <gerald@wireshark.org>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 * We currently return a single string for each database. Some databases,
29 * e.g. GeoIPCity, can return other info such as area codes.
40 #include "GeoIPCity.h"
45 #include "report_err.h"
46 #include "value_string.h"
47 #include <wsutil/file_util.h>
49 /* This needs to match NUM_GEOIP_COLS in hostlist_table.h */
50 #define MAX_GEOIP_DBS 13
52 /* Column names for each database type */
53 value_string geoip_type_name_vals[] = {
54 { GEOIP_COUNTRY_EDITION, "Country" },
55 { GEOIP_REGION_EDITION_REV0, "Region" },
56 { GEOIP_CITY_EDITION_REV0, "City"},
57 { GEOIP_ORG_EDITION, "Organization" },
58 { GEOIP_ISP_EDITION, "ISP" },
59 { GEOIP_CITY_EDITION_REV1, "City" },
60 { GEOIP_REGION_EDITION_REV1, "Region" },
61 { GEOIP_PROXY_EDITION, "Proxy" },
62 { GEOIP_ASNUM_EDITION, "AS Number" },
63 { GEOIP_NETSPEED_EDITION, "Speed" },
64 { GEOIP_DOMAIN_EDITION, "Domain" },
65 #ifdef GEOIP_COUNTRY_EDITION_V6
66 { GEOIP_COUNTRY_EDITION_V6, "Country" },
68 { WS_LAT_FAKE_EDITION, "Latitude" }, /* fake database */
69 { WS_LON_FAKE_EDITION, "Longitude" }, /* fake database */
73 static GArray *geoip_dat_arr = NULL;
75 /* UAT definitions. Copied from oids.c */
76 typedef struct _geoip_db_path_t {
80 static geoip_db_path_t *geoip_db_paths = NULL;
81 static guint num_geoip_db_paths = 0;
82 static uat_t *geoip_db_paths_uat = NULL;
83 UAT_CSTRING_CB_DEF(geoip_mod, path, geoip_db_path_t)
87 * Scan a directory for GeoIP databases and load them
90 geoip_dat_scan_dir(const char *dirname) {
97 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) {
98 while ((file = ws_dir_read_name(dir)) != NULL) {
99 name = ws_dir_get_name(file);
100 if (g_str_has_prefix(file, "Geo") && g_str_has_suffix(file, ".dat")) {
101 datname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name);
102 gi = GeoIP_open(datname, GEOIP_MEMORY_CACHE);
104 g_array_append_val(geoip_dat_arr, gi);
113 static void* geoip_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) {
114 const geoip_db_path_t *m = orig;
115 geoip_db_path_t *d = dest;
117 d->path = g_strdup(m->path);
122 static void geoip_db_path_free_cb(void* p) {
123 geoip_db_path_t *m = p;
128 * Initialize GeoIP lookups
131 geoip_db_init(void) {
133 static uat_field_t geoip_db_paths_fields[] = {
134 UAT_FLD_PATHNAME(geoip_mod, path, "Database pathname", "The database path"),
137 char* geoip_load_error = NULL;
139 geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
141 geoip_db_paths_uat = uat_new("GeoIP Database Paths",
142 sizeof(geoip_db_path_t),
145 (void*)&geoip_db_paths,
149 geoip_db_path_copy_cb,
151 geoip_db_path_free_cb,
153 geoip_db_paths_fields);
155 uat_load(geoip_db_paths_uat, &geoip_load_error);
157 if (geoip_load_error) {
158 report_failure("Error loading GeoIP database path table: %s", geoip_load_error);
162 for (i = 0; i < num_geoip_db_paths; i++) {
163 if (geoip_db_paths[i].path) {
164 geoip_dat_scan_dir(geoip_db_paths[i].path);
168 /* add fake databases for latitude and longitude (using "City" in reality) */
173 gi_lat = g_malloc(sizeof (GeoIP));
174 gi_lat->databaseType = WS_LAT_FAKE_EDITION;
175 g_array_append_val(geoip_dat_arr, gi_lat);
176 gi_lon = g_malloc(sizeof (GeoIP));
177 gi_lon->databaseType = WS_LON_FAKE_EDITION;
178 g_array_append_val(geoip_dat_arr, gi_lon);
183 geoip_db_num_dbs(void) {
184 return geoip_dat_arr->len;
188 geoip_db_name(guint dbnum) {
191 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
193 return (val_to_str(gi->databaseType, geoip_type_name_vals, "Unknown database"));
195 return "Invalid database";
199 geoip_db_type(guint dbnum) {
202 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
204 return (gi->databaseType);
210 geoip_db_lookup_latlon(guint32 addr, float *lat, float *lon) {
215 for (i = 0; i < geoip_db_num_dbs(); i++) {
216 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
218 switch (gi->databaseType) {
219 case GEOIP_CITY_EDITION_REV0:
220 case GEOIP_CITY_EDITION_REV1:
221 gir = GeoIP_record_by_ipnum(gi, addr);
223 *lat = gir->latitude;
224 *lon = gir->longitude;
238 #define VAL_STR_LEN 100
240 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, char *not_found) {
243 const char *ret = not_found;
244 static char val[VAL_STR_LEN];
246 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
248 switch (gi->databaseType) {
249 case GEOIP_COUNTRY_EDITION:
250 ret = GeoIP_country_name_by_ipnum(gi, addr);
253 case GEOIP_CITY_EDITION_REV0:
254 case GEOIP_CITY_EDITION_REV1:
255 gir = GeoIP_record_by_ipnum(gi, addr);
256 if (gir && gir->city && gir->region) {
257 g_snprintf(val, VAL_STR_LEN, "%s, %s", gir->city, gir->region);
259 } else if (gir && gir->city) {
260 g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
265 case GEOIP_ORG_EDITION:
266 case GEOIP_ISP_EDITION:
267 case GEOIP_ASNUM_EDITION:
268 ret = GeoIP_name_by_ipnum(gi, addr);
271 case WS_LAT_FAKE_EDITION:
276 if(geoip_db_lookup_latlon(addr, &lat, &lon) == 0) {
277 g_snprintf(val, VAL_STR_LEN, "%f", lat);
278 c = strchr(val, ',');
279 if (c != NULL) *c = '.';
285 case WS_LON_FAKE_EDITION:
290 if(geoip_db_lookup_latlon(addr, &lat, &lon) == 0) {
291 g_snprintf(val, VAL_STR_LEN, "%f", lon);
292 c = strchr(val, ',');
293 if (c != NULL) *c = '.';
310 geoip_db_get_paths(void) {
311 GString* path_str = NULL;
316 path_str = g_string_new("");
318 path_separator = ';';
320 path_separator = ':';
323 for (i = 0; i < num_geoip_db_paths; i++) {
324 if (geoip_db_paths[i].path) {
325 g_string_append_printf(path_str, "%s%c", geoip_db_paths[i].path, path_separator);
329 g_string_truncate(path_str, path_str->len-1);
330 path_ret = path_str->str;
331 g_string_free(path_str, FALSE);
336 #else /* HAVE_GEOIP */
338 geoip_db_init(void) {}
341 geoip_db_num_dbs(void) {
346 geoip_db_name(guint dbnum _U_) {
347 return "Unsupported";
351 geoip_db_type(guint dbnum _U_) {
356 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, char *not_found) {
361 geoip_db_get_paths(void) {
365 #endif /* HAVE_GEOIP */
373 * indent-tabs-mode: t
376 * ex: set shiftwidth=4 tabstop=4 noexpandtab
377 * :indentSize=4:tabSize=4:noTabs=false: