amxmodx/dlls/geoip/geolib/libGeoIP/GeoIPUpdate.c
2004-06-29 05:31:05 +00:00

306 lines
8.1 KiB
C
Executable File

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
/* GeoIPUpdate.c
*
* Copyright (C) 2002 MaxMind.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "GeoIP.h"
#include "GeoIPUpdate.h"
#include "global.h"
#include "md5.h"
#include <sys/types.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <windows.h>
#include <winsock.h>
#endif
#include <zlib.h>
#include <time.h>
#include <stdio.h>
//#include <unistd.h>
extern void _setup_dbfilename();
const char *GeoIPUpdateHost = "updates.maxmind.com";
const char *GeoIPHTTPRequest = "GET /app/update?license_key=%s&md5=%s HTTP/1.0\nHost: updates.maxmind.com\n\n";
/* messages */
const char *NoCurrentDB = "%s can't be opened, proceeding to download database\n";
const char *MD5Info = "MD5 Digest of installed database is %s\n";
const char *SavingGzip = "Saving gzip file to %s ... ";
const char *WritingFile = "Writing uncompressed data to %s ...";
void GeoIP_printf(void (*f)(char *), const char *str) {
char * f_str;
f_str = malloc(strlen(str)+1);
strcpy(f_str,str);
if (f != NULL)
(*f)(f_str);
}
short int GeoIP_update_database (char * license_key, int verbose, void (*f)( char *)) {
struct hostent *hostlist;
int sock, len;
char * buf;
struct sockaddr_in sa;
int offset = 0, err;
int block_size = 1024;
char * request_uri;
char *uncompr = NULL, *compr;
unsigned long comprLen;
FILE *comp_fh, *cur_db_fh, *gi_fh;
gzFile gz_fh;
char * file_path_gz, * file_path_test;
MD5_CTX context;
unsigned char buffer[1024], digest[16];
char hex_digest[32] = "00000000000000000000000000000000";
unsigned int i;
char *f_str;
GeoIP * gi;
char * db_info;
_setup_dbfilename();
/* get MD5 of current GeoIP database file */
if ((cur_db_fh = fopen (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], "rb")) == NULL) {
f_str = malloc(strlen(NoCurrentDB) + strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) - 1);
sprintf(f_str,NoCurrentDB, GeoIPDBFileName[GEOIP_COUNTRY_EDITION]);
if (f != NULL)
(*f)(f_str);
} else {
MD5Init(&context);
while ((len = fread (buffer, 1, 1024, cur_db_fh)) > 0)
MD5Update (&context, buffer, len);
MD5Final (digest, &context);
fclose (cur_db_fh);
for (i = 0; i < 16; i++)
sprintf (&hex_digest[2*i], "%02x", digest[i]);
f_str = malloc(strlen(MD5Info) + strlen(hex_digest) - 1);
sprintf(f_str, MD5Info, hex_digest);
if (f != NULL)
(*f)(f_str);
}
hostlist = gethostbyname(GeoIPUpdateHost);
if (hostlist == NULL)
return GEOIP_DNS_ERR;
if (hostlist->h_addrtype != AF_INET)
return GEOIP_NON_IPV4_ERR;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return GEOIP_SOCKET_OPEN_ERR;
}
memset(&sa, 0, sizeof(struct sockaddr_in));
sa.sin_port = htons(80);
memcpy(&sa.sin_addr, hostlist->h_addr_list[0], hostlist->h_length);
sa.sin_family = AF_INET;
if (verbose == 1)
GeoIP_printf(f,"Connecting to MaxMind GeoIP Update server\n");
/* Download gzip file */
if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))< 0)
return GEOIP_CONNECTION_ERR;
request_uri = malloc(sizeof(char) * (strlen(license_key) + strlen(GeoIPHTTPRequest)+36));
if (request_uri == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
sprintf(request_uri,GeoIPHTTPRequest,license_key, hex_digest);
send(sock, request_uri, strlen(request_uri),0);
free(request_uri);
buf = malloc(sizeof(char) * block_size);
if (buf == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
if (verbose == 1)
GeoIP_printf(f,"Downloading gzipped GeoIP Database...\n");
for (;;) {
int amt;
amt = recv(sock, &buf[offset], block_size,0);
if (amt == 0) {
break;
} else if (amt == -1) {
free(buf);
return GEOIP_SOCKET_READ_ERR;
}
offset += amt;
buf = realloc(buf, offset+block_size);
if (buf == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
}
compr = strstr(buf, "\r\n\r\n") + 4;
comprLen = offset + buf - compr;
if (strstr(compr, "License Key Invalid") != NULL) {
if (verbose == 1)
GeoIP_printf(f,"Failed\n");
free(buf);
return GEOIP_LICENSE_KEY_INVALID_ERR;
} else if (strstr(compr, "No new updates available") != NULL) {
free(buf);
return GEOIP_NO_NEW_UPDATES;
}
if (verbose == 1)
GeoIP_printf(f,"Done\n");
/* save gzip file */
file_path_gz = malloc(sizeof(char) * (strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) + 4));
if (file_path_gz == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
strcpy(file_path_gz,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]);
strcat(file_path_gz,".gz");
if (verbose == 1) {
f_str = malloc(strlen(SavingGzip) + strlen(file_path_gz) - 1);
sprintf(f_str,SavingGzip,file_path_gz);
if (f != NULL)
(*f)(f_str);
}
comp_fh = fopen(file_path_gz, "wb");
if(comp_fh == NULL) {
free(buf);
return GEOIP_GZIP_IO_ERR;
}
fwrite(compr, 1, comprLen, comp_fh);
fclose(comp_fh);
free(buf);
if (verbose == 1)
GeoIP_printf(f,"Done\n");
if (verbose == 1)
GeoIP_printf(f,"Uncompressing gzip file ... ");
/* uncompress gzip file */
offset = 0;
gz_fh = gzopen(file_path_gz, "rb");
free(file_path_gz);
for (;;) {
int amt;
uncompr = realloc(uncompr, offset+block_size);
if (uncompr == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
amt = gzread(gz_fh, &uncompr[offset], block_size);
if (amt == -1) {
gzclose(gz_fh);
return GEOIP_GZIP_READ_ERR;
}
if (amt == 0) {
break;
}
offset += amt;
}
gzclose(gz_fh);
unlink(file_path_gz);
if (verbose == 1)
GeoIP_printf(f,"Done\n");
if (verbose == 1) {
f_str = malloc(strlen(WritingFile) + strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) - 1);
sprintf(f_str,WritingFile,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]);
}
/* write uncompressed GeoIP.dat.test file */
file_path_test = malloc(sizeof(char) * (strlen(GeoIPDBFileName[GEOIP_COUNTRY_EDITION]) + 6));
if (file_path_test == NULL)
return GEOIP_OUT_OF_MEMORY_ERR;
strcpy(file_path_test,GeoIPDBFileName[GEOIP_COUNTRY_EDITION]);
strcat(file_path_test,".test");
gi_fh = fopen(file_path_test, "wb");
if(gi_fh == NULL) {
free(uncompr);
return GEOIP_TEST_IO_ERR;
}
fwrite(uncompr, 1, offset, gi_fh);
fclose(gi_fh);
free(uncompr);
/* sanity check */
gi = GeoIP_open(file_path_test, GEOIP_STANDARD);
if (verbose == 1)
GeoIP_printf(f,"Performing santity checks ... ");
if (gi == NULL) {
GeoIP_printf(f,"Error opening sanity check database\n");
return GEOIP_SANITY_OPEN_ERR;
}
/* this checks to make sure the files is complete, since info is at the end */
/* dependent on future databases having MaxMind in info */
if (verbose == 1)
GeoIP_printf(f,"database_info ");
db_info = GeoIP_database_info(gi);
if (db_info == NULL) {
GeoIP_delete(gi);
if (verbose == 1)
GeoIP_printf(f,"FAIL\n");
return GEOIP_SANITY_INFO_FAIL;
}
if (strstr(db_info, "MaxMind") == NULL) {
free(db_info);
GeoIP_delete(gi);
if (verbose == 1)
GeoIP_printf(f,"FAIL\n");
return GEOIP_SANITY_INFO_FAIL;
}
free(db_info);
if (verbose == 1)
GeoIP_printf(f,"PASS ");
/* this performs an IP lookup test of a US IP address */
if (verbose == 1)
GeoIP_printf(f,"lookup ");
if (strcmp(GeoIP_country_code_by_addr(gi,"24.24.24.24"), "US") != 0) {
GeoIP_delete(gi);
if (verbose == 1)
GeoIP_printf(f,"FAIL\n");
return GEOIP_SANITY_LOOKUP_FAIL;
}
GeoIP_delete(gi);
if (verbose == 1)
GeoIP_printf(f,"PASS\n");
/* install GeoIP.dat.test -> GeoIP.dat */
err = rename(file_path_test, GeoIPDBFileName[GEOIP_COUNTRY_EDITION]);
if (err != 0) {
GeoIP_printf(f,"GeoIP Install error while renaming file\n");
return GEOIP_RENAME_ERR;
}
if (verbose == 1)
GeoIP_printf(f,"Done\n");
return 0;
}