diff --git a/clamav-milter/clamav-milter.c b/clamav-milter/clamav-milter.c index b94f9e4fc..7bdad51b1 100644 --- a/clamav-milter/clamav-milter.c +++ b/clamav-milter/clamav-milter.c @@ -48,7 +48,7 @@ struct smfiDesc descr = { "ClamAV", /* filter name */ SMFI_VERSION, /* milter version */ SMFIF_ADDHDRS|SMFIF_ADDRCPT, /* flags */ - NULL, /* connection info filter */ + clamfi_connect, /* connection info filter */ NULL, /* SMTP HELO command filter */ NULL, /* envelope sender filter */ NULL, /* envelope recipient filter */ diff --git a/clamav-milter/clamfi.c b/clamav-milter/clamfi.c index 4bc74de5e..1face531a 100644 --- a/clamav-milter/clamfi.c +++ b/clamav-milter/clamfi.c @@ -104,20 +104,15 @@ sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv) { struct CLAMFI *cf; sfsistat ret; - if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) { - cf = (struct CLAMFI *)malloc(sizeof(*cf)); - if(!cf) { - logg("!Failed to allocate CLAMFI struct\n"); - return SMFIS_TEMPFAIL; - } - cf->totsz = 0; - cf->bufsz = 0; + if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) + return SMFIS_CONTINUE; /* whatever */ + + if(!cf->totsz) { if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) { logg("!Failed to initiate streaming/fdpassing\n"); free(cf); return SMFIS_TEMPFAIL; } - smfi_setpriv(ctx, (void *)cf); if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) return ret; } @@ -206,6 +201,40 @@ sfsistat clamfi_eom(SMFICTX *ctx) { return ret; } + +sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { + struct CLAMFI *cf; + + while(1) { + /* Postfix doesn't seem to honor passing a NULL hostaddr and hostname + set to "localhost" for non-smtp messages (they still appear as SMTP + messages from 127.0.0.1). Here's a small workaround. */ + if(hostaddr) { + if(islocalnet_sock(hostaddr)) { + logg("*Skipping scan for %s (in LocalNet)\n", hostname); + return SMFIS_ACCEPT; + } + break; + } + if(!strcasecmp(hostname, "localhost")) + hostname = NULL; + if(islocalnet_name(hostname)) { + logg("*Skipping scan for %s (in LocalNet)\n", hostname ? hostname : "local"); + return SMFIS_ACCEPT; + } + break; + } + + if(!(cf = (struct CLAMFI *)malloc(sizeof(*cf)))) { + logg("!Failed to allocate CLAMFI struct\n"); + return SMFIS_TEMPFAIL; + } + cf->totsz = 0; + cf->bufsz = 0; + smfi_setpriv(ctx, (void *)cf); + return SMFIS_CONTINUE; +} + /* * Local Variables: * mode: c diff --git a/clamav-milter/clamfi.h b/clamav-milter/clamfi.h index 4f4469254..8be3cf1b3 100644 --- a/clamav-milter/clamfi.h +++ b/clamav-milter/clamfi.h @@ -8,4 +8,5 @@ uint64_t maxfilesize; sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len); sfsistat clamfi_eom(SMFICTX *ctx); sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv); +sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr); #endif diff --git a/clamav-milter/netcode.c b/clamav-milter/netcode.c index ee92d2bfe..93547f80f 100644 --- a/clamav-milter/netcode.c +++ b/clamav-milter/netcode.c @@ -338,10 +338,11 @@ int nc_connect_rand(int *main, int *alt, int *local) { return 0; } + int resolve(char *name, uint32_t *family, uint32_t *host) { struct addrinfo hints, *res; - if(!strcasecmp("local", name)) { + if(!name) { /* l->basehost[0] = l->basehost[1] = l->basehost[2] = l->basehost[3] = 0; DONT BOTHER*/ *family = NON_SMTP; return 0; @@ -430,15 +431,10 @@ struct LOCALNET *localnet(char *name, char *mask) { } -int islocalnet(char *name) { - uint32_t host[4], family; +static int islocalnet(uint32_t family, uint32_t *host) { struct LOCALNET* l = lnet; if(!l) return 0; - if(resolve(name, &family, host)) { - logg("^Cannot resolv %s\n", name); - return 0; - } while(l) { if( (l->family == family) && @@ -450,29 +446,73 @@ int islocalnet(char *name) { return 0; } + +int islocalnet_name(char *name) { + uint32_t host[4], family; + + if(!lnet) return 0; + if(resolve(name, &family, host)) { + logg("^Cannot resolv %s\n", name); + return 0; + } + return islocalnet(family, host); +} + + +int islocalnet_sock(struct sockaddr *sa) { + uint32_t host[4], family; + + if(!lnet) return 0; + + if(sa->sa_family == AF_INET) { + struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; + + family = INET_HOST; + host[0] = htonl(sa4->sin_addr.s_addr); + } else if(sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + unsigned int i, j; + uint32_t u = 0; + + family = INET6_HOST; + for(i=0, j=0; i<16; i++) { + u += (sa6->sin6_addr.s6_addr[i] << (8*j)); + if(++j == 4) { + host[i>>2] = u; + j = u = 0; + } + } + } else return 0; + + return islocalnet(family, host); +} + + void localnets_free(void) { while(lnet) { struct LOCALNET *l = lnet->next; + free(lnet); lnet = l; } } + int localnets_init(struct cfgstruct *copt) { const struct cfgstruct *cpt; if((cpt = cfgopt(copt, "LocalNet"))->enabled) { while(cpt) { - char *lnet = cpt->strarg; + char *lnetname = cpt->strarg; struct LOCALNET *l; - char *mask = strrchr(lnet, '/'); + char *mask = strrchr(lnetname, '/'); if(mask) { *mask='\0'; mask++; } - - if((l = localnet(lnet, mask)) == NULL) { + if(!strcasecmp(lnetname, "local")) lnetname = NULL; + if((l = localnet(lnetname, mask)) == NULL) { localnets_free(); return 1; } diff --git a/clamav-milter/netcode.h b/clamav-milter/netcode.h index 22db1cfc1..5d1468156 100644 --- a/clamav-milter/netcode.h +++ b/clamav-milter/netcode.h @@ -1,6 +1,9 @@ #ifndef _NETCODE_H #define _NETCODE_H +#include +#include + #include "shared/cfgparser.h" #include "connpool.h" @@ -12,7 +15,8 @@ int nc_sendmsg(int s, int fd); int nc_connect_entry(struct CP_ENTRY *cpe); int localnets_init(struct cfgstruct *copt); void localnets_free(void); -int islocalnet(char *name); +int islocalnet_name(char *name); +int islocalnet_sock(struct sockaddr *sa); extern long readtimeout;