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
23 static geoipv6_t IPV6_NULL
;
25 #if !defined(WIN32) && !defined(WIN64)
27 #include <sys/socket.h>
28 #include <netinet/in.h> /* For ntohl */
29 #include <arpa/inet.h>
35 #define snprintf _snprintf
42 #include <sys/types.h> /* for fstat */
43 #include <sys/stat.h> /* for fstat */
45 #ifdef HAVE_GETTIMEOFDAY
46 #include <sys/time.h> /* for gettimeofday */
50 #include <stdint.h> /* For uint32_t */
54 #define INADDR_NONE -1
57 #define COUNTRY_BEGIN 16776960
58 #define STATE_BEGIN_REV0 16700000
59 #define STATE_BEGIN_REV1 16000000
60 #define STRUCTURE_INFO_MAX_SIZE 20
61 #define DATABASE_INFO_MAX_SIZE 100
62 #define MAX_ORG_RECORD_LENGTH 300
64 #define CANADA_OFFSET 677
65 #define WORLD_OFFSET 1353
66 #define FIPS_RANGE 360
68 #define CHECK_ERR(err, msg) { \
70 fprintf(stderr, "%s error: %d\n", msg, err); \
75 const char GeoIP_country_code
[253][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
76 "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
77 "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
78 "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
79 "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
80 "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
81 "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
82 "FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
83 "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
84 "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
85 "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
86 "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
87 "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
88 "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
89 "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
90 "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
91 "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
92 "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
93 "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
94 "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
95 "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
96 "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
97 "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
98 "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
99 "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE",
102 static const unsigned num_GeoIP_countries
= (unsigned)(sizeof(GeoIP_country_code
)/sizeof(GeoIP_country_code
[0]));
104 const char GeoIP_country_code3
[253][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
105 "AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
106 "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
107 "BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
108 "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
109 "CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
110 "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
111 "FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
112 "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
113 "GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
114 "IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
115 "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
116 "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
117 "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
118 "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
119 "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
120 "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
121 "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
122 "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
123 "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
124 "SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
125 "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
126 "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
127 "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
128 "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY",
131 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",
132 "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
133 "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
134 "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
135 "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
136 "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
137 "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
138 "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
139 "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
140 "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
141 "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
142 "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
143 "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
144 "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
145 "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
146 "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
147 "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
148 "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
149 "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
150 "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
151 "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
152 "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
153 "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",
154 "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
155 "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
156 "Saint Barthelemy","Saint Martin"};
158 /* Possible continent codes are AF, AS, EU, NA, OC, SA for Africa, Asia, Europe, North America, Oceania
159 and South America. */
161 const char GeoIP_country_continent
[253][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
162 "AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
163 "AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
164 "SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
165 "AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
166 "SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
167 "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
168 "SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
169 "AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
170 "OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
171 "EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
172 "AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
173 "SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
174 "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
175 "AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
176 "AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
177 "EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
178 "OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
179 "SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
180 "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
181 "SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
182 "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
183 "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
184 "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
185 "AF","EU","AF","--","--","--","EU","EU","EU","EU",
188 geoipv6_t
_GeoIP_lookupaddress_v6 (const char *host
);
190 int __GEOIP_V6_IS_NULL(geoipv6_t v6
) {
199 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", "GeoIP Country V6 Edition"};
201 char * custom_directory
= NULL
;
203 void GeoIP_setup_custom_directory (char * dir
) {
204 custom_directory
= dir
;
207 char *_GeoIP_full_path_to(const char *file_name
) {
209 char *path
= malloc(sizeof(char) * 1024);
211 if (custom_directory
== NULL
){
212 #if !defined(WIN32) && !defined(WIN64)
213 memset(path
, 0, sizeof(char) * 1024);
214 snprintf(path
, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR
, file_name
);
216 char buf
[MAX_PATH
], *p
, *q
= NULL
;
217 memset(buf
, 0, sizeof(buf
));
218 len
= GetModuleFileName(GetModuleHandle(NULL
), buf
, sizeof(buf
) - 1);
219 for (p
= buf
+ len
; p
> buf
; p
--)
228 memset(path
, 0, sizeof(char) * 1024);
229 snprintf(path
, sizeof(char) * 1024 - 1, "%s/%s", buf
, file_name
);
232 len
= strlen(custom_directory
);
233 if (custom_directory
[len
-1] != '/') {
234 snprintf(path
, sizeof(char) * 1024 - 1, "%s/%s",custom_directory
, file_name
);
236 snprintf(path
, sizeof(char) * 1024 - 1, "%s%s", custom_directory
, file_name
);
242 char ** GeoIPDBFileName
= NULL
;
244 void _GeoIP_setup_dbfilename() {
245 if (NULL
== GeoIPDBFileName
) {
246 GeoIPDBFileName
= malloc(sizeof(char *) * NUM_DB_TYPES
);
247 memset(GeoIPDBFileName
, 0, sizeof(char *) * NUM_DB_TYPES
);
249 GeoIPDBFileName
[GEOIP_COUNTRY_EDITION
] = _GeoIP_full_path_to("GeoIP.dat");
250 GeoIPDBFileName
[GEOIP_REGION_EDITION_REV0
] = _GeoIP_full_path_to("GeoIPRegion.dat");
251 GeoIPDBFileName
[GEOIP_REGION_EDITION_REV1
] = _GeoIP_full_path_to("GeoIPRegion.dat");
252 GeoIPDBFileName
[GEOIP_CITY_EDITION_REV0
] = _GeoIP_full_path_to("GeoIPCity.dat");
253 GeoIPDBFileName
[GEOIP_CITY_EDITION_REV1
] = _GeoIP_full_path_to("GeoIPCity.dat");
254 GeoIPDBFileName
[GEOIP_ISP_EDITION
] = _GeoIP_full_path_to("GeoIPISP.dat");
255 GeoIPDBFileName
[GEOIP_ORG_EDITION
] = _GeoIP_full_path_to("GeoIPOrg.dat");
256 GeoIPDBFileName
[GEOIP_PROXY_EDITION
] = _GeoIP_full_path_to("GeoIPProxy.dat");
257 GeoIPDBFileName
[GEOIP_ASNUM_EDITION
] = _GeoIP_full_path_to("GeoIPASNum.dat");
258 GeoIPDBFileName
[GEOIP_NETSPEED_EDITION
] = _GeoIP_full_path_to("GeoIPNetSpeed.dat");
259 GeoIPDBFileName
[GEOIP_DOMAIN_EDITION
] = _GeoIP_full_path_to("GeoIPDomain.dat");
260 GeoIPDBFileName
[GEOIP_COUNTRY_EDITION_V6
] = _GeoIP_full_path_to("GeoIPv6.dat");
265 int _file_exists(const char *file_name
) {
266 struct stat file_stat
;
267 return( (stat(file_name
, &file_stat
) == 0) ? 1:0);
270 int GeoIP_db_avail(int type
) {
271 const char * filePath
;
272 if (type
< 0 || type
>= NUM_DB_TYPES
) {
275 _GeoIP_setup_dbfilename();
276 filePath
= GeoIPDBFileName
[type
];
277 if (NULL
== filePath
) {
280 return _file_exists(filePath
);
284 void _setup_segments(GeoIP
* gi
) {
286 unsigned char delim
[3];
287 unsigned char buf
[SEGMENT_RECORD_LENGTH
];
289 gi
->databaseSegments
= NULL
;
291 /* default to GeoIP Country Edition */
292 gi
->databaseType
= GEOIP_COUNTRY_EDITION
;
293 gi
->record_length
= STANDARD_RECORD_LENGTH
;
294 fseek(gi
->GeoIPDatabase
, -3l, SEEK_END
);
295 for (i
= 0; i
< STRUCTURE_INFO_MAX_SIZE
; i
++) {
296 fread(delim
, 1, 3, gi
->GeoIPDatabase
);
297 if (delim
[0] == 255 && delim
[1] == 255 && delim
[2] == 255) {
298 fread(&gi
->databaseType
, 1, 1, gi
->GeoIPDatabase
);
299 if (gi
->databaseType
>= 106) {
300 /* backwards compatibility with databases from April 2003 and earlier */
301 gi
->databaseType
-= 105;
304 if (gi
->databaseType
== GEOIP_REGION_EDITION_REV0
) {
305 /* Region Edition, pre June 2003 */
306 gi
->databaseSegments
= malloc(sizeof(int));
307 gi
->databaseSegments
[0] = STATE_BEGIN_REV0
;
308 } else if (gi
->databaseType
== GEOIP_REGION_EDITION_REV1
) {
309 /* Region Edition, post June 2003 */
310 gi
->databaseSegments
= malloc(sizeof(int));
311 gi
->databaseSegments
[0] = STATE_BEGIN_REV1
;
312 } else if (gi
->databaseType
== GEOIP_CITY_EDITION_REV0
||
313 gi
->databaseType
== GEOIP_CITY_EDITION_REV1
||
314 gi
->databaseType
== GEOIP_ORG_EDITION
||
315 gi
->databaseType
== GEOIP_ISP_EDITION
||
316 gi
->databaseType
== GEOIP_ASNUM_EDITION
) {
317 /* City/Org Editions have two segments, read offset of second segment */
318 gi
->databaseSegments
= malloc(sizeof(int));
319 gi
->databaseSegments
[0] = 0;
320 fread(buf
, SEGMENT_RECORD_LENGTH
, 1, gi
->GeoIPDatabase
);
321 for (j
= 0; j
< SEGMENT_RECORD_LENGTH
; j
++) {
322 gi
->databaseSegments
[0] += (buf
[j
] << (j
* 8));
324 if (gi
->databaseType
== GEOIP_ORG_EDITION
||
325 gi
->databaseType
== GEOIP_ISP_EDITION
)
326 gi
->record_length
= ORG_RECORD_LENGTH
;
330 fseek(gi
->GeoIPDatabase
, -4l, SEEK_CUR
);
333 if (gi
->databaseType
== GEOIP_COUNTRY_EDITION
||
334 gi
->databaseType
== GEOIP_PROXY_EDITION
||
335 gi
->databaseType
== GEOIP_NETSPEED_EDITION
||
336 gi
->databaseType
== GEOIP_COUNTRY_EDITION_V6
) {
337 gi
->databaseSegments
= malloc(sizeof(int));
338 gi
->databaseSegments
[0] = COUNTRY_BEGIN
;
343 int _check_mtime(GeoIP
*gi
) {
347 /* stat only has second granularity, so don't
348 call it more than once a second */
349 gettimeofday(&t
, NULL
);
350 if (t
.tv_sec
== gi
->last_mtime_check
){
353 gi
->last_mtime_check
= t
.tv_sec
;
355 if (gi
->flags
& GEOIP_CHECK_CACHE
) {
356 if (stat(gi
->file_path
, &buf
) != -1) {
357 if (buf
.st_mtime
!= gi
->mtime
) {
358 /* GeoIP Database file updated */
359 if (gi
->flags
& (GEOIP_MEMORY_CACHE
| GEOIP_MMAP_CACHE
)) {
360 if ( gi
->flags
& GEOIP_MMAP_CACHE
) {
361 #if !defined(WIN32) && !defined(WIN64)
362 /* MMAP is only avail on UNIX */
363 munmap(gi
->cache
, gi
->size
);
367 /* reload database into memory cache */
368 if ((gi
->cache
= (unsigned char*) realloc(gi
->cache
, buf
.st_size
)) == NULL
) {
369 fprintf(stderr
,"Out of memory when reloading %s\n",gi
->file_path
);
374 /* refresh filehandle */
375 fclose(gi
->GeoIPDatabase
);
376 gi
->GeoIPDatabase
= fopen(gi
->file_path
,"rb");
377 if (gi
->GeoIPDatabase
== NULL
) {
378 fprintf(stderr
,"Error Opening file %s when reloading\n",gi
->file_path
);
381 gi
->mtime
= buf
.st_mtime
;
382 gi
->size
= buf
.st_size
;
384 if ( gi
->flags
& GEOIP_MMAP_CACHE
) {
385 #if defined(WIN32) || defined(WIN64)
386 fprintf(stderr
, "GEOIP_MMAP_CACHE is not supported on WIN32\n");
390 gi
->cache
= mmap(NULL
, buf
.st_size
, PROT_READ
, MAP_PRIVATE
, fileno(gi
->GeoIPDatabase
), 0);
391 if ( gi
->cache
== MAP_FAILED
) {
393 fprintf(stderr
,"Error remapping file %s when reloading\n",gi
->file_path
);
399 } else if ( gi
->flags
& GEOIP_MEMORY_CACHE
) {
400 if (fread(gi
->cache
, sizeof(unsigned char), buf
.st_size
, gi
->GeoIPDatabase
) != (size_t) buf
.st_size
) {
401 fprintf(stderr
,"Error reading file %s when reloading\n",gi
->file_path
);
406 if (gi
->databaseSegments
!= NULL
) {
407 free(gi
->databaseSegments
);
408 gi
->databaseSegments
= NULL
;
411 if (gi
->databaseSegments
== NULL
) {
412 fprintf(stderr
, "Error reading file %s -- corrupt\n", gi
->file_path
);
415 if (gi
->flags
& GEOIP_INDEX_CACHE
) {
416 gi
->index_cache
= (unsigned char *) realloc(gi
->index_cache
, sizeof(unsigned char) * ((gi
->databaseSegments
[0] * (long)gi
->record_length
* 2)));
417 if (gi
->index_cache
!= NULL
) {
418 fseek(gi
->GeoIPDatabase
, 0, SEEK_SET
);
419 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)) {
420 fprintf(stderr
,"Error reading file %s where reloading\n",gi
->file_path
);
431 unsigned int _GeoIP_seek_record_v6 (GeoIP
*gi
, geoipv6_t ipnum
) {
433 char paddr
[8 * 4 + 7 + 1];
435 unsigned char stack_buffer
[2 * MAX_RECORD_LENGTH
];
436 const unsigned char *buf
= (gi
->cache
== NULL
) ? stack_buffer
: NULL
;
437 unsigned int offset
= 0;
439 const unsigned char * p
;
443 for (depth
= 127; depth
>= 0; depth
--) {
444 if (gi
->cache
== NULL
&& gi
->index_cache
== NULL
) {
446 fseek(gi
->GeoIPDatabase
, (long)gi
->record_length
* 2 * offset
, SEEK_SET
);
447 fread(stack_buffer
,gi
->record_length
,2,gi
->GeoIPDatabase
);
448 } else if (gi
->index_cache
== NULL
) {
449 /* simply point to record in memory */
450 buf
= gi
->cache
+ (long)gi
->record_length
* 2 *offset
;
452 buf
= gi
->index_cache
+ (long)gi
->record_length
* 2 * offset
;
455 if (GEOIP_CHKBIT_V6(depth
, ipnum
.s6_addr
)) {
456 /* Take the right-hand branch */
457 if ( gi
->record_length
== 3 ) {
458 /* Most common case is completely unrolled and uses constants. */
459 x
= (buf
[3*1 + 0] << (0*8))
460 + (buf
[3*1 + 1] << (1*8))
461 + (buf
[3*1 + 2] << (2*8));
465 j
= gi
->record_length
;
475 /* Take the left-hand branch */
476 if ( gi
->record_length
== 3 ) {
477 /* Most common case is completely unrolled and uses constants. */
478 x
= (buf
[3*0 + 0] << (0*8))
479 + (buf
[3*0 + 1] << (1*8))
480 + (buf
[3*0 + 2] << (2*8));
483 j
= gi
->record_length
;
493 if (x
>= gi
->databaseSegments
[0]) {
494 gi
->netmask
= 128 - depth
;
500 /* shouldn't reach here */
501 inet_pton(AF_INET6
, &ipnum
.s6_addr
[0], paddr
);
502 fprintf(stderr
,"Error Traversing Database for ipnum = %s - Perhaps database is corrupt?\n", paddr
);
507 _GeoIP_addr_to_num_v6(const char *addr
)
510 if ( 1 == inet_pton(AF_INET6
, addr
, &ipnum
.s6_addr
[0] ) )
515 unsigned int _GeoIP_seek_record (GeoIP
*gi
, unsigned long ipnum
) {
518 unsigned char stack_buffer
[2 * MAX_RECORD_LENGTH
];
519 const unsigned char *buf
= (gi
->cache
== NULL
) ? stack_buffer
: NULL
;
520 unsigned int offset
= 0;
522 const unsigned char * p
;
526 for (depth
= 31; depth
>= 0; depth
--) {
527 if (gi
->cache
== NULL
&& gi
->index_cache
== NULL
) {
529 fseek(gi
->GeoIPDatabase
, (long)gi
->record_length
* 2 * offset
, SEEK_SET
);
530 fread(stack_buffer
,gi
->record_length
,2,gi
->GeoIPDatabase
);
531 } else if (gi
->index_cache
== NULL
) {
532 /* simply point to record in memory */
533 buf
= gi
->cache
+ (long)gi
->record_length
* 2 *offset
;
535 buf
= gi
->index_cache
+ (long)gi
->record_length
* 2 * offset
;
538 if (ipnum
& (1 << depth
)) {
539 /* Take the right-hand branch */
540 if ( gi
->record_length
== 3 ) {
541 /* Most common case is completely unrolled and uses constants. */
542 x
= (buf
[3*1 + 0] << (0*8))
543 + (buf
[3*1 + 1] << (1*8))
544 + (buf
[3*1 + 2] << (2*8));
548 j
= gi
->record_length
;
558 /* Take the left-hand branch */
559 if ( gi
->record_length
== 3 ) {
560 /* Most common case is completely unrolled and uses constants. */
561 x
= (buf
[3*0 + 0] << (0*8))
562 + (buf
[3*0 + 1] << (1*8))
563 + (buf
[3*0 + 2] << (2*8));
566 j
= gi
->record_length
;
576 if (x
>= gi
->databaseSegments
[0]) {
577 gi
->netmask
= 32 - depth
;
583 /* shouldn't reach here */
584 fprintf(stderr
,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum
);
589 _GeoIP_addr_to_num(const char *addr
)
591 unsigned int c
, octet
, t
;
596 while ((c
= *addr
++)) {
615 if ((octet
> 255) || (i
!= 0))
618 return ipnum
+ octet
;
621 GeoIP
* GeoIP_open_type (int type
, int flags
) {
623 const char * filePath
;
624 if (type
< 0 || type
>= NUM_DB_TYPES
) {
625 printf("Invalid database type %d\n", type
);
628 _GeoIP_setup_dbfilename();
629 filePath
= GeoIPDBFileName
[type
];
630 if (filePath
== NULL
) {
631 printf("Invalid database type %d\n", type
);
634 gi
= GeoIP_open (filePath
, flags
);
638 GeoIP
* GeoIP_new (int flags
) {
640 _GeoIP_setup_dbfilename();
641 gi
= GeoIP_open (GeoIPDBFileName
[GEOIP_COUNTRY_EDITION
], flags
);
645 GeoIP
* GeoIP_open (const char * filename
, int flags
) {
650 #if defined(WIN32) || defined(WIN64)
652 if (WSAStartup(MAKEWORD(1, 1), &wsa
) != 0)
656 gi
= (GeoIP
*)malloc(sizeof(GeoIP
));
659 len
= sizeof(char) * (strlen(filename
)+1);
660 gi
->file_path
= malloc(len
);
661 if (gi
->file_path
== NULL
) {
665 strncpy(gi
->file_path
, filename
, len
);
666 gi
->GeoIPDatabase
= fopen(filename
,"rb");
667 if (gi
->GeoIPDatabase
== NULL
) {
668 fprintf(stderr
,"Error Opening file %s\n",filename
);
673 if (flags
& (GEOIP_MEMORY_CACHE
| GEOIP_MMAP_CACHE
) ) {
674 if (fstat(fileno(gi
->GeoIPDatabase
), &buf
) == -1) {
675 fprintf(stderr
,"Error stating file %s\n",filename
);
680 gi
->mtime
= buf
.st_mtime
;
681 gi
->size
= buf
.st_size
;
683 /* MMAP added my Peter Shipley */
684 if ( flags
& GEOIP_MMAP_CACHE
) {
685 #if !defined(WIN32) && !defined(WIN64)
686 gi
->cache
= mmap(NULL
, buf
.st_size
, PROT_READ
, MAP_PRIVATE
, fileno(gi
->GeoIPDatabase
), 0);
687 if ( gi
->cache
== MAP_FAILED
) {
688 fprintf(stderr
,"Error mmaping file %s\n",filename
);
695 gi
->cache
= (unsigned char *) malloc(sizeof(unsigned char) * buf
.st_size
);
697 if (gi
->cache
!= NULL
) {
698 if (fread(gi
->cache
, sizeof(unsigned char), buf
.st_size
, gi
->GeoIPDatabase
) != (size_t) buf
.st_size
) {
699 fprintf(stderr
,"Error reading file %s\n",filename
);
708 if (flags
& GEOIP_CHECK_CACHE
) {
709 if (fstat(fileno(gi
->GeoIPDatabase
), &buf
) == -1) {
710 fprintf(stderr
,"Error stating file %s\n",filename
);
715 gi
->mtime
= buf
.st_mtime
;
720 gi
->charset
= GEOIP_CHARSET_ISO_8859_1
;
723 if (flags
& GEOIP_INDEX_CACHE
) {
724 gi
->index_cache
= (unsigned char *) malloc(sizeof(unsigned char) * ((gi
->databaseSegments
[0] * (long)gi
->record_length
* 2)));
725 if (gi
->index_cache
!= NULL
) {
726 fseek(gi
->GeoIPDatabase
, 0, SEEK_SET
);
727 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)) {
728 fprintf(stderr
,"Error reading file %s\n",filename
);
729 free(gi
->databaseSegments
);
730 free(gi
->index_cache
);
736 gi
->index_cache
= NULL
;
742 void GeoIP_delete (GeoIP
*gi
) {
745 if (gi
->GeoIPDatabase
!= NULL
)
746 fclose(gi
->GeoIPDatabase
);
747 if (gi
->cache
!= NULL
) {
748 if ( gi
->flags
& GEOIP_MMAP_CACHE
) {
749 #if !defined(WIN32) && !defined(WIN64)
750 munmap(gi
->cache
, gi
->size
);
757 if (gi
->index_cache
!= NULL
)
758 free(gi
->index_cache
);
759 if (gi
->file_path
!= NULL
)
761 if (gi
->databaseSegments
!= NULL
)
762 free(gi
->databaseSegments
);
766 const char *GeoIP_country_code_by_name (GeoIP
* gi
, const char *name
) {
768 country_id
= GeoIP_id_by_name(gi
, name
);
769 return (country_id
> 0) ? GeoIP_country_code
[country_id
] : NULL
;
772 const char *GeoIP_country_code3_by_name (GeoIP
* gi
, const char *name
) {
774 country_id
= GeoIP_id_by_name(gi
, name
);
775 return (country_id
> 0) ? GeoIP_country_code3
[country_id
] : NULL
;
778 const char *GeoIP_country_name_by_name (GeoIP
* gi
, const char *name
) {
780 country_id
= GeoIP_id_by_name(gi
, name
);
781 return (country_id
> 0) ? GeoIP_country_name
[country_id
] : NULL
;
784 unsigned long _GeoIP_lookupaddress (const char *host
) {
785 unsigned long addr
= inet_addr(host
);
787 struct hostent
* phe
= &phe2
;
789 #ifdef HAVE_GETHOSTBYNAME_R
790 int buflength
= 16384;
794 #ifdef HAVE_GETHOSTBYNAME_R
795 buf
= malloc(buflength
);
797 if (addr
== INADDR_NONE
) {
798 #ifdef HAVE_GETHOSTBYNAME_R
800 /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
801 #ifdef GETHOSTBYNAME_R_RETURNS_INT
802 result
= gethostbyname_r(host
,&phe2
,buf
,buflength
,&phe
,&herr
);
804 phe
= gethostbyname_r(host
,&phe2
,buf
,buflength
,&herr
);
810 /* double the buffer if the buffer is too small */
811 buflength
= buflength
* 2;
812 buf
= realloc(buf
,buflength
);
815 #ifndef HAVE_GETHOSTBYNAME_R
816 /* Some systems do not support gethostbyname_r, such as Mac OS X */
817 phe
= gethostbyname(host
);
819 if (!phe
|| result
!= 0) {
823 addr
= *((unsigned long *) phe
->h_addr_list
[0]);
825 #ifdef HAVE_GETHOSTBYNAME_R
832 _GeoIP_lookupaddress_v6(const char *host
)
836 struct addrinfo hints
, *aifirst
;
838 memset(&hints
, 0, sizeof(hints
));
839 hints
.ai_family
= AF_INET6
;
840 /* hints.ai_flags = AI_V4MAPPED; */
841 hints
.ai_socktype
= SOCK_STREAM
;
843 if ((gaierr
= getaddrinfo(host
, NULL
, &hints
, &aifirst
)) != 0) {
844 /* fprintf(stderr, "Err: %s (%d %s)\n", host, gaierr, gai_strerror(gaierr)); */
847 memcpy(ipnum
.s6_addr
, ((struct sockaddr_in6
*) aifirst
->ai_addr
)->sin6_addr
.s6_addr
, sizeof(geoipv6_t
));
848 freeaddrinfo(aifirst
);
849 /* inet_pton(AF_INET6, host, ipnum.s6_addr); */
854 int GeoIP_id_by_name (GeoIP
* gi
, const char *name
) {
860 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION
&& gi
->databaseType
!= GEOIP_PROXY_EDITION
&& gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
861 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_COUNTRY_EDITION
]);
864 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
866 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
871 int GeoIP_id_by_name_v6 (GeoIP
* gi
, const char *name
) {
877 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION_V6
&& gi
->databaseType
!= GEOIP_PROXY_EDITION
&& gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
878 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_COUNTRY_EDITION_V6
]);
881 ipnum
= _GeoIP_lookupaddress_v6(name
);
882 if (__GEOIP_V6_IS_NULL(ipnum
))
884 ret
= _GeoIP_seek_record_v6(gi
, ipnum
) - COUNTRY_BEGIN
;
888 const char *GeoIP_country_code_by_addr (GeoIP
* gi
, const char *addr
) {
890 country_id
= GeoIP_id_by_addr(gi
, addr
);
891 return (country_id
> 0) ? GeoIP_country_code
[country_id
] : NULL
;
894 const char *GeoIP_country_code3_by_addr (GeoIP
* gi
, const char *addr
) {
896 country_id
= GeoIP_id_by_addr(gi
, addr
);
897 return (country_id
> 0) ? GeoIP_country_code3
[country_id
] : NULL
;
900 const char *GeoIP_country_name_by_addr (GeoIP
* gi
, const char *addr
) {
902 country_id
= GeoIP_id_by_addr(gi
, addr
);
903 return (country_id
> 0) ? GeoIP_country_name
[country_id
] : NULL
;
906 const char *GeoIP_country_name_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
908 country_id
= GeoIP_id_by_ipnum(gi
, ipnum
);
909 return (country_id
> 0) ? GeoIP_country_name
[country_id
] : NULL
;
912 const char *GeoIP_country_name_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
914 country_id
= GeoIP_id_by_ipnum_v6(gi
, ipnum
);
915 return (country_id
> 0) ? GeoIP_country_name
[country_id
] : NULL
;
918 const char *GeoIP_country_code_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
920 country_id
= GeoIP_id_by_ipnum(gi
, ipnum
);
921 return (country_id
> 0) ? GeoIP_country_code
[country_id
] : NULL
;
924 const char *GeoIP_country_code_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
926 country_id
= GeoIP_id_by_ipnum_v6(gi
, ipnum
);
927 return (country_id
> 0) ? GeoIP_country_code
[country_id
] : NULL
;
930 const char *GeoIP_country_code3_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
932 country_id
= GeoIP_id_by_ipnum(gi
, ipnum
);
933 return (country_id
> 0) ? GeoIP_country_code3
[country_id
] : NULL
;
936 const char *GeoIP_country_code3_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
938 country_id
= GeoIP_id_by_ipnum_v6(gi
, ipnum
);
939 return (country_id
> 0) ? GeoIP_country_code3
[country_id
] : NULL
;
942 int GeoIP_country_id_by_addr (GeoIP
* gi
, const char *addr
) {
943 return GeoIP_id_by_addr(gi
, addr
);
946 int GeoIP_country_id_by_name (GeoIP
* gi
, const char *host
) {
947 return GeoIP_id_by_name(gi
, host
);
950 int GeoIP_id_by_addr_v6 (GeoIP
* gi
, const char *addr
) {
956 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION_V6
&&
957 gi
->databaseType
!= GEOIP_PROXY_EDITION
&&
958 gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
959 printf("Invalid database type %s, expected %s\n",
960 GeoIPDBDescription
[(int)gi
->databaseType
],
961 GeoIPDBDescription
[GEOIP_COUNTRY_EDITION_V6
]);
964 ipnum
= _GeoIP_addr_to_num_v6(addr
);
965 ret
= _GeoIP_seek_record_v6(gi
, ipnum
) - COUNTRY_BEGIN
;
969 int GeoIP_id_by_addr (GeoIP
* gi
, const char *addr
) {
975 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION
&&
976 gi
->databaseType
!= GEOIP_PROXY_EDITION
&&
977 gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
978 printf("Invalid database type %s, expected %s\n",
979 GeoIPDBDescription
[(int)gi
->databaseType
],
980 GeoIPDBDescription
[GEOIP_COUNTRY_EDITION
]);
983 ipnum
= _GeoIP_addr_to_num(addr
);
984 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
988 int GeoIP_id_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
994 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION_V6
&&
995 gi
->databaseType
!= GEOIP_PROXY_EDITION
&&
996 gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
997 printf("Invalid database type %s, expected %s\n",
998 GeoIPDBDescription
[(int)gi
->databaseType
],
999 GeoIPDBDescription
[GEOIP_COUNTRY_EDITION_V6
]);
1002 ret
= _GeoIP_seek_record_v6(gi
, ipnum
) - COUNTRY_BEGIN
;
1008 int GeoIP_id_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
1013 if (gi
->databaseType
!= GEOIP_COUNTRY_EDITION
&&
1014 gi
->databaseType
!= GEOIP_PROXY_EDITION
&&
1015 gi
->databaseType
!= GEOIP_NETSPEED_EDITION
) {
1016 printf("Invalid database type %s, expected %s\n",
1017 GeoIPDBDescription
[(int)gi
->databaseType
],
1018 GeoIPDBDescription
[GEOIP_COUNTRY_EDITION
]);
1021 ret
= _GeoIP_seek_record(gi
, ipnum
) - COUNTRY_BEGIN
;
1025 char *GeoIP_database_info (GeoIP
* gi
) {
1027 unsigned char buf
[3];
1029 int hasStructureInfo
= 0;
1035 fseek(gi
->GeoIPDatabase
, -3l, SEEK_END
);
1037 /* first get past the database structure information */
1038 for (i
= 0; i
< STRUCTURE_INFO_MAX_SIZE
; i
++) {
1039 fread(buf
, 1, 3, gi
->GeoIPDatabase
);
1040 if (buf
[0] == 255 && buf
[1] == 255 && buf
[2] == 255) {
1041 hasStructureInfo
= 1;
1044 fseek(gi
->GeoIPDatabase
, -4l, SEEK_CUR
);
1046 if (hasStructureInfo
== 1) {
1047 fseek(gi
->GeoIPDatabase
, -6l, SEEK_CUR
);
1049 /* no structure info, must be pre Sep 2002 database, go back to end */
1050 fseek(gi
->GeoIPDatabase
, -3l, SEEK_END
);
1053 for (i
= 0; i
< DATABASE_INFO_MAX_SIZE
; i
++) {
1054 fread(buf
, 1, 3, gi
->GeoIPDatabase
);
1055 if (buf
[0] == 0 && buf
[1] == 0 && buf
[2] == 0) {
1056 retval
= malloc(sizeof(char) * (i
+1));
1057 if (retval
== NULL
) {
1060 fread(retval
, 1, i
, gi
->GeoIPDatabase
);
1064 fseek(gi
->GeoIPDatabase
, -4l, SEEK_CUR
);
1069 /* GeoIP Region Edition functions */
1071 void GeoIP_assign_region_by_inetaddr(GeoIP
* gi
, unsigned long inetaddr
, GeoIPRegion
*region
) {
1072 unsigned int seek_region
;
1074 /* This also writes in the terminating NULs (if you decide to
1075 * keep them) and clear any fields that are not set. */
1076 memset(region
, 0, sizeof(GeoIPRegion
));
1078 seek_region
= _GeoIP_seek_record(gi
, ntohl(inetaddr
));
1080 if (gi
->databaseType
== GEOIP_REGION_EDITION_REV0
) {
1081 /* Region Edition, pre June 2003 */
1082 seek_region
-= STATE_BEGIN_REV0
;
1083 if (seek_region
>= 1000) {
1084 region
->country_code
[0] = 'U';
1085 region
->country_code
[1] = 'S';
1086 region
->region
[0] = (char) ((seek_region
- 1000)/26 + 65);
1087 region
->region
[1] = (char) ((seek_region
- 1000)%26
+ 65);
1089 memcpy(region
->country_code
, GeoIP_country_code
[seek_region
], 2);
1091 } else if (gi
->databaseType
== GEOIP_REGION_EDITION_REV1
) {
1092 /* Region Edition, post June 2003 */
1093 seek_region
-= STATE_BEGIN_REV1
;
1094 if (seek_region
< US_OFFSET
) {
1096 /* we don't need to do anything here b/c we memset region to 0 */
1097 } else if (seek_region
< CANADA_OFFSET
) {
1099 region
->country_code
[0] = 'U';
1100 region
->country_code
[1] = 'S';
1101 region
->region
[0] = (char) ((seek_region
- US_OFFSET
)/26 + 65);
1102 region
->region
[1] = (char) ((seek_region
- US_OFFSET
)%26
+ 65);
1103 } else if (seek_region
< WORLD_OFFSET
) {
1104 /* Canada Province */
1105 region
->country_code
[0] = 'C';
1106 region
->country_code
[1] = 'A';
1107 region
->region
[0] = (char) ((seek_region
- CANADA_OFFSET
)/26 + 65);
1108 region
->region
[1] = (char) ((seek_region
- CANADA_OFFSET
)%26
+ 65);
1110 /* Not US or Canada */
1111 memcpy(region
->country_code
, GeoIP_country_code
[(seek_region
- WORLD_OFFSET
) / FIPS_RANGE
], 2);
1116 void GeoIP_assign_region_by_inetaddr_v6(GeoIP
* gi
, geoipv6_t inetaddr
, GeoIPRegion
*region
) {
1117 unsigned int seek_region
;
1119 /* This also writes in the terminating NULs (if you decide to
1120 * keep them) and clear any fields that are not set. */
1121 memset(region
, 0, sizeof(GeoIPRegion
));
1123 seek_region
= _GeoIP_seek_record_v6(gi
, inetaddr
);
1125 if (gi
->databaseType
== GEOIP_REGION_EDITION_REV0
) {
1126 /* Region Edition, pre June 2003 */
1127 seek_region
-= STATE_BEGIN_REV0
;
1128 if (seek_region
>= 1000) {
1129 region
->country_code
[0] = 'U';
1130 region
->country_code
[1] = 'S';
1131 region
->region
[0] = (char) ((seek_region
- 1000)/26 + 65);
1132 region
->region
[1] = (char) ((seek_region
- 1000)%26
+ 65);
1134 memcpy(region
->country_code
, GeoIP_country_code
[seek_region
], 2);
1136 } else if (gi
->databaseType
== GEOIP_REGION_EDITION_REV1
) {
1137 /* Region Edition, post June 2003 */
1138 seek_region
-= STATE_BEGIN_REV1
;
1139 if (seek_region
< US_OFFSET
) {
1141 /* we don't need to do anything here b/c we memset region to 0 */
1142 } else if (seek_region
< CANADA_OFFSET
) {
1144 region
->country_code
[0] = 'U';
1145 region
->country_code
[1] = 'S';
1146 region
->region
[0] = (char) ((seek_region
- US_OFFSET
)/26 + 65);
1147 region
->region
[1] = (char) ((seek_region
- US_OFFSET
)%26
+ 65);
1148 } else if (seek_region
< WORLD_OFFSET
) {
1149 /* Canada Province */
1150 region
->country_code
[0] = 'C';
1151 region
->country_code
[1] = 'A';
1152 region
->region
[0] = (char) ((seek_region
- CANADA_OFFSET
)/26 + 65);
1153 region
->region
[1] = (char) ((seek_region
- CANADA_OFFSET
)%26
+ 65);
1155 /* Not US or Canada */
1156 memcpy(region
->country_code
, GeoIP_country_code
[(seek_region
- WORLD_OFFSET
) / FIPS_RANGE
], 2);
1162 GeoIPRegion
* _get_region(GeoIP
* gi
, unsigned long ipnum
) {
1163 GeoIPRegion
* region
;
1165 region
= malloc(sizeof(GeoIPRegion
));
1167 GeoIP_assign_region_by_inetaddr(gi
, htonl(ipnum
), region
);
1173 GeoIPRegion
* _get_region_v6(GeoIP
* gi
, geoipv6_t ipnum
) {
1174 GeoIPRegion
* region
;
1176 region
= malloc(sizeof(GeoIPRegion
));
1178 GeoIP_assign_region_by_inetaddr_v6(gi
, ipnum
, region
);
1183 GeoIPRegion
* GeoIP_region_by_addr (GeoIP
* gi
, const char *addr
) {
1184 unsigned long ipnum
;
1188 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1189 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1190 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1193 ipnum
= _GeoIP_addr_to_num(addr
);
1194 return _get_region(gi
, ipnum
);
1197 GeoIPRegion
* GeoIP_region_by_addr_v6 (GeoIP
* gi
, const char *addr
) {
1202 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1203 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1204 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1207 ipnum
= _GeoIP_addr_to_num_v6(addr
);
1208 return _get_region_v6(gi
, ipnum
);
1211 GeoIPRegion
* GeoIP_region_by_name (GeoIP
* gi
, const char *name
) {
1212 unsigned long ipnum
;
1216 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1217 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1218 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1221 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
1223 return _get_region(gi
, ipnum
);
1226 GeoIPRegion
* GeoIP_region_by_name_v6 (GeoIP
* gi
, const char *name
) {
1231 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1232 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1233 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1237 ipnum
= _GeoIP_lookupaddress_v6(name
);
1238 if (__GEOIP_V6_IS_NULL(ipnum
))
1240 return _get_region_v6(gi
, ipnum
);
1243 GeoIPRegion
* GeoIP_region_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
1244 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1245 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1246 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1249 return _get_region(gi
, ipnum
);
1252 GeoIPRegion
* GeoIP_region_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
1253 if (gi
->databaseType
!= GEOIP_REGION_EDITION_REV0
&&
1254 gi
->databaseType
!= GEOIP_REGION_EDITION_REV1
) {
1255 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_REGION_EDITION_REV1
]);
1258 return _get_region_v6(gi
, ipnum
);
1261 void GeoIPRegion_delete (GeoIPRegion
*gir
) {
1265 /* GeoIP Organization, ISP and AS Number Edition private method */
1267 char *_get_name (GeoIP
* gi
, unsigned long ipnum
) {
1269 char buf
[MAX_ORG_RECORD_LENGTH
];
1270 char * org_buf
, * buf_pointer
;
1274 if (gi
->databaseType
!= GEOIP_ORG_EDITION
&&
1275 gi
->databaseType
!= GEOIP_ISP_EDITION
&&
1276 gi
->databaseType
!= GEOIP_ASNUM_EDITION
) {
1277 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_ORG_EDITION
]);
1281 seek_org
= _GeoIP_seek_record(gi
, ipnum
);
1282 if (seek_org
== gi
->databaseSegments
[0])
1285 record_pointer
= seek_org
+ (2 * gi
->record_length
- 1) * gi
->databaseSegments
[0];
1287 if (gi
->cache
== NULL
) {
1288 fseek(gi
->GeoIPDatabase
, record_pointer
, SEEK_SET
);
1289 fread(buf
, sizeof(char), MAX_ORG_RECORD_LENGTH
, gi
->GeoIPDatabase
);
1290 len
= sizeof(char) * (strlen(buf
)+1);
1291 org_buf
= malloc(len
);
1292 strncpy(org_buf
, buf
, len
);
1294 buf_pointer
= gi
->cache
+ (long)record_pointer
;
1295 len
= sizeof(char) * (strlen(buf_pointer
)+1);
1296 org_buf
= malloc(len
);
1297 strncpy(org_buf
, buf_pointer
, len
);
1302 char *_get_name_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
1304 char buf
[MAX_ORG_RECORD_LENGTH
];
1305 char * org_buf
, * buf_pointer
;
1309 if (gi
->databaseType
!= GEOIP_ORG_EDITION
&&
1310 gi
->databaseType
!= GEOIP_ISP_EDITION
&&
1311 gi
->databaseType
!= GEOIP_ASNUM_EDITION
) {
1312 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription
[(int)gi
->databaseType
], GeoIPDBDescription
[GEOIP_ORG_EDITION
]);
1316 seek_org
= _GeoIP_seek_record_v6(gi
, ipnum
);
1317 if (seek_org
== gi
->databaseSegments
[0])
1320 record_pointer
= seek_org
+ (2 * gi
->record_length
- 1) * gi
->databaseSegments
[0];
1322 if (gi
->cache
== NULL
) {
1323 fseek(gi
->GeoIPDatabase
, record_pointer
, SEEK_SET
);
1324 fread(buf
, sizeof(char), MAX_ORG_RECORD_LENGTH
, gi
->GeoIPDatabase
);
1325 len
= sizeof(char) * (strlen(buf
)+1);
1326 org_buf
= malloc(len
);
1327 strncpy(org_buf
, buf
, len
);
1329 buf_pointer
= gi
->cache
+ (long)record_pointer
;
1330 len
= sizeof(char) * (strlen(buf_pointer
)+1);
1331 org_buf
= malloc(len
);
1332 strncpy(org_buf
, buf_pointer
, len
);
1337 char *_GeoIP_num_to_addr (GeoIP
* gi
, unsigned long ipnum
) {
1341 int num_chars_written
, i
;
1343 ret_str
= malloc(sizeof(char) * 16);
1346 for (i
= 0; i
<4; i
++) {
1347 octet
[3 - i
] = ipnum
% 256;
1351 for (i
= 0; i
<4; i
++) {
1352 num_chars_written
= sprintf(cur_str
, "%d", octet
[i
]);
1353 cur_str
+= num_chars_written
;
1364 char **GeoIP_range_by_ip (GeoIP
* gi
, const char *addr
) {
1365 unsigned long ipnum
;
1366 unsigned long left_seek
;
1367 unsigned long right_seek
;
1377 ret
= malloc(sizeof(char *) * 2);
1379 ipnum
= _GeoIP_addr_to_num(addr
);
1380 target_value
= _GeoIP_seek_record(gi
, ipnum
);
1381 orig_netmask
= GeoIP_last_netmask(gi
);
1382 mask
= 0xffffffff << ( 32 - orig_netmask
);
1383 left_seek
= ipnum
& mask
;
1384 right_seek
= left_seek
+ ( 0xffffffff & ~mask
);
1386 while (left_seek
!= 0
1387 && target_value
== _GeoIP_seek_record(gi
, left_seek
- 1) ) {
1389 /* Go to beginning of netblock defined by netmask */
1390 mask
= 0xffffffff << ( 32 - GeoIP_last_netmask(gi
) );
1391 left_seek
= --left_seek
& mask
;
1393 ret
[0] = _GeoIP_num_to_addr(gi
, left_seek
);
1395 while (right_seek
!= 0xffffffff
1396 && target_value
== _GeoIP_seek_record(gi
, right_seek
+ 1) ) {
1398 /* Go to end of netblock defined by netmask */
1399 mask
= 0xffffffff << ( 32 - GeoIP_last_netmask(gi
) );
1400 right_seek
= ++right_seek
& mask
;
1401 right_seek
+= 0xffffffff & ~mask
;
1403 ret
[1] = _GeoIP_num_to_addr(gi
, right_seek
);
1405 gi
->netmask
= orig_netmask
;
1410 void GeoIP_range_by_ip_delete( char ** ptr
){
1420 char *GeoIP_name_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
1421 return _get_name(gi
,ipnum
);
1424 char *GeoIP_name_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
1425 return _get_name_v6(gi
,ipnum
);
1428 char *GeoIP_name_by_addr (GeoIP
* gi
, const char *addr
) {
1429 unsigned long ipnum
;
1433 ipnum
= _GeoIP_addr_to_num(addr
);
1434 return _get_name(gi
, ipnum
);
1437 char *GeoIP_name_by_addr_v6 (GeoIP
* gi
, const char *addr
) {
1442 ipnum
= _GeoIP_addr_to_num_v6(addr
);
1443 return _get_name_v6(gi
, ipnum
);
1446 char *GeoIP_name_by_name (GeoIP
* gi
, const char *name
) {
1447 unsigned long ipnum
;
1451 if (!(ipnum
= _GeoIP_lookupaddress(name
)))
1453 return _get_name(gi
, ipnum
);
1456 char *GeoIP_name_by_name_v6 (GeoIP
* gi
, const char *name
) {
1461 ipnum
= _GeoIP_lookupaddress_v6(name
);
1462 if (__GEOIP_V6_IS_NULL(ipnum
))
1464 return _get_name_v6(gi
, ipnum
);
1467 char *GeoIP_org_by_ipnum (GeoIP
* gi
, unsigned long ipnum
) {
1468 return GeoIP_name_by_ipnum(gi
, ipnum
);
1471 char *GeoIP_org_by_ipnum_v6 (GeoIP
* gi
, geoipv6_t ipnum
) {
1472 return GeoIP_name_by_ipnum_v6(gi
, ipnum
);
1475 char *GeoIP_org_by_addr (GeoIP
* gi
, const char *addr
) {
1476 return GeoIP_name_by_addr(gi
, addr
);
1479 char *GeoIP_org_by_addr_v6 (GeoIP
* gi
, const char *addr
) {
1480 return GeoIP_name_by_addr_v6(gi
, addr
);
1483 char *GeoIP_org_by_name (GeoIP
* gi
, const char *name
) {
1484 return GeoIP_name_by_name(gi
, name
);
1487 char *GeoIP_org_by_name_v6 (GeoIP
* gi
, const char *name
) {
1488 return GeoIP_name_by_name_v6(gi
, name
);
1491 unsigned char GeoIP_database_edition (GeoIP
* gi
) {
1492 return gi
->databaseType
;
1495 int GeoIP_charset( GeoIP
* gi
){
1499 int GeoIP_set_charset( GeoIP
* gi
, int charset
){
1500 int old_charset
= gi
->charset
;
1501 gi
->charset
= charset
;
1505 int GeoIP_last_netmask (GeoIP
* gi
) {
1510 /** return two letter country code */
1511 const char* GeoIP_code_by_id(int id
)
1513 if (id
< 0 || id
>= num_GeoIP_countries
)
1516 return GeoIP_country_code
[id
];
1519 /** return three letter country code */
1520 const char* GeoIP_code3_by_id(int id
)
1522 if (id
< 0 || id
>= num_GeoIP_countries
)
1525 return GeoIP_country_code3
[id
];
1529 /** return full name of country */
1530 const char* GeoIP_name_by_id(int id
)
1532 if (id
< 0 || id
>= num_GeoIP_countries
)
1535 return GeoIP_country_name
[id
];
1538 /** return continent of country */
1539 const char* GeoIP_continent_by_id(int id
)
1541 if (id
< 0 || id
>= num_GeoIP_countries
)
1544 return GeoIP_country_continent
[id
];
1547 /** return id by country code **/
1548 int GeoIP_id_by_code(const char *country
)
1552 for ( i
= 0; i
< num_GeoIP_countries
; ++i
)
1554 if (strcmp(country
, GeoIP_country_code
[i
]) == 0)
1561 unsigned GeoIP_num_countries(void)
1563 return num_GeoIP_countries
;