git-svn: trunk@2068
Nigel Horne authored on 2006/07/12 00:29:16... | ... |
@@ -1,7 +1,13 @@ |
1 |
+Tue Jul 11 16:26:46 BST 2006 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * clamav-milter: Added -I flag based on an idea by |
|
4 |
+ Dugal James P. <jpd*louisiana.edu> |
|
5 |
+ Added first draft of blacklist support |
|
6 |
+ |
|
1 | 7 |
Mon Jul 10 19:40:59 BST 2006 (njh) |
2 | 8 |
---------------------------------- |
3 | 9 |
* libclamav/mbox.c: Some HTML.Phishing.Bank-566 were not being found, bug |
4 |
- reported by Sven |
|
10 |
+ reported by Sven |
|
5 | 11 |
|
6 | 12 |
Sat Jul 8 20:57:31 BST 2006 (njh) |
7 | 13 |
---------------------------------- |
... | ... |
@@ -23,7 +23,7 @@ |
23 | 23 |
* |
24 | 24 |
* For installation instructions see the file INSTALL that came with this file |
25 | 25 |
*/ |
26 |
-static char const rcsid[] = "$Id: clamav-milter.c,v 1.247 2006/06/21 09:09:59 njh Exp $"; |
|
26 |
+static char const rcsid[] = "$Id: clamav-milter.c,v 1.248 2006/07/11 15:25:26 njh Exp $"; |
|
27 | 27 |
|
28 | 28 |
#define CM_VERSION "devel-210606" |
29 | 29 |
|
... | ... |
@@ -82,6 +82,7 @@ static char const rcsid[] = "$Id: clamav-milter.c,v 1.247 2006/06/21 09:09:59 nj |
82 | 82 |
#include <sys/sendfile.h> /* FIXME: use sendfile on BSD not Linux */ |
83 | 83 |
#include <libintl.h> |
84 | 84 |
#include <locale.h> |
85 |
+#include <resolv.h> |
|
85 | 86 |
|
86 | 87 |
#define gettext_noop(s) s |
87 | 88 |
#define _(s) gettext(s) |
... | ... |
@@ -195,6 +196,7 @@ static const struct cidr_net { |
195 | 195 |
{ PACKADDR( 10, 0, 0, 0), MAKEMASK(24) }, /* 10.0.0.0/24 */ |
196 | 196 |
{ PACKADDR(172, 16, 0, 0), MAKEMASK(20) }, /* 172.16.0.0/20 */ |
197 | 197 |
{ PACKADDR(169, 254, 0, 0), MAKEMASK(16) }, /* 169.254.0.0/16 */ |
198 |
+ { 0, 0 }, /* space to put one more via -I addr */ |
|
198 | 199 |
{ 0, 0 } |
199 | 200 |
}; |
200 | 201 |
|
... | ... |
@@ -205,8 +207,8 @@ struct privdata { |
205 | 205 |
char *from; /* Who sent the message */ |
206 | 206 |
char *subject; /* Original subject */ |
207 | 207 |
char *sender; /* Secretary - often used in mailing lists */ |
208 |
- char *helo; /* The HELO string */ |
|
209 | 208 |
char **to; /* Who is the message going to */ |
209 |
+ char *ip; /* IP address of the other end */ |
|
210 | 210 |
int numTo; /* Number of people the message is going to */ |
211 | 211 |
#ifndef SESSION |
212 | 212 |
int cmdSocket; /* |
... | ... |
@@ -285,6 +287,7 @@ static char clamav_version[VERSION_LENGTH + 1]; |
285 | 285 |
static int fflag = 0; /* force a scan, whatever */ |
286 | 286 |
static int oflag = 0; /* scan messages from our machine? */ |
287 | 287 |
static int lflag = 0; /* scan messages from our site? */ |
288 |
+static int Iflag = 0; /* Added an IP addr to localNets? */ |
|
288 | 289 |
static const char *progname; /* our name - usually clamav-milter */ |
289 | 290 |
|
290 | 291 |
/* Variables for --external */ |
... | ... |
@@ -445,6 +448,10 @@ static const char *whitelistFile; /* |
445 | 445 |
static const char *sendmailCF; /* location of sendmail.cf to verify */ |
446 | 446 |
static const char *pidfile; |
447 | 447 |
|
448 |
+static table_t *blacklist; /* never freed */ |
|
449 |
+static int blacklist_time; /* How long to blacklist an IP */ |
|
450 |
+static pthread_mutex_t blacklist_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
451 |
+ |
|
448 | 452 |
#ifdef CL_DEBUG |
449 | 453 |
#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 |
450 | 454 |
#define HAVE_BACKTRACE |
... | ... |
@@ -464,7 +471,10 @@ static void print_trace(void); |
464 | 464 |
|
465 | 465 |
static int verifyIncomingSocketName(const char *sockName); |
466 | 466 |
static int isWhitelisted(const char *emailaddress); |
467 |
+static int isBlacklisted(const char *ip_address); |
|
467 | 468 |
static void logger(const char *mess); |
469 |
+static void mx(void); |
|
470 |
+static void resolve(const char *host); |
|
468 | 471 |
|
469 | 472 |
short logg_time, logg_lock, logok; |
470 | 473 |
int logg_size; |
... | ... |
@@ -476,6 +486,7 @@ help(void) |
476 | 476 |
puts("\tCopyright (C) 2006 Nigel Horne <njh@clamav.net>\n"); |
477 | 477 |
|
478 | 478 |
puts(_("\t--advisory\t\t-A\tFlag viruses rather than deleting them.")); |
479 |
+ puts(_("\t--blacklist=time\t-k\tTime (in seconds) to blacklist an IP.")); |
|
479 | 480 |
puts(_("\t--bounce\t\t-b\tSend a failure message to the sender.")); |
480 | 481 |
puts(_("\t--broadcast\t\t-B [IFACE]\tBroadcast to a network manager when a virus is found.")); |
481 | 482 |
puts(_("\t--config-file=FILE\t-c FILE\tRead configuration from FILE.")); |
... | ... |
@@ -490,6 +501,7 @@ help(void) |
490 | 490 |
puts(_("\t--force-scan\t\t-f\tForce scan all messages (overrides (-o and -l).")); |
491 | 491 |
puts(_("\t--help\t\t\t-h\tThis message.")); |
492 | 492 |
puts(_("\t--headers\t\t-H\tInclude original message headers in the report.")); |
493 |
+ puts(_("\t--ignore IPaddr\t\t-I IPaddr\tAdd IPaddr to LAN IP list (see --local).")); |
|
493 | 494 |
puts(_("\t--local\t\t\t-l\tScan messages sent from machines on our LAN.")); |
494 | 495 |
puts(_("\t--max-childen\t\t-m\tMaximum number of concurrent scans.")); |
495 | 496 |
puts(_("\t--outgoing\t\t-o\tScan outgoing messages from this machine.")); |
... | ... |
@@ -556,6 +568,7 @@ main(int argc, char **argv) |
556 | 556 |
if(setrlimit(RLIMIT_CORE, &rlim) < 0) |
557 | 557 |
perror("setrlimit"); |
558 | 558 |
#endif |
559 |
+ |
|
559 | 560 |
/* |
560 | 561 |
* Temporarily enter guessed value into version, will |
561 | 562 |
* be overwritten later by the value returned by clamd |
... | ... |
@@ -578,10 +591,12 @@ main(int argc, char **argv) |
578 | 578 |
|
579 | 579 |
for(;;) { |
580 | 580 |
int opt_index = 0; |
581 |
+ struct cidr_net *net; |
|
582 |
+ struct in_addr ignoreIP; |
|
581 | 583 |
#ifdef CL_DEBUG |
582 |
- const char *args = "a:AbB:c:CdDefF:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:x:0:"; |
|
584 |
+ const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:x:0:"; |
|
583 | 585 |
#else |
584 |
- const char *args = "a:AbB:c:CdDefF:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:0:"; |
|
586 |
+ const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:0:"; |
|
585 | 587 |
#endif |
586 | 588 |
|
587 | 589 |
static struct option long_options[] = { |
... | ... |
@@ -628,9 +643,15 @@ main(int argc, char **argv) |
628 | 628 |
"help", 0, NULL, 'h' |
629 | 629 |
}, |
630 | 630 |
{ |
631 |
+ "ignore", 1, NULL, 'I' |
|
632 |
+ }, |
|
633 |
+ { |
|
631 | 634 |
"pidfile", 1, NULL, 'i' |
632 | 635 |
}, |
633 | 636 |
{ |
637 |
+ "blacklist", 1, NULL, 'k' |
|
638 |
+ }, |
|
639 |
+ { |
|
634 | 640 |
"local", 0, NULL, 'l' |
635 | 641 |
}, |
636 | 642 |
{ |
... | ... |
@@ -754,6 +775,32 @@ main(int argc, char **argv) |
754 | 754 |
case 'i': /* pidfile */ |
755 | 755 |
pidfile = optarg; |
756 | 756 |
break; |
757 |
+ case 'k': /* blacklist time */ |
|
758 |
+ blacklist_time = atoi(optarg); |
|
759 |
+ break; |
|
760 |
+ case 'I': /* --ignore, -I hostname */ |
|
761 |
+ /* |
|
762 |
+ * Based on patch by jpd@louisiana.edu |
|
763 |
+ */ |
|
764 |
+ if(Iflag) { |
|
765 |
+ fprintf(stderr, |
|
766 |
+ _("%s: %s, -I may only be given once"), |
|
767 |
+ argv[0], optarg); |
|
768 |
+ return EX_USAGE; |
|
769 |
+ } |
|
770 |
+ if(!inet_aton(optarg, &ignoreIP)) { |
|
771 |
+ fprintf(stderr, |
|
772 |
+ _("%s: Cannot convert -I%s to IPaddr"), |
|
773 |
+ argv[0], optarg); |
|
774 |
+ return EX_USAGE; |
|
775 |
+ } |
|
776 |
+ for(net = (struct cidr_net *)localNets; net->base; net++) |
|
777 |
+ ; |
|
778 |
+ /* TODO: allow netmasks */ |
|
779 |
+ net->base = ntohl(ignoreIP.s_addr); |
|
780 |
+ net->mask = ntohl(0xffffffffU); |
|
781 |
+ Iflag++; |
|
782 |
+ break; |
|
757 | 783 |
case 'l': /* scan mail from the lan */ |
758 | 784 |
lflag++; |
759 | 785 |
break; |
... | ... |
@@ -878,7 +925,7 @@ main(int argc, char **argv) |
878 | 878 |
* Sanity checks on the clamav configuration file |
879 | 879 |
*/ |
880 | 880 |
if(cfgfile == NULL) { |
881 |
- cfgfile = cli_malloc(strlen(CONFDIR) + 12); |
|
881 |
+ cfgfile = cli_malloc(strlen(CONFDIR) + 12); /* leak */ |
|
882 | 882 |
sprintf(cfgfile, "%s/clamd.conf", CONFDIR); |
883 | 883 |
} |
884 | 884 |
if((copt = getcfg(cfgfile, 1)) == NULL) { |
... | ... |
@@ -1639,6 +1686,13 @@ main(int argc, char **argv) |
1639 | 1639 |
#endif |
1640 | 1640 |
} |
1641 | 1641 |
|
1642 |
+ if(blacklist_time) { |
|
1643 |
+ mx(); |
|
1644 |
+ if(blacklist) |
|
1645 |
+ /* We must never blacklist ourself */ |
|
1646 |
+ tableInsert(blacklist, "127.0.0.1", 0); |
|
1647 |
+ } |
|
1648 |
+ |
|
1642 | 1649 |
cli_dbgmsg("Started: %s\n", clamav_version); |
1643 | 1650 |
#ifdef SESSION |
1644 | 1651 |
pthread_mutex_unlock(&version_mutex); |
... | ... |
@@ -1767,19 +1821,26 @@ pingServer(int serverNumber) |
1767 | 1767 |
return 0; |
1768 | 1768 |
} |
1769 | 1769 |
if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { |
1770 |
- /* |
|
1771 |
- * During startup there is a race condition: clamd can |
|
1772 |
- * start and fork, then rc will start clamav-milter |
|
1773 |
- * before clamd has run accept(2), so we fail to |
|
1774 |
- * connect. In case this is the situation here, we wait |
|
1775 |
- * for a couple of seconds and try again. The sync() is |
|
1776 |
- * because during startup the machine won't be doing |
|
1777 |
- * much for most of the time, so we may as well do |
|
1778 |
- * something constructive! |
|
1779 |
- */ |
|
1780 |
- sync(); |
|
1781 |
- sleep(2); |
|
1782 |
- if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { |
|
1770 |
+ int is_connected = 0; |
|
1771 |
+ |
|
1772 |
+ if(errno == ECONNREFUSED) { |
|
1773 |
+ /* |
|
1774 |
+ * During startup there is a race condition: |
|
1775 |
+ * clamd can start and fork, then rc will start |
|
1776 |
+ * clamav-milter before clamd has run accept(2), |
|
1777 |
+ * so we fail to connect. |
|
1778 |
+ * In case this is the situation here, we wait |
|
1779 |
+ * for a couple of seconds and try again. The |
|
1780 |
+ * sync() is because during startup the machine |
|
1781 |
+ * won't be doing much for most of the time, so |
|
1782 |
+ * we may as well do something constructive! |
|
1783 |
+ */ |
|
1784 |
+ sync(); |
|
1785 |
+ sleep(2); |
|
1786 |
+ if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) >= 0) |
|
1787 |
+ is_connected = 1; |
|
1788 |
+ } |
|
1789 |
+ if(!is_connected) { |
|
1783 | 1790 |
char *hostname = cli_strtok(serverHostNames, |
1784 | 1791 |
serverNumber, ":"); |
1785 | 1792 |
|
... | ... |
@@ -1952,6 +2013,14 @@ findServer(void) |
1952 | 1952 |
for(i = 0, server = servers; i < numServers; i++, server++) { |
1953 | 1953 |
int sock; |
1954 | 1954 |
|
1955 |
+ if(((i + j) % numServers) >= numServers) |
|
1956 |
+ /* "can't happen" */ |
|
1957 |
+ if(use_syslog) { |
|
1958 |
+ syslog(LOG_ERR, "FindServer: looking for %d from %d - report to bugs@clamav.net\n", |
|
1959 |
+ (i + j) % numServers, numServers); |
|
1960 |
+ return 0; |
|
1961 |
+ } |
|
1962 |
+ |
|
1955 | 1963 |
server->sin_family = AF_INET; |
1956 | 1964 |
server->sin_port = (in_port_t)htons(tcpSocket); |
1957 | 1965 |
server->sin_addr.s_addr = serverIPs[(i + j) % numServers]; |
... | ... |
@@ -2059,6 +2128,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) |
2059 | 2059 |
char ip[INET_ADDRSTRLEN]; /* IPv4 only */ |
2060 | 2060 |
#endif |
2061 | 2061 |
const char *remoteIP; |
2062 |
+ struct privdata *privdata; |
|
2062 | 2063 |
|
2063 | 2064 |
if(quitting) |
2064 | 2065 |
return cl_error; |
... | ... |
@@ -2224,7 +2294,37 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) |
2224 | 2224 |
return SMFIS_REJECT; |
2225 | 2225 |
} |
2226 | 2226 |
} |
2227 |
- return SMFIS_CONTINUE; |
|
2227 |
+ if(isBlacklisted(remoteIP)) { |
|
2228 |
+ if(use_syslog) |
|
2229 |
+ syslog(LOG_NOTICE, "Rejected email from blacklisted IP %s", |
|
2230 |
+ remoteIP); |
|
2231 |
+ /* |
|
2232 |
+ * TODO: Option to greylist rather than blacklist, by sending |
|
2233 |
+ * a try again code |
|
2234 |
+ */ |
|
2235 |
+ smfi_setreply(ctx, "550", "5.7.1", _("Your IP is blacklisted")); |
|
2236 |
+ broadcast(_("Blacklisted IP detected")); |
|
2237 |
+ return SMFIS_REJECT; |
|
2238 |
+ } |
|
2239 |
+ if(smfi_getpriv(ctx) != NULL) { |
|
2240 |
+ /* More than one MAIL FROM command, "can't happen" */ |
|
2241 |
+ cli_warnmsg("clamfi_connect: called more than once\n"); |
|
2242 |
+ return SMFIS_TEMPFAIL; |
|
2243 |
+ } |
|
2244 |
+ |
|
2245 |
+ privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata)); |
|
2246 |
+ if(privdata == NULL) |
|
2247 |
+ return cl_error; |
|
2248 |
+ |
|
2249 |
+ if(smfi_setpriv(ctx, privdata) == MI_SUCCESS) { |
|
2250 |
+ if(blacklist_time) |
|
2251 |
+ privdata->ip = strdup(remoteIP); |
|
2252 |
+ return SMFIS_CONTINUE; |
|
2253 |
+ } |
|
2254 |
+ |
|
2255 |
+ clamfi_free(privdata); |
|
2256 |
+ |
|
2257 |
+ return cl_error; |
|
2228 | 2258 |
} |
2229 | 2259 |
|
2230 | 2260 |
/* |
... | ... |
@@ -2262,15 +2362,19 @@ clamfi_envfrom(SMFICTX *ctx, char **argv) |
2262 | 2262 |
mailaddr = "<>"; |
2263 | 2263 |
} |
2264 | 2264 |
} |
2265 |
- if(smfi_getpriv(ctx) != NULL) { |
|
2266 |
- /* More than one MAIL FROM command, "can't happen" */ |
|
2267 |
- cli_warnmsg("clamfi_envfrom: called more than once\n"); |
|
2268 |
- return SMFIS_CONTINUE; |
|
2269 |
- } |
|
2265 |
+ privdata = smfi_getpriv(ctx); |
|
2270 | 2266 |
|
2271 |
- privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata)); |
|
2272 |
- if(privdata == NULL) |
|
2273 |
- return cl_error; |
|
2267 |
+ if(privdata == NULL) { |
|
2268 |
+ /* More than one message on this connection */ |
|
2269 |
+ privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata)); |
|
2270 |
+ if(privdata == NULL) |
|
2271 |
+ return cl_error; |
|
2272 |
+ |
|
2273 |
+ if(smfi_setpriv(ctx, privdata) != MI_SUCCESS) { |
|
2274 |
+ free(privdata); |
|
2275 |
+ return cl_error; |
|
2276 |
+ } |
|
2277 |
+ } |
|
2274 | 2278 |
|
2275 | 2279 |
if(max_children > 0) { |
2276 | 2280 |
int rc = 0; |
... | ... |
@@ -2300,9 +2404,12 @@ clamfi_envfrom(SMFICTX *ctx, char **argv) |
2300 | 2300 |
n_children, max_children); |
2301 | 2301 |
|
2302 | 2302 |
if(dont_wait) { |
2303 |
- free(privdata); |
|
2304 | 2303 |
pthread_mutex_unlock(&n_children_mutex); |
2305 | 2304 |
smfi_setreply(ctx, "451", "4.3.2", _("AV system temporarily overloaded - please try later")); |
2305 |
+ if(privdata->ip) |
|
2306 |
+ free(privdata->ip); |
|
2307 |
+ free(privdata); |
|
2308 |
+ smfi_setpriv(ctx, NULL); |
|
2306 | 2309 |
return SMFIS_TEMPFAIL; |
2307 | 2310 |
} |
2308 | 2311 |
/* |
... | ... |
@@ -2371,12 +2478,7 @@ clamfi_envfrom(SMFICTX *ctx, char **argv) |
2371 | 2371 |
if(hflag) |
2372 | 2372 |
privdata->headers = header_list_new(); |
2373 | 2373 |
|
2374 |
- if(smfi_setpriv(ctx, privdata) == MI_SUCCESS) |
|
2375 |
- return SMFIS_CONTINUE; |
|
2376 |
- |
|
2377 |
- clamfi_free(privdata); |
|
2378 |
- |
|
2379 |
- return cl_error; |
|
2374 |
+ return SMFIS_CONTINUE; |
|
2380 | 2375 |
} |
2381 | 2376 |
|
2382 | 2377 |
#ifdef CL_DEBUG |
... | ... |
@@ -2593,7 +2695,7 @@ clamfi_body(SMFICTX *ctx, u_char *bodyp, size_t len) |
2593 | 2593 |
* avoid FP matches in the scanning code, which will speed it up |
2594 | 2594 |
*/ |
2595 | 2595 |
if((len >= 6) && cli_memstr((char *)bodyp, len, "\nFrom ", 6)) { |
2596 |
- const char *ptr = bodyp; |
|
2596 |
+ const char *ptr = (const char *)bodyp; |
|
2597 | 2597 |
int left = len; |
2598 | 2598 |
|
2599 | 2599 |
nbytes = 0; |
... | ... |
@@ -3285,6 +3387,19 @@ clamfi_eom(SMFICTX *ctx) |
3285 | 3285 |
snprintf(reject, sizeof(reject) - 1, _("virus %s detected by ClamAV - http://www.clamav.net"), virusname); |
3286 | 3286 |
smfi_setreply(ctx, (char *)privdata->rejectCode, "5.7.1", reject); |
3287 | 3287 |
broadcast(mess); |
3288 |
+ |
|
3289 |
+ if(privdata->ip) { |
|
3290 |
+ pthread_mutex_lock(&blacklist_mutex); |
|
3291 |
+ /* |
|
3292 |
+ * FIXME: should be able to update here, otherwise we |
|
3293 |
+ * can't reblacklist an entry that has timed out |
|
3294 |
+ */ |
|
3295 |
+ (void)tableInsert(blacklist, privdata->ip, |
|
3296 |
+ (int)time((time_t *)0)); |
|
3297 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
3298 |
+ free(privdata->ip); |
|
3299 |
+ privdata->ip = NULL; |
|
3300 |
+ } |
|
3288 | 3301 |
} else if((strstr(mess, "OK") == NULL) && (strstr(mess, "Empty file") == NULL)) { |
3289 | 3302 |
if(!nflag) |
3290 | 3303 |
smfi_addheader(ctx, "X-Virus-Status", _("Unknown")); |
... | ... |
@@ -3409,6 +3524,11 @@ clamfi_free(struct privdata *privdata) |
3409 | 3409 |
privdata->filename = NULL; |
3410 | 3410 |
} |
3411 | 3411 |
|
3412 |
+ if(privdata->ip) { |
|
3413 |
+ free(privdata->ip); |
|
3414 |
+ privdata->ip = NULL; |
|
3415 |
+ } |
|
3416 |
+ |
|
3412 | 3417 |
if(privdata->from) { |
3413 | 3418 |
#ifdef CL_DEBUG |
3414 | 3419 |
if(debug_level >= 9) |
... | ... |
@@ -5283,7 +5403,7 @@ verifyIncomingSocketName(const char *sockName) |
5283 | 5283 |
static int |
5284 | 5284 |
isWhitelisted(const char *emailaddress) |
5285 | 5285 |
{ |
5286 |
- static table_t *whitelist; |
|
5286 |
+ static table_t *whitelist; /* never freed */ |
|
5287 | 5287 |
|
5288 | 5288 |
cli_dbgmsg("isWhitelisted %s\n", emailaddress); |
5289 | 5289 |
|
... | ... |
@@ -5302,12 +5422,19 @@ isWhitelisted(const char *emailaddress) |
5302 | 5302 |
if(fin == NULL) { |
5303 | 5303 |
perror(whitelistFile); |
5304 | 5304 |
if(use_syslog) |
5305 |
- syslog(LOG_ERR, _("Can't open white-list file %s"), |
|
5305 |
+ syslog(LOG_ERR, _("Can't open whitelist file %s"), |
|
5306 | 5306 |
whitelistFile); |
5307 | 5307 |
return 0; |
5308 | 5308 |
} |
5309 | 5309 |
whitelist = tableCreate(); |
5310 | 5310 |
|
5311 |
+ if(whitelist == NULL) { |
|
5312 |
+ if(use_syslog) |
|
5313 |
+ syslog(LOG_ERR, _("Can't create whitelist table")); |
|
5314 |
+ fclose(fin); |
|
5315 |
+ return 0; |
|
5316 |
+ } |
|
5317 |
+ |
|
5311 | 5318 |
while(fgets(buf, sizeof(buf), fin) != NULL) { |
5312 | 5319 |
/* comment line? */ |
5313 | 5320 |
switch(buf[0]) { |
... | ... |
@@ -5330,6 +5457,64 @@ isWhitelisted(const char *emailaddress) |
5330 | 5330 |
return 0; |
5331 | 5331 |
} |
5332 | 5332 |
|
5333 |
+/* |
|
5334 |
+ * Blacklist IP addresses that send malware. Often in the phishing world, one |
|
5335 |
+ * phish is quickly followed by another. IP addresses are blacklisted for one |
|
5336 |
+ * minute. We can't blacklist for longer since DHCP means we could hit innocent |
|
5337 |
+ * parties, and in theory malware could go through a smart host and affect |
|
5338 |
+ * innocent parties |
|
5339 |
+ * |
|
5340 |
+ * Note that sites which can't be blacklisted will have their timestamp set |
|
5341 |
+ * to 0, since that can never be less than blacklist_time seconds from now |
|
5342 |
+ */ |
|
5343 |
+static int |
|
5344 |
+isBlacklisted(const char *ip_address) |
|
5345 |
+{ |
|
5346 |
+ time_t t, now; |
|
5347 |
+ |
|
5348 |
+ if(blacklist_time == 0) |
|
5349 |
+ /* Blacklisting not being used */ |
|
5350 |
+ return 0; |
|
5351 |
+ |
|
5352 |
+ cli_dbgmsg("isBlacklisted %s\n", ip_address); |
|
5353 |
+ |
|
5354 |
+ if(isLocalAddr(inet_addr(ip_address))) |
|
5355 |
+ return 0; |
|
5356 |
+ |
|
5357 |
+ time(&now); |
|
5358 |
+ |
|
5359 |
+ pthread_mutex_lock(&blacklist_mutex); |
|
5360 |
+ if(blacklist == NULL) { |
|
5361 |
+ blacklist = tableCreate(); |
|
5362 |
+ |
|
5363 |
+ if(blacklist == NULL) { |
|
5364 |
+ if(use_syslog) |
|
5365 |
+ syslog(LOG_ERR, _("Can't create blacklist table")); |
|
5366 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
5367 |
+ return 0; |
|
5368 |
+ } |
|
5369 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
5370 |
+ return 0; |
|
5371 |
+ } |
|
5372 |
+ t = tableFind(blacklist, ip_address); |
|
5373 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
5374 |
+ |
|
5375 |
+ if(t == (time_t)-1) |
|
5376 |
+ /* IP address is not blacklisted */ |
|
5377 |
+ return 0; |
|
5378 |
+ |
|
5379 |
+ if(t == (time_t)0) |
|
5380 |
+ /* IP cannot be blacklisted */ |
|
5381 |
+ return 0; |
|
5382 |
+ |
|
5383 |
+ if((now - t) < blacklist_time) |
|
5384 |
+ /* FIXME: should be able to renew the certificate */ |
|
5385 |
+ return 1; |
|
5386 |
+ |
|
5387 |
+ /* FIXME: should be able to remove the certificate */ |
|
5388 |
+ return 0; |
|
5389 |
+} |
|
5390 |
+ |
|
5333 | 5391 |
static void |
5334 | 5392 |
logger(const char *mess) |
5335 | 5393 |
{ |
... | ... |
@@ -5367,3 +5552,141 @@ logger(const char *mess) |
5367 | 5367 |
fclose(fout); |
5368 | 5368 |
#endif |
5369 | 5369 |
} |
5370 |
+ |
|
5371 |
+/* |
|
5372 |
+ * Determine our MX peers, they must never be blacklisted |
|
5373 |
+ * See RFC1034 for the definition of the record formats |
|
5374 |
+ */ |
|
5375 |
+static void |
|
5376 |
+mx(void) |
|
5377 |
+{ |
|
5378 |
+ const u_char *p, *end; |
|
5379 |
+ char name[MAXHOSTNAMELEN + 1]; |
|
5380 |
+ u_char buf[BUFSIZ]; |
|
5381 |
+ union { |
|
5382 |
+ HEADER h; |
|
5383 |
+ u_char u[PACKETSZ]; |
|
5384 |
+ } q; |
|
5385 |
+ const HEADER *hp; |
|
5386 |
+ int len, i; |
|
5387 |
+ u_short type, pref; |
|
5388 |
+ u_long ttl; |
|
5389 |
+ |
|
5390 |
+ if(gethostname(name, sizeof(name)) < 0) { |
|
5391 |
+ perror("gethostname"); |
|
5392 |
+ return; |
|
5393 |
+ } |
|
5394 |
+ |
|
5395 |
+ if(blacklist == NULL) { |
|
5396 |
+ blacklist = tableCreate(); |
|
5397 |
+ |
|
5398 |
+ if(blacklist == NULL) |
|
5399 |
+ return; |
|
5400 |
+ } |
|
5401 |
+ |
|
5402 |
+ len = res_query(name, C_IN, T_MX, (u_char *)&q, sizeof(q)); |
|
5403 |
+ if(len < 0) |
|
5404 |
+ /* Host has no MX records */ |
|
5405 |
+ return; |
|
5406 |
+ |
|
5407 |
+ if((unsigned int)len > sizeof(q)) |
|
5408 |
+ return; |
|
5409 |
+ |
|
5410 |
+ hp = &(q.h); |
|
5411 |
+ p = q.u + HFIXEDSZ; |
|
5412 |
+ end = q.u + len; |
|
5413 |
+ |
|
5414 |
+ for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ) |
|
5415 |
+ if((len = dn_skipname(p, end)) < 0) |
|
5416 |
+ return; |
|
5417 |
+ |
|
5418 |
+ i = ntohs(hp->ancount); |
|
5419 |
+ |
|
5420 |
+ while((--i >= 0) && (p < end)) { |
|
5421 |
+ long addr; |
|
5422 |
+ |
|
5423 |
+ if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) |
|
5424 |
+ break; |
|
5425 |
+ p += len; |
|
5426 |
+ GETSHORT(type, p); |
|
5427 |
+ p += INT16SZ; |
|
5428 |
+ GETLONG(ttl, p); |
|
5429 |
+ GETSHORT(len, p); |
|
5430 |
+ if(type != T_MX) { |
|
5431 |
+ p += len; |
|
5432 |
+ continue; |
|
5433 |
+ } |
|
5434 |
+ GETSHORT(pref, p); |
|
5435 |
+ if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) |
|
5436 |
+ break; |
|
5437 |
+ p += len; |
|
5438 |
+ addr = inet_addr(buf); |
|
5439 |
+ if(addr != -1L) { |
|
5440 |
+ if(use_syslog) |
|
5441 |
+ syslog(LOG_INFO, "Won't blacklist %s", buf); |
|
5442 |
+ (void)tableInsert(blacklist, buf, 0); |
|
5443 |
+ } else |
|
5444 |
+ resolve(buf); |
|
5445 |
+ } |
|
5446 |
+} |
|
5447 |
+ |
|
5448 |
+static void |
|
5449 |
+resolve(const char *host) |
|
5450 |
+{ |
|
5451 |
+ const u_char *p, *end; |
|
5452 |
+ u_char buf[BUFSIZ]; |
|
5453 |
+ union { |
|
5454 |
+ HEADER h; |
|
5455 |
+ u_char u[PACKETSZ]; |
|
5456 |
+ } q; |
|
5457 |
+ const HEADER *hp; |
|
5458 |
+ int len, i; |
|
5459 |
+ u_short type; |
|
5460 |
+ u_long ttl; |
|
5461 |
+ |
|
5462 |
+ if((host == NULL) || (*host == '\0')) |
|
5463 |
+ return; |
|
5464 |
+ |
|
5465 |
+ len = res_query(host, C_IN, T_A, (u_char *)&q, sizeof(q)); |
|
5466 |
+ if(len < 0) |
|
5467 |
+ /* Host has no A records */ |
|
5468 |
+ return; |
|
5469 |
+ |
|
5470 |
+ if((unsigned int)len > sizeof(q)) |
|
5471 |
+ return; |
|
5472 |
+ |
|
5473 |
+ hp = &(q.h); |
|
5474 |
+ p = q.u + HFIXEDSZ; |
|
5475 |
+ end = q.u + len; |
|
5476 |
+ |
|
5477 |
+ for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ) |
|
5478 |
+ if((len = dn_skipname(p, end)) < 0) |
|
5479 |
+ return; |
|
5480 |
+ |
|
5481 |
+ i = ntohs(hp->ancount); |
|
5482 |
+ |
|
5483 |
+ while((--i >= 0) && (p < end)) { |
|
5484 |
+ struct in_addr addr; |
|
5485 |
+ const char *ip; |
|
5486 |
+ |
|
5487 |
+ if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) |
|
5488 |
+ return; |
|
5489 |
+ p += len; |
|
5490 |
+ GETSHORT(type, p); |
|
5491 |
+ p += INT16SZ; |
|
5492 |
+ GETLONG(ttl, p); |
|
5493 |
+ GETSHORT(len, p); |
|
5494 |
+ if(type != T_A) { |
|
5495 |
+ p += len; |
|
5496 |
+ continue; |
|
5497 |
+ } |
|
5498 |
+ memcpy(&addr, p, sizeof(struct in_addr)); |
|
5499 |
+ p += 4; |
|
5500 |
+ ip = inet_ntoa(addr); |
|
5501 |
+ if(ip) { |
|
5502 |
+ if(use_syslog) |
|
5503 |
+ syslog(LOG_INFO, "Won't blacklist %s", ip); |
|
5504 |
+ (void)tableInsert(blacklist, ip, 0); |
|
5505 |
+ } |
|
5506 |
+ } |
|
5507 |
+} |
... | ... |
@@ -102,6 +102,19 @@ The \-\-external option informs clamav\-milter to use an external program such |
102 | 102 |
as clamd(8) running either on the local server or other server(s) to perform |
103 | 103 |
the scanning. |
104 | 104 |
.TP |
105 |
+\fB\-k, \-\-blacklist-time=time\fR |
|
106 |
+Tells the number in seconds to black list an IP address (IPv4 only). This |
|
107 |
+is especially useful with phishing which often send a number of emails one |
|
108 |
+after the other. |
|
109 |
+.TP |
|
110 |
+Blacklisting speeds up scanning significantly, however it does have drawbacks |
|
111 |
+since it is possible for a site to be incorrectly blacklisted because of DHCP |
|
112 |
+or an unsafe smart-host. |
|
113 |
+To avoid this, blacklisting does not last for ever. The recommended value is |
|
114 |
+60. |
|
115 |
+.TP |
|
116 |
+Machines on the LAN, the local host, and machines that are our MX peers are |
|
117 |
+never blacklisted. |
|
105 | 118 |
\fB-l, \-\-local\fR |
106 | 119 |
Also scan messages sent from LAN. You probably want this especially if |
107 | 120 |
your LAN is populated by machines running Windows or DOS. |
... | ... |
@@ -109,6 +122,7 @@ your LAN is populated by machines running Windows or DOS. |
109 | 109 |
Machines with IP addresses within the ranges 192.168.0.0/16, 10.0.0.0/24, |
110 | 110 |
172.16.0.0/20 and 169.254.0.0/16 are defined as 'local'. Messages from |
111 | 111 |
other machines are always scanned. |
112 |
+An extra IP address may be added with the \-\-ignore option. |
|
112 | 113 |
.TP |
113 | 114 |
\fB-M, \-\-freshclam-monitor\fR |
114 | 115 |
When not running in external mode, this option tells clamav\-milter how |
... | ... |
@@ -207,6 +221,10 @@ Usually clamav\-milter waits until a child dies or the timeout value has been |
207 | 207 |
exceeded, which ever comes first, however with dont-wait enabled, clamav\-milter |
208 | 208 |
will inform the remote SMTP client to retry later. |
209 | 209 |
.TP |
210 |
+\fB\-\-ignore ipAddr\fR |
|
211 |
+\fIipAddr\fR is taken to be an extra IPv4 address which is treated as being on |
|
212 |
+the LAN for the purposes of the \-\-local argument. |
|
213 |
+.TP |
|
210 | 214 |
\fB\-\-template\-file=file \-t file\fR |
211 | 215 |
File points to a file whose contents is sent as the warning message whenever a |
212 | 216 |
virus is intercepted. |