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