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