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 #define GEOIPDATADIR ""
27 #include <sys/socket.h>
28 #include <netinet/in.h> /* For ntohl */
29 #include <arpa/inet.h>
32 #define snprintf _snprintf
39 #include <sys/types.h> /* for fstat */
40 #include <sys/stat.h> /* for fstat */
43 #include <stdint.h> /* For uint32_t */
47 #define INADDR_NONE -1
50 #define COUNTRY_BEGIN 16776960
51 #define STATE_BEGIN_REV0 16700000
52 #define STATE_BEGIN_REV1 16000000
53 #define STRUCTURE_INFO_MAX_SIZE 20
54 #define DATABASE_INFO_MAX_SIZE 100
55 #define MAX_ORG_RECORD_LENGTH 300
57 #define CANADA_OFFSET 677
58 #define WORLD_OFFSET 1353
59 #define FIPS_RANGE 360
61 #define CHECK_ERR(err, msg) { \
63 fprintf(stderr, "%s error: %d\n", msg, err); \
68 const char GeoIP_country_code[251][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
69 "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
70 "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
71 "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
72 "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
73 "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
74 "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
75 "FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
76 "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
77 "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
78 "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
79 "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
80 "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
81 "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
82 "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
83 "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
84 "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
85 "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
86 "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
87 "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
88 "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
89 "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
90 "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
91 "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
92 "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"};
94 const char GeoIP_country_code3[251][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
95 "AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
96 "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
97 "BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
98 "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
99 "CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
100 "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
101 "FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
102 "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
103 "GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
104 "IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
105 "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
106 "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
107 "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
108 "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
109 "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
110 "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
111 "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
112 "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
113 "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
114 "SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
115 "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
116 "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
117 "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
118 "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"};
120 const char * GeoIP_country_name[251] = {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
121 "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
122 "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
123 "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
124 "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
125 "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
126 "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
127 "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
128 "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
129 "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
130 "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
131 "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
132 "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
133 "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
134 "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
135 "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
136 "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
137 "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
138 "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
139 "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
140 "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
141 "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
142 "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",
143 "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
144 "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"};
146 const char GeoIP_country_continent[251][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
147 "AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
148 "AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
149 "SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
150 "AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
151 "SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
152 "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
153 "SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
154 "AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
155 "OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
156 "EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
157 "AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
158 "SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
159 "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
160 "AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
161 "AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
162 "EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
163 "OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
164 "SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
165 "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
166 "SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
167 "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
168 "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
169 "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
170 "AF","EU","AF","--","--","--","EU","EU","EU","EU"};
172 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"};
174 char * custom_directory = NULL;
176 void GeoIP_setup_custom_directory (char * dir) {
177 custom_directory = dir;
180 char *_GeoIP_full_path_to(const char *file_name) {
181 char *path = malloc(sizeof(char) * 1024);
183 if (custom_directory == NULL){
185 memset(path, 0, sizeof(char) * 1024);
186 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
188 char buf[MAX_PATH], *p, *q = NULL;
190 memset(buf, 0, sizeof(buf));
191 len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1);
192 for (p = buf + len; p > buf; p--)
201 memset(path, 0, sizeof(char) * 1024);
202 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
205 size_t l = strlen(custom_directory);
206 if (custom_directory[l-1] != '/') {
207 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s",custom_directory, file_name);
209 snprintf(path, sizeof(char) * 1024 - 1, "%s%s", custom_directory, file_name);
215 char ** GeoIPDBFileName = NULL;
217 void _GeoIP_setup_dbfilename() {
218 if (NULL == GeoIPDBFileName) {
219 GeoIPDBFileName = malloc(sizeof(char *) * NUM_DB_TYPES);
220 memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES);
222 GeoIPDBFileName[GEOIP_COUNTRY_EDITION] = _GeoIP_full_path_to("GeoIP.dat");
223 GeoIPDBFileName[GEOIP_REGION_EDITION_REV0] = _GeoIP_full_path_to("GeoIPRegion.dat");
224 GeoIPDBFileName[GEOIP_REGION_EDITION_REV1] = _GeoIP_full_path_to("GeoIPRegion.dat");
225 GeoIPDBFileName[GEOIP_CITY_EDITION_REV0] = _GeoIP_full_path_to("GeoIPCity.dat");
226 GeoIPDBFileName[GEOIP_CITY_EDITION_REV1] = _GeoIP_full_path_to("GeoIPCity.dat");
227 GeoIPDBFileName[GEOIP_ISP_EDITION] = _GeoIP_full_path_to("GeoIPISP.dat");
228 GeoIPDBFileName[GEOIP_ORG_EDITION] = _GeoIP_full_path_to("GeoIPOrg.dat");
229 GeoIPDBFileName[GEOIP_PROXY_EDITION] = _GeoIP_full_path_to("GeoIPProxy.dat");
230 GeoIPDBFileName[GEOIP_ASNUM_EDITION] = _GeoIP_full_path_to("GeoIPASNum.dat");
231 GeoIPDBFileName[GEOIP_NETSPEED_EDITION] = _GeoIP_full_path_to("GeoIPNetSpeed.dat");
232 GeoIPDBFileName[GEOIP_DOMAIN_EDITION] = _GeoIP_full_path_to("GeoIPDomain.dat");
237 int _file_exists(const char *file_name) {
238 struct stat file_stat;
239 return( (stat(file_name, &file_stat) == 0) ? 1:0);
242 int GeoIP_db_avail(int type) {
243 const char * filePath;
244 if (type < 0 || type >= NUM_DB_TYPES) {
247 filePath = GeoIPDBFileName[type];
248 if (NULL == filePath) {
251 return _file_exists(filePath);
255 void _setup_segments(GeoIP * gi) {
257 unsigned char delim[3];
258 unsigned char buf[SEGMENT_RECORD_LENGTH];
260 gi->databaseSegments = NULL;
262 /* default to GeoIP Country Edition */
263 gi->databaseType = GEOIP_COUNTRY_EDITION;
264 gi->record_length = STANDARD_RECORD_LENGTH;
265 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
266 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
267 fread(delim, 1, 3, gi->GeoIPDatabase);
268 if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
269 fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase);
270 if (gi->databaseType >= 106) {
271 /* backwards compatibility with databases from April 2003 and earlier */
272 gi->databaseType -= 105;
275 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
276 /* Region Edition, pre June 2003 */
277 gi->databaseSegments = malloc(sizeof(int));
278 gi->databaseSegments[0] = STATE_BEGIN_REV0;
279 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
280 /* Region Edition, post June 2003 */
281 gi->databaseSegments = malloc(sizeof(int));
282 gi->databaseSegments[0] = STATE_BEGIN_REV1;
283 } else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 ||
284 gi->databaseType == GEOIP_CITY_EDITION_REV1 ||
285 gi->databaseType == GEOIP_ORG_EDITION ||
286 gi->databaseType == GEOIP_ISP_EDITION ||
287 gi->databaseType == GEOIP_ASNUM_EDITION) {
288 /* City/Org Editions have two segments, read offset of second segment */
289 gi->databaseSegments = malloc(sizeof(int));
290 gi->databaseSegments[0] = 0;
291 fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase);
292 for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
293 gi->databaseSegments[0] += (buf[j] << (j * 8));
295 if (gi->databaseType == GEOIP_ORG_EDITION ||
296 gi->databaseType == GEOIP_ISP_EDITION)
297 gi->record_length = ORG_RECORD_LENGTH;
301 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
304 if (gi->databaseType == GEOIP_COUNTRY_EDITION ||
305 gi->databaseType == GEOIP_PROXY_EDITION ||
306 gi->databaseType == GEOIP_NETSPEED_EDITION) {
307 gi->databaseSegments = malloc(sizeof(int));
308 gi->databaseSegments[0] = COUNTRY_BEGIN;
313 int _check_mtime(GeoIP *gi) {
315 if (gi->flags & GEOIP_CHECK_CACHE) {
316 if (stat(gi->file_path, &buf) != -1) {
317 if (buf.st_mtime != gi->mtime) {
318 /* GeoIP Database file updated */
319 if (gi->flags & GEOIP_MEMORY_CACHE) {
320 /* reload database into memory cache */
321 if ((gi->cache = (unsigned char*) realloc(gi->cache, buf.st_size)) == NULL) {
322 fprintf(stderr,"Out of memory when reloading %s\n",gi->file_path);
326 /* refresh filehandle */
327 fclose(gi->GeoIPDatabase);
328 gi->GeoIPDatabase = fopen(gi->file_path,"rb");
329 if (gi->GeoIPDatabase == NULL) {
330 fprintf(stderr,"Error Opening file %s when reloading\n",gi->file_path);
333 gi->mtime = buf.st_mtime;
334 if (gi->flags & GEOIP_MEMORY_CACHE) {
335 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
336 fprintf(stderr,"Error reading file %s when reloading\n",gi->file_path);
340 if (gi->databaseSegments != NULL) {
341 free(gi->databaseSegments);
342 gi->databaseSegments = NULL;
345 if (gi->databaseSegments == NULL) {
346 fprintf(stderr, "Error reading file %s -- corrupt\n", gi->file_path);
349 if (gi->flags & GEOIP_INDEX_CACHE) {
350 gi->index_cache = (unsigned char *) realloc(gi->index_cache, sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
351 if (gi->index_cache != NULL) {
352 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
353 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)) {
354 fprintf(stderr,"Error reading file %s where reloading\n",gi->file_path);
365 unsigned int _GeoIP_seek_record (GeoIP *gi, unsigned long ipnum) {
368 unsigned char stack_buffer[2 * MAX_RECORD_LENGTH];
369 const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL;
370 unsigned int offset = 0;
372 const unsigned char * p;
376 for (depth = 31; depth >= 0; depth--) {
377 if (gi->cache == NULL && gi->index_cache == NULL) {
379 fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET);
380 fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase);
381 } else if (gi->index_cache == NULL) {
382 /* simply point to record in memory */
383 buf = gi->cache + (long)gi->record_length * 2 *offset;
385 buf = gi->index_cache + (long)gi->record_length * 2 * offset;
388 if (ipnum & (1 << depth)) {
389 /* Take the right-hand branch */
390 if ( gi->record_length == 3 ) {
391 /* Most common case is completely unrolled and uses constants. */
392 x = (buf[3*1 + 0] << (0*8))
393 + (buf[3*1 + 1] << (1*8))
394 + (buf[3*1 + 2] << (2*8));
398 j = gi->record_length;
408 /* Take the left-hand branch */
409 if ( gi->record_length == 3 ) {
410 /* Most common case is completely unrolled and uses constants. */
411 x = (buf[3*0 + 0] << (0*8))
412 + (buf[3*0 + 1] << (1*8))
413 + (buf[3*0 + 2] << (2*8));
416 j = gi->record_length;
426 if (x >= gi->databaseSegments[0]) {
432 /* shouldn't reach here */
433 fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum);
437 unsigned long _GeoIP_addr_to_num (const char *addr) {
442 unsigned long ipnum = 0;
445 for (i=0; i<4; i++) {
448 if (c == '.' || c == '\0') {
453 ipnum += (octet << ((3-i)*8));
456 } else if (c >= '0' && c<= '9') {
465 if(c == '\0' && i<3) {
472 GeoIP* GeoIP_open_type (int type, int flags) {
474 const char * filePath;
475 if (type < 0 || type >= NUM_DB_TYPES) {
476 printf("Invalid database type %d\n", type);
479 _GeoIP_setup_dbfilename();
480 filePath = GeoIPDBFileName[type];
481 if (filePath == NULL) {
482 printf("Invalid database type %d\n", type);
485 gi = GeoIP_open (filePath, flags);
489 GeoIP* GeoIP_new (int flags) {
491 _GeoIP_setup_dbfilename();
492 gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags);
496 GeoIP* GeoIP_open (const char * filename, int flags) {
503 if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
507 gi = (GeoIP *)malloc(sizeof(GeoIP));
510 len = sizeof(char) * (strlen(filename)+1);
511 gi->file_path = malloc(len);
512 if (gi->file_path == NULL) {
516 strncpy(gi->file_path, filename, len);
517 gi->GeoIPDatabase = fopen(filename,"rb");
518 if (gi->GeoIPDatabase == NULL) {
519 fprintf(stderr,"Error Opening file %s\n",filename);
524 if (flags & GEOIP_MEMORY_CACHE) {
525 if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
526 fprintf(stderr,"Error stating file %s\n",filename);
531 gi->mtime = buf.st_mtime;
532 gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * buf.st_size);
533 if (gi->cache != NULL) {
534 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
535 fprintf(stderr,"Error reading file %s\n",filename);
543 if (flags & GEOIP_CHECK_CACHE) {
544 if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
545 fprintf(stderr,"Error stating file %s\n",filename);
550 gi->mtime = buf.st_mtime;
556 if (flags & GEOIP_INDEX_CACHE) {
557 gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
558 if (gi->index_cache != NULL) {
559 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
560 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)) {
561 fprintf(stderr,"Error reading file %s\n",filename);
562 free(gi->databaseSegments);
563 free(gi->index_cache);
569 gi->index_cache = NULL;
575 void GeoIP_delete (GeoIP *gi) {
578 if (gi->GeoIPDatabase != NULL)
579 fclose(gi->GeoIPDatabase);
580 if (gi->cache != NULL)
582 if (gi->index_cache != NULL)
583 free(gi->index_cache);
584 if (gi->file_path != NULL)
586 if (gi->databaseSegments != NULL)
587 free(gi->databaseSegments);
591 const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) {
593 country_id = GeoIP_id_by_name(gi, name);
594 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
597 const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) {
599 country_id = GeoIP_id_by_name(gi, name);
600 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
603 const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) {
605 country_id = GeoIP_id_by_name(gi, name);
606 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
609 unsigned long _GeoIP_lookupaddress (const char *host) {
610 unsigned long addr = inet_addr(host);
612 struct hostent * phe = &phe2;
615 #ifdef HAVE_GETHOSTBYNAME_R
616 buf = malloc(buflength);
618 if (addr == INADDR_NONE) {
619 #ifdef HAVE_GETHOSTBYNAME_R
621 /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
622 #ifdef GETHOSTBYNAME_R_RETURNS_INT
623 result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr);
625 phe = gethostbyname_r(host,&phe2,buf,buflength,&herr);
631 /* double the buffer if the buffer is too small */
632 buflength = buflength * 2;
633 buf = realloc(buf,buflength);
636 #ifndef HAVE_GETHOSTBYNAME_R
637 /* Some systems do not support gethostbyname_r, such as Mac OS X */
638 phe = gethostbyname(host);
640 if (!phe || result != 0) {
644 addr = *((unsigned long *) phe->h_addr_list[0]);
646 #ifdef HAVE_GETHOSTBYNAME_R
652 int GeoIP_id_by_name (GeoIP* gi, const char *name) {
658 if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) {
659 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
662 if (!(ipnum = _GeoIP_lookupaddress(name)))
664 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
669 const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) {
671 country_id = GeoIP_id_by_addr(gi, addr);
672 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
675 const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) {
677 country_id = GeoIP_id_by_addr(gi, addr);
678 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
679 return GeoIP_country_code3[country_id];
682 const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) {
684 country_id = GeoIP_id_by_addr(gi, addr);
685 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
686 return GeoIP_country_name[country_id];
689 const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
691 country_id = GeoIP_id_by_ipnum(gi, ipnum);
692 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
695 const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) {
697 country_id = GeoIP_id_by_ipnum(gi, ipnum);
698 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
701 const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum) {
703 country_id = GeoIP_id_by_ipnum(gi, ipnum);
704 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
707 int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) {
708 return GeoIP_id_by_addr(gi, addr);
711 int GeoIP_country_id_by_name (GeoIP* gi, const char *host) {
712 return GeoIP_id_by_name(gi, host);
715 int GeoIP_id_by_addr (GeoIP* gi, const char *addr) {
721 if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
722 gi->databaseType != GEOIP_PROXY_EDITION &&
723 gi->databaseType != GEOIP_NETSPEED_EDITION) {
724 printf("Invalid database type %s, expected %s\n",
725 GeoIPDBDescription[(int)gi->databaseType],
726 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
729 ipnum = _GeoIP_addr_to_num(addr);
730 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
734 int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) {
739 if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
740 gi->databaseType != GEOIP_PROXY_EDITION &&
741 gi->databaseType != GEOIP_NETSPEED_EDITION) {
742 printf("Invalid database type %s, expected %s\n",
743 GeoIPDBDescription[(int)gi->databaseType],
744 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
747 ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
751 char *GeoIP_database_info (GeoIP* gi) {
753 unsigned char buf[3];
755 int hasStructureInfo = 0;
761 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
763 /* first get past the database structure information */
764 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
765 fread(buf, 1, 3, gi->GeoIPDatabase);
766 if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) {
767 hasStructureInfo = 1;
770 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
772 if (hasStructureInfo == 1) {
773 fseek(gi->GeoIPDatabase, -3l, SEEK_CUR);
775 /* no structure info, must be pre Sep 2002 database, go back to end */
776 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
779 for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
780 fread(buf, 1, 3, gi->GeoIPDatabase);
781 if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) {
782 retval = malloc(sizeof(char) * (i+1));
783 if (retval == NULL) {
786 fread(retval, 1, i, gi->GeoIPDatabase);
790 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
795 /* GeoIP Region Edition functions */
797 void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) {
798 unsigned int seek_region;
800 /* This also writes in the terminating NULs (if you decide to
801 * keep them) and clear any fields that are not set. */
802 memset(region, 0, sizeof(GeoIPRegion));
804 seek_region = _GeoIP_seek_record(gi, ntohl(inetaddr));
806 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
807 /* Region Edition, pre June 2003 */
808 seek_region -= STATE_BEGIN_REV0;
809 if (seek_region >= 1000) {
810 region->country_code[0] = 'U';
811 region->country_code[1] = 'S';
812 region->region[0] = (char) ((seek_region - 1000)/26 + 65);
813 region->region[1] = (char) ((seek_region - 1000)%26 + 65);
815 memcpy(region->country_code, GeoIP_country_code[seek_region], 2);
817 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
818 /* Region Edition, post June 2003 */
819 seek_region -= STATE_BEGIN_REV1;
820 if (seek_region < US_OFFSET) {
822 /* we don't need to do anything here b/c we memset region to 0 */
823 } else if (seek_region < CANADA_OFFSET) {
825 region->country_code[0] = 'U';
826 region->country_code[1] = 'S';
827 region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65);
828 region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65);
829 } else if (seek_region < WORLD_OFFSET) {
830 /* Canada Province */
831 region->country_code[0] = 'C';
832 region->country_code[1] = 'A';
833 region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65);
834 region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65);
836 /* Not US or Canada */
837 memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2);
843 GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) {
844 GeoIPRegion * region;
846 region = malloc(sizeof(GeoIPRegion));
848 GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region);
853 GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) {
858 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
859 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
860 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
863 ipnum = _GeoIP_addr_to_num(addr);
864 return _get_region(gi, ipnum);
867 GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) {
872 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
873 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
874 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
877 if (!(ipnum = _GeoIP_lookupaddress(name)))
879 return _get_region(gi, ipnum);
882 GeoIPRegion * GeoIP_region_by_ipnum (GeoIP* gi, unsigned long ipnum) {
883 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
884 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
885 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
888 return _get_region(gi, ipnum);
891 void GeoIPRegion_delete (GeoIPRegion *gir) {
895 /* GeoIP Organization, ISP and AS Number Edition private method */
897 char *_get_name (GeoIP* gi, unsigned long ipnum) {
899 char buf[MAX_ORG_RECORD_LENGTH];
900 char * org_buf, * buf_pointer;
904 if (gi->databaseType != GEOIP_ORG_EDITION &&
905 gi->databaseType != GEOIP_ISP_EDITION &&
906 gi->databaseType != GEOIP_ASNUM_EDITION) {
907 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]);
911 seek_org = _GeoIP_seek_record(gi, ipnum);
912 if (seek_org == gi->databaseSegments[0])
915 record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0];
917 if (gi->cache == NULL) {
918 fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET);
919 fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase);
920 len = sizeof(char) * (strlen(buf)+1);
921 org_buf = malloc(len);
922 strncpy(org_buf, buf, len);
924 buf_pointer = (char *)(gi->cache + (long)record_pointer);
925 len = sizeof(char) * (strlen(buf_pointer)+1);
926 org_buf = malloc(len);
927 strncpy(org_buf, buf_pointer, len);
932 char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
933 return _get_name(gi,ipnum);
936 char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) {
941 ipnum = _GeoIP_addr_to_num(addr);
942 return _get_name(gi, ipnum);
945 char *GeoIP_name_by_name (GeoIP* gi, const char *name) {
950 if (!(ipnum = _GeoIP_lookupaddress(name)))
952 return _get_name(gi, ipnum);
955 char *GeoIP_org_by_ipnum (GeoIP* gi, unsigned long ipnum) {
956 return GeoIP_name_by_ipnum(gi, ipnum);
959 char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) {
960 return GeoIP_name_by_addr(gi, addr);
963 char *GeoIP_org_by_name (GeoIP* gi, const char *name) {
964 return GeoIP_name_by_name(gi, name);
967 unsigned char GeoIP_database_edition (GeoIP* gi) {
968 return gi->databaseType;