Clean up the blurbs indicated by checkAPIs.
[obnox/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  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
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.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <glib.h>
37
38 #ifdef HAVE_GEOIP
39 #include "GeoIP.h"
40 #include "GeoIPCity.h"
41
42 #include "geoip_db.h"
43 #include "uat.h"
44 #include "prefs.h"
45 #include "report_err.h"
46 #include "value_string.h"
47 #include <wsutil/file_util.h>
48
49 /* This needs to match NUM_GEOIP_COLS in hostlist_table.h */
50 #define MAX_GEOIP_DBS 13
51
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" },
67 #endif
68         { WS_LAT_FAKE_EDITION,                  "Latitude" },   /* fake database */
69         { WS_LON_FAKE_EDITION,                  "Longitude" },  /* fake database */
70         { 0, NULL }
71 };
72
73 static GArray *geoip_dat_arr = NULL;
74
75 /* UAT definitions. Copied from oids.c */
76 typedef struct _geoip_db_path_t {
77         char* path;
78 } geoip_db_path_t;
79
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)
84
85
86 /**
87  * Scan a directory for GeoIP databases and load them
88  */
89 static void
90 geoip_dat_scan_dir(const char *dirname) {
91         WS_DIR *dir;
92         WS_DIRENT *file;
93         const char *name;
94         char *datname;
95         GeoIP *gi;
96
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);
103                                 if (gi) {
104                                         g_array_append_val(geoip_dat_arr, gi);
105                                 }
106                                 g_free(datname);
107                         }
108                 }
109         }
110 }
111
112 /* UAT callbacks */
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;
116
117         d->path = g_strdup(m->path);
118
119         return d;
120 }
121
122 static void geoip_db_path_free_cb(void* p) {
123         geoip_db_path_t *m = p;
124         g_free(m->path);
125 }
126
127 /**
128  * Initialize GeoIP lookups
129  */
130 void
131 geoip_db_init(void) {
132         guint i;
133         static uat_field_t geoip_db_paths_fields[] = {
134                 UAT_FLD_PATHNAME(geoip_mod, path, "Database pathname", "The database path"),
135                 UAT_END_FIELDS
136         };
137         char* geoip_load_error = NULL;
138
139         geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *));
140
141         geoip_db_paths_uat = uat_new("GeoIP Database Paths",
142                         sizeof(geoip_db_path_t),
143                         "geoip_db_paths",
144                         FALSE,
145                         (void*)&geoip_db_paths,
146                         &num_geoip_db_paths,
147                         UAT_CAT_GENERAL,
148                         "ChGeoIPDbPaths",
149                         geoip_db_path_copy_cb,
150                         NULL,
151                         geoip_db_path_free_cb,
152                         NULL,
153                         geoip_db_paths_fields);
154
155         uat_load(geoip_db_paths_uat, &geoip_load_error);
156
157         if (geoip_load_error) {
158                 report_failure("Error loading GeoIP database path table: %s", geoip_load_error);
159                 return;
160         }
161
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);
165                 }
166         }
167
168     /* add fake databases for latitude and longitude (using "City" in reality) */
169     {
170         GeoIP *gi_lat;
171         GeoIP *gi_lon;
172
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);
179     }
180 }
181
182 guint
183 geoip_db_num_dbs(void) {
184         return geoip_dat_arr->len;
185 }
186
187 const gchar *
188 geoip_db_name(guint dbnum) {
189         GeoIP *gi;
190
191         gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
192         if (gi) {
193                 return (val_to_str(gi->databaseType, geoip_type_name_vals, "Unknown database"));
194         }
195         return "Invalid database";
196 }
197
198 int
199 geoip_db_type(guint dbnum) {
200         GeoIP *gi;
201
202         gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
203         if (gi) {
204                 return (gi->databaseType);
205         }
206         return -1;
207 }
208
209 int
210 geoip_db_lookup_latlon(guint32 addr, float *lat, float *lon) {
211         GeoIP *gi;
212         GeoIPRecord *gir;
213     guint i;
214
215         for (i = 0; i < geoip_db_num_dbs(); i++) {
216         gi = g_array_index(geoip_dat_arr, GeoIP *, i);
217         if (gi) {
218             switch (gi->databaseType) {
219                 case GEOIP_CITY_EDITION_REV0:
220                 case GEOIP_CITY_EDITION_REV1:
221                     gir = GeoIP_record_by_ipnum(gi, addr);
222                     if(gir) {
223                         *lat = gir->latitude;
224                         *lon = gir->longitude;
225                                                 return 0;
226                     }
227                     return -1;
228                     /*break;*/
229
230                 default:
231                     break;
232             }
233         }
234     }
235         return -1;
236 }
237
238 #define VAL_STR_LEN 100
239 const char *
240 geoip_db_lookup_ipv4(guint dbnum, guint32 addr, char *not_found) {
241         GeoIP *gi;
242         GeoIPRecord *gir;
243         const char *ret = not_found;
244         static char val[VAL_STR_LEN];
245
246         gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
247         if (gi) {
248                 switch (gi->databaseType) {
249                         case GEOIP_COUNTRY_EDITION:
250                                 ret = GeoIP_country_name_by_ipnum(gi, addr);
251                                 break;
252
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);
258                                         ret = val;
259                                 } else if (gir && gir->city) {
260                                         g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
261                                         ret = val;
262                                 }
263                                 break;
264
265                         case GEOIP_ORG_EDITION:
266                         case GEOIP_ISP_EDITION:
267                         case GEOIP_ASNUM_EDITION:
268                                 ret = GeoIP_name_by_ipnum(gi, addr);
269                                 break;
270
271             case WS_LAT_FAKE_EDITION:
272             {
273                 float lat;
274                 float lon;
275                                 char *c;
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 = '.';
280                     ret = val;
281                 }
282             }
283                 break;
284
285             case WS_LON_FAKE_EDITION:
286             {
287                 float lat;
288                 float lon;
289                                 char *c;
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 = '.';
294                     ret = val;
295                 }
296             }
297                 break;
298
299                         default:
300                                 break;
301                 }
302         }
303         if (ret) {
304                 return ret;
305         }
306         return not_found;
307 }
308
309 gchar *
310 geoip_db_get_paths(void) {
311         GString* path_str = NULL;
312         gchar *path_ret;
313         char path_separator;
314         guint i;
315
316         path_str = g_string_new("");
317 #ifdef _WIN32
318         path_separator = ';';
319 #else
320         path_separator = ':';
321 #endif
322
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);
326                 }
327         }
328
329         g_string_truncate(path_str, path_str->len-1);
330         path_ret = path_str->str;
331         g_string_free(path_str, FALSE);
332
333         return path_ret;
334 }
335
336 #else /* HAVE_GEOIP */
337 void
338 geoip_db_init(void) {}
339
340 guint
341 geoip_db_num_dbs(void) {
342         return 0;
343 }
344
345 const gchar *
346 geoip_db_name(guint dbnum _U_) {
347         return "Unsupported";
348 }
349
350 int
351 geoip_db_type(guint dbnum _U_) {
352         return -1;
353 }
354
355 const char *
356 geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, char *not_found) {
357         return not_found;
358 }
359
360 gchar *
361 geoip_db_get_paths(void) {
362         return "";
363 }
364
365 #endif /* HAVE_GEOIP */
366
367 /*
368  * Editor modelines
369  *
370  * Local Variables:
371  * c-basic-offset: 4
372  * tab-width: 4
373  * indent-tabs-mode: t
374  * End:
375  *
376  * ex: set shiftwidth=4 tabstop=4 noexpandtab
377  * :indentSize=4:tabSize=4:noTabs=false:
378  */