added some precautionary checks in bdecoder
[libtorrent.git] / src / GeoIP.c
blob562cdc9a2de0271dc13d21e9d8b241f0d1702ccb
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
2 /* GeoIP.c
4 * Copyright (C) 2006 MaxMind LLC
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "libtorrent/GeoIP.h"
23 #ifndef WIN32
24 #include <netdb.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h> /* For ntohl */
27 #include <arpa/inet.h>
29 #include <sys/mman.h>
31 #else
32 #include <windows.h>
33 #include <winsock2.h>
34 #define snprintf _snprintf
35 #endif
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <assert.h>
41 #include <sys/types.h> /* for fstat */
42 #include <sys/stat.h> /* for fstat */
44 #ifdef HAVE_STDINT_H
45 #include <stdint.h> /* For uint32_t */
46 #endif
48 #ifndef INADDR_NONE
49 #define INADDR_NONE -1
50 #endif
52 #define COUNTRY_BEGIN 16776960
53 #define STATE_BEGIN_REV0 16700000
54 #define STATE_BEGIN_REV1 16000000
55 #define STRUCTURE_INFO_MAX_SIZE 20
56 #define DATABASE_INFO_MAX_SIZE 100
57 #define MAX_ORG_RECORD_LENGTH 300
58 #define US_OFFSET 1
59 #define CANADA_OFFSET 677
60 #define WORLD_OFFSET 1353
61 #define FIPS_RANGE 360
63 #define CHECK_ERR(err, msg) { \
64 if (err != Z_OK) { \
65 fprintf(stderr, "%s error: %d\n", msg, err); \
66 exit(1); \
67 } \
70 const char GeoIP_country_code[253][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
71 "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
72 "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
73 "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
74 "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
75 "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
76 "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
77 "FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
78 "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
79 "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
80 "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
81 "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
82 "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
83 "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
84 "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
85 "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
86 "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
87 "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
88 "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
89 "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
90 "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
91 "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
92 "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
93 "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
94 "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE",
95 "BL","MF"};
97 const char GeoIP_country_code3[253][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
98 "AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
99 "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
100 "BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
101 "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
102 "CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
103 "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
104 "FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
105 "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
106 "GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
107 "IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
108 "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
109 "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
110 "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
111 "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
112 "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
113 "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
114 "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
115 "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
116 "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
117 "SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
118 "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
119 "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
120 "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
121 "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY",
122 "BLM","MAF"};
124 const char * GeoIP_country_name[253] = {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
125 "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
126 "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
127 "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
128 "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
129 "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
130 "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
131 "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
132 "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
133 "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
134 "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
135 "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
136 "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
137 "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
138 "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
139 "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
140 "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
141 "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
142 "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
143 "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
144 "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
145 "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
146 "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
147 "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
148 "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
149 "Saint Barthelemy","Saint Martin"};
151 /* Possible continent codes are AF, AS, EU, NA, OC, SA for Africa, Asia, Europe, North America, Oceania
152 and South America. */
154 const char GeoIP_country_continent[253][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
155 "AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
156 "AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
157 "SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
158 "AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
159 "SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
160 "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
161 "SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
162 "AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
163 "OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
164 "EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
165 "AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
166 "SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
167 "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
168 "AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
169 "AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
170 "EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
171 "OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
172 "SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
173 "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
174 "SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
175 "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
176 "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
177 "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
178 "AF","EU","AF","--","--","--","EU","EU","EU","EU",
179 "SA","SA"};
181 const char * GeoIPDBDescription[NUM_DB_TYPES] = {NULL, "GeoIP Country Edition", "GeoIP City Edition, Rev 1", "GeoIP Region Edition, Rev 1", "GeoIP ISP Edition", "GeoIP Organization Edition", "GeoIP City Edition, Rev 0", "GeoIP Region Edition, Rev 0","GeoIP Proxy Edition","GeoIP ASNum Edition","GeoIP Netspeed Edition","GeoIP Domain Name Edition"};
183 char * custom_directory = NULL;
185 void GeoIP_setup_custom_directory (char * dir) {
186 custom_directory = dir;
189 char *_GeoIP_full_path_to(const char *file_name) {
190 int len;
191 char *path = malloc(sizeof(char) * 1024);
193 if (custom_directory == NULL){
194 #ifndef WIN32
195 memset(path, 0, sizeof(char) * 1024);
196 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
197 #else
198 char buf[MAX_PATH], *p, *q = NULL;
199 memset(buf, 0, sizeof(buf));
200 len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1);
201 for (p = buf + len; p > buf; p--)
202 if (*p == '\\')
204 if (!q)
205 q = p;
206 else
207 *p = '/';
209 *q = 0;
210 memset(path, 0, sizeof(char) * 1024);
211 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
212 #endif
213 } else {
214 len = strlen(custom_directory);
215 if (custom_directory[len-1] != '/') {
216 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s",custom_directory, file_name);
217 } else {
218 snprintf(path, sizeof(char) * 1024 - 1, "%s%s", custom_directory, file_name);
221 return path;
224 char ** GeoIPDBFileName = NULL;
226 void _GeoIP_setup_dbfilename() {
227 if (NULL == GeoIPDBFileName) {
228 GeoIPDBFileName = malloc(sizeof(char *) * NUM_DB_TYPES);
229 memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES);
231 GeoIPDBFileName[GEOIP_COUNTRY_EDITION] = _GeoIP_full_path_to("GeoIP.dat");
232 GeoIPDBFileName[GEOIP_REGION_EDITION_REV0] = _GeoIP_full_path_to("GeoIPRegion.dat");
233 GeoIPDBFileName[GEOIP_REGION_EDITION_REV1] = _GeoIP_full_path_to("GeoIPRegion.dat");
234 GeoIPDBFileName[GEOIP_CITY_EDITION_REV0] = _GeoIP_full_path_to("GeoIPCity.dat");
235 GeoIPDBFileName[GEOIP_CITY_EDITION_REV1] = _GeoIP_full_path_to("GeoIPCity.dat");
236 GeoIPDBFileName[GEOIP_ISP_EDITION] = _GeoIP_full_path_to("GeoIPISP.dat");
237 GeoIPDBFileName[GEOIP_ORG_EDITION] = _GeoIP_full_path_to("GeoIPOrg.dat");
238 GeoIPDBFileName[GEOIP_PROXY_EDITION] = _GeoIP_full_path_to("GeoIPProxy.dat");
239 GeoIPDBFileName[GEOIP_ASNUM_EDITION] = _GeoIP_full_path_to("GeoIPASNum.dat");
240 GeoIPDBFileName[GEOIP_NETSPEED_EDITION] = _GeoIP_full_path_to("GeoIPNetSpeed.dat");
241 GeoIPDBFileName[GEOIP_DOMAIN_EDITION] = _GeoIP_full_path_to("GeoIPDomain.dat");
246 static
247 int _file_exists(const char *file_name) {
248 struct stat file_stat;
249 return( (stat(file_name, &file_stat) == 0) ? 1:0);
252 int GeoIP_db_avail(int type) {
253 const char * filePath;
254 if (type < 0 || type >= NUM_DB_TYPES) {
255 return 0;
257 _GeoIP_setup_dbfilename();
258 filePath = GeoIPDBFileName[type];
259 if (NULL == filePath) {
260 return 0;
262 return _file_exists(filePath);
265 static
266 void _setup_segments(GeoIP * gi) {
267 int i, j;
268 unsigned char delim[3];
269 unsigned char buf[SEGMENT_RECORD_LENGTH];
271 gi->databaseSegments = NULL;
273 /* default to GeoIP Country Edition */
274 gi->databaseType = GEOIP_COUNTRY_EDITION;
275 gi->record_length = STANDARD_RECORD_LENGTH;
276 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
277 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
278 fread(delim, 1, 3, gi->GeoIPDatabase);
279 if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
280 fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase);
281 if (gi->databaseType >= 106) {
282 /* backwards compatibility with databases from April 2003 and earlier */
283 gi->databaseType -= 105;
286 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
287 /* Region Edition, pre June 2003 */
288 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
289 gi->databaseSegments[0] = STATE_BEGIN_REV0;
290 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
291 /* Region Edition, post June 2003 */
292 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
293 gi->databaseSegments[0] = STATE_BEGIN_REV1;
294 } else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 ||
295 gi->databaseType == GEOIP_CITY_EDITION_REV1 ||
296 gi->databaseType == GEOIP_ORG_EDITION ||
297 gi->databaseType == GEOIP_ISP_EDITION ||
298 gi->databaseType == GEOIP_ASNUM_EDITION) {
299 /* City/Org Editions have two segments, read offset of second segment */
300 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
301 gi->databaseSegments[0] = 0;
302 fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase);
303 for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
304 gi->databaseSegments[0] += (buf[j] << (j * 8));
306 if (gi->databaseType == GEOIP_ORG_EDITION ||
307 gi->databaseType == GEOIP_ISP_EDITION)
308 gi->record_length = ORG_RECORD_LENGTH;
310 break;
311 } else {
312 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
315 if (gi->databaseType == GEOIP_COUNTRY_EDITION ||
316 gi->databaseType == GEOIP_PROXY_EDITION ||
317 gi->databaseType == GEOIP_NETSPEED_EDITION) {
318 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
319 gi->databaseSegments[0] = COUNTRY_BEGIN;
323 static
324 int _check_mtime(GeoIP *gi) {
325 struct stat buf;
326 if (gi->flags & GEOIP_CHECK_CACHE) {
327 if (stat(gi->file_path, &buf) != -1) {
328 if (buf.st_mtime != gi->mtime) {
329 /* GeoIP Database file updated */
330 if (gi->flags & (GEOIP_MEMORY_CACHE | GEOIP_MMAP_CACHE)) {
331 #ifndef WIN32
332 if ( gi->flags & GEOIP_MMAP_CACHE) {
333 munmap(gi->cache, gi->size);
334 gi->cache = NULL;
335 } else
336 #endif
338 /* reload database into memory cache */
339 if ((gi->cache = (unsigned char*) realloc(gi->cache, buf.st_size)) == NULL) {
340 fprintf(stderr,"Out of memory when reloading %s\n",gi->file_path);
341 return -1;
345 /* refresh filehandle */
346 fclose(gi->GeoIPDatabase);
347 gi->GeoIPDatabase = fopen(gi->file_path,"rb");
348 if (gi->GeoIPDatabase == NULL) {
349 fprintf(stderr,"Error Opening file %s when reloading\n",gi->file_path);
350 return -1;
352 gi->mtime = buf.st_mtime;
353 gi->size = buf.st_size;
355 #ifndef WIN32
356 if ( gi->flags & GEOIP_MMAP_CACHE) {
357 gi->cache = (unsigned char*)mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fileno(gi->GeoIPDatabase), 0);
358 if ( gi->cache == MAP_FAILED ) {
360 fprintf(stderr,"Error remapping file %s when reloading\n",gi->file_path);
361 gi->cache = 0;
362 return -1;
364 } else
365 #endif
366 if ( gi->flags & GEOIP_MEMORY_CACHE ) {
367 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
368 fprintf(stderr,"Error reading file %s when reloading\n",gi->file_path);
369 return -1;
372 if (gi->databaseSegments != NULL) {
373 free(gi->databaseSegments);
374 gi->databaseSegments = NULL;
376 _setup_segments(gi);
377 if (gi->databaseSegments == NULL) {
378 fprintf(stderr, "Error reading file %s -- corrupt\n", gi->file_path);
379 return -1;
381 if (gi->flags & GEOIP_INDEX_CACHE) {
382 gi->index_cache = (unsigned char *) realloc(gi->index_cache, sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
383 if (gi->index_cache != NULL) {
384 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
385 if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) {
386 fprintf(stderr,"Error reading file %s where reloading\n",gi->file_path);
387 return -1;
394 return 0;
397 unsigned int _GeoIP_seek_record (GeoIP *gi, unsigned long ipnum) {
398 int depth;
399 unsigned int x;
400 unsigned char stack_buffer[2 * MAX_RECORD_LENGTH];
401 const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL;
402 unsigned int offset = 0;
404 const unsigned char * p;
405 int j;
407 _check_mtime(gi);
408 for (depth = 31; depth >= 0; depth--) {
409 if (gi->cache == NULL && gi->index_cache == NULL) {
410 /* read from disk */
411 fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET);
412 fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase);
413 } else if (gi->index_cache == NULL) {
414 /* simply point to record in memory */
415 buf = gi->cache + (long)gi->record_length * 2 *offset;
416 } else {
417 buf = gi->index_cache + (long)gi->record_length * 2 * offset;
420 if (ipnum & (1 << depth)) {
421 /* Take the right-hand branch */
422 if ( gi->record_length == 3 ) {
423 /* Most common case is completely unrolled and uses constants. */
424 x = (buf[3*1 + 0] << (0*8))
425 + (buf[3*1 + 1] << (1*8))
426 + (buf[3*1 + 2] << (2*8));
428 } else {
429 /* General case */
430 j = gi->record_length;
431 p = &buf[2*j];
432 x = 0;
433 do {
434 x <<= 8;
435 x += *(--p);
436 } while ( --j );
439 } else {
440 /* Take the left-hand branch */
441 if ( gi->record_length == 3 ) {
442 /* Most common case is completely unrolled and uses constants. */
443 x = (buf[3*0 + 0] << (0*8))
444 + (buf[3*0 + 1] << (1*8))
445 + (buf[3*0 + 2] << (2*8));
446 } else {
447 /* General case */
448 j = gi->record_length;
449 p = &buf[1*j];
450 x = 0;
451 do {
452 x <<= 8;
453 x += *(--p);
454 } while ( --j );
458 if (x >= gi->databaseSegments[0]) {
459 gi->netmask = 32 - depth;
460 return x;
462 offset = x;
465 /* shouldn't reach here */
466 fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum);
467 return 0;
470 unsigned long
471 _GeoIP_addr_to_num(const char *addr)
473 unsigned int c, octet, t;
474 unsigned long ipnum;
475 int i = 3;
477 octet = ipnum = 0;
478 while ((c = *addr++)) {
479 if (c == '.') {
480 if (octet > 255)
481 return 0;
482 ipnum <<= 8;
483 ipnum += octet;
484 i--;
485 octet = 0;
486 } else {
487 t = octet;
488 octet <<= 3;
489 octet += t;
490 octet += t;
491 c -= '0';
492 if (c > 9)
493 return 0;
494 octet += c;
497 if ((octet > 255) || (i != 0))
498 return 0;
499 ipnum <<= 8;
500 return ipnum + octet;
503 GeoIP* GeoIP_open_type (int type, int flags) {
504 GeoIP * gi;
505 const char * filePath;
506 if (type < 0 || type >= NUM_DB_TYPES) {
507 printf("Invalid database type %d\n", type);
508 return NULL;
510 _GeoIP_setup_dbfilename();
511 filePath = GeoIPDBFileName[type];
512 if (filePath == NULL) {
513 printf("Invalid database type %d\n", type);
514 return NULL;
516 gi = GeoIP_open (filePath, flags);
517 return gi;
520 GeoIP* GeoIP_new (int flags) {
521 GeoIP * gi;
522 _GeoIP_setup_dbfilename();
523 gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags);
524 return gi;
527 GeoIP* GeoIP_open (const char * filename, int flags) {
528 struct stat buf;
529 GeoIP * gi;
530 size_t len;
532 gi = (GeoIP *)malloc(sizeof(GeoIP));
533 if (gi == NULL)
534 return NULL;
535 len = sizeof(char) * (strlen(filename)+1);
536 gi->file_path = (char*)malloc(len);
537 if (gi->file_path == NULL) {
538 free(gi);
539 return NULL;
541 strncpy(gi->file_path, filename, len);
542 gi->GeoIPDatabase = fopen(filename,"rb");
543 if (gi->GeoIPDatabase == NULL) {
544 fprintf(stderr,"Error Opening file %s\n",filename);
545 free(gi->file_path);
546 free(gi);
547 return NULL;
548 } else {
549 if (flags & (GEOIP_MEMORY_CACHE | GEOIP_MMAP_CACHE) ) {
550 if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
551 fprintf(stderr,"Error stating file %s\n",filename);
552 free(gi->file_path);
553 free(gi);
554 return NULL;
556 gi->mtime = buf.st_mtime;
557 gi->size = buf.st_size;
558 #ifndef WIN32
559 /* MMAP added my Peter Shipley */
560 if ( flags & GEOIP_MMAP_CACHE) {
561 gi->cache = (unsigned char*)mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fileno(gi->GeoIPDatabase), 0);
562 if ( gi->cache == MAP_FAILED ) {
563 fprintf(stderr,"Error mmaping file %s\n",filename);
564 free(gi->file_path);
565 free(gi);
566 return NULL;
568 } else
569 #endif
571 gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * buf.st_size);
573 if (gi->cache != NULL) {
574 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
575 fprintf(stderr,"Error reading file %s\n",filename);
576 free(gi->cache);
577 free(gi->file_path);
578 free(gi);
579 return NULL;
583 } else {
584 if (flags & GEOIP_CHECK_CACHE) {
585 if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
586 fprintf(stderr,"Error stating file %s\n",filename);
587 free(gi->file_path);
588 free(gi);
589 return NULL;
591 gi->mtime = buf.st_mtime;
593 gi->cache = NULL;
595 gi->flags = flags;
596 gi->charset = GEOIP_CHARSET_ISO_8859_1;
598 _setup_segments(gi);
599 if (flags & GEOIP_INDEX_CACHE) {
600 gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
601 if (gi->index_cache != NULL) {
602 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
603 if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) {
604 fprintf(stderr,"Error reading file %s\n",filename);
605 free(gi->databaseSegments);
606 free(gi->index_cache);
607 free(gi);
608 return NULL;
611 } else {
612 gi->index_cache = NULL;
614 return gi;
618 void GeoIP_delete (GeoIP *gi) {
619 if (gi == NULL )
620 return;
621 if (gi->GeoIPDatabase != NULL)
622 fclose(gi->GeoIPDatabase);
623 if (gi->cache != NULL) {
624 #ifndef WIN32
625 if ( gi->flags & GEOIP_MMAP_CACHE) {
626 munmap(gi->cache, gi->size);
627 } else
628 #endif
630 free(gi->cache);
632 gi->cache = NULL;
634 if (gi->index_cache != NULL)
635 free(gi->index_cache);
636 if (gi->file_path != NULL)
637 free(gi->file_path);
638 if (gi->databaseSegments != NULL)
639 free(gi->databaseSegments);
640 free(gi);
643 const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) {
644 int country_id;
645 country_id = GeoIP_id_by_name(gi, name);
646 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
649 const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) {
650 int country_id;
651 country_id = GeoIP_id_by_name(gi, name);
652 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
655 const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) {
656 int country_id;
657 country_id = GeoIP_id_by_name(gi, name);
658 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
661 unsigned long _GeoIP_lookupaddress (const char *host) {
662 unsigned long addr = inet_addr(host);
663 struct hostent phe2;
664 struct hostent * phe = &phe2;
665 char *buf = NULL;
666 int buflength = 16384;
667 int herr = 0;
668 int result = 0;
669 #ifdef HAVE_GETHOSTBYNAME_R
670 buf = malloc(buflength);
671 #endif
672 if (addr == INADDR_NONE) {
673 #ifdef HAVE_GETHOSTBYNAME_R
674 while (1) {
675 /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
676 #ifdef GETHOSTBYNAME_R_RETURNS_INT
677 result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr);
678 #else
679 phe = gethostbyname_r(host,&phe2,buf,buflength,&herr);
680 #endif
681 if (herr != ERANGE)
682 break;
683 if (result == 0)
684 break;
685 /* double the buffer if the buffer is too small */
686 buflength = buflength * 2;
687 buf = realloc(buf,buflength);
689 #endif
690 #ifndef HAVE_GETHOSTBYNAME_R
691 /* Some systems do not support gethostbyname_r, such as Mac OS X */
692 phe = gethostbyname(host);
693 #endif
694 if (!phe || result != 0) {
695 free(buf);
696 return 0;
698 addr = *((unsigned long *) phe->h_addr_list[0]);
700 #ifdef HAVE_GETHOSTBYNAME_R
701 free(buf);
702 #endif
703 return ntohl(addr);
706 int GeoIP_id_by_name (GeoIP* gi, const char *name) {
707 unsigned long ipnum;
708 int ret;
709 if (name == NULL) {
710 return 0;
712 if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) {
713 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
714 return 0;
716 if (!(ipnum = _GeoIP_lookupaddress(name)))
717 return 0;
718 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
719 return ret;
723 const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) {
724 int country_id;
725 country_id = GeoIP_id_by_addr(gi, addr);
726 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
729 const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) {
730 int country_id;
731 country_id = GeoIP_id_by_addr(gi, addr);
732 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
733 return GeoIP_country_code3[country_id];
736 const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) {
737 int country_id;
738 country_id = GeoIP_id_by_addr(gi, addr);
739 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
740 return GeoIP_country_name[country_id];
743 const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
744 int country_id;
745 country_id = GeoIP_id_by_ipnum(gi, ipnum);
746 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
749 const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) {
750 int country_id;
751 country_id = GeoIP_id_by_ipnum(gi, ipnum);
752 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
755 const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum) {
756 int country_id;
757 country_id = GeoIP_id_by_ipnum(gi, ipnum);
758 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
761 int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) {
762 return GeoIP_id_by_addr(gi, addr);
765 int GeoIP_country_id_by_name (GeoIP* gi, const char *host) {
766 return GeoIP_id_by_name(gi, host);
769 int GeoIP_id_by_addr (GeoIP* gi, const char *addr) {
770 unsigned long ipnum;
771 int ret;
772 if (addr == NULL) {
773 return 0;
775 if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
776 gi->databaseType != GEOIP_PROXY_EDITION &&
777 gi->databaseType != GEOIP_NETSPEED_EDITION) {
778 printf("Invalid database type %s, expected %s\n",
779 GeoIPDBDescription[(int)gi->databaseType],
780 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
781 return 0;
783 ipnum = _GeoIP_addr_to_num(addr);
784 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
785 return ret;
788 int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) {
789 int ret;
790 if (ipnum == 0) {
791 return 0;
793 if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
794 gi->databaseType != GEOIP_PROXY_EDITION &&
795 gi->databaseType != GEOIP_NETSPEED_EDITION) {
796 printf("Invalid database type %s, expected %s\n",
797 GeoIPDBDescription[(int)gi->databaseType],
798 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
799 return 0;
801 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
802 return ret;
805 char *GeoIP_database_info (GeoIP* gi) {
806 int i;
807 unsigned char buf[3];
808 char *retval;
809 int hasStructureInfo = 0;
811 if(gi == NULL)
812 return NULL;
814 _check_mtime(gi);
815 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
817 /* first get past the database structure information */
818 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
819 fread(buf, 1, 3, gi->GeoIPDatabase);
820 if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) {
821 hasStructureInfo = 1;
822 break;
824 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
826 if (hasStructureInfo == 1) {
827 fseek(gi->GeoIPDatabase, -6l, SEEK_CUR);
828 } else {
829 /* no structure info, must be pre Sep 2002 database, go back to end */
830 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
833 for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
834 fread(buf, 1, 3, gi->GeoIPDatabase);
835 if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) {
836 retval = (char*)malloc(sizeof(char) * (i+1));
837 if (retval == NULL) {
838 return NULL;
840 fread(retval, 1, i, gi->GeoIPDatabase);
841 retval[i] = '\0';
842 return retval;
844 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
846 return NULL;
849 /* GeoIP Region Edition functions */
851 void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) {
852 unsigned int seek_region;
854 /* This also writes in the terminating NULs (if you decide to
855 * keep them) and clear any fields that are not set. */
856 memset(region, 0, sizeof(GeoIPRegion));
858 seek_region = _GeoIP_seek_record(gi, ntohl(inetaddr));
860 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
861 /* Region Edition, pre June 2003 */
862 seek_region -= STATE_BEGIN_REV0;
863 if (seek_region >= 1000) {
864 region->country_code[0] = 'U';
865 region->country_code[1] = 'S';
866 region->region[0] = (char) ((seek_region - 1000)/26 + 65);
867 region->region[1] = (char) ((seek_region - 1000)%26 + 65);
868 } else {
869 memcpy(region->country_code, GeoIP_country_code[seek_region], 2);
871 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
872 /* Region Edition, post June 2003 */
873 seek_region -= STATE_BEGIN_REV1;
874 if (seek_region < US_OFFSET) {
875 /* Unknown */
876 /* we don't need to do anything here b/c we memset region to 0 */
877 } else if (seek_region < CANADA_OFFSET) {
878 /* USA State */
879 region->country_code[0] = 'U';
880 region->country_code[1] = 'S';
881 region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65);
882 region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65);
883 } else if (seek_region < WORLD_OFFSET) {
884 /* Canada Province */
885 region->country_code[0] = 'C';
886 region->country_code[1] = 'A';
887 region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65);
888 region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65);
889 } else {
890 /* Not US or Canada */
891 memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2);
896 static
897 GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) {
898 GeoIPRegion * region;
900 region = (GeoIPRegion*)malloc(sizeof(GeoIPRegion));
901 if (region) {
902 GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region);
904 return region;
907 GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) {
908 unsigned long ipnum;
909 if (addr == NULL) {
910 return 0;
912 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
913 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
914 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
915 return 0;
917 ipnum = _GeoIP_addr_to_num(addr);
918 return _get_region(gi, ipnum);
921 GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) {
922 unsigned long ipnum;
923 if (name == NULL) {
924 return 0;
926 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
927 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
928 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
929 return 0;
931 if (!(ipnum = _GeoIP_lookupaddress(name)))
932 return 0;
933 return _get_region(gi, ipnum);
936 GeoIPRegion * GeoIP_region_by_ipnum (GeoIP* gi, unsigned long ipnum) {
937 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
938 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
939 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
940 return 0;
942 return _get_region(gi, ipnum);
945 void GeoIPRegion_delete (GeoIPRegion *gir) {
946 free(gir);
949 /* GeoIP Organization, ISP and AS Number Edition private method */
950 static
951 char *_get_name (GeoIP* gi, unsigned long ipnum) {
952 int seek_org;
953 char buf[MAX_ORG_RECORD_LENGTH];
954 char * org_buf, * buf_pointer;
955 int record_pointer;
956 size_t len;
958 if (gi->databaseType != GEOIP_ORG_EDITION &&
959 gi->databaseType != GEOIP_ISP_EDITION &&
960 gi->databaseType != GEOIP_ASNUM_EDITION) {
961 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]);
962 return 0;
965 seek_org = _GeoIP_seek_record(gi, ipnum);
966 if (seek_org == gi->databaseSegments[0])
967 return NULL;
969 record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0];
971 if (gi->cache == NULL) {
972 fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET);
973 fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase);
974 len = sizeof(char) * (strlen(buf)+1);
975 org_buf = (char*)malloc(len);
976 strncpy(org_buf, buf, len);
977 } else {
978 buf_pointer = (char*)(gi->cache + (long)record_pointer);
979 len = sizeof(char) * (strlen(buf_pointer)+1);
980 org_buf = (char*)malloc(len);
981 strncpy(org_buf, buf_pointer, len);
983 return org_buf;
986 char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
987 return _get_name(gi,ipnum);
990 char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) {
991 unsigned long ipnum;
992 if (addr == NULL) {
993 return 0;
995 ipnum = _GeoIP_addr_to_num(addr);
996 return _get_name(gi, ipnum);
999 char *GeoIP_name_by_name (GeoIP* gi, const char *name) {
1000 unsigned long ipnum;
1001 if (name == NULL) {
1002 return 0;
1004 if (!(ipnum = _GeoIP_lookupaddress(name)))
1005 return 0;
1006 return _get_name(gi, ipnum);
1009 char *GeoIP_org_by_ipnum (GeoIP* gi, unsigned long ipnum) {
1010 return GeoIP_name_by_ipnum(gi, ipnum);
1013 char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) {
1014 return GeoIP_name_by_addr(gi, addr);
1017 char *GeoIP_org_by_name (GeoIP* gi, const char *name) {
1018 return GeoIP_name_by_name(gi, name);
1021 unsigned char GeoIP_database_edition (GeoIP* gi) {
1022 return gi->databaseType;
1025 int GeoIP_charset( GeoIP* gi){
1026 return gi->charset;
1029 int GeoIP_set_charset( GeoIP* gi, int charset ){
1030 int old_charset = gi->charset;
1031 gi->charset = charset;
1032 return old_charset;
1035 int GeoIP_last_netmask (GeoIP* gi) {
1036 return gi->netmask;