Add a ws_in6_addr typedef for struct e_in6_addr.
[metze/wireshark/wip.git] / epan / geoip_db.c
1 /* geoip_db.c
2  * GeoIP database support
3  *
4  * Copyright 2008, Gerald Combs <gerald@wireshark.org>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 /* To do:
26  * We currently return a single string for each database. Some databases,
27  * e.g. GeoIPCity, can return other info such as area codes.
28  */
29
30 #include "config.h"
31
32 #include <glib.h>
33
34 #include <epan/wmem/wmem.h>
35
36 #ifdef HAVE_GEOIP
37 #include <GeoIP.h>
38 #include <GeoIPCity.h>
39
40 #include <epan/geoip_db.h>
41 #include <epan/uat.h>
42 #include <epan/prefs.h>
43 #include <epan/value_string.h>
44
45 #include <wsutil/report_message.h>
46 #include <wsutil/file_util.h>
47
48 /* This needs to match NUM_GEOIP_COLS in hostlist_table.h */
49 #define MAX_GEOIP_DBS 13
50
51 #ifndef HAVE_GEOIP_FREE
52 #define GeoIP_free  free
53 #endif
54
55 /* Column names for each database type */
56 value_string geoip_type_name_vals[] = {
57     { GEOIP_COUNTRY_EDITION,        "Country" },
58     { GEOIP_REGION_EDITION_REV0,    "Region" },
59     { GEOIP_CITY_EDITION_REV0,      "City"},
60     { GEOIP_ORG_EDITION,            "Organization" },
61     { GEOIP_ISP_EDITION,            "ISP" },
62     { GEOIP_CITY_EDITION_REV1,      "City" },
63     { GEOIP_REGION_EDITION_REV1,    "Region" },
64     { GEOIP_PROXY_EDITION,          "Proxy" },
65     { GEOIP_ASNUM_EDITION,          "AS Number" },
66     { GEOIP_NETSPEED_EDITION,       "Speed" },
67     { GEOIP_DOMAIN_EDITION,         "Domain" },
68 #ifdef HAVE_GEOIP_V6
69     { GEOIP_COUNTRY_EDITION_V6,     "Country" },
70 /* This is the closest thing to a version that GeoIP.h seems to provide. */
71 #if NUM_DB_TYPES > 31 /* 1.4.7 */
72     { GEOIP_CITY_EDITION_REV0_V6,   "City"},
73     { GEOIP_CITY_EDITION_REV1_V6,   "City"},
74     { GEOIP_ASNUM_EDITION_V6,       "AS Number" },
75     { GEOIP_ISP_EDITION_V6,         "ISP" },
76     { GEOIP_ORG_EDITION_V6,         "Organization" },
77     { GEOIP_DOMAIN_EDITION_V6,      "Domain" },
78 #endif /* NUM_DB_TYPES > 31 */
79 #if NUM_DB_TYPES > 32 /* 1.4.8 */
80     { GEOIP_NETSPEED_EDITION_REV1_V6, "Speed" },
81 #endif /* NUM_DB_TYPES > 32 */
82 #endif /* HAVE_GEOIP_V6 */
83     { WS_LAT_FAKE_EDITION,          "Latitude" },   /* fake database */
84     { WS_LON_FAKE_EDITION,          "Longitude" },  /* fake database */
85     { 0, NULL }
86 };
87
88 static GArray *geoip_dat_arr = NULL;
89
90 /* UAT definitions. Copied from oids.c */
91 typedef struct _geoip_db_path_t {
92     char* path;
93 } geoip_db_path_t;
94
95 static geoip_db_path_t *geoip_db_paths = NULL;
96 static guint num_geoip_db_paths = 0;
97 static const geoip_db_path_t geoip_db_system_paths[] = {
98 #ifdef G_OS_UNIX
99     { "/usr/share/GeoIP" },
100 #endif
101     { NULL }
102 };
103 static uat_t *geoip_db_paths_uat = NULL;
104 UAT_DIRECTORYNAME_CB_DEF(geoip_mod, path, geoip_db_path_t)
105
106
107 /**
108  * Scan a directory for GeoIP databases and load them
109  */
110 static void
111 geoip_dat_scan_dir(const char *dirname) {
112     WS_DIR *dir;
113     WS_DIRENT *file;
114     const char *name;
115     char *datname;
116     GeoIP *gi;
117
118     if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) {
119         while ((file = ws_dir_read_name(dir)) != NULL) {
120             name = ws_dir_get_name(file);
121             if (g_str_has_prefix(file, "Geo") && g_str_has_suffix(file, ".dat")) {
122                 datname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name);
123                 gi = GeoIP_open(datname, GEOIP_MEMORY_CACHE);
124                 if (gi) {
125                     g_array_append_val(geoip_dat_arr, gi);
126                 }
127                 g_free(datname);
128             }
129         }
130         ws_dir_close (dir);
131     }
132 }
133
134 /* UAT callbacks */
135 static void* geoip_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) {
136     const geoip_db_path_t *m = (const geoip_db_path_t *)orig;
137     geoip_db_path_t *d = (geoip_db_path_t *)dest;
138
139     d->path = g_strdup(m->path);
140
141     return d;
142 }
143
144 static void geoip_db_path_free_cb(void* p) {
145     geoip_db_path_t *m = (geoip_db_path_t *)p;
146     g_free(m->path);
147 }
148
149 static void geoip_dat_cleanup(void) {
150     GeoIP *gi;
151     guint i;
152
153     /* If we have old data, clear out the whole thing
154      * and start again. TODO: Just update the ones that
155      * have changed for efficiency's sake. */
156     if (geoip_dat_arr) {
157         /* skip the last two, as they are fake */
158         for (i = 0; i < geoip_db_num_dbs() - 2; i++) {
159             gi = g_array_index(geoip_dat_arr, GeoIP *, i);
160             if (gi) {
161                 GeoIP_delete(gi);
162             }
163         }
164         /* don't use GeoIP_delete() on the two fake
165          * databases as they weren't created by GeoIP_new()
166          * or GeoIP_open() */
167         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
168         g_free(gi);
169         gi = g_array_index(geoip_dat_arr, GeoIP *, i+1);
170         g_free(gi);
171         /* finally, free the array itself */
172         g_array_free(geoip_dat_arr, TRUE);
173         geoip_dat_arr = NULL;
174     }
175 }
176
177 /* called every time the user presses "Apply" or "OK in the list of
178  * GeoIP directories, and also once on startup */
179 static void geoip_db_post_update_cb(void) {
180     guint i;
181     GeoIP* gi;
182
183     geoip_dat_cleanup();
184
185     /* allocate the array */
186     geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
187
188     /* First try the system paths */
189     for (i = 0; geoip_db_system_paths[i].path != NULL; i++) {
190         geoip_dat_scan_dir(geoip_db_system_paths[i].path);
191     }
192
193     /* Walk all the directories */
194     for (i = 0; i < num_geoip_db_paths; i++) {
195         if (geoip_db_paths[i].path) {
196             geoip_dat_scan_dir(geoip_db_paths[i].path);
197         }
198     }
199
200     /* add fake databases for latitude and longitude
201      * (using "City" in reality) */
202
203     /* latitude */
204     gi = (GeoIP *)g_malloc(sizeof (GeoIP));
205     gi->databaseType = WS_LAT_FAKE_EDITION;
206     g_array_append_val(geoip_dat_arr, gi);
207
208     /* longitude */
209     gi = (GeoIP *)g_malloc(sizeof (GeoIP));
210     gi->databaseType = WS_LON_FAKE_EDITION;
211     g_array_append_val(geoip_dat_arr, gi);
212 }
213
214 static void geoip_db_cleanup(void)
215 {
216     geoip_dat_cleanup();
217 }
218
219 /**
220  * Initialize GeoIP lookups
221  */
222 void
223 geoip_db_pref_init(module_t *nameres)
224 {
225     static uat_field_t geoip_db_paths_fields[] = {
226         UAT_FLD_DIRECTORYNAME(geoip_mod, path, "GeoIP Database Directory", "The GeoIP database directory path"),
227         UAT_END_FIELDS
228     };
229
230     geoip_db_paths_uat = uat_new("GeoIP Database Paths",
231             sizeof(geoip_db_path_t),
232             "geoip_db_paths",
233             FALSE,
234             (void**)&geoip_db_paths,
235             &num_geoip_db_paths,
236             /* affects dissection of packets (as the GeoIP database is
237                used when dissecting), but not set of named fields */
238             UAT_AFFECTS_DISSECTION,
239             "ChGeoIPDbPaths",
240             geoip_db_path_copy_cb,
241             NULL,
242             geoip_db_path_free_cb,
243             geoip_db_post_update_cb,
244             geoip_db_cleanup,
245             geoip_db_paths_fields);
246
247     prefs_register_uat_preference(nameres,
248             "geoip_db_paths",
249             "GeoIP database directories",
250             "Search paths for GeoIP address mapping databases."
251             " Wireshark will look in each directory for files beginning"
252             " with \"Geo\" and ending with \".dat\".",
253             geoip_db_paths_uat);
254 }
255
256 guint
257 geoip_db_num_dbs(void) {
258     return (geoip_dat_arr == NULL) ? 0 : geoip_dat_arr->len;
259 }
260
261 const gchar *
262 geoip_db_name(guint dbnum) {
263     GeoIP *gi;
264
265     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
266     if (gi) {
267         return (val_to_str_const(gi->databaseType, geoip_type_name_vals, "Unknown database"));
268     }
269     return "Invalid database";
270 }
271
272 int
273 geoip_db_type(guint dbnum) {
274     GeoIP *gi;
275
276     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
277     if (gi) {
278         return (gi->databaseType);
279     }
280     return -1;
281 }
282
283 static int
284 geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) {
285     GeoIP *gi;
286     GeoIPRecord *gir;
287     guint i;
288
289     for (i = 0; i < geoip_db_num_dbs(); i++) {
290         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
291         if (gi) {
292             switch (gi->databaseType) {
293                 case GEOIP_CITY_EDITION_REV0:
294                 case GEOIP_CITY_EDITION_REV1:
295                     gir = GeoIP_record_by_ipnum(gi, addr);
296                     if (gir) {
297                         *lat = gir->latitude;
298                         *lon = gir->longitude;
299                         GeoIPRecord_delete(gir);
300                         return 0;
301                     }
302                     return -1;
303                     /*break;*/
304
305                 default:
306                     break;
307             }
308         }
309     }
310     return -1;
311 }
312
313 /*
314  * GeoIP 1.4.3 and later provide GeoIP_set_charset(), but in versions
315  * 1.4.3 to 1.4.6 that only applies to the City databases. I.e., it's
316  * possible to produce invalid UTF-8 sequences even if GeoIP_set_charset()
317  * is used.
318  */
319
320 /* Ensure that a given db value is UTF-8 */
321 static char *
322 db_val_to_utf_8(const char *val, GeoIP *gi) {
323
324     if (GeoIP_charset(gi) == GEOIP_CHARSET_ISO_8859_1) {
325         char *utf8_val;
326         utf8_val = g_convert(val, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
327         if (utf8_val) {
328             char *ret_val = wmem_strdup(NULL, utf8_val);
329             g_free(utf8_val);
330             return ret_val;
331         }
332     }
333     return wmem_strdup(NULL, val);
334 }
335
336 char *
337 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
338     GeoIP *gi;
339     GeoIPRecord *gir;
340     char *name;
341     const char *country;
342     char *val, *ret = NULL;
343
344     if (dbnum > geoip_db_num_dbs()) {
345         if (not_found == NULL)
346             return NULL;
347
348         return wmem_strdup(NULL, not_found);
349     }
350     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
351     if (gi) {
352         switch (gi->databaseType) {
353             case GEOIP_COUNTRY_EDITION:
354                 country = GeoIP_country_name_by_ipnum(gi, addr);
355                 if (country) {
356                     ret = db_val_to_utf_8(country, gi);
357                 }
358                 break;
359
360             case GEOIP_CITY_EDITION_REV0:
361             case GEOIP_CITY_EDITION_REV1:
362                 gir = GeoIP_record_by_ipnum(gi, addr);
363                 if (gir && gir->city && gir->region) {
364                     val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region);
365                     ret = db_val_to_utf_8(val, gi);
366                     wmem_free(NULL, val);
367                 } else if (gir && gir->city) {
368                     ret = db_val_to_utf_8(gir->city, gi);
369                 }
370                 if (gir)
371                     GeoIPRecord_delete(gir);
372                 break;
373
374             case GEOIP_ORG_EDITION:
375             case GEOIP_ISP_EDITION:
376             case GEOIP_ASNUM_EDITION:
377                 name = GeoIP_name_by_ipnum(gi, addr);
378                 if (name) {
379                     ret = db_val_to_utf_8(name, gi);
380                     GeoIP_free(name);
381                 }
382                 break;
383
384             case WS_LAT_FAKE_EDITION:
385             {
386                 float lat;
387                 float lon;
388                 char *c;
389                 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
390                     val = wmem_strdup_printf(NULL, "%f", lat);
391                     c = strchr(val, ',');
392                     if (c != NULL) *c = '.';
393                     ret = val;
394                 }
395             }
396                 break;
397
398             case WS_LON_FAKE_EDITION:
399             {
400                 float lat;
401                 float lon;
402                 char *c;
403                 if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
404                     val = wmem_strdup_printf(NULL, "%f", lon);
405                     c = strchr(val, ',');
406                     if (c != NULL) *c = '.';
407                     ret = val;
408                 }
409             }
410                 break;
411
412             default:
413                 break;
414         }
415     }
416
417     if (ret == NULL) {
418         if (not_found == NULL)
419             return NULL;
420
421         return wmem_strdup(NULL, not_found);
422     }
423
424     return ret;
425 }
426
427 #ifdef HAVE_GEOIP_V6
428
429 static int
430 #if NUM_DB_TYPES > 31 /* 1.4.7 */
431 geoip_db_lookup_latlon6(geoipv6_t addr, float *lat, float *lon) {
432     GeoIP *gi;
433     GeoIPRecord *gir;
434     guint i;
435
436     for (i = 0; i < geoip_db_num_dbs(); i++) {
437         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
438         if (gi) {
439             switch (gi->databaseType) {
440                 case GEOIP_CITY_EDITION_REV0_V6:
441                 case GEOIP_CITY_EDITION_REV1_V6:
442                     gir = GeoIP_record_by_ipnum_v6(gi, addr);
443                     if(gir) {
444                         *lat = gir->latitude;
445                         *lon = gir->longitude;
446                         return 0;
447                     }
448                     return -1;
449                     /*break;*/
450
451                 default:
452                     break;
453             }
454         }
455     }
456     return -1;
457 }
458 #else /* NUM_DB_TYPES */
459 geoip_db_lookup_latlon6(geoipv6_t addr _U_, float *lat _U_, float *lon _U_) {
460     return -1;
461 }
462 #endif /* NUM_DB_TYPES */
463
464 char *
465 geoip_db_lookup_ipv6(guint dbnum, ws_in6_addr addr, const char *not_found) {
466     GeoIP *gi;
467     geoipv6_t gaddr;
468     char *name;
469     const char *country;
470     char *val, *ret = NULL;
471 #if NUM_DB_TYPES > 31
472     GeoIPRecord *gir;
473 #endif
474     if (dbnum > geoip_db_num_dbs()) {
475         if (not_found == NULL)
476             return NULL;
477
478         return wmem_strdup(NULL, not_found);
479     }
480
481     memcpy(&gaddr, &addr, sizeof(addr));
482
483     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
484     if (gi) {
485         switch (gi->databaseType) {
486             case GEOIP_COUNTRY_EDITION_V6:
487                 country = GeoIP_country_name_by_ipnum_v6(gi, gaddr);
488                 if (country) {
489                     ret = db_val_to_utf_8(country, gi);
490                 }
491                 break;
492
493 #if NUM_DB_TYPES > 31
494             case GEOIP_CITY_EDITION_REV0_V6:
495             case GEOIP_CITY_EDITION_REV1_V6:
496                 gir = GeoIP_record_by_ipnum_v6(gi, gaddr);
497                 if (gir && gir->city && gir->region) {
498                     val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region);
499                     ret = db_val_to_utf_8(val, gi);
500                     wmem_free(NULL, val);
501                 } else if (gir && gir->city) {
502                     ret = db_val_to_utf_8(gir->city, gi);
503                 }
504                 break;
505
506             case GEOIP_ORG_EDITION_V6:
507             case GEOIP_ISP_EDITION_V6:
508             case GEOIP_ASNUM_EDITION_V6:
509                 name = GeoIP_name_by_ipnum_v6(gi, gaddr);
510                 if (name) {
511                     ret = db_val_to_utf_8(name, gi);
512                     GeoIP_free(name);
513                 }
514                 break;
515 #endif /* NUM_DB_TYPES */
516
517             case WS_LAT_FAKE_EDITION:
518             {
519                 float lat;
520                 float lon;
521                 char *c;
522                 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
523                     val = wmem_strdup_printf(NULL, "%f", lat);
524                     c = strchr(val, ',');
525                     if (c != NULL) *c = '.';
526                     ret = val;
527                 }
528             }
529                 break;
530
531             case WS_LON_FAKE_EDITION:
532             {
533                 float lat;
534                 float lon;
535                 char *c;
536                 if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
537                     val = wmem_strdup_printf(NULL, "%f", lon);
538                     c = strchr(val, ',');
539                     if (c != NULL) *c = '.';
540                     ret = val;
541                 }
542             }
543                 break;
544
545             default:
546                 break;
547         }
548     }
549
550     if (ret == NULL) {
551         if (not_found == NULL)
552             return NULL;
553
554         return wmem_strdup(NULL, not_found);
555     }
556
557     return ret;
558 }
559
560 #else /* HAVE_GEOIP_V6 */
561
562 char *
563 geoip_db_lookup_ipv6(guint dbnum _U_, ws_in6_addr addr _U_, const char *not_found) {
564     if (not_found == NULL)
565         return NULL;
566
567     return wmem_strdup(NULL, not_found);
568 }
569
570 #endif /* HAVE_GEOIP_V6 */
571
572 gchar *
573 geoip_db_get_paths(void) {
574     GString* path_str = NULL;
575     guint i;
576
577     path_str = g_string_new("");
578
579     for (i = 0; geoip_db_system_paths[i].path != NULL; i++) {
580         g_string_append_printf(path_str,
581                 "%s" G_SEARCHPATH_SEPARATOR_S, geoip_db_system_paths[i].path);
582     }
583
584     for (i = 0; i < num_geoip_db_paths; i++) {
585         if (geoip_db_paths[i].path) {
586             g_string_append_printf(path_str,
587                     "%s" G_SEARCHPATH_SEPARATOR_S, geoip_db_paths[i].path);
588         }
589     }
590
591     g_string_truncate(path_str, path_str->len-1);
592
593     return g_string_free(path_str, FALSE);
594 }
595
596 #else /* HAVE_GEOIP */
597 guint
598 geoip_db_num_dbs(void) {
599     return 0;
600 }
601
602 const gchar *
603 geoip_db_name(guint dbnum _U_) {
604     return "Unsupported";
605 }
606
607 int
608 geoip_db_type(guint dbnum _U_) {
609     return -1;
610 }
611
612 char *
613 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
614     if (not_found == NULL)
615         return NULL;
616
617     return (char *)wmem_strdup(NULL, not_found);
618 }
619
620 char *
621 geoip_db_lookup_ipv6(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
622     if (not_found == NULL)
623         return NULL;
624
625     return (char *)wmem_strdup(NULL, not_found);
626 }
627
628 gchar *
629 geoip_db_get_paths(void) {
630     return g_strdup("");
631 }
632
633 #endif /* HAVE_GEOIP */
634
635 /*
636  * Editor modelines
637  *
638  * Local Variables:
639  * c-basic-offset: 4
640  * tab-width: 8
641  * indent-tabs-mode: nil
642  * End:
643  *
644  * ex: set shiftwidth=4 tabstop=8 expandtab:
645  * :indentSize=4:tabSize=8:noTabs=true:
646  */