]> jfr.im git - irc/quakenet/newserv.git/blob - nterface/libGeoIP/GeoIP.c
e3f7818472d69bc36c7cf245b315673789c751b2
[irc/quakenet/newserv.git] / nterface / libGeoIP / GeoIP.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
2 /* GeoIP.c
3 *
4 * Copyright (C) 2003 MaxMind LLC All Rights Reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
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 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "GeoIP.h"
22
23 #include <netdb.h>
24 #include <sys/socket.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #ifndef _WIN32
30 #include <netdb.h>
31 #include <netinet/in.h> /* For ntohl */
32 #include <arpa/inet.h>
33 #else
34 #include <windows.h>
35 #endif
36 #include <assert.h>
37 #include <sys/types.h> /* for fstat */
38 #include <sys/stat.h> /* for fstat */
39
40 #ifdef HAVE_STDINT_H
41 #include <stdint.h> /* For uint32_t */
42 #endif
43
44 #ifndef INADDR_NONE
45 #define INADDR_NONE -1
46 #endif
47
48 #define COUNTRY_BEGIN 16776960
49 #define STATE_BEGIN_REV0 16700000
50 #define STATE_BEGIN_REV1 16000000
51 #define STRUCTURE_INFO_MAX_SIZE 20
52 #define DATABASE_INFO_MAX_SIZE 100
53 #define MAX_ORG_RECORD_LENGTH 300
54 #define US_OFFSET 1
55 #define CANADA_OFFSET 677
56 #define WORLD_OFFSET 1353
57 #define FIPS_RANGE 360
58
59 #define CHECK_ERR(err, msg) { \
60 if (err != Z_OK) { \
61 fprintf(stderr, "%s error: %d\n", msg, err); \
62 exit(1); \
63 } \
64 }
65
66 const char GeoIP_country_code[247][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","FX","GA","GB","GD","GE","GF","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TM","TN","TO","TP","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","YU","ZA","ZM","ZR","ZW","A1","A2","O1"};
67
68 const char GeoIP_country_code3[247][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT","AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB","BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL","BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD","CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI","CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM","DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI","FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF","GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM","GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN","IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR","JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT","CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU","LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI","MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV","MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC","NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF","PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW","PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN","SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM","SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA","TJK","TKL","TLS","TKM","TUN","TON","TUR","TTO","TUV","TWN","TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN","VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","YUG","ZAF","ZMB","ZR","ZWE","A1","A2","O1"};
69
70 const char * GeoIP_country_name[247] = {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles","Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados","Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia","Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the","Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic","Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji","Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana","Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala","Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia","Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan","Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis",
71 "Korea, Democratic People's Republic of","Korea, Republic of","Kuwait","Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania","Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali","Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia","Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory, Occupied","Portugal","Palau","Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname","Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand","Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","East Timor","Turkey","Trinidad and Tobago","Tuvalu","Taiwan","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","Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Yugoslavia","South Africa","Zambia","Zaire","Zimbabwe",
72 "Anonymous Proxy","Satellite Provider","Other"};
73
74 const char GeoIP_country_continent[247][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA","AF","AN","SA","OC","EU","OC","SA","AS","EU","SA","AS","EU","AF","EU","AS","AF","AF","SA","AS","SA","SA","SA","AS","AF","AF","EU","SA","NA","AS","AF","AF","AF","EU","AF","OC","SA","AF","AS","SA","SA","SA","AF","AS","AS","EU","EU","AF","EU","SA","SA","AF","SA","EU","AF","AF","AF","EU","AF","EU","OC","SA","OC","EU","EU","EU","AF","EU","SA","AS","SA","AF","EU","SA","AF","AF","SA","AF","EU","SA","SA","OC","AF","SA","AS","AF","SA","EU","SA","EU","AS","EU","AS","AS","AS","AS","AS","EU","EU","SA","AS","AS","AF","AS","AS","OC","AF","SA","AS","AS","AS","SA","AS","AS","AS","SA","EU","AS","AF","AF","EU","EU","EU","AF","AF","EU","EU","AF","OC","EU","AF","AS","AS","AS","OC","SA","AF","SA","EU","AF","AS","AF","NA","AS","AF","AF","OC","AF","OC","AF","SA","EU","EU","AS","OC","OC","OC","AS","SA","SA","OC","OC","AS","AS","EU","SA","OC","SA","AS","EU","OC","SA","AS","AF","EU","AS","AF","AS","OC","AF","AF","EU","AS","AF","EU","EU","EU","AF","EU","AF","AF","SA","AF","SA","AS","AF","SA","AF","AF","AF","AS","AS","OC","AS","AF","OC","AS","AS","SA","OC","AS","AF","EU","AF","OC","NA","SA","AS","EU","SA","SA","SA","SA","AS","OC","OC","OC","AS","AF","EU","AF","AF","AF","AF"};
75
76 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"};
77
78 #define GEOIPDATADIR "/"
79
80 char *_full_path_to(const char *file_name) {
81 char *path = malloc(sizeof(char) * 1024);
82
83 #ifndef _WIN32
84 memset(path, 0, sizeof(char) * 1024);
85 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
86 #else
87 char buf[MAX_PATH], *p, *q = NULL;
88 int len;
89 memset(buf, 0, sizeof(buf));
90 len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1);
91 for (p = buf + len; p > buf; p--)
92 if (*p == '\\')
93 {
94 if (!q)
95 q = p;
96 else
97 *p = '/';
98 }
99 *q = 0;
100 memset(path, 0, sizeof(char) * 1024);
101 snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
102 #endif
103
104 return path;
105 }
106
107 char ** GeoIPDBFileName = NULL;
108
109 void _setup_dbfilename() {
110 if (NULL == GeoIPDBFileName) {
111 GeoIPDBFileName = malloc(sizeof(char *) * NUM_DB_TYPES);
112 memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES);
113
114 GeoIPDBFileName[GEOIP_COUNTRY_EDITION] = _full_path_to("GeoIP.dat");
115 GeoIPDBFileName[GEOIP_REGION_EDITION_REV0] = _full_path_to("GeoIPRegion.dat");
116 GeoIPDBFileName[GEOIP_REGION_EDITION_REV1] = _full_path_to("GeoIPRegion.dat");
117 GeoIPDBFileName[GEOIP_CITY_EDITION_REV0] = _full_path_to("GeoIPCity.dat");
118 GeoIPDBFileName[GEOIP_CITY_EDITION_REV1] = _full_path_to("GeoIPCity.dat");
119 GeoIPDBFileName[GEOIP_ISP_EDITION] = _full_path_to("GeoIPISP.dat");
120 GeoIPDBFileName[GEOIP_ORG_EDITION] = _full_path_to("GeoIPOrg.dat");
121 GeoIPDBFileName[GEOIP_PROXY_EDITION] = _full_path_to("GeoIPProxy.dat");
122 GeoIPDBFileName[GEOIP_ASNUM_EDITION] = _full_path_to("GeoIPASNum.dat");
123 GeoIPDBFileName[GEOIP_NETSPEED_EDITION] = _full_path_to("GeoIPNetSpeed.dat");
124 }
125 }
126
127 int _file_exists(const char *file_name) {
128 FILE *f;
129 f = fopen(file_name, "r");
130 if(!f)
131 return 0;
132 fclose(f);
133 return 1;
134 }
135
136 int GeoIP_db_avail(int type) {
137 const char * filePath;
138 if (type < 0 || type >= NUM_DB_TYPES) {
139 return 0;
140 }
141 filePath = GeoIPDBFileName[type];
142 if (NULL == filePath) {
143 return 0;
144 }
145 return _file_exists(filePath);
146 }
147
148 void _setup_segments(GeoIP * gi) {
149 int i, j;
150 unsigned char delim[3];
151 unsigned char buf[SEGMENT_RECORD_LENGTH];
152
153 /* default to GeoIP Country Edition */
154 gi->databaseType = GEOIP_COUNTRY_EDITION;
155 gi->record_length = STANDARD_RECORD_LENGTH;
156 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
157 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
158 fread(delim, 1, 3, gi->GeoIPDatabase);
159 if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
160 fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase);
161 if (gi->databaseType >= 106) {
162 /* backwards compatibility with databases from April 2003 and earlier */
163 gi->databaseType -= 105;
164 }
165
166 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
167 /* Region Edition, pre June 2003 */
168 gi->databaseSegments = malloc(sizeof(int));
169 gi->databaseSegments[0] = STATE_BEGIN_REV0;
170 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
171 /* Region Edition, post June 2003 */
172 gi->databaseSegments = malloc(sizeof(int));
173 gi->databaseSegments[0] = STATE_BEGIN_REV1;
174 } else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 ||
175 gi->databaseType == GEOIP_CITY_EDITION_REV1 ||
176 gi->databaseType == GEOIP_ORG_EDITION ||
177 gi->databaseType == GEOIP_ISP_EDITION ||
178 gi->databaseType == GEOIP_ASNUM_EDITION) {
179 /* City/Org Editions have two segments, read offset of second segment */
180 gi->databaseSegments = malloc(sizeof(int));
181 gi->databaseSegments[0] = 0;
182 fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase);
183 for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
184 gi->databaseSegments[0] += (buf[j] << (j * 8));
185 }
186 if (gi->databaseType == GEOIP_ORG_EDITION ||
187 gi->databaseType == GEOIP_ISP_EDITION)
188 gi->record_length = ORG_RECORD_LENGTH;
189 }
190 break;
191 } else {
192 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
193 }
194 }
195 if (gi->databaseType == GEOIP_COUNTRY_EDITION ||
196 gi->databaseType == GEOIP_PROXY_EDITION ||
197 gi->databaseType == GEOIP_NETSPEED_EDITION) {
198 gi->databaseSegments = malloc(sizeof(int));
199 gi->databaseSegments[0] = COUNTRY_BEGIN;
200 }
201 }
202
203 unsigned int _seek_record (GeoIP *gi, unsigned long ipnum) {
204 int depth;
205 unsigned int x;
206 unsigned char stack_buffer[2 * MAX_RECORD_LENGTH];
207 const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL;
208 unsigned int offset = 0;
209
210 const unsigned char * p;
211 int j;
212
213 for (depth = 31; depth >= 0; depth--) {
214 if (gi->cache == NULL && gi->index_cache == NULL) {
215 /* read from disk */
216 fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET);
217 fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase);
218 } else if (gi->index_cache == NULL) {
219 /* simply point to record in memory */
220 buf = gi->cache + (long)gi->record_length * 2 *offset;
221 } else {
222 buf = gi->index_cache + (long)gi->record_length * 2 * offset;
223 }
224
225 if (ipnum & (1 << depth)) {
226 /* Take the right-hand branch */
227 if ( gi->record_length == 3 ) {
228 /* Most common case is completely unrolled and uses constants. */
229 x = (buf[3*1 + 0] << (0*8))
230 + (buf[3*1 + 1] << (1*8))
231 + (buf[3*1 + 2] << (2*8));
232
233 } else {
234 /* General case */
235 j = gi->record_length;
236 p = &buf[2*j];
237 x = 0;
238 do {
239 x <<= 8;
240 x += *(--p);
241 } while ( --j );
242 }
243
244 } else {
245 /* Take the left-hand branch */
246 if ( gi->record_length == 3 ) {
247 /* Most common case is completely unrolled and uses constants. */
248 x = (buf[3*0 + 0] << (0*8))
249 + (buf[3*0 + 1] << (1*8))
250 + (buf[3*0 + 2] << (2*8));
251 } else {
252 /* General case */
253 j = gi->record_length;
254 p = &buf[1*j];
255 x = 0;
256 do {
257 x <<= 8;
258 x += *(--p);
259 } while ( --j );
260 }
261 }
262
263 if (x >= gi->databaseSegments[0]) {
264 return x;
265 }
266 offset = x;
267 }
268
269 /* shouldn't reach here */
270 fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum);
271 return 0;
272 }
273
274 unsigned long _addr_to_num (const char *addr) {
275 int i;
276 char tok[4];
277 int octet;
278 int j = 0, k = 0;
279 unsigned long ipnum = 0;
280 char c = 0;
281
282 for (i=0; i<4; i++) {
283 for (;;) {
284 c = addr[k++];
285 if (c == '.' || c == '\0') {
286 tok[j] = '\0';
287 octet = atoi(tok);
288 if (octet > 255)
289 return 0;
290 ipnum += (octet << ((3-i)*8));
291 j = 0;
292 break;
293 } else if (c >= '0' && c<= '9') {
294 if (j > 2) {
295 return 0;
296 }
297 tok[j++] = c;
298 } else {
299 return 0;
300 }
301 }
302 if(c == '\0' && i<3) {
303 return 0;
304 }
305 }
306 return ipnum;
307 }
308
309 GeoIP* GeoIP_open_type (int type, int flags) {
310 GeoIP * gi;
311 const char * filePath;
312 if (type < 0 || type >= NUM_DB_TYPES) {
313 printf("Invalid database type %d\n", type);
314 return NULL;
315 }
316 _setup_dbfilename();
317 filePath = GeoIPDBFileName[type];
318 if (filePath == NULL) {
319 printf("Invalid database type %d\n", type);
320 return NULL;
321 }
322 gi = GeoIP_open (filePath, flags);
323 return gi;
324 }
325
326 GeoIP* GeoIP_new (int flags, char *filename) {
327 GeoIP * gi;
328 gi = GeoIP_open (filename, flags);
329 return gi;
330 }
331
332 GeoIP* GeoIP_open (const char * filename, int flags) {
333 #ifdef _WIN32
334 WSADATA wsa;
335 if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
336 return NULL;
337 #endif
338
339 GeoIP *gi = (GeoIP *)malloc(sizeof(GeoIP));
340 if (gi == NULL)
341 return NULL;
342 gi->file_path = malloc(sizeof(char) * (strlen(filename)+1));
343 if (gi->file_path == NULL)
344 return NULL;
345 strcpy(gi->file_path, filename);
346 gi->GeoIPDatabase = fopen(filename,"rb");
347 if (gi->GeoIPDatabase == NULL) {
348 fprintf(stderr,"Error Opening file %s\n",filename);
349 free(gi->file_path);
350 free(gi);
351 return NULL;
352 } else {
353 long st_size;
354 fseek(gi->GeoIPDatabase, 0, SEEK_END);
355 st_size = ftell(gi->GeoIPDatabase);
356 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
357 if (flags & GEOIP_MEMORY_CACHE) {
358 gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * st_size);
359 if (gi->cache != NULL) {
360 if (fread(gi->cache, sizeof(unsigned char), st_size, gi->GeoIPDatabase) != st_size) {
361 fprintf(stderr,"Error reading file %s\n",filename);
362 free(gi->cache);
363 free(gi);
364 return NULL;
365 }
366 }
367 } else {
368 gi->cache = NULL;
369 }
370 gi->flags = flags;
371 _setup_segments(gi);
372 if (flags & GEOIP_INDEX_CACHE) {
373 gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * gi->databaseSegments[0]);
374 if (gi->index_cache != NULL) {
375 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
376 if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0], gi->GeoIPDatabase) != (size_t) gi->databaseSegments[0]) {
377 fprintf(stderr,"Error reading file %s\n",filename);
378 free(gi->index_cache);
379 free(gi);
380 return NULL;
381 }
382 }
383 } else {
384 gi->index_cache = NULL;
385 }
386 return gi;
387 }
388 }
389
390 void GeoIP_delete (GeoIP *gi) {
391 if (gi->GeoIPDatabase != NULL)
392 fclose(gi->GeoIPDatabase);
393 if (gi->cache != NULL)
394 free(gi->cache);
395 if (gi->index_cache != NULL)
396 free(gi->index_cache);
397 if (gi->file_path != NULL)
398 free(gi->file_path);
399 if (gi->databaseSegments != NULL)
400 free(gi->databaseSegments);
401 free(gi);
402 }
403
404 const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) {
405 int country_id;
406 country_id = GeoIP_id_by_name(gi, name);
407 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
408 }
409
410 const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) {
411 int country_id;
412 country_id = GeoIP_id_by_name(gi, name);
413 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
414 }
415
416 const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) {
417 int country_id;
418 country_id = GeoIP_id_by_name(gi, name);
419 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
420 }
421
422 unsigned long lookupaddress (const char *host) {
423 unsigned long addr = inet_addr(host);
424 struct hostent phe2;
425 struct hostent * phe = &phe2;
426 char *buf = NULL;
427 int result = 0;
428
429 #ifdef HAVE_GETHOSTBYNAME_R
430 int herr = 0;
431 int buflength = 16384;
432 buf = malloc(buflength);
433 #endif
434 if (addr == INADDR_NONE) {
435 #ifdef HAVE_GETHOSTBYNAME_R
436 while (1) {
437 /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
438 #ifdef GETHOSTBYNAME_R_RETURNS_INT
439 result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr);
440 #else
441 phe = gethostbyname_r(host,&phe2,buf,buflength,&herr);
442 #endif
443 if (herr != ERANGE)
444 break;
445 if (result == 0)
446 break;
447 /* double the buffer if the buffer is too small */
448 buflength = buflength * 2;
449 buf = realloc(buf,buflength);
450 }
451 #endif
452 #ifndef HAVE_GETHOSTBYNAME_R
453 /* Some systems do not support gethostbyname_r, such as Mac OS X */
454 phe = gethostbyname(host);
455 #endif
456 if (!phe || result != 0) {
457 free(buf);
458 return 0;
459 }
460 addr = *((unsigned long *) phe->h_addr_list[0]);
461 }
462 #ifdef HAVE_GETHOSTBYNAME_R
463 free(buf);
464 #endif
465 return ntohl(addr);
466 }
467
468 int GeoIP_id_by_name (GeoIP* gi, const char *name) {
469 unsigned long ipnum;
470 int ret;
471 if (name == NULL) {
472 return 0;
473 }
474 if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) {
475 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
476 return 0;
477 }
478 if (!(ipnum = lookupaddress(name)))
479 return 0;
480 ret = _seek_record(gi, ipnum) - COUNTRY_BEGIN;
481 return ret;
482
483 }
484
485 const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) {
486 int country_id;
487 country_id = GeoIP_id_by_addr(gi, addr);
488 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
489 }
490
491 const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) {
492 int country_id;
493 country_id = GeoIP_id_by_addr(gi, addr);
494 return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
495 return GeoIP_country_code3[country_id];
496 }
497
498 const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) {
499 int country_id;
500 country_id = GeoIP_id_by_addr(gi, addr);
501 return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
502 return GeoIP_country_name[country_id];
503 }
504
505 const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) {
506 int country_id;
507 country_id = GeoIP_id_by_ipnum(gi, ipnum);
508 return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
509 }
510
511 int GeoIP_country_info_by_id(int id, char **two, char **three, char **full) {
512 if(id < 0)
513 return 0;
514 *two = (char *)GeoIP_country_code[id];
515 *three = (char *)GeoIP_country_code3[id];
516 *full = (char *)GeoIP_country_name[id];
517
518 return 1;
519 }
520
521 int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) {
522 return GeoIP_id_by_addr(gi, addr);
523 }
524
525 int GeoIP_country_id_by_name (GeoIP* gi, const char *host) {
526 return GeoIP_id_by_name(gi, host);
527 }
528
529 int GeoIP_id_by_addr (GeoIP* gi, const char *addr) {
530 unsigned long ipnum;
531 int ret;
532 if (addr == NULL) {
533 return 0;
534 }
535 if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
536 gi->databaseType != GEOIP_PROXY_EDITION &&
537 gi->databaseType != GEOIP_NETSPEED_EDITION) {
538 printf("Invalid database type %s, expected %s\n",
539 GeoIPDBDescription[(int)gi->databaseType],
540 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
541 return 0;
542 }
543 ipnum = _addr_to_num(addr);
544 ret = _seek_record(gi, ipnum) - COUNTRY_BEGIN;
545 return ret;
546 }
547
548 int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) {
549 if (ipnum == 0)
550 return 0;
551 return _seek_record(gi, ipnum) - COUNTRY_BEGIN;
552 }
553
554 char *GeoIP_database_info (GeoIP* gi) {
555 int i;
556 unsigned char buf[3];
557 char *retval;
558 int hasStructureInfo = 0;
559
560 if(gi == NULL)
561 return NULL;
562
563 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
564
565 /* first get past the database structure information */
566 for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
567 fread(buf, 1, 3, gi->GeoIPDatabase);
568 if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) {
569 hasStructureInfo = 1;
570 break;
571 }
572 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
573 }
574 if (hasStructureInfo == 1) {
575 fseek(gi->GeoIPDatabase, -3l, SEEK_CUR);
576 } else {
577 /* no structure info, must be pre Sep 2002 database, go back to end */
578 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
579 }
580
581 for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
582 fread(buf, 1, 3, gi->GeoIPDatabase);
583 if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) {
584 retval = malloc(sizeof(char) * (i+1));
585 if (retval == NULL) {
586 return NULL;
587 }
588 fread(retval, 1, i, gi->GeoIPDatabase);
589 retval[i] = '\0';
590 return retval;
591 }
592 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
593 }
594 return NULL;
595 }
596
597 /* GeoIP Region Edition functions */
598
599 void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) {
600 unsigned int seek_region;
601
602 /* This also writes in the terminating NULs (if you decide to
603 * keep them) and clear any fields that are not set. */
604 memset(region, 0, sizeof(GeoIPRegion));
605
606 seek_region = _seek_record(gi, ntohl(inetaddr));
607
608 if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
609 /* Region Edition, pre June 2003 */
610 seek_region -= STATE_BEGIN_REV0;
611 if (seek_region >= 1000) {
612 region->country_code[0] = 'U';
613 region->country_code[1] = 'S';
614 region->region[0] = (char) ((seek_region - 1000)/26 + 65);
615 region->region[1] = (char) ((seek_region - 1000)%26 + 65);
616 } else {
617 memcpy(region->country_code, GeoIP_country_code[seek_region], 2);
618 }
619 } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
620 /* Region Edition, post June 2003 */
621 seek_region -= STATE_BEGIN_REV1;
622 if (seek_region < US_OFFSET) {
623 /* Unknown */
624 /* we don't need to do anything here b/c we memset region to 0 */
625 } else if (seek_region < CANADA_OFFSET) {
626 /* USA State */
627 region->country_code[0] = 'U';
628 region->country_code[1] = 'S';
629 region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65);
630 region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65);
631 } else if (seek_region < WORLD_OFFSET) {
632 /* Canada Province */
633 region->country_code[0] = 'C';
634 region->country_code[1] = 'A';
635 region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65);
636 region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65);
637 } else {
638 /* Not US or Canada */
639 memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2);
640 }
641 }
642 }
643
644 GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) {
645 GeoIPRegion * region;
646
647 region = malloc(sizeof(GeoIPRegion));
648 if (region) {
649 GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region);
650 }
651 return region;
652 }
653
654 GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) {
655 unsigned long ipnum;
656 if (addr == NULL) {
657 return 0;
658 }
659 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
660 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
661 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
662 return 0;
663 }
664 ipnum = _addr_to_num(addr);
665 return _get_region(gi, ipnum);
666 }
667
668 GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) {
669 unsigned long ipnum;
670 if (name == NULL) {
671 return 0;
672 }
673 if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
674 gi->databaseType != GEOIP_REGION_EDITION_REV1) {
675 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
676 return 0;
677 }
678 if (!(ipnum = lookupaddress(name)))
679 return 0;
680 return _get_region(gi, ipnum);
681 }
682
683 void GeoIPRegion_delete (GeoIPRegion *gir) {
684 free(gir);
685 }
686
687 /* GeoIP Organization, ISP and AS Number Edition private method */
688 char *_get_name (GeoIP* gi, unsigned long ipnum) {
689 int seek_org;
690 char buf[MAX_ORG_RECORD_LENGTH];
691 char * org_buf, * buf_pointer;
692 int record_pointer;
693
694 if (gi->databaseType != GEOIP_ORG_EDITION &&
695 gi->databaseType != GEOIP_ISP_EDITION &&
696 gi->databaseType != GEOIP_ASNUM_EDITION) {
697 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]);
698 return 0;
699 }
700
701 seek_org = _seek_record(gi, ipnum);
702 if (seek_org == gi->databaseSegments[0])
703 return NULL;
704
705 record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0];
706
707 if (gi->cache == NULL) {
708 fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET);
709 fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase);
710 org_buf = malloc(sizeof(char) * (strlen(buf)+1));
711 strcpy(org_buf, buf);
712 } else {
713 buf_pointer = (char *)gi->cache + (long)record_pointer;
714 org_buf = malloc(sizeof(char) * (strlen(buf_pointer)+1));
715 strcpy(org_buf, buf_pointer);
716 }
717 return org_buf;
718 }
719
720 char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) {
721 unsigned long ipnum;
722 if (addr == NULL) {
723 return 0;
724 }
725 ipnum = _addr_to_num(addr);
726 return _get_name(gi, ipnum);
727 }
728
729 char *GeoIP_name_by_name (GeoIP* gi, const char *name) {
730 unsigned long ipnum;
731 if (name == NULL) {
732 return 0;
733 }
734 if (!(ipnum = lookupaddress(name)))
735 return 0;
736 return _get_name(gi, ipnum);
737 }
738
739 char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) {
740 return GeoIP_name_by_addr(gi, addr);
741 }
742
743 char *GeoIP_org_by_name (GeoIP* gi, const char *name) {
744 return GeoIP_name_by_name(gi, name);
745 }
746
747 unsigned char GeoIP_database_edition (GeoIP* gi) {
748 return gi->databaseType;
749 }