1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ 2/* GeoIPUpdate.c 3 * 4 * Copyright (C) 2006 MaxMind LLC 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "base64.h" 22 23#include "GeoIPCity.h" 24#include "GeoIP.h" 25#include "GeoIPUpdate.h" 26#include "GeoIP_internal.h" 27 28#include "global.h" 29#include "md5.h" 30#include <sys/types.h> 31#if !defined(_WIN32) 32#include <netinet/in.h> 33#include <arpa/inet.h> 34#include <sys/socket.h> 35#include <netdb.h> 36#else 37#include <windows.h> 38#include <winsock.h> 39#endif 40#include <zlib.h> 41#include <time.h> 42#include <stdio.h> 43#include <unistd.h> 44 45#ifdef _UNUSED 46#elif defined(__GNUC__) 47#define _UNUSED __attribute__ ((unused)) 48#else 49#define _UNUSED 50#endif 51 52#define BLOCK_SIZE 1024 53 54/* Update DB Host & HTTP GET Request formats: 55 * ------------------------------------------ 56 * GET must support an optional HTTP Proxy. 57 */ 58const char *GeoIPUpdateHost = "updates.maxmind.com"; 59/* This is the direct, or proxy port number. */ 60static int GeoIPHTTPPort = 80; 61/* License-only format (OLD) */ 62const char *GeoIPHTTPRequest = "GET %s%s/app/update?license_key=%s&md5=%s HTTP/1.0\r\nHost: updates.maxmind.com\r\n"; 63/* General DB Types formats */ 64const char *GeoIPHTTPRequestFilename = "GET %s%s/app/update_getfilename?product_id=%s HTTP/1.0\r\nHost: %s\r\n"; 65const char *GeoIPHTTPRequestClientIP = "GET %s%s/app/update_getipaddr HTTP/1.0\r\nHost: %s\r\n"; 66const char *GeoIPHTTPRequestMD5 = "GET %s%s/app/update_secure?db_md5=%s&challenge_md5=%s&user_id=%s&edition_id=%s HTTP/1.0\r\nHost: updates.maxmind.com\r\n"; 67const char *ProxyAuthorization = "Proxy-Authorization: Basic %s\r\n"; 68 69/* messages */ 70const char *NoCurrentDB = "%s can't be opened, proceeding to download database\n"; 71const char *MD5Info = "MD5 Digest of installed database is %s\n"; 72const char *SavingGzip = "Saving gzip file to %s ... "; 73const char *WritingFile = "Writing uncompressed data to %s ..."; 74 75const char * GeoIP_get_error_message(int i) { 76 switch (i) { 77 case GEOIP_NO_NEW_UPDATES: 78 return "no new updates"; 79 case GEOIP_SUCCESS: 80 return "Success"; 81 case GEOIP_LICENSE_KEY_INVALID_ERR: 82 return "License Key Invalid"; 83 case GEOIP_DNS_ERR: 84 return "Unable to resolve hostname"; 85 case GEOIP_NON_IPV4_ERR: 86 return "Non - IPv4 address"; 87 case GEOIP_SOCKET_OPEN_ERR: 88 return "Error opening socket"; 89 case GEOIP_CONNECTION_ERR: 90 return "Unable to connect"; 91 case GEOIP_GZIP_IO_ERR: 92 return "Unable to write GeoIP.dat.gz file"; 93 case GEOIP_TEST_IO_ERR: 94 return "Unable to write GeoIP.dat.test file"; 95 case GEOIP_GZIP_READ_ERR: 96 return "Unable to read gzip data"; 97 case GEOIP_OUT_OF_MEMORY_ERR: 98 return "Out of memory error"; 99 case GEOIP_SOCKET_READ_ERR: 100 return "Error reading from socket, see errno"; 101 case GEOIP_SANITY_OPEN_ERR: 102 return "Sanity check GeoIP_open error"; 103 case GEOIP_SANITY_INFO_FAIL: 104 return "Sanity check database_info string failed"; 105 case GEOIP_SANITY_LOOKUP_FAIL: 106 return "Sanity check ip address lookup failed"; 107 case GEOIP_RENAME_ERR: 108 return "Rename error while installing db, check errno"; 109 case GEOIP_USER_ID_INVALID_ERR: 110 return "Invalid userID"; 111 case GEOIP_PRODUCT_ID_INVALID_ERR: 112 return "Invalid product ID or subscription expired"; 113 case GEOIP_INVALID_SERVER_RESPONSE: 114 return "Server returned something unexpected"; 115 default: 116 return "no error"; 117 } 118} 119int GeoIP_fprintf(int (*f)(FILE *, char *),FILE *fp, const char *str, ...) { 120 va_list ap; 121 int rc; 122 char * f_str; 123 int silence _UNUSED; 124 125 if ( f == NULL ) 126 return 0; 127 va_start(ap, str); 128#if defined(HAVE_VASPRINTF) 129 silence = vasprintf(&f_str, str, ap); 130#elif defined (HAVE_VSNPRINTF) 131 f_str = malloc(4096); 132 if ( f_str ) 133 silence = vsnprintf(f_str, 4096, str, ap); 134#else 135 f_str = malloc(4096); 136 if ( f_str ) 137 silence = vsprintf(f_str, str, ap); 138#endif 139 va_end(ap); 140 if ( f_str == NULL ) 141 return -1; 142 rc = (*f)(fp, f_str); 143 free(f_str); 144 return(rc); 145} 146 147void GeoIP_printf(void (*f)(char *), const char *str,...) { 148 va_list params; 149 char * f_str; 150 int silence _UNUSED; 151 if (f == NULL) 152 return; 153 va_start(params, str); 154#if defined(HAVE_VASPRINTF) 155 silence = vasprintf(&f_str, str, params); 156#elif defined (HAVE_VSNPRINTF) 157 f_str = malloc(4096); 158 if ( f_str ) 159 silence = vsnprintf(f_str, 4096, str, params); 160#else 161 f_str = malloc(4096); 162 if ( f_str ) 163 silence = vsprintf(f_str, str, params); 164#endif 165 va_end(params); 166 if ( f_str == NULL ) 167 return; 168 (*f)(f_str); 169 free(f_str); 170} 171 172/* Support HTTP Proxy Host 173 * -------------------------------------------------- 174 * Use typical OS support for the optional HTTP Proxy. 175 * 176 * Proxy adds http://{real-hostname} to URI format strings: 177 * sprintf("GET %s%s/ HTTP/1.1\r\n",GeoIPProxyHTTP,GeoIPProxiedHost, ...); 178 */ 179 180/* The Protocol is usually "" OR "http://" with a proxy. */ 181static char *GeoIPProxyHTTP = ""; 182/* GeoIP Hostname where proxy forwards requests. */ 183static char *GeoIPProxiedHost = ""; 184 185/* base64-encoded username and password that may be required by the proxy */ 186static char *GeoIPProxyCreds = NULL; 187 188/* Read http_proxy env. variable & parse it. 189 * ----------------------------------------- 190 * Allow only these formats: 191 * "http://server.com", "http://server.com:8080" 192 * OR 193 * "server.com", "server.com:8080" 194 * 195 * A "user:password@" part will break this. 196 */ 197short int parse_http_proxy(char **proxy_host, char **proxy_creds, int *port) { 198 char * http_proxy; 199 char * port_value; 200 char * at_sign; 201 202 if ((http_proxy = getenv("http_proxy"))) { 203 204 if (! strncmp("http://", http_proxy, 7)) http_proxy += 7; 205 206 *proxy_host = strdup(http_proxy); 207 if ( *proxy_host == NULL ) 208 return 0; /* let the other functions deal with the memory error */ 209 210 if ((port_value = strrchr(*proxy_host, ':'))) { 211 *port_value++ = '\0'; 212 *port = atoi(port_value); 213 } 214 else { 215 *port = 80; 216 } 217 218 if ((at_sign = strchr(*proxy_host,'@'))) { 219 *proxy_creds = *proxy_host; 220 *proxy_host = at_sign +1; 221 *at_sign = '\0'; 222 } else { 223 *proxy_creds = NULL; 224 } 225 226 return(1); 227 } 228 else { 229 return(0); 230 } 231} 232 233/* Get the GeoIP host or the current HTTP Proxy host. */ 234struct hostent *GeoIP_get_host_or_proxy ( void (*f)( char * ) ) { 235 char * hostname = (char *) GeoIPUpdateHost; 236 char * proxy_host; 237 char * proxy_creds; 238 char * encoded_proxy_creds; 239 size_t encoded_proxy_creds_len; 240 int proxy_port; 241 242 /* Set Proxy from OS: Unix/Linux */ 243 if (parse_http_proxy(&proxy_host, &proxy_creds, &proxy_port)) { 244 245 GeoIPProxyHTTP = "http://"; 246 hostname = proxy_host; 247 248 if ( proxy_creds == NULL ) 249 proxy_creds = ""; 250 251 // The current code assumes there are no reserved/unsafe characters in the username or password. 252 // The username and password should be URL decoding before they are base64-encoded for the Proxy-Authorization 253 encoded_proxy_creds_len = base64_encode_alloc(proxy_creds, strlen(proxy_creds), &encoded_proxy_creds); 254 if (encoded_proxy_creds == NULL) { 255 if (encoded_proxy_creds_len == 0 && strlen(proxy_creds) != 0) { 256 GeoIP_printf(f,"Error processing proxy credentials: data too long: %d", strlen(proxy_creds)); 257 } else { 258 GeoIP_printf(f,"Error processing proxy credentials: out of memory"); 259 } 260 } else { 261 GeoIPProxyCreds = malloc(sizeof(char) * (strlen(ProxyAuthorization) + strlen(encoded_proxy_creds) + 1)); 262 sprintf(GeoIPProxyCreds, ProxyAuthorization, encoded_proxy_creds); 263 GeoIPProxiedHost = (char *) GeoIPUpdateHost; 264 GeoIPHTTPPort = proxy_port; 265 } 266 267 free(encoded_proxy_creds); 268 269 } 270 271 /* Resolve DNS host entry. */ 272 return(gethostbyname(hostname)); 273} 274 275void GeoIP_send_request_uri(const int sock, const char *request_uri) { 276 277 send(sock, request_uri, strlen(request_uri),0); 278 if (GeoIPProxyCreds) { 279 send(sock,GeoIPProxyCreds,strlen(GeoIPProxyCreds),0); 280 } 281 send(sock, "\r\n", 2 ,0); 282} 283 284short int GeoIP_update_database (char * license_key, int verbose, void (*f)( char * )) { 285 struct hostent *hostlist; 286 int sock; 287 char * buf, *tmp; 288 struct sockaddr_in sa; 289 int offset = 0, err; 290 char * request_uri; 291 char * compr; 292 unsigned long comprLen; 293 FILE *comp_fh, *cur_db_fh, *gi_fh; 294 gzFile gz_fh; 295 char * file_path_gz, * file_path_test; 296 MD5_CONTEXT context; 297 unsigned char buffer[1024], digest[16]; 298 char hex_digest[33] = "00000000000000000000000000000000\0"; 299 unsigned int i; 300 GeoIP * gi; 301 char * db_info; 302 char block[BLOCK_SIZE]; 303 int block_size = BLOCK_SIZE; 304 size_t len; 305 size_t written; 306 _GeoIP_setup_dbfilename(); 307 308 /* get MD5 of current GeoIP database file */ 309 if ((cur_db_fh = fopen (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], "rb")) == NULL) { 310 GeoIP_printf(f, NoCurrentDB, GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 311 } else { 312 md5_init(&context); 313 while ((len = fread (buffer, 1, 1024, cur_db_fh)) > 0) 314 md5_write (&context, buffer, len); 315 md5_final (&context); 316 memcpy(digest,context.buf,16); 317 fclose (cur_db_fh); 318 for (i = 0; i < 16; i++) { 319 // "%02x" will write 3 chars 320 snprintf (&hex_digest[2*i], 3, "%02x", digest[i]); 321 } 322 GeoIP_printf(f, MD5Info, hex_digest); 323 } 324 325 hostlist = GeoIP_get_host_or_proxy(f); 326 327 if (hostlist == NULL) 328 return GEOIP_DNS_ERR; 329 330 if (hostlist->h_addrtype != AF_INET) 331 return GEOIP_NON_IPV4_ERR; 332 333 if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 334 return GEOIP_SOCKET_OPEN_ERR; 335 } 336 337 memset(&sa, 0, sizeof(struct sockaddr_in)); 338 sa.sin_port = htons(GeoIPHTTPPort); 339 memcpy(&sa.sin_addr, hostlist->h_addr_list[0], hostlist->h_length); 340 sa.sin_family = AF_INET; 341 342 if (verbose == 1){ 343 GeoIP_printf(f,"Connecting to MaxMind GeoIP Update server\n"); 344 GeoIP_printf(f, "via Host or Proxy Server: %s:%d\n", hostlist->h_name, GeoIPHTTPPort); 345 } 346 347 /* Download gzip file */ 348 if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))< 0) 349 return GEOIP_CONNECTION_ERR; 350 351 request_uri = malloc(sizeof(char) * (strlen(license_key) + strlen(GeoIPHTTPRequest) 352 + strlen(GeoIPProxyHTTP) + strlen(GeoIPProxiedHost) + 36 + 1)); 353 if (request_uri == NULL) 354 return GEOIP_OUT_OF_MEMORY_ERR; 355 sprintf(request_uri,GeoIPHTTPRequest,GeoIPProxyHTTP,GeoIPProxiedHost,license_key, hex_digest); 356 357 GeoIP_send_request_uri(sock, request_uri); 358 free(request_uri); 359 360 buf = malloc(sizeof(char) * block_size + 1); 361 if (buf == NULL) 362 return GEOIP_OUT_OF_MEMORY_ERR; 363 364 if (verbose == 1) 365 GeoIP_printf(f,"Downloading gzipped GeoIP Database...\n"); 366 367 for (;;) { 368 int amt; 369 amt = recv(sock, &buf[offset], block_size,0); 370 if (amt == 0) { 371 break; 372 } else if (amt == -1) { 373 free(buf); 374 return GEOIP_SOCKET_READ_ERR; 375 } 376 offset += amt; 377 tmp = buf; 378 buf = realloc(buf, offset+block_size + 1); 379 if (buf == NULL){ 380 free(tmp); 381 return GEOIP_OUT_OF_MEMORY_ERR; 382 } 383 } 384 385 buf[offset]=0; 386 compr = strstr(buf, "\r\n\r\n"); 387 if ( compr == NULL ) { 388 free(buf); 389 return GEOIP_INVALID_SERVER_RESPONSE; 390 } 391 /* skip searchstr "\r\n\r\n" */ 392 compr += 4; 393 comprLen = offset + buf - compr; 394 395 if (strstr(compr, "License Key Invalid") != NULL) { 396 if (verbose == 1) 397 GeoIP_printf(f,"Failed\n"); 398 free(buf); 399 return GEOIP_LICENSE_KEY_INVALID_ERR; 400 } else if (strstr(compr, "Invalid product ID or subscription expired") != NULL){ 401 free(buf); 402 return GEOIP_PRODUCT_ID_INVALID_ERR; 403 } else if (strstr(compr, "No new updates available") != NULL) { 404 free(buf); 405 return GEOIP_NO_NEW_UPDATES; 406 } 407 408 if (verbose == 1) 409 GeoIP_printf(f,"Done\n"); 410 411 /* save gzip file */ 412 file_path_gz = malloc(sizeof(char) * (strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) + 4)); 413 if (file_path_gz == NULL) 414 return GEOIP_OUT_OF_MEMORY_ERR; 415 strcpy(file_path_gz,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 416 strcat(file_path_gz,".gz"); 417 if (verbose == 1) { 418 GeoIP_printf(f, SavingGzip, file_path_gz); 419 } 420 comp_fh = fopen(file_path_gz, "wb"); 421 422 if(comp_fh == NULL) { 423 free(file_path_gz); 424 free(buf); 425 return GEOIP_GZIP_IO_ERR; 426 } 427 428 written = fwrite(compr, 1, comprLen, comp_fh); 429 fclose(comp_fh); 430 free(buf); 431 432 if ( written != comprLen ) 433 return GEOIP_GZIP_IO_ERR; 434 435 if (verbose == 1) 436 GeoIP_printf(f,"Done\n"); 437 438 if (verbose == 1) 439 GeoIP_printf(f,"Uncompressing gzip file ... "); 440 441 /* uncompress gzip file */ 442 gz_fh = gzopen(file_path_gz, "rb"); 443 file_path_test = malloc(sizeof(char) * (strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) + 6)); 444 if (file_path_test == NULL) 445 return GEOIP_OUT_OF_MEMORY_ERR; 446 strcpy(file_path_test,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 447 strcat(file_path_test,".test"); 448 gi_fh = fopen(file_path_test, "wb"); 449 450 if(gi_fh == NULL) { 451 free(file_path_test); 452 return GEOIP_TEST_IO_ERR; 453 } 454 for (;;) { 455 int amt; 456 amt = gzread(gz_fh, block, block_size); 457 if (amt == -1) { 458 free(file_path_test); 459 fclose(gi_fh); 460 gzclose(gz_fh); 461 return GEOIP_GZIP_READ_ERR; 462 } 463 if (amt == 0) { 464 break; 465 } 466 if ( fwrite(block,1,amt,gi_fh) != amt ){ 467 free(file_path_test); 468 fclose(gi_fh); 469 gzclose(gz_fh); 470 return GEOIP_GZIP_READ_ERR; 471 } 472 } 473 gzclose(gz_fh); 474 unlink(file_path_gz); 475 free(file_path_gz); 476 fclose(gi_fh); 477 478 if (verbose == 1) 479 GeoIP_printf(f,"Done\n"); 480 481 if (verbose == 1) { 482 GeoIP_printf(f, WritingFile, GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 483 } 484 485 /* sanity check */ 486 gi = GeoIP_open(file_path_test, GEOIP_STANDARD); 487 488 if (verbose == 1) 489 GeoIP_printf(f,"Performing sanity checks ... "); 490 491 if (gi == NULL) { 492 GeoIP_printf(f,"Error opening sanity check database\n"); 493 return GEOIP_SANITY_OPEN_ERR; 494 } 495 496 /* this checks to make sure the files is complete, since info is at the end */ 497 /* dependent on future databases having MaxMind in info */ 498 if (verbose == 1) 499 GeoIP_printf(f,"database_info "); 500 db_info = GeoIP_database_info(gi); 501 if (db_info == NULL) { 502 GeoIP_delete(gi); 503 if (verbose == 1) 504 GeoIP_printf(f,"FAIL\n"); 505 return GEOIP_SANITY_INFO_FAIL; 506 } 507 if (strstr(db_info, "MaxMind") == NULL) { 508 free(db_info); 509 GeoIP_delete(gi); 510 if (verbose == 1) 511 GeoIP_printf(f,"FAIL\n"); 512 return GEOIP_SANITY_INFO_FAIL; 513 } 514 free(db_info); 515 if (verbose == 1) 516 GeoIP_printf(f,"PASS "); 517 518 /* this performs an IP lookup test of a US IP address */ 519 if (verbose == 1) 520 GeoIP_printf(f,"lookup "); 521 if (strcmp(GeoIP_country_code_by_addr(gi,"24.24.24.24"), "US") != 0) { 522 GeoIP_delete(gi); 523 if (verbose == 1) 524 GeoIP_printf(f,"FAIL\n"); 525 return GEOIP_SANITY_LOOKUP_FAIL; 526 } 527 GeoIP_delete(gi); 528 if (verbose == 1) 529 GeoIP_printf(f,"PASS\n"); 530 531 /* install GeoIP.dat.test -> GeoIP.dat */ 532 err = rename(file_path_test, GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 533 if (err != 0) { 534 GeoIP_printf(f,"GeoIP Install error while renaming file\n"); 535 return GEOIP_RENAME_ERR; 536 } 537 538 if (verbose == 1) 539 GeoIP_printf(f,"Done\n"); 540 541 return 0; 542} 543 544short int GeoIP_update_database_general (char * user_id,char * license_key,char *data_base_type, int verbose,char ** client_ipaddr, void (*f)( char *)) { 545 struct hostent *hostlist; 546 int sock; 547 char * buf, * tmp; 548 struct sockaddr_in sa; 549 int offset = 0, err; 550 char * request_uri; 551 char * compr; 552 unsigned long comprLen; 553 FILE *comp_fh, *cur_db_fh, *gi_fh; 554 gzFile gz_fh; 555 char * file_path_gz, * file_path_test; 556 MD5_CONTEXT context; 557 MD5_CONTEXT context2; 558 unsigned char buffer[1024], digest[16] ,digest2[16]; 559 char hex_digest[33] = "0000000000000000000000000000000\0"; 560 char hex_digest2[33] = "0000000000000000000000000000000\0"; 561 unsigned int i; 562 char *f_str; 563 GeoIP * gi; 564 char * db_info; 565 char *ipaddress; 566 char *geoipfilename; 567 char *tmpstr; 568 int dbtype; 569 int lookupresult = 1; 570 char block[BLOCK_SIZE]; 571 int block_size = BLOCK_SIZE; 572 size_t len; 573 size_t request_uri_len; 574 size_t size; 575 576 hostlist = GeoIP_get_host_or_proxy(f); 577 578 if (hostlist == NULL) 579 return GEOIP_DNS_ERR; 580 581 if (hostlist->h_addrtype != AF_INET) 582 return GEOIP_NON_IPV4_ERR; 583 if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 584 return GEOIP_SOCKET_OPEN_ERR; 585 } 586 587 memset(&sa, 0, sizeof(struct sockaddr_in)); 588 sa.sin_port = htons(GeoIPHTTPPort); 589 memcpy(&sa.sin_addr, hostlist->h_addr_list[0], hostlist->h_length); 590 sa.sin_family = AF_INET; 591 592 if (verbose == 1) { 593 GeoIP_printf(f,"Connecting to MaxMind GeoIP server\n"); 594 GeoIP_printf(f, "via Host or Proxy Server: %s:%d\n", hostlist->h_name, GeoIPHTTPPort); 595 } 596 597 if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))< 0) 598 return GEOIP_CONNECTION_ERR; 599 request_uri = malloc(sizeof(char) * (strlen(GeoIPHTTPRequestFilename) 600 + strlen(GeoIPProxyHTTP) + strlen(GeoIPProxiedHost) 601 + strlen(data_base_type) + strlen(GeoIPUpdateHost) + 1)); 602 if (request_uri == NULL) 603 return GEOIP_OUT_OF_MEMORY_ERR; 604 605 /* get the file name from a web page using the product id */ 606 sprintf(request_uri,GeoIPHTTPRequestFilename,GeoIPProxyHTTP,GeoIPProxiedHost,data_base_type,GeoIPUpdateHost); 607 if (verbose == 1) { 608 GeoIP_printf(f, "sending request %s \n",request_uri); 609 } 610 611 GeoIP_send_request_uri(sock, request_uri); 612 613 free(request_uri); 614 buf = malloc(sizeof(char) * (block_size+4)); 615 if (buf == NULL) 616 return GEOIP_OUT_OF_MEMORY_ERR; 617 offset = 0; 618 for (;;){ 619 int amt; 620 amt = recv(sock, &buf[offset], block_size,0); 621 if (amt == 0){ 622 break; 623 } else if (amt == -1) { 624 free(buf); 625 return GEOIP_SOCKET_READ_ERR; 626 } 627 offset += amt; 628 tmp = buf; 629 buf = realloc(buf, offset + block_size + 4); 630 if ( buf == NULL ){ 631 free(tmp); 632 return GEOIP_OUT_OF_MEMORY_ERR; 633 } 634 } 635 buf[offset] = 0; 636 offset = 0; 637 tmpstr = strstr(buf, "\r\n\r\n"); 638 if ( tmpstr == NULL ) { 639 free(buf); 640 return GEOIP_INVALID_SERVER_RESPONSE; 641 } 642 /* skip searchstr "\r\n\r\n" */ 643 tmpstr += 4; 644 if (tmpstr[0] == '.' || strchr(tmpstr, '/') != NULL || strchr(tmpstr, '\\') != NULL) { 645 free(buf); 646 return GEOIP_INVALID_SERVER_RESPONSE; 647 } 648 geoipfilename = _GeoIP_full_path_to(tmpstr); 649 free(buf); 650 651 /* print the database product id and the database filename */ 652 if (verbose == 1){ 653 GeoIP_printf(f, "database product id %s database file name %s \n",data_base_type,geoipfilename); 654 } 655 _GeoIP_setup_dbfilename(); 656 657 /* get MD5 of current GeoIP database file */ 658 if ((cur_db_fh = fopen (geoipfilename, "rb")) == NULL) { 659 GeoIP_printf(f, NoCurrentDB, geoipfilename); 660 } else { 661 md5_init(&context); 662 while ((len = fread (buffer, 1, 1024, cur_db_fh)) > 0) 663 md5_write (&context, buffer, len); 664 md5_final (&context); 665 memcpy(digest,context.buf,16); 666 fclose (cur_db_fh); 667 for (i = 0; i < 16; i++) 668 sprintf (&hex_digest[2*i], "%02x", digest[i]); 669 GeoIP_printf(f, MD5Info, hex_digest ); 670 } 671 if (verbose == 1) { 672 GeoIP_printf(f,"MD5 sum of database %s is %s \n",geoipfilename,hex_digest); 673 } 674 if (client_ipaddr[0] == NULL) { 675 /* We haven't gotten our IP address yet, so let's request it */ 676 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 677 free(geoipfilename); 678 return GEOIP_SOCKET_OPEN_ERR; 679 } 680 681 memset(&sa, 0, sizeof(struct sockaddr_in)); 682 sa.sin_port = htons(GeoIPHTTPPort); 683 memcpy(&sa.sin_addr, hostlist->h_addr_list[0], hostlist->h_length); 684 sa.sin_family = AF_INET; 685 686 if (verbose == 1) 687 GeoIP_printf(f,"Connecting to MaxMind GeoIP Update server\n"); 688 689 /* Download gzip file */ 690 if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))< 0) { 691 free(geoipfilename); 692 return GEOIP_CONNECTION_ERR; 693 } 694 request_uri = malloc(sizeof(char) * (strlen(GeoIPHTTPRequestClientIP) 695 + strlen(GeoIPProxyHTTP) 696 + strlen(GeoIPProxiedHost) 697 + strlen(GeoIPUpdateHost) + 1 )); 698 if (request_uri == NULL) { 699 free(geoipfilename); 700 return GEOIP_OUT_OF_MEMORY_ERR; 701 } 702 703 /* get client ip address from MaxMind web page */ 704 sprintf(request_uri,GeoIPHTTPRequestClientIP,GeoIPProxyHTTP,GeoIPProxiedHost,GeoIPUpdateHost); 705 GeoIP_send_request_uri(sock, request_uri); 706 if (verbose == 1) { 707 GeoIP_printf(f, "sending request %s", request_uri); 708 } 709 free(request_uri); 710 buf = malloc(sizeof(char) * (block_size+1)); 711 if (buf == NULL) { 712 free(geoipfilename); 713 return GEOIP_OUT_OF_MEMORY_ERR; 714 } 715 offset = 0; 716 717 for (;;){ 718 int amt; 719 amt = recv(sock, &buf[offset], block_size,0); 720 if (amt == 0) { 721 break; 722 } else if (amt == -1) { 723 free(buf); 724 return GEOIP_SOCKET_READ_ERR; 725 } 726 offset += amt; 727 tmp = buf; 728 buf = realloc(buf, offset+block_size+1); 729 if ( buf == NULL){ 730 free(tmp); 731 return GEOIP_OUT_OF_MEMORY_ERR; 732 } 733 } 734 735 buf[offset] = 0; 736 offset = 0; 737 ipaddress = strstr(buf, "\r\n\r\n") + 4; /* get the ip address */ 738 ipaddress = malloc(strlen(strstr(buf, "\r\n\r\n") + 4)+5); 739 strcpy(ipaddress,strstr(buf, "\r\n\r\n") + 4); 740 client_ipaddr[0] = ipaddress; 741 if (verbose == 1) { 742 GeoIP_printf(f, "client ip address: %s\n",ipaddress); 743 } 744 free(buf); 745 close(sock); 746 } 747 748 ipaddress = client_ipaddr[0]; 749 750 /* make a md5 sum of ip address and license_key and store it in hex_digest2 */ 751 md5_init(&context2); 752 md5_write (&context2, (byte *)license_key, 12);//add license key to the md5 sum 753 md5_write (&context2, (byte *)ipaddress, strlen(ipaddress));//add ip address to the md5 sum 754 md5_final (&context2); 755 memcpy(digest2,context2.buf,16); 756 for (i = 0; i < 16; i++) 757 snprintf (&hex_digest2[2*i], 3, "%02x", digest2[i]);// change the digest to a hex digest 758 if (verbose == 1) { 759 GeoIP_printf(f, "md5sum of ip address and license key is %s \n",hex_digest2); 760 } 761 762 /* send the request using the user id,product id, 763 * md5 sum of the prev database and 764 * the md5 sum of the license_key and ip address */ 765 if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 766 return GEOIP_SOCKET_OPEN_ERR; 767 } 768 memset(&sa, 0, sizeof(struct sockaddr_in)); 769 sa.sin_port = htons(GeoIPHTTPPort); 770 memcpy(&sa.sin_addr, hostlist->h_addr_list[0], hostlist->h_length); 771 sa.sin_family = AF_INET; 772 if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))< 0) 773 return GEOIP_CONNECTION_ERR; 774 request_uri_len = sizeof(char) * 2036; 775 request_uri = malloc(request_uri_len); 776 if (request_uri == NULL) 777 return GEOIP_OUT_OF_MEMORY_ERR; 778 snprintf(request_uri, request_uri_len, GeoIPHTTPRequestMD5,GeoIPProxyHTTP,GeoIPProxiedHost,hex_digest,hex_digest2,user_id,data_base_type); 779 GeoIP_send_request_uri(sock, request_uri); 780 if (verbose == 1) { 781 GeoIP_printf(f, "sending request %s\n",request_uri); 782 } 783 784 free(request_uri); 785 786 offset = 0; 787 buf = malloc(sizeof(char) * block_size); 788 if (buf == NULL) 789 return GEOIP_OUT_OF_MEMORY_ERR; 790 791 if (verbose == 1) 792 GeoIP_printf(f,"Downloading gzipped GeoIP Database...\n"); 793 794 for (;;) { 795 int amt; 796 amt = recv(sock, &buf[offset], block_size,0); 797 798 if (amt == 0) { 799 break; 800 } else if (amt == -1) { 801 free(buf); 802 return GEOIP_SOCKET_READ_ERR; 803 } 804 offset += amt; 805 tmp = buf; 806 buf = realloc(buf, offset+block_size); 807 if (buf == NULL){ 808 free(tmp); 809 return GEOIP_OUT_OF_MEMORY_ERR; 810 } 811 } 812 813 compr = strstr(buf, "\r\n\r\n") + 4; 814 comprLen = offset + buf - compr; 815 816 if (strstr(compr, "License Key Invalid") != NULL) { 817 if (verbose == 1) 818 GeoIP_printf(f,"Failed\n"); 819 free(buf); 820 return GEOIP_LICENSE_KEY_INVALID_ERR; 821 } else if (strstr(compr, "No new updates available") != NULL) { 822 free(buf); 823 GeoIP_printf(f, "%s is up to date, no updates required\n", geoipfilename); 824 return GEOIP_NO_NEW_UPDATES; 825 } else if (strstr(compr, "Invalid UserId") != NULL){ 826 free(buf); 827 return GEOIP_USER_ID_INVALID_ERR; 828 } else if (strstr(compr, "Invalid product ID or subscription expired") != NULL){ 829 free(buf); 830 return GEOIP_PRODUCT_ID_INVALID_ERR; 831 } 832 833 if (verbose == 1) 834 GeoIP_printf(f,"Done\n"); 835 836 GeoIP_printf(f, "Updating %s\n", geoipfilename); 837 838 /* save gzip file */ 839 file_path_gz = malloc(sizeof(char) * (strlen(geoipfilename) + 4)); 840 841 if (file_path_gz == NULL) 842 return GEOIP_OUT_OF_MEMORY_ERR; 843 strcpy(file_path_gz,geoipfilename); 844 strcat(file_path_gz,".gz"); 845 if (verbose == 1) { 846 GeoIP_printf(f, SavingGzip, file_path_gz ); 847 } 848 comp_fh = fopen(file_path_gz, "wb"); 849 850 if(comp_fh == NULL) { 851 free(file_path_gz); 852 free(buf); 853 return GEOIP_GZIP_IO_ERR; 854 } 855 856 size = fwrite(compr, 1, comprLen, comp_fh); 857 fclose(comp_fh); 858 free(buf); 859 if ( size != comprLen ) { 860 return GEOIP_GZIP_IO_ERR; 861 } 862 863 if (verbose == 1) { 864 GeoIP_printf(f, "download data to a gz file named %s \n",file_path_gz); 865 GeoIP_printf(f,"Done\n"); 866 GeoIP_printf(f,"Uncompressing gzip file ... "); 867 } 868 869 file_path_test = malloc(sizeof(char) * (strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) + 6)); 870 if (file_path_test == NULL) { 871 free(file_path_gz); 872 return GEOIP_OUT_OF_MEMORY_ERR; 873 } 874 strcpy(file_path_test,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]); 875 strcat(file_path_test,".test"); 876 gi_fh = fopen(file_path_test, "wb"); 877 if(gi_fh == NULL) { 878 free(file_path_test); 879 free(file_path_gz); 880 return GEOIP_TEST_IO_ERR; 881 } 882 /* uncompress gzip file */ 883 offset = 0; 884 gz_fh = gzopen(file_path_gz, "rb"); 885 for (;;) { 886 int amt; 887 amt = gzread(gz_fh, block, block_size); 888 if (amt == -1) { 889 free(file_path_gz); 890 free(file_path_test); 891 gzclose(gz_fh); 892 fclose(gi_fh); 893 return GEOIP_GZIP_READ_ERR; 894 } 895 if (amt == 0) { 896 break; 897 } 898 if ( amt != fwrite(block,1,amt,gi_fh) ){ 899 return GEOIP_GZIP_IO_ERR; 900 } 901 } 902 gzclose(gz_fh); 903 unlink(file_path_gz); 904 free(file_path_gz); 905 fclose(gi_fh); 906 907 if (verbose == 1) 908 GeoIP_printf(f,"Done\n"); 909 910 if (verbose == 1) { 911 len = strlen(WritingFile) + strlen(geoipfilename) - 1; 912 f_str = malloc(len); 913 snprintf(f_str,len,WritingFile,geoipfilename); 914 free(f_str); 915 } 916 917 /* sanity check */ 918 gi = GeoIP_open(file_path_test, GEOIP_STANDARD); 919 920 if (verbose == 1) 921 GeoIP_printf(f,"Performing sanity checks ... "); 922 923 if (gi == NULL) { 924 GeoIP_printf(f,"Error opening sanity check database\n"); 925 return GEOIP_SANITY_OPEN_ERR; 926 } 927 928 929 /* get the database type */ 930 dbtype = GeoIP_database_edition(gi); 931 if (verbose == 1) { 932 GeoIP_printf(f, "Database type is %d\n",dbtype); 933 } 934 935 /* this checks to make sure the files is complete, since info is at the end 936 dependent on future databases having MaxMind in info (ISP and Organization databases currently don't have info string */ 937 938 if ((dbtype != GEOIP_ISP_EDITION)&& 939 (dbtype != GEOIP_ORG_EDITION)) { 940 if (verbose == 1) 941 GeoIP_printf(f,"database_info "); 942 db_info = GeoIP_database_info(gi); 943 if (db_info == NULL) { 944 GeoIP_delete(gi); 945 if (verbose == 1) 946 GeoIP_printf(f,"FAIL null\n"); 947 return GEOIP_SANITY_INFO_FAIL; 948 } 949 if (strstr(db_info, "MaxMind") == NULL) { 950 free(db_info); 951 GeoIP_delete(gi); 952 if (verbose == 1) 953 GeoIP_printf(f,"FAIL maxmind\n"); 954 return GEOIP_SANITY_INFO_FAIL; 955 } 956 free(db_info); 957 if (verbose == 1) 958 GeoIP_printf(f,"PASS "); 959 } 960 961 /* this performs an IP lookup test of a US IP address */ 962 if (verbose == 1) 963 GeoIP_printf(f,"lookup "); 964 if (dbtype == GEOIP_NETSPEED_EDITION) { 965 int netspeed = GeoIP_id_by_name(gi,"24.24.24.24"); 966 lookupresult = 0; 967 if (netspeed == GEOIP_CABLEDSL_SPEED){ 968 lookupresult = 1; 969 } 970 } 971 if (dbtype == GEOIP_COUNTRY_EDITION) { 972 /* if data base type is country then call the function 973 * named GeoIP_country_code_by_addr */ 974 lookupresult = 1; 975 if (strcmp(GeoIP_country_code_by_addr(gi,"24.24.24.24"), "US") != 0) { 976 lookupresult = 0; 977 } 978 if (verbose == 1) { 979 GeoIP_printf(f,"testing GEOIP_COUNTRY_EDITION\n"); 980 } 981 } 982 if (dbtype == GEOIP_REGION_EDITION_REV1) { 983 /* if data base type is region then call the function 984 * named GeoIP_region_by_addr */ 985 GeoIPRegion *r = GeoIP_region_by_addr(gi,"24.24.24.24"); 986 lookupresult = 0; 987 if (r != NULL) { 988 lookupresult = 1; 989 free(r); 990 } 991 if (verbose == 1) { 992 GeoIP_printf(f,"testing GEOIP_REGION_EDITION\n"); 993 } 994 } 995 if (dbtype == GEOIP_CITY_EDITION_REV1) { 996 /* if data base type is city then call the function 997 * named GeoIP_record_by_addr */ 998 GeoIPRecord *r = GeoIP_record_by_addr(gi,"24.24.24.24"); 999 lookupresult = 0; 1000 if (r != NULL) { 1001 lookupresult = 1; 1002 free(r); 1003 } 1004 if (verbose == 1) { 1005 GeoIP_printf(f,"testing GEOIP_CITY_EDITION\n"); 1006 } 1007 } 1008 if ((dbtype == GEOIP_ISP_EDITION)|| 1009 (dbtype == GEOIP_ORG_EDITION)) { 1010 /* if data base type is isp or org then call the function 1011 * named GeoIP_org_by_addr */ 1012 GeoIPRecord *r = (GeoIPRecord*)GeoIP_org_by_addr(gi,"24.24.24.24"); 1013 lookupresult = 0; 1014 if (r != NULL) { 1015 lookupresult = 1; 1016 free(r); 1017 } 1018 if (verbose == 1) { 1019 if (dbtype == GEOIP_ISP_EDITION) { 1020 GeoIP_printf(f,"testing GEOIP_ISP_EDITION\n"); 1021 } 1022 if (dbtype == GEOIP_ORG_EDITION) { 1023 GeoIP_printf(f,"testing GEOIP_ORG_EDITION\n"); 1024 } 1025 } 1026 } 1027 if (lookupresult == 0) { 1028 GeoIP_delete(gi); 1029 if (verbose == 1) 1030 GeoIP_printf(f,"FAIL\n"); 1031 return GEOIP_SANITY_LOOKUP_FAIL; 1032 } 1033 GeoIP_delete(gi); 1034 if (verbose == 1) 1035 GeoIP_printf(f,"PASS\n"); 1036 1037 /* install GeoIP.dat.test -> GeoIP.dat */ 1038 err = rename(file_path_test, geoipfilename); 1039 if (err != 0) { 1040 GeoIP_printf(f,"GeoIP Install error while renaming file\n"); 1041 return GEOIP_RENAME_ERR; 1042 } 1043 1044 if (verbose == 1) 1045 GeoIP_printf(f,"Done\n"); 1046 free(geoipfilename); 1047 return 0; 1048} 1049