git-svn: trunk@4241
Tomasz Kojm authored on 2008/10/10 23:22:00... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Fri Oct 10 16:38:45 CEST 2008 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * freshclam: add support for submitting detection statistics (bb#777) |
|
4 |
+ New options: SubmitDetectionStats and --submit-stats |
|
5 |
+ |
|
1 | 6 |
Thu Oct 9 12:17:45 EEST 2008 (edwin) |
2 | 7 |
------------------------------------- |
3 | 8 |
* ChangeLog, clamav-config.h.in, configure, configure.in, |
... | ... |
@@ -67,6 +67,9 @@ Execute COMMAND when freshclam reports outdated version. In the command string % |
67 | 67 |
.TP |
68 | 68 |
\fB\-\-list\-mirrors\fR |
69 | 69 |
Print mirror details from mirrors.dat (cache file for the mirror manager). |
70 |
+.TP |
|
71 |
+\fB\-\-submit\-stats[=/path/to/clamd.conf]\fR |
|
72 |
+Upload detection statistics to the ClamAV Project (see freshclam.conf(5):SubmitDetectionStats for more details). No database update will be performed. This option only works in the interactive mode. |
|
70 | 73 |
.SH "EXAMPLES" |
71 | 74 |
.LP |
72 | 75 |
.TP |
... | ... |
@@ -143,6 +143,11 @@ Default: 10 |
143 | 143 |
Timeout in seconds when reading from database server. |
144 | 144 |
.br |
145 | 145 |
Default: 30 |
146 |
+.TP |
|
147 |
+\fBSubmitDetectionStats STRING\fR |
|
148 |
+When enabled freshclam will submit statistics to the ClamAV Project about the latest virus detections in your environment. The ClamAV maintainers will then use this data to determine what types of malware are the most detected in the field and in what geographic area they are. This feature requires LogTime and LogFile to be enabled in clamd.conf. The path for clamd.conf file must be provided. |
|
149 |
+.br |
|
150 |
+Default: disabled |
|
146 | 151 |
.SH "FILES" |
147 | 152 |
.LP |
148 | 153 |
@CFGDIR@/freshclam.conf |
... | ... |
@@ -141,3 +141,11 @@ DatabaseMirror database.clamav.net |
141 | 141 |
# Timeout in seconds when reading from database server. |
142 | 142 |
# Default: 30 |
143 | 143 |
#ReceiveTimeout 60 |
144 |
+ |
|
145 |
+# When enabled freshclam will submit statistics to the ClamAV Project about |
|
146 |
+# the latest virus detections in your environment. The ClamAV maintainers |
|
147 |
+# will then use this data to determine what types of malware are the most |
|
148 |
+# detected in the field and in what geographic area they are. |
|
149 |
+# This feature requires LogTime and LogFile to be enabled in clamd.conf. |
|
150 |
+# Default: no |
|
151 |
+#SubmitDetectionStats /path/to/clamd.conf |
... | ... |
@@ -144,6 +144,7 @@ static void help(void) |
144 | 144 |
mprintf(" --on-error-execute=COMMAND execute COMMAND if errors occured\n"); |
145 | 145 |
mprintf(" --on-outdated-execute=COMMAND execute COMMAND when software is outdated\n"); |
146 | 146 |
mprintf(" --list-mirrors print mirrors from mirrors.dat\n"); |
147 |
+ mprintf(" --submit-stats[=/path/clamd.conf] only submit detection statistics\n"); |
|
147 | 148 |
|
148 | 149 |
mprintf("\n"); |
149 | 150 |
} |
... | ... |
@@ -233,6 +234,7 @@ int main(int argc, char **argv) |
233 | 233 |
{"on-error-execute", 1, 0, 0}, |
234 | 234 |
{"on-outdated-execute", 1, 0, 0}, |
235 | 235 |
{"list-mirrors", 0, 0, 0}, |
236 |
+ {"submit-stats", 2, 0, 0}, |
|
236 | 237 |
{0, 0, 0, 0} |
237 | 238 |
}; |
238 | 239 |
|
... | ... |
@@ -526,7 +528,10 @@ int main(int argc, char **argv) |
526 | 526 |
while(!terminate) { |
527 | 527 |
ret = download(copt, opt, newdir, cfgfile); |
528 | 528 |
|
529 |
- if(ret > 1) { |
|
529 |
+ if(ret <= 1) { |
|
530 |
+ if((cpt = cfgopt(copt, "SubmitDetectionStats"))->enabled) |
|
531 |
+ submitstats(cpt->strarg, copt); |
|
532 |
+ } else { |
|
530 | 533 |
if(opt_check(opt, "on-error-execute")) |
531 | 534 |
arg = opt_arg(opt, "on-error-execute"); |
532 | 535 |
else if((cpt = cfgopt(copt, "OnErrorExecute"))->enabled) |
... | ... |
@@ -575,8 +580,19 @@ int main(int argc, char **argv) |
575 | 575 |
#endif |
576 | 576 |
} |
577 | 577 |
|
578 |
- } else |
|
579 |
- ret = download(copt, opt, newdir, cfgfile); |
|
578 |
+ } else { |
|
579 |
+ if(opt_check(opt, "submit-stats")) { |
|
580 |
+ cfgfile = opt_arg(opt, "submit-stats"); |
|
581 |
+ if(!cfgfile) |
|
582 |
+ cfgfile = CONFDIR"/clamd.conf"; |
|
583 |
+ ret = submitstats(cfgfile, copt); |
|
584 |
+ } else { |
|
585 |
+ ret = download(copt, opt, newdir, cfgfile); |
|
586 |
+ |
|
587 |
+ if((cpt = cfgopt(copt, "SubmitDetectionStats"))->enabled) |
|
588 |
+ submitstats(cpt->strarg, copt); |
|
589 |
+ } |
|
590 |
+ } |
|
580 | 591 |
|
581 | 592 |
if(ret > 1) { |
582 | 593 |
if(opt_check(opt, "on-error-execute")) |
... | ... |
@@ -26,6 +26,8 @@ |
26 | 26 |
#include <winsock.h> /* only needed in CL_EXPERIMENTAL */ |
27 | 27 |
#endif |
28 | 28 |
|
29 |
+#define _XOPEN_SOURCE 500 |
|
30 |
+ |
|
29 | 31 |
#if HAVE_CONFIG_H |
30 | 32 |
#include "clamav-config.h" |
31 | 33 |
#endif |
... | ... |
@@ -36,6 +38,7 @@ |
36 | 36 |
#include <unistd.h> |
37 | 37 |
#endif |
38 | 38 |
#include <string.h> |
39 |
+#include <strings.h> |
|
39 | 40 |
#include <ctype.h> |
40 | 41 |
#ifndef C_WINDOWS |
41 | 42 |
#include <netinet/in.h> |
... | ... |
@@ -260,7 +263,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip |
260 | 260 |
return -1; |
261 | 261 |
} |
262 | 262 |
|
263 |
- if((ret = mirman_check(addr, rp->ai_family, mdat, &md))) { |
|
263 |
+ if(mdat && (ret = mirman_check(addr, rp->ai_family, mdat, &md))) { |
|
264 | 264 |
if(ret == 1) |
265 | 265 |
logg("Ignoring mirror %s (due to previous errors)\n", ipaddr); |
266 | 266 |
else |
... | ... |
@@ -271,7 +274,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip |
271 | 271 |
continue; |
272 | 272 |
} |
273 | 273 |
|
274 |
- if(loadbal) { |
|
274 |
+ if(mdat && loadbal) { |
|
275 | 275 |
if(!ret) { |
276 | 276 |
if(!md) { |
277 | 277 |
loadbal_rp = rp; |
... | ... |
@@ -327,11 +330,13 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip |
327 | 327 |
} |
328 | 328 |
continue; |
329 | 329 |
} else { |
330 |
- if(rp->ai_family == AF_INET) |
|
331 |
- mdat->currip[0] = *((uint32_t *) addr); |
|
332 |
- else |
|
333 |
- memcpy(mdat->currip, addr, 4 * sizeof(uint32_t)); |
|
334 |
- mdat->af = rp->ai_family; |
|
330 |
+ if(mdat) { |
|
331 |
+ if(rp->ai_family == AF_INET) |
|
332 |
+ mdat->currip[0] = *((uint32_t *) addr); |
|
333 |
+ else |
|
334 |
+ memcpy(mdat->currip, addr, 4 * sizeof(uint32_t)); |
|
335 |
+ mdat->af = rp->ai_family; |
|
336 |
+ } |
|
335 | 337 |
freeaddrinfo(res); |
336 | 338 |
return socketfd; |
337 | 339 |
} |
... | ... |
@@ -351,7 +356,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip |
351 | 351 |
sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]); |
352 | 352 |
|
353 | 353 |
ips++; |
354 |
- if((ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat, NULL))) { |
|
354 |
+ if(mdat && (ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat, NULL))) { |
|
355 | 355 |
if(ret == 1) |
356 | 356 |
logg("Ignoring mirror %s (due to previous errors)\n", ipaddr); |
357 | 357 |
else |
... | ... |
@@ -384,19 +389,309 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip |
384 | 384 |
closesocket(socketfd); |
385 | 385 |
continue; |
386 | 386 |
} else { |
387 |
- mdat->currip[0] = ((struct in_addr *) ia)->s_addr; |
|
388 |
- mdat->af = AF_INET; |
|
387 |
+ if(mdat) { |
|
388 |
+ mdat->currip[0] = ((struct in_addr *) ia)->s_addr; |
|
389 |
+ mdat->af = AF_INET; |
|
390 |
+ } |
|
389 | 391 |
return socketfd; |
390 | 392 |
} |
391 | 393 |
} |
392 | 394 |
#endif |
393 | 395 |
|
394 |
- if(can_whitelist && ips && (ips == ignored)) |
|
396 |
+ if(mdat && can_whitelist && ips && (ips == ignored)) |
|
395 | 397 |
mirman_whitelist(mdat); |
396 | 398 |
|
397 | 399 |
return -2; |
398 | 400 |
} |
399 | 401 |
|
402 |
+static const char *readbline(int fd, char *buf, int bufsize, int filesize, int *bread) |
|
403 |
+{ |
|
404 |
+ char *pt; |
|
405 |
+ int ret, end; |
|
406 |
+ |
|
407 |
+ if(!*bread) { |
|
408 |
+ if(bufsize < filesize) |
|
409 |
+ lseek(fd, -bufsize, SEEK_END); |
|
410 |
+ *bread = read(fd, buf, bufsize - 1); |
|
411 |
+ if(!*bread || *bread == -1) |
|
412 |
+ return NULL; |
|
413 |
+ buf[*bread] = 0; |
|
414 |
+ } |
|
415 |
+ |
|
416 |
+ pt = strrchr(buf, '\n'); |
|
417 |
+ if(!pt) |
|
418 |
+ return NULL; |
|
419 |
+ *pt = 0; |
|
420 |
+ pt = strrchr(buf, '\n'); |
|
421 |
+ if(pt) { |
|
422 |
+ return ++pt; |
|
423 |
+ } else if(*bread == filesize) { |
|
424 |
+ return buf; |
|
425 |
+ } else { |
|
426 |
+ *bread -= strlen(buf) + 1; |
|
427 |
+ end = filesize - *bread; |
|
428 |
+ if(end < bufsize) { |
|
429 |
+ if((ret = lseek(fd, 0, SEEK_SET)) != -1) |
|
430 |
+ ret = read(fd, buf, end); |
|
431 |
+ } else { |
|
432 |
+ if((ret = lseek(fd, end - bufsize, SEEK_SET)) != -1) |
|
433 |
+ ret = read(fd, buf, bufsize - 1); |
|
434 |
+ } |
|
435 |
+ if(!ret || ret == -1) |
|
436 |
+ return NULL; |
|
437 |
+ buf[ret] = 0; |
|
438 |
+ *bread += ret; |
|
439 |
+ pt = strrchr(buf, '\n'); |
|
440 |
+ if(!pt) |
|
441 |
+ return buf; |
|
442 |
+ *pt = 0; |
|
443 |
+ pt = strrchr(buf, '\n'); |
|
444 |
+ if(pt) |
|
445 |
+ return ++pt; |
|
446 |
+ else if(strlen(buf)) |
|
447 |
+ return buf; |
|
448 |
+ else |
|
449 |
+ return NULL; |
|
450 |
+ } |
|
451 |
+} |
|
452 |
+ |
|
453 |
+/* |
|
454 |
+ * TODO: |
|
455 |
+ * - strptime() is most likely not portable enough |
|
456 |
+ * - proxy support |
|
457 |
+ */ |
|
458 |
+int submitstats(const char *clamdcfg, const struct cfgstruct *copt) |
|
459 |
+{ |
|
460 |
+ int fd, sd, bread, lread = 0, cnt, ret; |
|
461 |
+ char post[SUBMIT_MIN_ENTRIES * 256 + 512]; |
|
462 |
+ char query[SUBMIT_MIN_ENTRIES * 256]; |
|
463 |
+ char buff[512], statsdat[512], newstatsdat[512], uastr[128]; |
|
464 |
+ char logfile[256], fbuff[FILEBUFF]; |
|
465 |
+ char *pt, *pt2; |
|
466 |
+ const char *line; |
|
467 |
+ struct cfgstruct *clamdopt; |
|
468 |
+ const struct cfgstruct *cpt; |
|
469 |
+ struct stat sb; |
|
470 |
+ struct tm tms; |
|
471 |
+ time_t epoch; |
|
472 |
+ unsigned int qcnt, entries, submitted = 0, permfail = 0; |
|
473 |
+ |
|
474 |
+ |
|
475 |
+ if(!(clamdopt = getcfg(clamdcfg, 1))) { |
|
476 |
+ logg("!SubmitDetectionStats: Can't open or parse configuration file %s\n", clamdcfg); |
|
477 |
+ return 56; |
|
478 |
+ } |
|
479 |
+ |
|
480 |
+ if(!(cpt = cfgopt(clamdopt, "LogFile"))->enabled) { |
|
481 |
+ logg("!SubmitDetectionStats: LogFile needs to be enabled in %s\n", clamdcfg); |
|
482 |
+ freecfg(clamdopt); |
|
483 |
+ return 56; |
|
484 |
+ } |
|
485 |
+ strncpy(logfile, cpt->strarg, sizeof(logfile)); |
|
486 |
+ logfile[sizeof(logfile) - 1] = 0; |
|
487 |
+ |
|
488 |
+ if(!cfgopt(clamdopt, "LogTime")->enabled) { |
|
489 |
+ logg("!SubmitDetectionStats: LogTime needs to be enabled in %s\n", clamdcfg); |
|
490 |
+ freecfg(clamdopt); |
|
491 |
+ return 56; |
|
492 |
+ } |
|
493 |
+ freecfg(clamdopt); |
|
494 |
+ |
|
495 |
+ if((fd = open("stats.dat", O_RDONLY)) != -1) { |
|
496 |
+ if((bread = read(fd, statsdat, sizeof(statsdat) - 1)) == -1) { |
|
497 |
+ logg("^SubmitDetectionStats: Can't read stats.dat\n"); |
|
498 |
+ bread = 0; |
|
499 |
+ } |
|
500 |
+ statsdat[bread] = 0; |
|
501 |
+ close(fd); |
|
502 |
+ } else { |
|
503 |
+ *statsdat = 0; |
|
504 |
+ } |
|
505 |
+ |
|
506 |
+ if((fd = open(logfile, O_RDONLY)) == -1) { |
|
507 |
+ logg("!SubmitDetectionStats: Can't open %s for reading\n", logfile); |
|
508 |
+ return 56; |
|
509 |
+ } |
|
510 |
+ |
|
511 |
+ if(fstat(fd, &sb) == -1) { |
|
512 |
+ logg("!SubmitDetectionStats: fstat() failed\n"); |
|
513 |
+ close(fd); |
|
514 |
+ return 56; |
|
515 |
+ } |
|
516 |
+ |
|
517 |
+ while((line = readbline(fd, fbuff, FILEBUFF, sb.st_size, &lread))) |
|
518 |
+ if(strstr(line, "FOUND")) |
|
519 |
+ break; |
|
520 |
+ |
|
521 |
+ if(!line) { |
|
522 |
+ logg("SubmitDetectionStats: No detection records found\n"); |
|
523 |
+ close(fd); |
|
524 |
+ return 1; |
|
525 |
+ } |
|
526 |
+ |
|
527 |
+ if(*statsdat && !strcmp(line, statsdat)) { |
|
528 |
+ logg("SubmitDetectionStats: No new detection records found\n"); |
|
529 |
+ close(fd); |
|
530 |
+ return 1; |
|
531 |
+ } else { |
|
532 |
+ strncpy(newstatsdat, line, sizeof(newstatsdat)); |
|
533 |
+ } |
|
534 |
+ |
|
535 |
+ if((cpt = cfgopt(copt, "HTTPUserAgent"))->enabled) |
|
536 |
+ strncpy(uastr, cpt->strarg, sizeof(uastr)); |
|
537 |
+ else |
|
538 |
+ snprintf(uastr, sizeof(uastr), PACKAGE"/%s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")", get_version()); |
|
539 |
+ uastr[sizeof(uastr) - 1] = 0; |
|
540 |
+ |
|
541 |
+ ret = 0; |
|
542 |
+ memset(query, 0, sizeof(query)); |
|
543 |
+ qcnt = 0; |
|
544 |
+ entries = 0; |
|
545 |
+ do { |
|
546 |
+ if(!strstr(line, " FOUND")) |
|
547 |
+ continue; |
|
548 |
+ |
|
549 |
+ if(*statsdat && !strcmp(line, statsdat)) |
|
550 |
+ break; |
|
551 |
+ |
|
552 |
+ strncpy(buff, line, sizeof(buff)); |
|
553 |
+ buff[sizeof(buff) - 1] = 0; |
|
554 |
+ |
|
555 |
+ if(!(pt = strstr(buff, " -> "))) { |
|
556 |
+ logg("*SubmitDetectionStats: Skipping detection entry logged without time\b"); |
|
557 |
+ continue; |
|
558 |
+ } |
|
559 |
+ *pt = 0; |
|
560 |
+ pt += 4; |
|
561 |
+ |
|
562 |
+ if(!strptime(buff, "%a %b %d %H:%M:%S %Y", &tms) || (epoch = mktime(&tms)) == -1) { |
|
563 |
+ logg("!SubmitDetectionStats: Failed to convert date string\n"); |
|
564 |
+ ret = 1; |
|
565 |
+ break; |
|
566 |
+ } |
|
567 |
+ |
|
568 |
+ pt2 = strstr(pt, " FOUND"); |
|
569 |
+ *pt2 = 0; |
|
570 |
+ |
|
571 |
+ if(!(pt2 = strrchr(pt, ':'))) { |
|
572 |
+ logg("!SubmitDetectionStats: Incorrect format of the log file (1)\n"); |
|
573 |
+ ret = 1; |
|
574 |
+ break; |
|
575 |
+ } |
|
576 |
+ *pt2 = 0; |
|
577 |
+ pt2 += 2; |
|
578 |
+ |
|
579 |
+#ifdef C_WINDOWS |
|
580 |
+ if(!(pt = strrchr(pt, '\\'))) { |
|
581 |
+#else |
|
582 |
+ if(!(pt = strrchr(pt, '/'))) { |
|
583 |
+#endif |
|
584 |
+ logg("!SubmitDetectionStats: Incorrect format of the log file (2)\n"); |
|
585 |
+ ret = 1; |
|
586 |
+ break; |
|
587 |
+ } |
|
588 |
+ *pt++ = 0; |
|
589 |
+ |
|
590 |
+ qcnt += snprintf(&query[qcnt], sizeof(query) - qcnt, "ts[]=%u&fname[]=%s&virus[]=%s&", (unsigned int) epoch, pt, pt2); |
|
591 |
+ entries++; |
|
592 |
+ |
|
593 |
+ if(entries == SUBMIT_MIN_ENTRIES) { |
|
594 |
+ sd = wwwconnect("stats.clamav.net", NULL, 0, NULL, cfgopt(copt, "LocalIPAddress")->strarg, cfgopt(copt, "ConnectTimeout")->numarg, NULL, 0, 0); |
|
595 |
+ if(sd == -1) { |
|
596 |
+ logg("!SubmitDetectionStats: Can't connect to server\n"); |
|
597 |
+ ret = 52; |
|
598 |
+ break; |
|
599 |
+ } |
|
600 |
+ |
|
601 |
+ query[sizeof(query) - 1] = 0; |
|
602 |
+ snprintf(post, sizeof(post), |
|
603 |
+ "POST /submit.php HTTP/1.0\r\n" |
|
604 |
+ "Host: stats.clamav.net\r\n" |
|
605 |
+ "Content-Type: application/x-www-form-urlencoded\r\n" |
|
606 |
+ "User-Agent: %s\r\n" |
|
607 |
+ "Content-Length: %u\r\n\n" |
|
608 |
+ "%s", |
|
609 |
+ uastr, (unsigned int) strlen(query), query); |
|
610 |
+ |
|
611 |
+ if(send(sd, post, strlen(post), 0) < 0) { |
|
612 |
+ logg("!SubmitDetectionStats: Can't write to socket\n"); |
|
613 |
+ ret = 52; |
|
614 |
+ closesocket(sd); |
|
615 |
+ break; |
|
616 |
+ } |
|
617 |
+ |
|
618 |
+ pt = post; |
|
619 |
+ cnt = sizeof(post) - 1; |
|
620 |
+#ifdef SO_ERROR |
|
621 |
+ while((bread = wait_recv(sd, pt, cnt, 0, cfgopt(copt, "ReceiveTimeout")->numarg)) > 0) { |
|
622 |
+#else |
|
623 |
+ while((bread = recv(sd, pt, cnt, 0)) > 0) { |
|
624 |
+#endif |
|
625 |
+ pt += bread; |
|
626 |
+ cnt -= bread; |
|
627 |
+ if(cnt <= 0) |
|
628 |
+ break; |
|
629 |
+ } |
|
630 |
+ *pt = 0; |
|
631 |
+ closesocket(sd); |
|
632 |
+ |
|
633 |
+ if(bread < 0) { |
|
634 |
+ logg("!SubmitDetectionStats: Can't read from socket\n"); |
|
635 |
+ ret = 52; |
|
636 |
+ break; |
|
637 |
+ } |
|
638 |
+ |
|
639 |
+ if(strstr(post, "SUBMIT_OK")) { |
|
640 |
+ submitted += entries; |
|
641 |
+ if(submitted + SUBMIT_MIN_ENTRIES > SUBMIT_MAX_ENTRIES) |
|
642 |
+ break; |
|
643 |
+ qcnt = 0; |
|
644 |
+ entries = 0; |
|
645 |
+ memset(query, 0, sizeof(query)); |
|
646 |
+ continue; |
|
647 |
+ } |
|
648 |
+ |
|
649 |
+ ret = 52; |
|
650 |
+ if(strstr(post, "SUBMIT_PERMANENT_FAILURE")) { |
|
651 |
+ if(!submitted) { |
|
652 |
+ logg("!SubmitDetectionStats: Permanent failure\n"); |
|
653 |
+ permfail = 1; |
|
654 |
+ } |
|
655 |
+ } else if(strstr(post, "SUBMIT_TEMPORARY_FAILURE")) { |
|
656 |
+ if(!submitted) |
|
657 |
+ logg("!SubmitDetectionStats: Temporary failure\n"); |
|
658 |
+ } else { |
|
659 |
+ if(!submitted) |
|
660 |
+ logg("!SubmitDetectionStats: Incorrect answer from server\n"); |
|
661 |
+ } |
|
662 |
+ |
|
663 |
+ break; |
|
664 |
+ } |
|
665 |
+ |
|
666 |
+ } while((line = readbline(fd, fbuff, FILEBUFF, sb.st_size, &lread))); |
|
667 |
+ |
|
668 |
+ close(fd); |
|
669 |
+ |
|
670 |
+ if(submitted || permfail) { |
|
671 |
+ if((fd = open("stats.dat", O_WRONLY)) == -1) { |
|
672 |
+ logg("^SubmitDetectionStats: Can't open stats.dat for writing\n"); |
|
673 |
+ } else { |
|
674 |
+ if((bread = write(fd, newstatsdat, sizeof(newstatsdat))) != sizeof(newstatsdat)) |
|
675 |
+ logg("^SubmitDetectionStats: Can't write to stats.dat\n"); |
|
676 |
+ close(fd); |
|
677 |
+ } |
|
678 |
+ } |
|
679 |
+ |
|
680 |
+ if(ret == 0) { |
|
681 |
+ if(!submitted) |
|
682 |
+ logg("SubmitDetectionStats: Not enough recent data for submission\n"); |
|
683 |
+ else |
|
684 |
+ logg("SubmitDetectionStats: Submitted %u records\n", submitted); |
|
685 |
+ } |
|
686 |
+ |
|
687 |
+ return ret; |
|
688 |
+} |
|
689 |
+ |
|
400 | 690 |
static int Rfc2822DateTime(char *buf, time_t mtime) |
401 | 691 |
{ |
402 | 692 |
struct tm *gmt; |
... | ... |
@@ -20,9 +20,14 @@ |
20 | 20 |
#ifndef __MANAGER_H |
21 | 21 |
#define __MANAGER_H |
22 | 22 |
|
23 |
+#define SUBMIT_MIN_ENTRIES 10 |
|
24 |
+#define SUBMIT_MAX_ENTRIES 50 |
|
25 |
+ |
|
23 | 26 |
#include "shared/cfgparser.h" |
24 | 27 |
#include "shared/options.h" |
25 | 28 |
|
26 | 29 |
int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, const char *hostname, const char *dbdir, int logerr); |
27 | 30 |
|
31 |
+int submitstats(const char *clamdcfg, const struct cfgstruct *copt); |
|
32 |
+ |
|
28 | 33 |
#endif |
... | ... |
@@ -125,6 +125,7 @@ struct cfgoption cfg_options[] = { |
125 | 125 |
{"LocalIPAddress", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
126 | 126 |
{"ConnectTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM}, |
127 | 127 |
{"ReceiveTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM}, |
128 |
+ {"SubmitDetectionStats", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
|
128 | 129 |
|
129 | 130 |
{"DevACOnly", OPT_BOOL, -1, NULL, 0, OPT_CLAMD}, |
130 | 131 |
{"DevACDepth", OPT_NUM, -1, NULL, 0, OPT_CLAMD}, |