Browse code

initial version of mirror manager; new option --list-mirrors

git-svn: trunk@2590

Tomasz Kojm authored on 2007/01/07 01:00:14
Showing 7 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Jan  6 16:57:23 CET 2007 (tk)
2
+---------------------------------
3
+  * freshclam: initial version of mirror manager; new option --list-mirrors
4
+
1 5
 Fri Jan  5 14:45:29 GMT 2007 (njh)
2 6
 ----------------------------------
3 7
   * libclamav/pst.c:	Commit fix from upstream detecting Outlook tasks
... ...
@@ -44,7 +44,9 @@ freshclam_SOURCES = \
44 44
     execute.c \
45 45
     execute.h \
46 46
     nonblock.c \
47
-    nonblock.h
47
+    nonblock.h \
48
+    mirman.c \
49
+    mirman.h
48 50
 
49 51
 DEFS = @DEFS@ -DCL_NOTHREADS
50 52
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav
... ...
@@ -74,7 +74,7 @@ am_freshclam_OBJECTS = output.$(OBJEXT) cfgparser.$(OBJEXT) \
74 74
 	getopt.$(OBJEXT) memory.$(OBJEXT) misc.$(OBJEXT) \
75 75
 	options.$(OBJEXT) cdiff.$(OBJEXT) freshclam.$(OBJEXT) \
76 76
 	manager.$(OBJEXT) notify.$(OBJEXT) dns.$(OBJEXT) \
77
-	execute.$(OBJEXT) nonblock.$(OBJEXT)
77
+	execute.$(OBJEXT) nonblock.$(OBJEXT) mirman.$(OBJEXT)
78 78
 freshclam_OBJECTS = $(am_freshclam_OBJECTS)
79 79
 freshclam_LDADD = $(LDADD)
80 80
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
... ...
@@ -243,7 +243,9 @@ freshclam_SOURCES = \
243 243
     execute.c \
244 244
     execute.h \
245 245
     nonblock.c \
246
-    nonblock.h
246
+    nonblock.h \
247
+    mirman.c \
248
+    mirman.h
247 249
 
248 250
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav
249 251
 all: all-am
... ...
@@ -325,6 +327,7 @@ distclean-compile:
325 325
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
326 326
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Po@am__quote@
327 327
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@
328
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mirman.Po@am__quote@
328 329
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
329 330
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonblock.Po@am__quote@
330 331
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Po@am__quote@
... ...
@@ -57,6 +57,7 @@
57 57
 
58 58
 #include "execute.h"
59 59
 #include "manager.h"
60
+#include "mirman.h"
60 61
 
61 62
 static short terminate = 0;
62 63
 extern int active_children;
... ...
@@ -142,6 +143,7 @@ void help(void)
142 142
     mprintf("    --on-update-execute=COMMAND          execute COMMAND after successful update\n");
143 143
     mprintf("    --on-error-execute=COMMAND           execute COMMAND if errors occured\n");
144 144
     mprintf("    --on-outdated-execute=COMMAND        execute COMMAND when software is outdated\n");
145
+    mprintf("    --list-mirrors                       print mirrors from mirrors.dat\n");
145 146
 
146 147
     mprintf("\n");
147 148
 }
... ...
@@ -174,7 +176,7 @@ int download(const struct cfgstruct *copt, const struct optstruct *opt)
174 174
 		    logg("Giving up on %s...\n", cpt->strarg);
175 175
 		    cpt = (struct cfgstruct *) cpt->nextarg;
176 176
 		    if(!cpt) {
177
-			logg("^Update failed. Your network may be down or none of the mirrors listed in freshclam.conf is working.\n");
177
+			logg("Update failed. Your network may be down or none of the mirrors listed in freshclam.conf is working. Check http://www.clamav.net/support/mirror-problem for possible reasons.\n");
178 178
 		    }
179 179
 		    try = 0;
180 180
 		}
... ...
@@ -203,6 +205,7 @@ int main(int argc, char **argv)
203 203
 	struct passwd *user;
204 204
 #endif
205 205
 	struct stat statbuf;
206
+	struct mirdat mdat;
206 207
 	struct optstruct *opt;
207 208
 	const char *short_options = "hvdp:Vl:c:u:a:";
208 209
 	static struct option long_options[] = {
... ...
@@ -228,6 +231,7 @@ int main(int argc, char **argv)
228 228
 	    {"on-update-execute", 1, 0, 0},
229 229
 	    {"on-error-execute", 1, 0, 0},
230 230
 	    {"on-outdated-execute", 1, 0, 0},
231
+	    {"list-mirrors", 0, 0, 0},
231 232
 	    {0, 0, 0, 0}
232 233
     	};
233 234
 
... ...
@@ -403,6 +407,17 @@ int main(int argc, char **argv)
403 403
     } else
404 404
 	logg("*Current working dir is %s\n", newdir);
405 405
 
406
+
407
+    if(opt_check(opt, "list-mirrors")) {
408
+	if(mirman_read("mirrors.dat", &mdat) == -1) {
409
+	    printf("Can't read mirrors.dat\n");
410
+	    return 55;
411
+	}
412
+	mirman_list(&mdat);
413
+	mirman_free(&mdat);
414
+	return 0;
415
+    }
416
+
406 417
 #ifdef	C_WINDOWS
407 418
     {
408 419
 	    WSADATA wsaData;
... ...
@@ -47,6 +47,7 @@
47 47
 #include "dns.h"
48 48
 #include "execute.h"
49 49
 #include "nonblock.h"
50
+#include "mirman.h"
50 51
 
51 52
 #include "shared/options.h"
52 53
 #include "shared/cfgparser.h"
... ...
@@ -64,9 +65,9 @@
64 64
 #endif
65 65
 
66 66
 
67
-static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout)
67
+static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat)
68 68
 {
69
-	int socketfd = -1, port, i;
69
+	int socketfd = -1, port, i, ret;
70 70
 	struct sockaddr_in name;
71 71
 	struct hostent *host;
72 72
 	char ipaddr[16];
... ...
@@ -187,6 +188,14 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
187 187
 	ia = (unsigned char *) host->h_addr_list[i];
188 188
 	sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
189 189
 
190
+	if((ret = mirman_check(((struct in_addr *) ia)->s_addr, mdat))) {
191
+	    if(ret == 1)
192
+		logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
193
+	    else
194
+		logg("Ignoring mirror %s (too often connections with outdated version)\n", ipaddr);
195
+	    continue;
196
+	}
197
+
190 198
 	if(ip)
191 199
 	    strcpy(ip, ipaddr);
192 200
 
... ...
@@ -204,6 +213,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
204 204
 	    logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
205 205
 	    continue;
206 206
 	} else {
207
+	    mdat->currip = ((struct in_addr *) ia)->s_addr;
207 208
 	    return socketfd;
208 209
 	}
209 210
     }
... ...
@@ -288,7 +298,7 @@ static char *proxyauth(const char *user, const char *pass)
288 288
     return auth;
289 289
 }
290 290
 
291
-static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims, int ctimeout, int rtimeout)
291
+static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, unsigned int *ims, int ctimeout, int rtimeout, struct mirdat *mdat)
292 292
 {
293 293
 	char cmd[512], head[513], buffer[FILEBUFF], ipaddr[16], *ch, *tmp;
294 294
 	int bread, cnt, sd;
... ...
@@ -352,9 +362,9 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
352 352
     memset(ipaddr, 0, sizeof(ipaddr));
353 353
 
354 354
     if(ip[0]) /* use ip to connect */
355
-	sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout);
355
+	sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat);
356 356
     else
357
-	sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout);
357
+	sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat);
358 358
 
359 359
     if(sd < 0) {
360 360
 	return NULL;
... ...
@@ -388,11 +398,13 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
388 388
 
389 389
     if(bread == -1) {
390 390
 	logg("!remote_cvdhead: Error while reading CVD header from %s\n", hostname);
391
+	mirman_update(mdat->currip, mdat, 1);
391 392
 	return NULL;
392 393
     }
393 394
 
394 395
     if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { 
395 396
 	logg("!CVD file not found on remote server\n");
397
+	mirman_update(mdat->currip, mdat, 1);
396 398
 	return NULL;
397 399
     }
398 400
 
... ...
@@ -400,6 +412,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
400 400
     if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) { 
401 401
 	*ims = 0;
402 402
 	logg("OK (IMS)\n");
403
+	mirman_update(mdat->currip, mdat, 0);
403 404
 	return NULL;
404 405
     } else {
405 406
 	*ims = 1;
... ...
@@ -408,6 +421,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
408 408
     if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
409 409
        !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
410 410
 	logg("!Unknown response from remote server\n");
411
+	mirman_update(mdat->currip, mdat, 1);
411 412
 	return NULL;
412 413
     }
413 414
 
... ...
@@ -425,6 +439,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
425 425
 
426 426
     if(sizeof(buffer) - i < 512) {
427 427
 	logg("!remote_cvdhead: Malformed CVD header (too short)\n");
428
+	mirman_update(mdat->currip, mdat, 1);
428 429
 	return NULL;
429 430
     }
430 431
 
... ...
@@ -433,20 +448,24 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
433 433
     for(j = 0; j < 512; j++) {
434 434
 	if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
435 435
 	    logg("!remote_cvdhead: Malformed CVD header (bad chars)\n");
436
+	    mirman_update(mdat->currip, mdat, 1);
436 437
 	    return NULL;
437 438
 	}
438 439
 	head[j] = ch[j];
439 440
     }
440 441
 
441
-    if(!(cvd = cl_cvdparse(head)))
442
-	logg("!Malformed CVD header (can't parser)\n");
443
-    else
442
+    if(!(cvd = cl_cvdparse(head))) {
443
+	logg("!Malformed CVD header (can't parse)\n");
444
+	mirman_update(mdat->currip, mdat, 1);
445
+    } else {
444 446
 	logg("OK\n");
447
+	mirman_update(mdat->currip, mdat, 0);
448
+    }
445 449
 
446 450
     return cvd;
447 451
 }
448 452
 
449
-static int getfile(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout)
453
+static int getfile(const char *srcfile, const char *destfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat)
450 454
 {
451 455
 	char cmd[512], buffer[FILEBUFF], *ch;
452 456
 	int bread, fd, totalsize = 0,  rot = 0, totaldownloaded = 0,
... ...
@@ -493,9 +512,9 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
493 493
     memset(ipaddr, 0, sizeof(ipaddr));
494 494
 
495 495
     if(ip[0]) /* use ip to connect */
496
-	sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout);
496
+	sd = wwwconnect(ip, proxy, port, ipaddr, localip, ctimeout, mdat);
497 497
     else
498
-	sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout);
498
+	sd = wwwconnect(hostname, proxy, port, ipaddr, localip, ctimeout, mdat);
499 499
 
500 500
     if(sd < 0) {
501 501
 	return 52;
... ...
@@ -527,7 +546,8 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
527 527
 #else
528 528
 	if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
529 529
 #endif
530
-	    logg("!getfile: Error while reading database from %s\n", hostname);
530
+	    logg("!getfile: Error while reading database from %s (IP: %s)\n", hostname, ipaddr);
531
+	    mirman_update(mdat->currip, mdat, 1);
531 532
 	    return 52;
532 533
 	}
533 534
 
... ...
@@ -543,14 +563,16 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
543 543
 
544 544
     /* check whether the resource actually existed or not */
545 545
     if((strstr(buffer, "HTTP/1.1 404")) != NULL || (strstr(buffer, "HTTP/1.0 404")) != NULL) { 
546
-	logg("!getfile: %s not found on remote server\n", srcfile);
546
+	logg("!getfile: %s not found on remote server (IP: %s)\n", srcfile, ipaddr);
547
+	mirman_update(mdat->currip, mdat, 1);
547 548
 	close(sd);
548 549
 	return 58;
549 550
     }
550 551
 
551 552
     if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
552 553
        !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
553
-	logg("!getfile: Unknown response from remote server\n");
554
+	logg("!getfile: Unknown response from remote server (IP: %s)\n", ipaddr);
555
+	mirman_update(mdat->currip, mdat, 1);
554 556
 	return 58;
555 557
     }
556 558
 
... ...
@@ -611,10 +633,11 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
611 611
     else
612 612
         logg("Downloading %s [*]\n", srcfile);
613 613
 
614
+    mirman_update(mdat->currip, mdat, 0);
614 615
     return 0;
615 616
 }
616 617
 
617
-static int getcvd(const char *dbfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int nodb, int newver, int ctimeout, int rtimeout)
618
+static int getcvd(const char *dbfile, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int nodb, unsigned int newver, int ctimeout, int rtimeout, struct mirdat *mdat)
618 619
 {
619 620
 	char *tempname;
620 621
 	struct cl_cvd *cvd;
... ...
@@ -624,8 +647,8 @@ static int getcvd(const char *dbfile, const char *hostname, char *ip, const char
624 624
     tempname = cli_gentemp(".");
625 625
 
626 626
     logg("*Retrieving http://%s/%s\n", hostname, dbfile);
627
-    if((ret = getfile(dbfile, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout))) {
628
-        logg("!Can't download %s from %s (IP: %s)\n", dbfile, hostname, ip);
627
+    if((ret = getfile(dbfile, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat))) {
628
+        logg("!Can't download %s from %s\n", dbfile, hostname);
629 629
         unlink(tempname);
630 630
         free(tempname);
631 631
         return ret;
... ...
@@ -704,7 +727,7 @@ static int chdir_inc(const char *dbname)
704 704
     return 0;
705 705
 }
706 706
 
707
-static int getpatch(const char *dbname, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout)
707
+static int getpatch(const char *dbname, int version, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int ctimeout, int rtimeout, struct mirdat *mdat)
708 708
 {
709 709
 	char *tempname, patch[32], olddir[512];
710 710
 	int ret, fd;
... ...
@@ -722,8 +745,8 @@ static int getpatch(const char *dbname, int version, const char *hostname, char
722 722
     snprintf(patch, sizeof(patch), "%s-%d.cdiff", dbname, version);
723 723
 
724 724
     logg("*Retrieving http://%s/%s\n", hostname, patch);
725
-    if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout))) {
726
-        logg("!getpatch: Can't download %s from %s (IP: %s)\n", patch, hostname, ip);
725
+    if((ret = getfile(patch, tempname, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat))) {
726
+        logg("!getpatch: Can't download %s from %s\n", patch, hostname);
727 727
         unlink(tempname);
728 728
         free(tempname);
729 729
 	chdir(olddir);
... ...
@@ -775,7 +798,7 @@ static struct cl_cvd *currentdb(const char *dbname, unsigned int *inc)
775 775
     return cvd;
776 776
 }
777 777
 
778
-int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct cfgstruct *copt, const char *dnsreply, char *localip, int outdated)
778
+static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct cfgstruct *copt, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat)
779 779
 {
780 780
 	struct cl_cvd *current, *remote;
781 781
 	struct cfgstruct *cpt;
... ...
@@ -809,6 +832,8 @@ int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, con
809 809
 		}
810 810
 	    }
811 811
 	}
812
+    } else {
813
+	mdat->dbflevel = current->fl;
812 814
     }
813 815
 
814 816
     if(!nodb && dnsreply) {
... ...
@@ -869,7 +894,7 @@ int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, con
869 869
 
870 870
     if(!nodb && !newver) {
871 871
 
872
-	remote = remote_cvdhead(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout);
872
+	remote = remote_cvdhead(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat);
873 873
 
874 874
 	if(!nodb && !ims) {
875 875
 	    logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", inc ? dbinc : dbfile, current->version, current->sigs, current->fl, current->builder);
... ...
@@ -928,7 +953,7 @@ int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, con
928 928
     */
929 929
 
930 930
     if(nodb) {
931
-	ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver, ctimeout, rtimeout);
931
+	ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, nodb, newver, ctimeout, rtimeout, mdat);
932 932
 	if(ret)
933 933
 	    return ret;
934 934
 
... ...
@@ -940,7 +965,7 @@ int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, con
940 940
 	     * !!! FIXME !!!: Redesign this code to make more than one attempt
941 941
 	     *		      to download a single cdiff.
942 942
 	     */
943
-	    ret = getpatch(dbname, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout);
943
+	    ret = getpatch(dbname, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat);
944 944
 	    if(ret) {
945 945
 		logg("^Removing incremental directory %s\n", dbinc);
946 946
 		rmdirs(dbinc);
... ...
@@ -951,7 +976,7 @@ int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, con
951 951
 	if(ret) {
952 952
 	    logg("^Incremental update failed, downloading complete database\n");
953 953
 
954
-	    ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, 1, newver, ctimeout, rtimeout);
954
+	    ret = getcvd(dbfile, hostname, ip, localip, proxy, port, user, pass, uas, 1, newver, ctimeout, rtimeout, mdat);
955 955
 	    if(ret)
956 956
 		return ret;
957 957
 	} else {
... ...
@@ -986,6 +1011,7 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
986 986
 	char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
987 987
 	const char *arg = NULL;
988 988
 	struct cfgstruct *cpt;
989
+	struct mirdat mdat;
989 990
 #ifdef HAVE_RESOLV_H
990 991
 	const char *dnsdbinfo;
991 992
 #endif
... ...
@@ -1069,28 +1095,32 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
1069 1069
 	localip = cpt->strarg;
1070 1070
     }
1071 1071
 
1072
+    mirman_read("mirrors.dat", &mdat);
1073
+
1072 1074
     memset(ipaddr, 0, sizeof(ipaddr));
1073 1075
 
1074
-    if((ret = updatedb("main", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
1076
+    if((ret = updatedb("main", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated, &mdat)) > 50) {
1075 1077
 	if(dnsreply)
1076 1078
 	    free(dnsreply);
1077 1079
 
1078 1080
 	if(newver)
1079 1081
 	    free(newver);
1080 1082
 
1083
+	mirman_write("mirrors.dat", &mdat);
1081 1084
 	return ret;
1082 1085
 
1083 1086
     } else if(ret == 0)
1084 1087
 	updated = 1;
1085 1088
 
1086 1089
     /* if ipaddr[0] != 0 it will use it to connect to the web host */
1087
-    if((ret = updatedb("daily", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated)) > 50) {
1090
+    if((ret = updatedb("daily", hostname, ipaddr, &signo, copt, dnsreply, localip, outdated, &mdat)) > 50) {
1088 1091
 	if(dnsreply)
1089 1092
 	    free(dnsreply);
1090 1093
 
1091 1094
 	if(newver)
1092 1095
 	    free(newver);
1093 1096
 
1097
+	mirman_write("mirrors.dat", &mdat);
1094 1098
 	return ret;
1095 1099
 
1096 1100
     } else if(ret == 0)
... ...
@@ -1099,6 +1129,8 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
1099 1099
     if(dnsreply)
1100 1100
 	free(dnsreply);
1101 1101
 
1102
+    mirman_write("mirrors.dat", &mdat);
1103
+
1102 1104
     if(updated) {
1103 1105
 	if(cfgopt(copt, "HTTPProxyServer")->enabled) {
1104 1106
 	    logg("Database updated (%d signatures) from %s\n", signo, hostname);
1105 1107
new file mode 100644
... ...
@@ -0,0 +1,208 @@
0
+/*
1
+ *  Copyright (C) 2007 Tomasz Kojm <tkojm@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License version 2 as
5
+ *  published by the Free Software Foundation.
6
+ *
7
+ *  This program is distributed in the hope that it will be useful,
8
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
+ *  GNU General Public License for more details.
11
+ *
12
+ *  You should have received a copy of the GNU General Public License
13
+ *  along with this program; if not, write to the Free Software
14
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15
+ *  MA 02110-1301, USA.
16
+ */
17
+
18
+#if HAVE_CONFIG_H
19
+#include "clamav-config.h"
20
+#endif
21
+
22
+#include <stdio.h>
23
+#include <string.h>
24
+#include <stdlib.h>
25
+#ifdef HAVE_UNISTD_H
26
+#include <unistd.h>
27
+#endif
28
+#include <sys/types.h>
29
+#include <sys/stat.h>
30
+#include <fcntl.h>
31
+#include <time.h>
32
+
33
+#include "mirman.h"
34
+
35
+#include "libclamav/cltypes.h"
36
+#include "libclamav/clamav.h"
37
+
38
+#include "shared/output.h"
39
+
40
+#ifndef O_BINARY
41
+#define O_BINARY    0
42
+#endif
43
+
44
+#define IGNTIME 3 * 86400
45
+
46
+void mirman_free(struct mirdat *mdat)
47
+{
48
+    if(mdat && mdat->num) {
49
+	free(mdat->mirtab);
50
+	mdat->num = 0;
51
+    }
52
+}
53
+
54
+int mirman_read(const char *file, struct mirdat *mdat)
55
+{
56
+	struct mirdat_ip mip;
57
+	int fd, bread;
58
+
59
+
60
+    memset(mdat, 0, sizeof(struct mirdat));
61
+
62
+    if((fd = open(file, O_RDONLY|O_BINARY)) == -1)
63
+	return -1;
64
+
65
+    while((bread = read(fd, &mip, sizeof(mip))) == sizeof(mip)) {
66
+	mdat->mirtab = (struct mirdat_ip *) realloc(mdat->mirtab, (mdat->num + 1) * sizeof(mip));
67
+	if(!mdat->mirtab) {
68
+	    logg("!Can't allocate memory for mdat->mirtab\n");
69
+	    mirman_free(mdat);
70
+	    close(fd);
71
+	    return -1;
72
+	}
73
+	memcpy(&mdat->mirtab[mdat->num], &mip, sizeof(mip));
74
+	mdat->num++;
75
+    }
76
+
77
+    close(fd);
78
+
79
+    if(bread) {
80
+	logg("^Removing broken %s file.\n");
81
+	unlink(file);
82
+	mirman_free(mdat);
83
+	return -1;
84
+    }
85
+
86
+    return 0;
87
+}
88
+
89
+int mirman_check(uint32_t ip, struct mirdat *mdat)
90
+{
91
+	unsigned int i, flevel = cl_retflevel();
92
+
93
+
94
+    for(i = 0; i < mdat->num; i++) {
95
+	if(mdat->mirtab[i].ip == ip) {
96
+
97
+	    if(mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3))
98
+		if(time(NULL) - mdat->mirtab[i].atime < 4 * 3600)
99
+		    return 2;
100
+
101
+	    if(mdat->mirtab[i].ignore) {
102
+		if(time(NULL) - mdat->mirtab[i].atime > IGNTIME) {
103
+		    mdat->mirtab[i].ignore = 0;
104
+		    return 0;
105
+		} else {
106
+		    return 1;
107
+		}
108
+	    }
109
+	}
110
+    }
111
+
112
+    return 0;
113
+}
114
+
115
+int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
116
+{
117
+	unsigned int i, found = 0;
118
+
119
+
120
+    for(i = 0; i < mdat->num; i++) {
121
+	if(mdat->mirtab[i].ip == ip) {
122
+	    found = 1;
123
+	    break;
124
+	}
125
+    }
126
+
127
+    if(found) {
128
+	mdat->mirtab[i].atime = (uint32_t) time(NULL);
129
+	if(broken)
130
+	    mdat->mirtab[i].fail++;
131
+	else
132
+	    mdat->mirtab[i].succ++;
133
+
134
+	/*
135
+	 * If the total number of failures is less than 3 then never
136
+	 * enable the ignore flag, in other case use the real status.
137
+	 */
138
+	if(mdat->mirtab[i].fail < 3)
139
+	    mdat->mirtab[i].ignore = 0;
140
+	else
141
+	    mdat->mirtab[i].ignore = broken;
142
+
143
+    } else {
144
+	mdat->mirtab = (struct mirdat_ip *) realloc(mdat->mirtab, (mdat->num + 1) * sizeof(struct mirdat_ip));
145
+	if(!mdat->mirtab) {
146
+	    logg("!Can't allocate memory for new element in mdat->mirtab\n");
147
+	    return -1;
148
+	}
149
+	mdat->mirtab[mdat->num].ip = ip;
150
+	mdat->mirtab[mdat->num].atime = (uint32_t) time(NULL);
151
+	mdat->mirtab[mdat->num].succ = 0;
152
+	mdat->mirtab[mdat->num].fail = 0;
153
+	mdat->mirtab[mdat->num].ignore = 0;
154
+	memset(&mdat->mirtab[mdat->num].res, 0xff, sizeof(mdat->mirtab[mdat->num].res));
155
+	if(broken)
156
+	    mdat->mirtab[mdat->num].fail++;
157
+	else
158
+	    mdat->mirtab[mdat->num].succ++;
159
+	mdat->num++;
160
+    }
161
+
162
+    return 0;
163
+}
164
+
165
+void mirman_list(const struct mirdat *mdat)
166
+{
167
+	unsigned int i;
168
+	unsigned char *ip;
169
+
170
+    for(i = 0; i < mdat->num; i++) {
171
+	printf("Mirror #%u\n", i + 1);
172
+	ip = (unsigned char *) &mdat->mirtab[i].ip;
173
+	printf("IP: %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
174
+	printf("Successes: %u\n", mdat->mirtab[i].succ);
175
+	printf("Failures: %u\n", mdat->mirtab[i].fail);
176
+	printf("Last access: %s", ctime((time_t *) &mdat->mirtab[i].atime));
177
+	printf("Ignore: %s\n", mdat->mirtab[i].ignore ? "Yes" : "No");
178
+	if(i != mdat->num - 1)
179
+	    printf("-------------------------------------\n");
180
+    }
181
+}
182
+
183
+int mirman_write(const char *file, struct mirdat *mdat)
184
+{
185
+	int fd;
186
+
187
+
188
+    if(!mdat->num)
189
+	return 0;
190
+
191
+    if((fd = open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) == -1) {
192
+	logg("!Can't open %s for writing\n", file);
193
+	mirman_free(mdat);
194
+	return -1;
195
+    }
196
+
197
+    if(write(fd, mdat->mirtab, mdat->num * sizeof(struct mirdat_ip)) == -1) {
198
+	logg("!Can't write to %s\n", file);
199
+	mirman_free(mdat);
200
+	close(fd);
201
+	return -1;
202
+    }
203
+
204
+    mirman_free(mdat);
205
+    close(fd);
206
+    return 0;
207
+}
0 208
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+/*
1
+ *  Copyright (C) 2007 Tomasz Kojm <tkojm@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License version 2 as
5
+ *  published by the Free Software Foundation.
6
+ *
7
+ *  This program is distributed in the hope that it will be useful,
8
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
+ *  GNU General Public License for more details.
11
+ *
12
+ *  You should have received a copy of the GNU General Public License
13
+ *  along with this program; if not, write to the Free Software
14
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15
+ *  MA 02110-1301, USA.
16
+ */
17
+
18
+#ifndef __MIRMAN_H
19
+#define __MIRMAN_H
20
+
21
+#include "libclamav/cltypes.h"
22
+
23
+struct mirdat_ip {
24
+    uint32_t ip;	    /* IP address */
25
+    uint32_t atime;	    /* last access time */
26
+    uint32_t succ;	    /* number of successful downloads from this ip */
27
+    uint32_t fail;	    /* number of failures */
28
+    uint8_t ignore;	    /* ignore flag */
29
+    char res[32];	    /* reserved */
30
+};
31
+
32
+struct mirdat {
33
+    unsigned int num;
34
+    uint32_t currip;
35
+    uint32_t dbflevel;
36
+    struct mirdat_ip *mirtab;
37
+};
38
+
39
+int mirman_read(const char *file, struct mirdat *mdat);
40
+int mirman_check(uint32_t ip, struct mirdat *mdat);
41
+int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken);
42
+void mirman_list(const struct mirdat *mdat);
43
+int mirman_write(const char *file, struct mirdat *mdat);
44
+void mirman_free(struct mirdat *mdat);
45
+
46
+#endif