1 2/* 3 * GeoIPCity.c 4 * 5 * Copyright (C) 2006 MaxMind LLC 6 * 7 * This library is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU Lesser General Public License as published by the 9 * Free Software Foundation; either version 2.1 of the License, or (at your 10 * option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 * License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "GeoIP.h" 23#include "GeoIP_internal.h" 24#include "GeoIPCity.h" 25#if !defined(_WIN32) 26#include <unistd.h> 27#include <netdb.h> 28#include <netinet/in.h> /* For ntohl */ 29#else 30#include <windows.h> 31#include <winsock.h> 32#endif 33#include <sys/types.h> /* For uint32_t */ 34#ifdef HAVE_STDINT_H 35#include <stdint.h> /* For uint32_t */ 36#endif 37 38#ifndef HAVE_PREAD 39#define pread(fd, buf, count, offset) \ 40 ( \ 41 lseek(fd, offset, SEEK_SET) == offset ? \ 42 read(fd, buf, count) : \ 43 -1 \ 44 ) 45#endif /* HAVE_PREAD */ 46 47 48static 49const int FULL_RECORD_LENGTH = 50; 50 51 52static 53GeoIPRecord * 54_extract_record(GeoIP * gi, unsigned int seek_record, int *next_record_ptr) 55{ 56 int record_pointer; 57 unsigned char *record_buf = NULL; 58 unsigned char *begin_record_buf = NULL; 59 GeoIPRecord *record; 60 int str_length = 0; 61 int j; 62 double latitude = 0, longitude = 0; 63 int metroarea_combo = 0; 64 int bytes_read = 0; 65 if (seek_record == gi->databaseSegments[0]) 66 return NULL; 67 68 record = malloc(sizeof(GeoIPRecord)); 69 memset(record, 0, sizeof(GeoIPRecord)); 70 record->charset = gi->charset; 71 72 record_pointer = seek_record + (2 * gi->record_length - 1) * gi->databaseSegments[0]; 73 74 if (gi->cache == NULL) { 75 begin_record_buf = record_buf = malloc(sizeof(char) * FULL_RECORD_LENGTH); 76 bytes_read = pread(fileno(gi->GeoIPDatabase), record_buf, FULL_RECORD_LENGTH, record_pointer); 77 if (bytes_read == 0) { 78 /* eof or other error */ 79 free(begin_record_buf); 80 free(record); 81 return NULL; 82 } 83 } 84 else { 85 record_buf = gi->cache + (long) record_pointer; 86 } 87 88 /* get country */ 89 record->continent_code = (char *) GeoIP_country_continent[record_buf[0]]; 90 record->country_code = (char *) GeoIP_country_code[record_buf[0]]; 91 record->country_code3 = (char *) GeoIP_country_code3[record_buf[0]]; 92 record->country_name = (char *) GeoIP_country_name_by_id(gi, record_buf[0]); 93 record_buf++; 94 95 /* get region */ 96 while (record_buf[str_length] != '\0') 97 str_length++; 98 if (str_length > 0) { 99 record->region = malloc(str_length + 1); 100 strncpy(record->region, (char *) record_buf, str_length + 1); 101 } 102 record_buf += str_length + 1; 103 str_length = 0; 104 105 /* get city */ 106 while (record_buf[str_length] != '\0') 107 str_length++; 108 if (str_length > 0) { 109 if (gi->charset == GEOIP_CHARSET_UTF8) { 110 record->city = _GeoIP_iso_8859_1__utf8((const char *) record_buf); 111 } 112 else { 113 record->city = malloc(str_length + 1); 114 strncpy(record->city, (const char *) record_buf, str_length + 1); 115 } 116 } 117 record_buf += (str_length + 1); 118 str_length = 0; 119 120 /* get postal code */ 121 while (record_buf[str_length] != '\0') 122 str_length++; 123 if (str_length > 0) { 124 record->postal_code = malloc(str_length + 1); 125 strncpy(record->postal_code, (char *) record_buf, str_length + 1); 126 } 127 record_buf += (str_length + 1); 128 129 /* get latitude */ 130 for (j = 0; j < 3; ++j) 131 latitude += (record_buf[j] << (j * 8)); 132 record->latitude = latitude / 10000 - 180; 133 record_buf += 3; 134 135 /* get longitude */ 136 for (j = 0; j < 3; ++j) 137 longitude += (record_buf[j] << (j * 8)); 138 record->longitude = longitude / 10000 - 180; 139 140 /* 141 * get area code and metro code for post April 2002 databases and for US 142 * locations 143 */ 144 if (GEOIP_CITY_EDITION_REV1 == gi->databaseType) { 145 if (!strcmp(record->country_code, "US")) { 146 record_buf += 3; 147 for (j = 0; j < 3; ++j) 148 metroarea_combo += (record_buf[j] << (j * 8)); 149 record->metro_code = metroarea_combo / 1000; 150 record->area_code = metroarea_combo % 1000; 151 } 152 } 153 154 if (gi->cache == NULL) 155 free(begin_record_buf); 156 157 /* Used for GeoIP_next_record */ 158 if (next_record_ptr != NULL) 159 *next_record_ptr = seek_record + record_buf - begin_record_buf + 3; 160 161 return record; 162} 163 164static 165GeoIPRecord * 166_get_record_gl(GeoIP * gi, unsigned long ipnum, GeoIPLookup * gl) 167{ 168 unsigned int seek_record; 169 GeoIPRecord * r; 170 if (gi->databaseType != GEOIP_CITY_EDITION_REV0 171 && gi->databaseType != GEOIP_CITY_EDITION_REV1) { 172 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int) gi->databaseType], GeoIPDBDescription[GEOIP_CITY_EDITION_REV1]); 173 return NULL; 174 } 175 176 seek_record = _GeoIP_seek_record_gl(gi, ipnum, gl); 177 r = _extract_record(gi, seek_record, NULL); 178 if ( r ) 179 r->netmask = gl->netmask; 180 return r; 181} 182 183static 184GeoIPRecord * 185_get_record(GeoIP * gi, unsigned long ipnum) 186{ 187 GeoIPLookup gl; 188 return _get_record_gl(gi, ipnum, &gl); 189} 190 191static 192GeoIPRecord * 193_get_record_v6_gl(GeoIP * gi, geoipv6_t ipnum, GeoIPLookup * gl) 194{ 195 GeoIPRecord * r; 196 unsigned int seek_record; 197 if (gi->databaseType != GEOIP_CITY_EDITION_REV0_V6 && 198 gi->databaseType != GEOIP_CITY_EDITION_REV1_V6) { 199 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int) gi->databaseType], GeoIPDBDescription[GEOIP_CITY_EDITION_REV1_V6]); 200 return NULL; 201 } 202 203 seek_record = _GeoIP_seek_record_v6_gl(gi, ipnum, gl); 204 r = _extract_record(gi, seek_record, NULL); 205 if ( r ) 206 r->netmask = gl->netmask; 207 return r; 208} 209 210static 211GeoIPRecord * 212_get_record_v6(GeoIP * gi, geoipv6_t ipnum) 213{ 214 GeoIPLookup gl; 215 return _get_record_v6_gl(gi, ipnum, &gl); 216} 217 218GeoIPRecord * 219GeoIP_record_by_ipnum(GeoIP * gi, unsigned long ipnum) 220{ 221 return _get_record(gi, ipnum); 222} 223 224GeoIPRecord * 225GeoIP_record_by_ipnum_v6(GeoIP * gi, geoipv6_t ipnum) 226{ 227 return _get_record_v6(gi, ipnum); 228} 229 230GeoIPRecord * 231GeoIP_record_by_addr(GeoIP * gi, const char *addr) 232{ 233 unsigned long ipnum; 234 GeoIPLookup gl; 235 if (addr == NULL) { 236 return 0; 237 } 238 ipnum = GeoIP_addr_to_num(addr); 239 return _get_record_gl(gi, ipnum, &gl); 240} 241 242GeoIPRecord * 243GeoIP_record_by_addr_v6(GeoIP * gi, const char *addr) 244{ 245 geoipv6_t ipnum; 246 if (addr == NULL) { 247 return 0; 248 } 249 ipnum = _GeoIP_addr_to_num_v6(addr); 250 return _get_record_v6(gi, ipnum); 251} 252 253GeoIPRecord * 254GeoIP_record_by_name(GeoIP * gi, const char *name) 255{ 256 unsigned long ipnum; 257 if (name == NULL) { 258 return 0; 259 } 260 ipnum = _GeoIP_lookupaddress(name); 261 return _get_record(gi, ipnum); 262} 263 264GeoIPRecord * 265GeoIP_record_by_name_v6(GeoIP * gi, const char *name) 266{ 267 geoipv6_t ipnum; 268 if (name == NULL) { 269 return 0; 270 } 271 ipnum = _GeoIP_lookupaddress_v6(name); 272 return _get_record_v6(gi, ipnum); 273} 274 275int 276GeoIP_record_id_by_addr(GeoIP * gi, const char *addr) 277{ 278 unsigned long ipnum; 279 if (gi->databaseType != GEOIP_CITY_EDITION_REV0 && 280 gi->databaseType != GEOIP_CITY_EDITION_REV1) { 281 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int) gi->databaseType], GeoIPDBDescription[GEOIP_CITY_EDITION_REV1]); 282 return 0; 283 } 284 if (addr == NULL) { 285 return 0; 286 } 287 ipnum = GeoIP_addr_to_num(addr); 288 return _GeoIP_seek_record(gi, ipnum); 289} 290 291int 292GeoIP_record_id_by_addr_v6(GeoIP * gi, const char *addr) 293{ 294 geoipv6_t ipnum; 295 if (gi->databaseType != GEOIP_CITY_EDITION_REV0_V6 && 296 gi->databaseType != GEOIP_CITY_EDITION_REV1_V6) { 297 printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int) gi->databaseType], GeoIPDBDescription[GEOIP_CITY_EDITION_REV1]); 298 return 0; 299 } 300 if (addr == NULL) { 301 return 0; 302 } 303 ipnum = _GeoIP_addr_to_num_v6(addr); 304 return _GeoIP_seek_record_v6(gi, ipnum); 305} 306 307int 308GeoIP_init_record_iter(GeoIP * gi) 309{ 310 return gi->databaseSegments[0] + 1; 311} 312 313int 314GeoIP_next_record(GeoIP * gi, GeoIPRecord ** gir, int *record_iter) 315{ 316 if (gi->cache != NULL) { 317 printf("GeoIP_next_record not supported in memory cache mode\n"); 318 return 1; 319 } 320 *gir = _extract_record(gi, *record_iter, record_iter); 321 return 0; 322} 323 324void 325GeoIPRecord_delete(GeoIPRecord * gir) 326{ 327 free(gir->region); 328 free(gir->city); 329 free(gir->postal_code); 330 free(gir); 331} 332