MSWSP: parse_CColumnGroupArray() etc.
[wireshark-wip.git] / epan / geoip_db.c
blobc591a0f75bd1dfe3e2c347af3c9883a75b1a34d5
1 /* geoip_db.c
2 * GeoIP database support
4 * Copyright 2008, Gerald Combs <gerald@wireshark.org>
6 * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 /* To do:
28 * We currently return a single string for each database. Some databases,
29 * e.g. GeoIPCity, can return other info such as area codes.
32 #include "config.h"
34 #include <glib.h>
36 #ifdef HAVE_GEOIP
37 #include <GeoIP.h>
38 #include <GeoIPCity.h>
40 #include "geoip_db.h"
41 #include "uat.h"
42 #include "prefs.h"
43 #include "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" },
64 #ifdef HAVE_GEOIP_V6
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 */
81 { 0, NULL }
84 static GArray *geoip_dat_arr = NULL;
86 /* UAT definitions. Copied from oids.c */
87 typedef struct _geoip_db_path_t {
88 char* path;
89 } 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)
97 /**
98 * Scan a directory for GeoIP databases and load them
100 static void
101 geoip_dat_scan_dir(const char *dirname) {
102 WS_DIR *dir;
103 WS_DIRENT *file;
104 const char *name;
105 char *datname;
106 GeoIP *gi;
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);
114 if (gi) {
115 g_array_append_val(geoip_dat_arr, gi);
117 g_free(datname);
120 ws_dir_close (dir);
124 /* UAT callbacks */
125 static void* geoip_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) {
126 const geoip_db_path_t *m = (geoip_db_path_t *)orig;
127 geoip_db_path_t *d = (geoip_db_path_t *)dest;
129 d->path = g_strdup(m->path);
131 return d;
134 static void geoip_db_path_free_cb(void* p) {
135 geoip_db_path_t *m = (geoip_db_path_t *)p;
136 g_free(m->path);
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) {
142 GeoIP *gi;
143 guint i;
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. */
148 if (geoip_dat_arr) {
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);
152 if (gi) {
153 GeoIP_delete(gi);
156 /* don't use GeoIP_delete() on the two fake
157 * databases as they weren't created by GeoIP_new()
158 * or GeoIP_open() */
159 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
160 if (gi) {
161 g_free(gi);
163 gi = g_array_index(geoip_dat_arr, GeoIP *, i+1);
164 if (gi) {
165 g_free(gi);
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) */
184 /* latitude */
185 gi = (GeoIP *)g_malloc(sizeof (GeoIP));
186 gi->databaseType = WS_LAT_FAKE_EDITION;
187 g_array_append_val(geoip_dat_arr, gi);
189 /* longitude */
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
198 void
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"),
203 UAT_END_FIELDS
206 geoip_db_paths_uat = uat_new("GeoIP Database Paths",
207 sizeof(geoip_db_path_t),
208 "geoip_db_paths",
209 FALSE,
210 (void**)&geoip_db_paths,
211 &num_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,
215 "ChGeoIPDbPaths",
216 geoip_db_path_copy_cb,
217 NULL,
218 geoip_db_path_free_cb,
219 geoip_db_post_update_cb,
220 geoip_db_paths_fields);
222 prefs_register_uat_preference(nameres,
223 "geoip_db_paths",
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\".",
228 geoip_db_paths_uat);
231 void
232 geoip_db_init(void) {
233 guint i;
235 geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
237 for (i = 0; i < num_geoip_db_paths; i++) {
238 if (geoip_db_paths[i].path) {
239 geoip_dat_scan_dir(geoip_db_paths[i].path);
243 /* add fake databases for latitude and longitude (using "City" in reality) */
245 GeoIP *gi_lat;
246 GeoIP *gi_lon;
248 gi_lat = (GeoIP *)g_malloc(sizeof (GeoIP));
249 gi_lat->databaseType = WS_LAT_FAKE_EDITION;
250 g_array_append_val(geoip_dat_arr, gi_lat);
251 gi_lon = (GeoIP *)g_malloc(sizeof (GeoIP));
252 gi_lon->databaseType = WS_LON_FAKE_EDITION;
253 g_array_append_val(geoip_dat_arr, gi_lon);
257 guint
258 geoip_db_num_dbs(void) {
259 return geoip_dat_arr->len;
262 const gchar *
263 geoip_db_name(guint dbnum) {
264 GeoIP *gi;
266 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
267 if (gi) {
268 return (val_to_str_const(gi->databaseType, geoip_type_name_vals, "Unknown database"));
270 return "Invalid database";
274 geoip_db_type(guint dbnum) {
275 GeoIP *gi;
277 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
278 if (gi) {
279 return (gi->databaseType);
281 return -1;
284 static int
285 geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) {
286 GeoIP *gi;
287 GeoIPRecord *gir;
288 guint i;
290 for (i = 0; i < geoip_db_num_dbs(); i++) {
291 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
292 if (gi) {
293 switch (gi->databaseType) {
294 case GEOIP_CITY_EDITION_REV0:
295 case GEOIP_CITY_EDITION_REV1:
296 gir = GeoIP_record_by_ipnum(gi, addr);
297 if(gir) {
298 *lat = gir->latitude;
299 *lon = gir->longitude;
300 return 0;
302 return -1;
303 /*break;*/
305 default:
306 break;
310 return -1;
313 #define VAL_STR_LEN 100
316 * GeoIP 1.4.3 and later provide GeoIP_set_charset(), but in versions
317 * 1.4.3 to 1.4.6 that only applies to the City databases. I.e., it's
318 * possible to produce invalid UTF-8 sequences even if GeoIP_set_charset()
319 * is used.
321 static void
322 iso_8859_1_to_utf_8(char *val) {
323 char *utf8_val;
325 utf8_val = g_convert(val, VAL_STR_LEN, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
326 if (utf8_val) {
327 g_strlcpy(val, utf8_val, VAL_STR_LEN);
328 g_free(utf8_val);
333 const char *
334 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
335 GeoIP *gi;
336 GeoIPRecord *gir;
337 const char *raw_val, *ret = not_found;
338 static char val[VAL_STR_LEN];
340 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
341 if (gi) {
342 switch (gi->databaseType) {
343 case GEOIP_COUNTRY_EDITION:
344 raw_val = GeoIP_country_name_by_ipnum(gi, addr);
345 if (raw_val) {
346 g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
347 iso_8859_1_to_utf_8(val);
348 ret = val;
350 break;
352 case GEOIP_CITY_EDITION_REV0:
353 case GEOIP_CITY_EDITION_REV1:
354 gir = GeoIP_record_by_ipnum(gi, addr);
355 if (gir && gir->city && gir->region) {
356 g_snprintf(val, VAL_STR_LEN, "%s, %s", gir->city, gir->region);
357 iso_8859_1_to_utf_8(val);
358 ret = val;
359 } else if (gir && gir->city) {
360 g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
361 iso_8859_1_to_utf_8(val);
362 ret = val;
364 break;
366 case GEOIP_ORG_EDITION:
367 case GEOIP_ISP_EDITION:
368 case GEOIP_ASNUM_EDITION:
369 raw_val = GeoIP_name_by_ipnum(gi, addr);
370 if (raw_val) {
371 g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
372 iso_8859_1_to_utf_8(val);
373 ret = val;
375 break;
377 case WS_LAT_FAKE_EDITION:
379 float lat;
380 float lon;
381 char *c;
382 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
383 g_snprintf(val, VAL_STR_LEN, "%f", lat);
384 c = strchr(val, ',');
385 if (c != NULL) *c = '.';
386 ret = val;
389 break;
391 case WS_LON_FAKE_EDITION:
393 float lat;
394 float lon;
395 char *c;
396 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
397 g_snprintf(val, VAL_STR_LEN, "%f", lon);
398 c = strchr(val, ',');
399 if (c != NULL) *c = '.';
400 ret = val;
403 break;
405 default:
406 break;
409 return ret;
412 #ifdef HAVE_GEOIP_V6
414 static int
415 #if NUM_DB_TYPES > 31 /* 1.4.7 */
416 geoip_db_lookup_latlon6(geoipv6_t addr, float *lat, float *lon) {
417 GeoIP *gi;
418 GeoIPRecord *gir;
419 guint i;
421 for (i = 0; i < geoip_db_num_dbs(); i++) {
422 gi = g_array_index(geoip_dat_arr, GeoIP *, i);
423 if (gi) {
424 switch (gi->databaseType) {
425 case GEOIP_CITY_EDITION_REV0_V6:
426 case GEOIP_CITY_EDITION_REV1_V6:
427 gir = GeoIP_record_by_ipnum_v6(gi, addr);
428 if(gir) {
429 *lat = gir->latitude;
430 *lon = gir->longitude;
431 return 0;
433 return -1;
434 /*break;*/
436 default:
437 break;
441 return -1;
443 #else /* NUM_DB_TYPES */
444 geoip_db_lookup_latlon6(geoipv6_t addr _U_, float *lat _U_, float *lon _U_) {
445 return -1;
447 #endif /* NUM_DB_TYPES */
449 const char *
450 geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found) {
451 GeoIP *gi;
452 geoipv6_t gaddr;
453 const char *raw_val, *ret = not_found;
454 static char val[VAL_STR_LEN];
455 #if NUM_DB_TYPES > 31
456 GeoIPRecord *gir;
457 #endif
459 memcpy(&gaddr, &addr, sizeof(addr));
461 gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
462 if (gi) {
463 switch (gi->databaseType) {
464 case GEOIP_COUNTRY_EDITION_V6:
465 raw_val = GeoIP_country_name_by_ipnum_v6(gi, gaddr);
466 if (raw_val) {
467 g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
468 iso_8859_1_to_utf_8(val);
469 ret = val;
471 break;
473 #if NUM_DB_TYPES > 31
474 case GEOIP_CITY_EDITION_REV0_V6:
475 case GEOIP_CITY_EDITION_REV1_V6:
476 gir = GeoIP_record_by_ipnum_v6(gi, gaddr);
477 if (gir && gir->city && gir->region) {
478 g_snprintf(val, VAL_STR_LEN, "%s, %s", gir->city, gir->region);
479 iso_8859_1_to_utf_8(val);
480 ret = val;
481 } else if (gir && gir->city) {
482 g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
483 iso_8859_1_to_utf_8(val);
484 ret = val;
486 break;
488 case GEOIP_ORG_EDITION_V6:
489 case GEOIP_ISP_EDITION_V6:
490 case GEOIP_ASNUM_EDITION_V6:
491 raw_val = GeoIP_name_by_ipnum_v6(gi, gaddr);
492 if (raw_val) {
493 g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
494 iso_8859_1_to_utf_8(val);
495 ret = val;
497 break;
498 #endif /* NUM_DB_TYPES */
500 case WS_LAT_FAKE_EDITION:
502 float lat;
503 float lon;
504 char *c;
505 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
506 g_snprintf(val, VAL_STR_LEN, "%f", lat);
507 c = strchr(val, ',');
508 if (c != NULL) *c = '.';
509 ret = val;
512 break;
514 case WS_LON_FAKE_EDITION:
516 float lat;
517 float lon;
518 char *c;
519 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
520 g_snprintf(val, VAL_STR_LEN, "%f", lon);
521 c = strchr(val, ',');
522 if (c != NULL) *c = '.';
523 ret = val;
526 break;
528 default:
529 break;
532 return ret;
535 #else /* HAVE_GEOIP_V6 */
537 const char *
538 geoip_db_lookup_ipv6(guint dbnum _U_, struct e_in6_addr addr _U_, const char *not_found) {
539 return not_found;
542 #endif /* HAVE_GEOIP_V6 */
544 gchar *
545 geoip_db_get_paths(void) {
546 GString* path_str = NULL;
547 gchar *path_ret;
548 char path_separator;
549 guint i;
551 path_str = g_string_new("");
552 #ifdef _WIN32
553 path_separator = ';';
554 #else
555 path_separator = ':';
556 #endif
558 for (i = 0; i < num_geoip_db_paths; i++) {
559 if (geoip_db_paths[i].path) {
560 g_string_append_printf(path_str, "%s%c", geoip_db_paths[i].path, path_separator);
564 g_string_truncate(path_str, path_str->len-1);
565 path_ret = path_str->str;
566 g_string_free(path_str, FALSE);
568 return path_ret;
571 #else /* HAVE_GEOIP */
572 void
573 geoip_db_init(void) {}
575 guint
576 geoip_db_num_dbs(void) {
577 return 0;
580 const gchar *
581 geoip_db_name(guint dbnum _U_) {
582 return "Unsupported";
586 geoip_db_type(guint dbnum _U_) {
587 return -1;
590 const char *
591 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
592 return not_found;
595 const char *
596 geoip_db_lookup_ipv6(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
597 return not_found;
600 gchar *
601 geoip_db_get_paths(void) {
602 return g_strdup("");
605 #endif /* HAVE_GEOIP */
608 * Editor modelines
610 * Local Variables:
611 * c-basic-offset: 4
612 * tab-width: 8
613 * indent-tabs-mode: nil
614 * End:
616 * ex: set shiftwidth=4 tabstop=8 expandtab:
617 * :indentSize=4:tabSize=8:noTabs=true: