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