1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
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"
25 #include <sys/socket.h>
26 #include <netinet/in.h> /* For ntohl */
27 #include <arpa/inet.h>
34 #define snprintf _snprintf
41 #include <sys/types.h> /* for fstat */
42 #include <sys/stat.h> /* for fstat */
45 #include <stdint.h> /* For uint32_t */
49 #define INADDR_NONE -1
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
59 #define CANADA_OFFSET 677
60 #define WORLD_OFFSET 1353
61 #define FIPS_RANGE 360
63 #define CHECK_ERR(err, msg) { \
65 fprintf(stderr, "%s error: %d\n", msg, err); \
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",
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",
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",
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) {
191 char *path = malloc(sizeof(char) * 1024);
193 if (custom_directory == NULL){
195 memset(path, 0, sizeof(char) * 1024);
196 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
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--)
210 memset(path, 0, sizeof(char) * 1024);
211 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
214 len = strlen(custom_directory);
215 if (custom_directory[len-1] != '/') {
216 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s",custom_directory, file_name);
218 snprintf(path, sizeof(char) * 1024 - 1, "%s%s", custom_directory, file_name);
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");
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) {
257 _GeoIP_setup_dbfilename();
258 filePath = GeoIPDBFileName[type];
259 if (NULL == filePath) {
262 return _file_exists(filePath);
266 void _setup_segments(GeoIP
* gi
) {
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
;
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
;
324 int _check_mtime(GeoIP
*gi
) {
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
)) {
332 if ( gi
->flags
& GEOIP_MMAP_CACHE
) {
333 munmap(gi
->cache
, gi
->size
);
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
);
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
);
352 gi
->mtime
= buf
.st_mtime
;
353 gi
->size
= buf
.st_size
;
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
);
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
);
372 if (gi
->databaseSegments
!= NULL
) {
373 free(gi
->databaseSegments
);
374 gi
->databaseSegments
= NULL
;
377 if (gi
->databaseSegments
== NULL
) {
378 fprintf(stderr
, "Error reading file %s -- corrupt\n", gi
->file_path
);
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
);
397 unsigned int _GeoIP_seek_record (GeoIP
*gi
, unsigned long ipnum
) {
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
;
408 for (depth
= 31; depth
>= 0; depth
--) {
409 if (gi
->cache
== NULL
&& gi
->index_cache
== NULL
) {
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
;
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));
430 j
= gi
->record_length
;
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));
448 j
= gi
->record_length
;
458 if (x
>= gi
->databaseSegments
[0]) {
459 gi
->netmask
= 32 - depth
;
465 /* shouldn't reach here */
466 fprintf(stderr
,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum
);
471 _GeoIP_addr_to_num(const char *addr
)
473 unsigned int c
, octet
, t
;
478 while ((c
= *addr
++)) {
497 if ((octet
> 255) || (i
!= 0))
500 return ipnum
+ octet
;
503 GeoIP* GeoIP_open_type (int type, int flags) {
505 const char * filePath;
506 if (type < 0 || type >= NUM_DB_TYPES) {
507 printf("Invalid database type %d\n", type);
510 _GeoIP_setup_dbfilename();
511 filePath = GeoIPDBFileName[type];
512 if (filePath == NULL) {
513 printf("Invalid database type %d\n", type);
516 gi = GeoIP_open (filePath, flags);
520 GeoIP* GeoIP_new (int flags) {
522 _GeoIP_setup_dbfilename();
523 gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags);
527 GeoIP
* GeoIP_open (const char * filename
, int flags
) {
532 gi
= (GeoIP
*)malloc(sizeof(GeoIP
));
535 len
= sizeof(char) * (strlen(filename
)+1);
536 gi
->file_path
= (char*)malloc(len
);
537 if (gi
->file_path
== 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
);
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
);
556 gi
->mtime
= buf
.st_mtime
;
557 gi
->size
= buf
.st_size
;
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
);
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
);
584 if (flags
& GEOIP_CHECK_CACHE
) {
585 if (fstat(fileno(gi
->GeoIPDatabase
), &buf
) == -1) {
586 fprintf(stderr
,"Error stating file %s\n",filename
);
591 gi
->mtime
= buf
.st_mtime
;
596 gi
->charset
= GEOIP_CHARSET_ISO_8859_1
;
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
);
612 gi
->index_cache
= NULL
;
618 void GeoIP_delete (GeoIP
*gi
) {
621 if (gi
->GeoIPDatabase
!= NULL
)
622 fclose(gi
->GeoIPDatabase
);
623 if (gi
->cache
!= NULL
) {
625 if ( gi
->flags
& GEOIP_MMAP_CACHE
) {
626 munmap(gi
->cache
, gi
->size
);
634 if (gi
->index_cache
!= NULL
)
635 free(gi
->index_cache
);
636 if (gi
->file_path
!= NULL
)
638 if (gi
->databaseSegments
!= NULL
)
639 free(gi
->databaseSegments
);
643 const char *GeoIP_country_code_by_name (GeoIP
* gi
, const char *name
) {
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
) {
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
) {
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
);
664 struct hostent
* phe
= &phe2
;
666 int buflength
= 16384;
669 #ifdef HAVE_GETHOSTBYNAME_R
670 buf
= malloc(buflength
);
672 if (addr
== INADDR_NONE
) {
673 #ifdef HAVE_GETHOSTBYNAME_R
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
);
679 phe
= gethostbyname_r(host
,&phe2
,buf
,buflength
,&herr
);
685 /* double the buffer if the buffer is too small */
686 buflength
= buflength
* 2;
687 buf
= realloc(buf
,buflength
);
690 #ifndef HAVE_GETHOSTBYNAME_R
691 /* Some systems do not support gethostbyname_r, such as Mac OS X */
692 phe
= gethostbyname(host
);
694 if (!phe
|| result
!= 0) {
698 addr
= *((unsigned long *) phe
->h_addr_list
[0]);
700 #ifdef HAVE_GETHOSTBYNAME_R
706 int GeoIP_id_by_name (GeoIP
* gi
, const char *name
) {
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
]);
716 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
718 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
723 const char *GeoIP_country_code_by_addr (GeoIP
* gi
, const char *addr
) {
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
) {
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
) {
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
) {
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
) {
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
) {
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
) {
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
]);
783 ipnum
= _GeoIP_addr_to_num(addr
);
784 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
788 int GeoIP_id_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
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
]);
801 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
805 char *GeoIP_database_info (GeoIP
* gi
) {
807 unsigned char buf
[3];
809 int hasStructureInfo
= 0;
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;
824 fseek(gi
->GeoIPDatabase
, -4l, SEEK_CUR
);
826 if (hasStructureInfo
== 1) {
827 fseek(gi
->GeoIPDatabase
, -6l, SEEK_CUR
);
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
) {
840 fread(retval
, 1, i
, gi
->GeoIPDatabase
);
844 fseek(gi
->GeoIPDatabase
, -4l, SEEK_CUR
);
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);
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
) {
876 /* we don't need to do anything here b/c we memset region to 0 */
877 } else if (seek_region
< CANADA_OFFSET
) {
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);
890 /* Not US or Canada */
891 memcpy(region
->country_code
, GeoIP_country_code
[(seek_region
- WORLD_OFFSET
) / FIPS_RANGE
], 2);
897 GeoIPRegion
* _get_region(GeoIP
* gi
, unsigned long ipnum
) {
898 GeoIPRegion
* region
;
900 region
= (GeoIPRegion
*)malloc(sizeof(GeoIPRegion
));
902 GeoIP_assign_region_by_inetaddr(gi
, htonl(ipnum
), region
);
907 GeoIPRegion
* GeoIP_region_by_addr (GeoIP
* gi
, const char *addr
) {
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
]);
917 ipnum
= _GeoIP_addr_to_num(addr
);
918 return _get_region(gi
, ipnum
);
921 GeoIPRegion
* GeoIP_region_by_name (GeoIP
* gi
, const char *name
) {
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
]);
931 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
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
]);
942 return _get_region(gi
, ipnum
);
945 void GeoIPRegion_delete (GeoIPRegion
*gir
) {
949 /* GeoIP Organization, ISP and AS Number Edition private method */
951 char *_get_name (GeoIP
* gi
, unsigned long ipnum
) {
953 char buf
[MAX_ORG_RECORD_LENGTH
];
954 char * org_buf
, * buf_pointer
;
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
]);
965 seek_org
= _GeoIP_seek_record(gi
, ipnum
);
966 if (seek_org
== gi
->databaseSegments
[0])
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
);
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
);
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
) {
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
;
1004 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
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
){
1029 int GeoIP_set_charset( GeoIP
* gi
, int charset
){
1030 int old_charset
= gi
->charset
;
1031 gi
->charset
= charset
;
1035 int GeoIP_last_netmask (GeoIP
* gi
) {