Main Page | Class List | File List | Class Members | File Members

GeoIP.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
00002 /* GeoIP.c
00003  *
00004  * Copyright (C) 2003 MaxMind LLC  All Rights Reserved.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * This file was renamed to GeoIP.cpp from GeoIP.c and edited by
00023  * Guwashi <guwashi[AT]fooos[DOT]com>.
00024  * Please see GeoIP.c.1.3.10.win32.patch.
00025  */
00026 
00027 
00028 #include "GeoIP.h"
00029 
00030 #include <errno.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #ifndef _WIN32
00035 #include <netdb.h>
00036 #include <sys/socket.h>
00037 #include <netinet/in.h> /* For ntohl */
00038 #include <arpa/inet.h>
00039 #else
00040 #include <winsock.h>
00041 #include <windows.h>
00042 #endif
00043 #include <assert.h>
00044 #include <sys/types.h> /* for fstat */
00045 #include <sys/stat.h>   /* for fstat */
00046 
00047 #ifdef HAVE_STDINT_H
00048 #include <stdint.h>     /* For uint32_t */
00049 #endif
00050 
00051 #ifdef _WIN32
00052 #pragma comment(lib, "wsock32.lib")
00053 /* #pragma comment(lib, "ws2_32.lib") */
00054 #endif
00055 
00056 #ifndef        INADDR_NONE
00057 #define        INADDR_NONE     -1
00058 #endif
00059 
00060 #define COUNTRY_BEGIN 16776960
00061 #define STATE_BEGIN_REV0 16700000
00062 #define STATE_BEGIN_REV1 16000000
00063 #define STRUCTURE_INFO_MAX_SIZE 20
00064 #define DATABASE_INFO_MAX_SIZE 100
00065 #define MAX_ORG_RECORD_LENGTH 300
00066 #define US_OFFSET 1
00067 #define CANADA_OFFSET 677
00068 #define WORLD_OFFSET 1353
00069 #define FIPS_RANGE 360
00070 
00071 #define GEOIPDATADIR "/usr/local/share/GeoIP"
00072 
00073 #define CHECK_ERR(err, msg) { \
00074                 if (err != Z_OK) { \
00075                                 fprintf(stderr, "%s error: %d\n", msg, err); \
00076                                 exit(1); \
00077                 } \
00078 }
00079 
00080 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"};
00081 
00082 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"};
00083 
00084 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",
00085 "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",
00086 "Anonymous Proxy","Satellite Provider","Other"};
00087 
00088 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"};
00089 
00090 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"};
00091 
00092 char *_full_path_to(const char *file_name) {
00093         char *path = (char*)malloc(sizeof(char) * 1024);
00094 
00095 #ifndef _WIN32
00096         memset(path, 0, sizeof(char) * 1024);
00097         snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
00098 #else
00099         char buf[MAX_PATH], *p, *q = NULL;
00100         int len;
00101         memset(buf, 0, sizeof(buf));
00102         len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1);
00103         for (p = buf + len; p > buf; p--)
00104                 if (*p == '\\')
00105                 {
00106                         if (!q)
00107                                 q = p;
00108                         else
00109                                 *p = '/';
00110                 }
00111         *q = 0;
00112         memset(path, 0, sizeof(char) * 1024);
00113         _snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
00114 #endif
00115 
00116         return path;
00117 }
00118 
00119 char ** GeoIPDBFileName = NULL;
00120 
00121 void _setup_dbfilename() {
00122         if (NULL == GeoIPDBFileName) {
00123                 GeoIPDBFileName = (char**)malloc(sizeof(char *) * NUM_DB_TYPES);
00124                 memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES);
00125 
00126                 GeoIPDBFileName[GEOIP_COUNTRY_EDITION]          = _full_path_to("GeoIP.dat");
00127                 GeoIPDBFileName[GEOIP_REGION_EDITION_REV0]      = _full_path_to("GeoIPRegion.dat");
00128                 GeoIPDBFileName[GEOIP_REGION_EDITION_REV1]      = _full_path_to("GeoIPRegion.dat");
00129                 GeoIPDBFileName[GEOIP_CITY_EDITION_REV0]        = _full_path_to("GeoIPCity.dat");
00130                 GeoIPDBFileName[GEOIP_CITY_EDITION_REV1]        = _full_path_to("GeoIPCity.dat");
00131                 GeoIPDBFileName[GEOIP_ISP_EDITION]              = _full_path_to("GeoIPISP.dat");
00132                 GeoIPDBFileName[GEOIP_ORG_EDITION]              = _full_path_to("GeoIPOrg.dat");
00133                 GeoIPDBFileName[GEOIP_PROXY_EDITION]            = _full_path_to("GeoIPProxy.dat");
00134                 GeoIPDBFileName[GEOIP_ASNUM_EDITION]            = _full_path_to("GeoIPASNum.dat");
00135                 GeoIPDBFileName[GEOIP_NETSPEED_EDITION]         = _full_path_to("GeoIPNetSpeed.dat");
00136         }
00137 }
00138 
00139 int _file_exists(const char *file_name) {
00140         struct stat file_stat;
00141         return( (stat(file_name, &file_stat) == 0) ? 1:0);
00142 }
00143 
00144 int GeoIP_db_avail(int type) {
00145         const char * filePath;
00146         if (type < 0 || type >= NUM_DB_TYPES) {
00147                 return 0;
00148         }
00149         filePath = GeoIPDBFileName[type];
00150         if (NULL == filePath) {
00151                 return 0;
00152         }
00153         return _file_exists(filePath);
00154 }
00155 
00156 void _setup_segments(GeoIP * gi) {
00157         int i, j;
00158         unsigned char delim[3];
00159         unsigned char buf[SEGMENT_RECORD_LENGTH];
00160 
00161         /* default to GeoIP Country Edition */
00162         gi->databaseType = GEOIP_COUNTRY_EDITION;
00163         gi->record_length = STANDARD_RECORD_LENGTH;
00164         fseek(gi->GeoIPDatabase, -3l, SEEK_END);
00165         for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
00166                 fread(delim, 1, 3, gi->GeoIPDatabase);
00167                 if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
00168                         fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase);
00169                         if (gi->databaseType >= 106) {
00170                                 /* backwards compatibility with databases from April 2003 and earlier */
00171                                 gi->databaseType -= 105;
00172                         }
00173 
00174                         if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
00175                                 /* Region Edition, pre June 2003 */
00176                                 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
00177                                 gi->databaseSegments[0] = STATE_BEGIN_REV0;
00178                         } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
00179                                 /* Region Edition, post June 2003 */
00180                                 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
00181                                 gi->databaseSegments[0] = STATE_BEGIN_REV1;
00182                         } else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 ||
00183                                                                  gi->databaseType == GEOIP_CITY_EDITION_REV1 ||
00184                                                                  gi->databaseType == GEOIP_ORG_EDITION ||
00185                                                                  gi->databaseType == GEOIP_ISP_EDITION ||
00186                                                                  gi->databaseType == GEOIP_ASNUM_EDITION) {
00187                                 /* City/Org Editions have two segments, read offset of second segment */
00188                                 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
00189                                 gi->databaseSegments[0] = 0;
00190                                 fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase);
00191                                 for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
00192                                         gi->databaseSegments[0] += (buf[j] << (j * 8));
00193                                 }
00194                                 if (gi->databaseType == GEOIP_ORG_EDITION ||
00195                                                 gi->databaseType == GEOIP_ISP_EDITION)
00196                                         gi->record_length = ORG_RECORD_LENGTH;
00197                         }
00198                         break;
00199                 } else {
00200                         fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
00201                 }
00202         }
00203         if (gi->databaseType == GEOIP_COUNTRY_EDITION ||
00204                         gi->databaseType == GEOIP_PROXY_EDITION ||
00205                         gi->databaseType == GEOIP_NETSPEED_EDITION) {
00206                 gi->databaseSegments = (unsigned int*)malloc(sizeof(int));
00207                 gi->databaseSegments[0] = COUNTRY_BEGIN;
00208         }
00209 }
00210 
00211 int _check_mtime(GeoIP *gi) {
00212         struct stat buf;
00213 
00214         if (gi->flags & GEOIP_CHECK_CACHE) {
00215                 if (fstat(fileno(gi->GeoIPDatabase), &buf) != -1) {
00216                         if (buf.st_mtime > gi->mtime) {
00217                                 /* GeoIP Database file updated */
00218                                 if (gi->flags & GEOIP_MEMORY_CACHE) {
00219                                         /* reload database into memory cache */
00220                                         if (realloc(gi->cache, buf.st_size) != NULL) {
00221                                                 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
00222                                                         fprintf(stderr,"Error reading file %s\n",gi->file_path);
00223                                                         return -1;
00224                                                 }
00225                                                 gi->mtime = buf.st_mtime;
00226                                         }
00227                                 } else {
00228                                         /* refresh filehandle */
00229                                         fclose(gi->GeoIPDatabase);
00230                                         gi->GeoIPDatabase = fopen(gi->file_path,"rb");
00231                                         if (gi->GeoIPDatabase == NULL) {
00232                                                 fprintf(stderr,"Error Opening file %s\n",gi->file_path);
00233                                                 return -1;
00234                                         }
00235                                         _setup_segments(gi);
00236                                 }
00237                         }
00238                 }
00239         }
00240         return 0;
00241 }
00242 
00243 unsigned int _seek_record (GeoIP *gi, unsigned long ipnum) {
00244         int depth;
00245         unsigned int x;
00246         unsigned char stack_buffer[2 * MAX_RECORD_LENGTH];
00247         const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL;
00248         unsigned int offset = 0;
00249 
00250         const unsigned char * p;
00251         int j;
00252 
00253         _check_mtime(gi);
00254         for (depth = 31; depth >= 0; depth--) {
00255                 if (gi->cache == NULL && gi->index_cache == NULL) {
00256                         /* read from disk */
00257                         fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET);
00258                         fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase);
00259                 } else if (gi->index_cache == NULL) {
00260                         /* simply point to record in memory */
00261                         buf = gi->cache + (long)gi->record_length * 2 *offset;
00262                 } else {
00263                         buf = gi->index_cache + (long)gi->record_length * 2 * offset;
00264                 }
00265 
00266                 if (ipnum & (1 << depth)) {
00267                         /* Take the right-hand branch */
00268                         if ( gi->record_length == 3 ) {
00269                                 /* Most common case is completely unrolled and uses constants. */
00270                                 x =   (buf[3*1 + 0] << (0*8))
00271                                         + (buf[3*1 + 1] << (1*8))
00272                                         + (buf[3*1 + 2] << (2*8));
00273 
00274                         } else {
00275                                 /* General case */
00276                                 j = gi->record_length;
00277                                 p = &buf[2*j];
00278                                 x = 0;
00279                                 do {
00280                                         x <<= 8;
00281                                         x += *(--p);
00282                                 } while ( --j );
00283                         }
00284 
00285                 } else {
00286                         /* Take the left-hand branch */
00287                         if ( gi->record_length == 3 ) {
00288                                 /* Most common case is completely unrolled and uses constants. */
00289                                 x =   (buf[3*0 + 0] << (0*8))
00290                                         + (buf[3*0 + 1] << (1*8))
00291                                         + (buf[3*0 + 2] << (2*8));
00292                         } else {
00293                                 /* General case */
00294                                 j = gi->record_length;
00295                                 p = &buf[1*j];
00296                                 x = 0;
00297                                 do {
00298                                         x <<= 8;
00299                                         x += *(--p);
00300                                 } while ( --j );
00301                         }
00302                 }
00303 
00304                 if (x >= gi->databaseSegments[0]) {
00305                         return x;
00306                 }
00307                 offset = x;
00308         }
00309 
00310         /* shouldn't reach here */
00311         fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum);
00312         return 0;
00313 }
00314 
00315 unsigned long _addr_to_num (const char *addr) {
00316         int i;
00317         char tok[4];
00318         int octet;
00319         int j = 0, k = 0;
00320         unsigned long ipnum = 0;
00321         char c = 0;
00322 
00323         for (i=0; i<4; i++) {
00324                 for (;;) {
00325                         c = addr[k++];
00326                         if (c == '.' || c == '\0') {
00327                                 tok[j] = '\0';
00328                                 octet = atoi(tok);
00329                                 if (octet > 255)
00330                                         return 0;
00331                                 ipnum += (octet << ((3-i)*8));
00332                                 j = 0;
00333                                 break;
00334                         } else if (c >= '0' && c<= '9') {
00335                                 if (j > 2) {
00336                                         return 0;
00337                                 }
00338                                 tok[j++] = c;
00339                         } else {
00340                                 return 0;
00341                         }
00342                 }
00343                 if(c == '\0' && i<3) {
00344                         return 0;
00345                 }
00346         }
00347         return ipnum;
00348 }
00349 
00350 GeoIP* GeoIP_open_type (int type, int flags) {
00351         GeoIP * gi;
00352         const char * filePath;
00353         if (type < 0 || type >= NUM_DB_TYPES) {
00354                 printf("Invalid database type %d\n", type);
00355                 return NULL;
00356         }
00357         _setup_dbfilename();
00358         filePath = GeoIPDBFileName[type];
00359         if (filePath == NULL) {
00360                 printf("Invalid database type %d\n", type);
00361                 return NULL;
00362         }
00363         gi = GeoIP_open (filePath, flags);
00364         return gi;
00365 }
00366 
00367 GeoIP* GeoIP_new (int flags) {
00368         GeoIP * gi;
00369         _setup_dbfilename();
00370         gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags);
00371         return gi;
00372 }
00373 
00374 GeoIP* GeoIP_open (const char * filename, int flags) {
00375         struct stat buf;
00376         GeoIP *gi;
00377 #ifdef _WIN32
00378         WSADATA wsa;
00379         if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
00380                 return NULL;
00381 #endif
00382 
00383         gi = (GeoIP *)malloc(sizeof(GeoIP));
00384         if (gi == NULL)
00385                 return NULL;
00386         gi->file_path = (char*)malloc(sizeof(char) * (strlen(filename)+1));
00387         if (gi->file_path == NULL)
00388                 return NULL;
00389         strcpy(gi->file_path, filename);
00390         gi->GeoIPDatabase = fopen(filename,"rb");
00391         if (gi->GeoIPDatabase == NULL) {
00392                 fprintf(stderr,"Error Opening file %s\n",filename);
00393                 free(gi->file_path);
00394                 free(gi);
00395                 return NULL;
00396         } else {
00397                 if (flags & GEOIP_MEMORY_CACHE) {
00398                         if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
00399                                 fprintf(stderr,"Error stating file %s\n",filename);
00400                                 free(gi);
00401                                 return NULL;
00402                         }
00403                         gi->mtime = buf.st_mtime;
00404                         gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * buf.st_size);
00405                         if (gi->cache != NULL) {
00406                                 if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
00407                                         fprintf(stderr,"Error reading file %s\n",filename);
00408                                         free(gi->cache);
00409                                         free(gi);
00410                                         return NULL;
00411                                 }
00412                         }
00413                 } else {
00414                         gi->cache = NULL;
00415                 }
00416                 gi->flags = flags;
00417                 _setup_segments(gi);
00418                 if (flags & GEOIP_INDEX_CACHE) {                        
00419                         gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
00420                         if (gi->index_cache != NULL) {
00421                                 fseek(gi->GeoIPDatabase, 0, SEEK_SET);
00422                                 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)) {
00423                                         fprintf(stderr,"Error reading file %s\n",filename);
00424                                         free(gi->index_cache);
00425                                         free(gi);
00426                                         return NULL;
00427                                 }
00428                         }
00429                 } else {
00430                         gi->index_cache = NULL;
00431                 }
00432                 return gi;
00433         }
00434 }
00435 
00436 void GeoIP_delete (GeoIP *gi) {
00437         if (gi->GeoIPDatabase != NULL)
00438                 fclose(gi->GeoIPDatabase);
00439         if (gi->cache != NULL)
00440                 free(gi->cache);
00441         if (gi->index_cache != NULL)
00442                 free(gi->index_cache);
00443         if (gi->file_path != NULL)
00444                 free(gi->file_path);
00445         if (gi->databaseSegments != NULL)
00446                 free(gi->databaseSegments);
00447         free(gi);
00448 }
00449 
00450 const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) {
00451         int country_id;
00452         country_id = GeoIP_id_by_name(gi, name);
00453         return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
00454 }
00455 
00456 const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) {
00457         int country_id;
00458         country_id = GeoIP_id_by_name(gi, name);
00459         return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
00460 }
00461 
00462 const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) {
00463         int country_id;
00464         country_id = GeoIP_id_by_name(gi, name);
00465         return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
00466 }
00467 
00468 unsigned long lookupaddress (const char *host) {
00469         unsigned long addr = inet_addr(host);
00470         struct hostent phe2;
00471         struct hostent * phe = &phe2;
00472         char *buf = NULL;
00473         int buflength = 16384;
00474         int herr = 0;
00475         int result = 0;
00476 #ifdef HAVE_GETHOSTBYNAME_R
00477         buf = (char*)malloc(buflength);
00478 #endif
00479         if (addr == INADDR_NONE) {
00480 #ifdef HAVE_GETHOSTBYNAME_R
00481                 while (1) {
00482                         /* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
00483 #ifdef GETHOSTBYNAME_R_RETURNS_INT
00484                         result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr);
00485 #else
00486                         phe = gethostbyname_r(host,&phe2,buf,buflength,&herr);
00487 #endif
00488                         if (herr != ERANGE)
00489                                 break;
00490                         if (result == 0)
00491                                 break;
00492                         /* double the buffer if the buffer is too small */
00493                         buflength = buflength * 2;
00494                         buf = realloc(buf,buflength);
00495                 }
00496 #endif
00497 #ifndef HAVE_GETHOSTBYNAME_R
00498                 /* Some systems do not support gethostbyname_r, such as Mac OS X */
00499                 phe = gethostbyname(host);
00500 #endif
00501                 if (!phe || result != 0) {
00502                         free(buf);
00503                         return 0;
00504                 }
00505                 addr = *((unsigned long *) phe->h_addr_list[0]);
00506         }
00507 #ifdef HAVE_GETHOSTBYNAME_R
00508         free(buf);
00509 #endif
00510         return ntohl(addr);
00511 }
00512 
00513 int GeoIP_id_by_name (GeoIP* gi, const char *name) {
00514         unsigned long ipnum;
00515         int ret;
00516         if (name == NULL) {
00517                 return 0;
00518         }
00519         if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) {
00520                 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
00521                 return 0;
00522         }
00523         if (!(ipnum = lookupaddress(name)))
00524                 return 0;
00525         ret = _seek_record(gi, ipnum) - COUNTRY_BEGIN;
00526         return ret;
00527 
00528 }
00529 
00530 const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) {
00531         int country_id;
00532         country_id = GeoIP_id_by_addr(gi, addr);
00533         return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
00534 }
00535 
00536 const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) {
00537         int country_id;
00538         country_id = GeoIP_id_by_addr(gi, addr);
00539         return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
00540         return GeoIP_country_code3[country_id];
00541 }
00542 
00543 const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) {
00544         int country_id;
00545         country_id = GeoIP_id_by_addr(gi, addr);
00546         return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
00547         return GeoIP_country_name[country_id];
00548 }
00549 
00550 const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) {
00551         int country_id;
00552         country_id = GeoIP_id_by_ipnum(gi, ipnum);
00553         return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
00554 }
00555 
00556 int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) {
00557         return GeoIP_id_by_addr(gi, addr);
00558 }
00559 
00560 int GeoIP_country_id_by_name (GeoIP* gi, const char *host) {
00561         return GeoIP_id_by_name(gi, host);
00562 }
00563 
00564 int GeoIP_id_by_addr (GeoIP* gi, const char *addr) {
00565         unsigned long ipnum;
00566         int ret;
00567         if (addr == NULL) {
00568                 return 0;
00569         }
00570         if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
00571                         gi->databaseType != GEOIP_PROXY_EDITION &&
00572                         gi->databaseType != GEOIP_NETSPEED_EDITION) {
00573                 printf("Invalid database type %s, expected %s\n",
00574                                          GeoIPDBDescription[(int)gi->databaseType],
00575                                          GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
00576                 return 0;
00577         }
00578         ipnum = _addr_to_num(addr);
00579         ret = _seek_record(gi, ipnum) - COUNTRY_BEGIN;
00580         return ret;
00581 }
00582 
00583 int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) {
00584         int ret;
00585         if (ipnum == 0) {
00586                 return 0;
00587         }
00588         if (gi->databaseType != GEOIP_COUNTRY_EDITION && 
00589                         gi->databaseType != GEOIP_PROXY_EDITION &&
00590                         gi->databaseType != GEOIP_NETSPEED_EDITION) {
00591                 printf("Invalid database type %s, expected %s\n",
00592                                          GeoIPDBDescription[(int)gi->databaseType],
00593                                          GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
00594                 return 0;
00595         }
00596         ret = _seek_record(gi, ipnum) - COUNTRY_BEGIN;
00597         return ret;
00598 }
00599 
00600 char *GeoIP_database_info (GeoIP* gi) {
00601         int i;
00602         unsigned char buf[3];
00603         char *retval;
00604         int hasStructureInfo = 0;
00605 
00606         if(gi == NULL)
00607                 return NULL;
00608 
00609         _check_mtime(gi);
00610         fseek(gi->GeoIPDatabase, -3l, SEEK_END);
00611 
00612         /* first get past the database structure information */
00613         for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
00614                 fread(buf, 1, 3, gi->GeoIPDatabase);
00615                 if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) {
00616                         hasStructureInfo = 1;
00617                         break;
00618                 }
00619                 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
00620         }
00621         if (hasStructureInfo == 1) {
00622                 fseek(gi->GeoIPDatabase, -3l, SEEK_CUR);
00623         } else {
00624                 /* no structure info, must be pre Sep 2002 database, go back to end */
00625                 fseek(gi->GeoIPDatabase, -3l, SEEK_END);
00626         }
00627 
00628         for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
00629                 fread(buf, 1, 3, gi->GeoIPDatabase);
00630                 if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) {
00631                         retval = (char*)malloc(sizeof(char) * (i+1));
00632                         if (retval == NULL) {
00633                                 return NULL;
00634                         }
00635                         fread(retval, 1, i, gi->GeoIPDatabase);
00636                         retval[i] = '\0';
00637                         return retval;
00638                 }
00639                 fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
00640         }
00641         return NULL;
00642 }
00643 
00644 /* GeoIP Region Edition functions */
00645 
00646 void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) {
00647         unsigned int seek_region;
00648 
00649         /* This also writes in the terminating NULs (if you decide to
00650          * keep them) and clear any fields that are not set. */
00651         memset(region, 0, sizeof(GeoIPRegion));
00652 
00653         seek_region = _seek_record(gi, ntohl(inetaddr));
00654 
00655         if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
00656                 /* Region Edition, pre June 2003 */
00657                 seek_region -= STATE_BEGIN_REV0;
00658                 if (seek_region >= 1000) {
00659                         region->country_code[0] = 'U';
00660                         region->country_code[1] = 'S';
00661                         region->region[0] = (char) ((seek_region - 1000)/26 + 65);
00662                         region->region[1] = (char) ((seek_region - 1000)%26 + 65);
00663                 } else {
00664                         memcpy(region->country_code, GeoIP_country_code[seek_region], 2);
00665                 }
00666         } else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
00667                 /* Region Edition, post June 2003 */
00668                 seek_region -= STATE_BEGIN_REV1;
00669                 if (seek_region < US_OFFSET) {
00670                         /* Unknown */
00671                         /* we don't need to do anything here b/c we memset region to 0 */
00672                 } else if (seek_region < CANADA_OFFSET) {
00673                         /* USA State */
00674                         region->country_code[0] = 'U';
00675                         region->country_code[1] = 'S';
00676                         region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65);
00677                         region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65);
00678                 } else if (seek_region < WORLD_OFFSET) {
00679                         /* Canada Province */
00680                         region->country_code[0] = 'C';
00681                         region->country_code[1] = 'A';
00682                         region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65);
00683                         region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65);
00684                 } else {
00685                         /* Not US or Canada */
00686                         memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2);
00687                 }
00688         }
00689 }
00690 
00691 GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) {
00692         GeoIPRegion * region;
00693  
00694         region = (GeoIPRegion*)malloc(sizeof(GeoIPRegion));
00695         if (region) {
00696                 GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region);
00697         }
00698         return region;
00699 }
00700 
00701 GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) {
00702         unsigned long ipnum;
00703         if (addr == NULL) {
00704                 return 0;
00705         }
00706         if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
00707                         gi->databaseType != GEOIP_REGION_EDITION_REV1) {
00708                 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
00709                 return 0;
00710         }
00711         ipnum = _addr_to_num(addr);
00712         return _get_region(gi, ipnum);
00713 }
00714 
00715 GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) {
00716         unsigned long ipnum;
00717         if (name == NULL) {
00718                 return 0;
00719         }
00720         if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
00721                         gi->databaseType != GEOIP_REGION_EDITION_REV1) {
00722                 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
00723                 return 0;
00724         }
00725         if (!(ipnum = lookupaddress(name)))
00726                 return 0;
00727         return _get_region(gi, ipnum);
00728 }
00729 
00730 void GeoIPRegion_delete (GeoIPRegion *gir) {
00731         free(gir);
00732 }
00733 
00734 /* GeoIP Organization, ISP and AS Number Edition private method */
00735 char *_get_name (GeoIP* gi, unsigned long ipnum) {
00736         int seek_org;
00737         char buf[MAX_ORG_RECORD_LENGTH];
00738         char * org_buf, * buf_pointer;
00739         int record_pointer;
00740 
00741         if (gi->databaseType != GEOIP_ORG_EDITION &&
00742                         gi->databaseType != GEOIP_ISP_EDITION &&
00743                         gi->databaseType != GEOIP_ASNUM_EDITION) {
00744                 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]);
00745                 return 0;
00746         }
00747 
00748         seek_org = _seek_record(gi, ipnum);
00749         if (seek_org == gi->databaseSegments[0])                
00750                 return NULL;
00751 
00752         record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0];
00753 
00754         if (gi->cache == NULL) {
00755                 fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET);
00756                 fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase);
00757                 org_buf = (char*)malloc(sizeof(char) * (strlen(buf)+1));
00758                 strcpy(org_buf, buf);
00759         } else {
00760                 buf_pointer = (char*)(gi->cache + (long)record_pointer);
00761                 org_buf = (char*)malloc(sizeof(char) * (strlen(buf_pointer)+1));
00762                 strcpy(org_buf, buf_pointer);
00763         }
00764         return org_buf;
00765 }
00766 
00767 char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) {
00768         unsigned long ipnum;
00769         if (addr == NULL) {
00770                 return 0;
00771         }
00772         ipnum = _addr_to_num(addr);
00773         return _get_name(gi, ipnum);
00774 }
00775 
00776 char *GeoIP_name_by_name (GeoIP* gi, const char *name) {
00777         unsigned long ipnum;
00778         if (name == NULL) {
00779                 return 0;
00780         }
00781         if (!(ipnum = lookupaddress(name)))
00782                 return 0;
00783         return _get_name(gi, ipnum);
00784 }
00785 
00786 char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) {
00787         return GeoIP_name_by_addr(gi, addr);
00788 }
00789 
00790 char *GeoIP_org_by_name (GeoIP* gi, const char *name) {
00791         return GeoIP_name_by_name(gi, name);
00792 }
00793 
00794 unsigned char GeoIP_database_edition (GeoIP* gi) {
00795         return gi->databaseType;
00796 }

Generated on Tue Jun 28 01:09:07 2005 for CountryFilter by  doxygen 1.4.3-20050623