MAX_MCS_INDEX is a valid array index.
[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_err.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 /* 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 }
82 };
83
84 static GArray *geoip_dat_arr = NULL;
85
86 /* UAT definitions. Copied from oids.c */
87 typedef struct _geoip_db_path_t {
88     char* path;
89 } geoip_db_path_t;
90
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)
95
96
97 /**
98  * Scan a directory for GeoIP databases and load them
99  */
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;
107
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);
116                 }
117                 g_free(datname);
118             }
119         }
120         ws_dir_close (dir);
121     }
122 }
123
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 = (const geoip_db_path_t *)orig;
127     geoip_db_path_t *d = (geoip_db_path_t *)dest;
128
129     d->path = g_strdup(m->path);
130
131     return d;
132 }
133
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);
137 }
138
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;
144
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);
154             }
155         }
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);
162         }
163         gi = g_array_index(geoip_dat_arr, GeoIP *, i+1);
164         if (gi) {
165             g_free(gi);
166         }
167         /* finally, free the array itself */
168         g_array_free(geoip_dat_arr, TRUE);
169     }
170
171     /* allocate the array */
172     geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
173
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);
178         }
179     }
180
181     /* add fake databases for latitude and longitude
182      * (using "City" in reality) */
183
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);
188
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);
193 }
194
195 /**
196  * Initialize GeoIP lookups
197  */
198 void
199 geoip_db_pref_init(module_t *nameres)
200 {
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
204     };
205
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);
221
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);
229 }
230
231 guint
232 geoip_db_num_dbs(void) {
233     return geoip_dat_arr->len;
234 }
235
236 const gchar *
237 geoip_db_name(guint dbnum) {
238     GeoIP *gi;
239
240     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
241     if (gi) {
242         return (val_to_str_const(gi->databaseType, geoip_type_name_vals, "Unknown database"));
243     }
244     return "Invalid database";
245 }
246
247 int
248 geoip_db_type(guint dbnum) {
249     GeoIP *gi;
250
251     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
252     if (gi) {
253         return (gi->databaseType);
254     }
255     return -1;
256 }
257
258 static int
259 geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) {
260     GeoIP *gi;
261     GeoIPRecord *gir;
262     guint i;
263
264     for (i = 0; i < geoip_db_num_dbs(); i++) {
265         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
266         if (gi) {
267             switch (gi->databaseType) {
268                 case GEOIP_CITY_EDITION_REV0:
269                 case GEOIP_CITY_EDITION_REV1:
270                     gir = GeoIP_record_by_ipnum(gi, addr);
271                     if(gir) {
272                         *lat = gir->latitude;
273                         *lon = gir->longitude;
274                         return 0;
275                     }
276                     return -1;
277                     /*break;*/
278
279                 default:
280                     break;
281             }
282         }
283     }
284     return -1;
285 }
286
287 /*
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()
291  * is used.
292  */
293
294 /* Ensure that a given db value is UTF-8 */
295 static char *
296 db_val_to_utf_8(const char *val, GeoIP *gi) {
297
298     if (GeoIP_charset(gi) == GEOIP_CHARSET_ISO_8859_1) {
299         char *utf8_val;
300         utf8_val = g_convert(val, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
301         if (utf8_val) {
302             char *ret_val = wmem_strdup(NULL, utf8_val);
303             g_free(utf8_val);
304             return ret_val;
305         }
306     }
307     return wmem_strdup(NULL, val);
308 }
309
310 char *
311 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
312     GeoIP *gi;
313     GeoIPRecord *gir;
314     const char *raw_val;
315     char *val, *ret = NULL;
316
317     if (dbnum > geoip_db_num_dbs()) {
318         if (not_found == NULL)
319             return NULL;
320
321         return wmem_strdup(NULL, not_found);
322     }
323     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
324     if (gi) {
325         switch (gi->databaseType) {
326             case GEOIP_COUNTRY_EDITION:
327                 raw_val = GeoIP_country_name_by_ipnum(gi, addr);
328                 if (raw_val) {
329                     ret = db_val_to_utf_8(raw_val, gi);
330                 }
331                 break;
332
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);
342                 }
343                 break;
344
345             case GEOIP_ORG_EDITION:
346             case GEOIP_ISP_EDITION:
347             case GEOIP_ASNUM_EDITION:
348                 raw_val = GeoIP_name_by_ipnum(gi, addr);
349                 if (raw_val) {
350                     ret = db_val_to_utf_8(raw_val, gi);
351                 }
352                 break;
353
354             case WS_LAT_FAKE_EDITION:
355             {
356                 float lat;
357                 float lon;
358                 char *c;
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 = '.';
363                     ret = val;
364                 }
365             }
366                 break;
367
368             case WS_LON_FAKE_EDITION:
369             {
370                 float lat;
371                 float lon;
372                 char *c;
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 = '.';
377                     ret = val;
378                 }
379             }
380                 break;
381
382             default:
383                 break;
384         }
385     }
386
387     if (ret == NULL) {
388         if (not_found == NULL)
389             return NULL;
390
391         return wmem_strdup(NULL, not_found);
392     }
393
394     return ret;
395 }
396
397 #ifdef HAVE_GEOIP_V6
398
399 static int
400 #if NUM_DB_TYPES > 31 /* 1.4.7 */
401 geoip_db_lookup_latlon6(geoipv6_t addr, float *lat, float *lon) {
402     GeoIP *gi;
403     GeoIPRecord *gir;
404     guint i;
405
406     for (i = 0; i < geoip_db_num_dbs(); i++) {
407         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
408         if (gi) {
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);
413                     if(gir) {
414                         *lat = gir->latitude;
415                         *lon = gir->longitude;
416                         return 0;
417                     }
418                     return -1;
419                     /*break;*/
420
421                 default:
422                     break;
423             }
424         }
425     }
426     return -1;
427 }
428 #else /* NUM_DB_TYPES */
429 geoip_db_lookup_latlon6(geoipv6_t addr _U_, float *lat _U_, float *lon _U_) {
430     return -1;
431 }
432 #endif /* NUM_DB_TYPES */
433
434 char *
435 geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found) {
436     GeoIP *gi;
437     geoipv6_t gaddr;
438     const char *raw_val;
439     char *val, *ret = NULL;
440 #if NUM_DB_TYPES > 31
441     GeoIPRecord *gir;
442 #endif
443     if (dbnum > geoip_db_num_dbs()) {
444         if (not_found == NULL)
445             return NULL;
446
447         return wmem_strdup(NULL, not_found);
448     }
449
450     memcpy(&gaddr, &addr, sizeof(addr));
451
452     gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
453     if (gi) {
454         switch (gi->databaseType) {
455             case GEOIP_COUNTRY_EDITION_V6:
456                 raw_val = GeoIP_country_name_by_ipnum_v6(gi, gaddr);
457                 if (raw_val) {
458                     ret = db_val_to_utf_8(raw_val, gi);
459                 }
460                 break;
461
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);
472                 }
473                 break;
474
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);
479                 if (raw_val) {
480                     ret = db_val_to_utf_8(raw_val, gi);
481                 }
482                 break;
483 #endif /* NUM_DB_TYPES */
484
485             case WS_LAT_FAKE_EDITION:
486             {
487                 float lat;
488                 float lon;
489                 char *c;
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 = '.';
494                     ret = val;
495                 }
496             }
497                 break;
498
499             case WS_LON_FAKE_EDITION:
500             {
501                 float lat;
502                 float lon;
503                 char *c;
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 = '.';
508                     ret = val;
509                 }
510             }
511                 break;
512
513             default:
514                 break;
515         }
516     }
517
518     if (ret == NULL) {
519         if (not_found == NULL)
520             return NULL;
521
522         return wmem_strdup(NULL, not_found);
523     }
524
525     return ret;
526 }
527
528 #else /* HAVE_GEOIP_V6 */
529
530 char *
531 geoip_db_lookup_ipv6(guint dbnum _U_, struct e_in6_addr addr _U_, const char *not_found) {
532     if (not_found == NULL)
533         return NULL;
534
535     return wmem_strdup(NULL, not_found);
536 }
537
538 #endif /* HAVE_GEOIP_V6 */
539
540 gchar *
541 geoip_db_get_paths(void) {
542     GString* path_str = NULL;
543     char path_separator;
544     guint i;
545
546     path_str = g_string_new("");
547 #ifdef _WIN32
548     path_separator = ';';
549 #else
550     path_separator = ':';
551 #endif
552
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);
556         }
557     }
558
559     g_string_truncate(path_str, path_str->len-1);
560
561     return g_string_free(path_str, FALSE);
562 }
563
564 #else /* HAVE_GEOIP */
565 guint
566 geoip_db_num_dbs(void) {
567     return 0;
568 }
569
570 const gchar *
571 geoip_db_name(guint dbnum _U_) {
572     return "Unsupported";
573 }
574
575 int
576 geoip_db_type(guint dbnum _U_) {
577     return -1;
578 }
579
580 char *
581 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
582     if (not_found == NULL)
583         return NULL;
584
585     return (char *)wmem_strdup(NULL, not_found);
586 }
587
588 char *
589 geoip_db_lookup_ipv6(guint dbnum _U_, guint32 addr _U_, const char *not_found) {
590     if (not_found == NULL)
591         return NULL;
592
593     return (char *)wmem_strdup(NULL, not_found);
594 }
595
596 gchar *
597 geoip_db_get_paths(void) {
598     return g_strdup("");
599 }
600
601 #endif /* HAVE_GEOIP */
602
603 /*
604  * Editor modelines
605  *
606  * Local Variables:
607  * c-basic-offset: 4
608  * tab-width: 8
609  * indent-tabs-mode: nil
610  * End:
611  *
612  * ex: set shiftwidth=4 tabstop=8 expandtab:
613  * :indentSize=4:tabSize=8:noTabs=true:
614  */