git-svn: trunk@4532
aCaB authored on 2008/12/05 01:27:22... | ... |
@@ -51,7 +51,7 @@ struct smfiDesc descr = { |
51 | 51 |
clamfi_connect, /* connection info filter */ |
52 | 52 |
NULL, /* SMTP HELO command filter */ |
53 | 53 |
clamfi_envfrom, /* envelope sender filter */ |
54 |
- NULL, /* envelope recipient filter */ |
|
54 |
+ clamfi_envrcpt, /* envelope recipient filter */ |
|
55 | 55 |
clamfi_header, /* header filter */ |
56 | 56 |
NULL, /* end of header */ |
57 | 57 |
clamfi_body, /* body block */ |
... | ... |
@@ -224,16 +224,10 @@ int main(int argc, char **argv) { |
224 | 224 |
return 1; |
225 | 225 |
} |
226 | 226 |
|
227 |
- /* FIXME: find a place for these: |
|
228 |
- * maxthreads = cfgopt(copt, "MaxThreads")->numarg; |
|
229 |
- */ |
|
230 |
- |
|
231 | 227 |
if(cfgopt(copt, "AddHeader")->enabled) { |
232 | 228 |
char myname[255]; |
233 | 229 |
|
234 | 230 |
if(!gethostname(myname, sizeof(myname))) { |
235 |
- char mydomain[255]; |
|
236 |
- |
|
237 | 231 |
myname[sizeof(myname)-1] = '\0'; |
238 | 232 |
snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname); |
239 | 233 |
xvirushdr[sizeof(xvirushdr)-1] = '\0'; |
... | ... |
@@ -14,6 +14,7 @@ sfsistat clamfi_eom(SMFICTX *ctx); |
14 | 14 |
sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv); |
15 | 15 |
sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr); |
16 | 16 |
sfsistat clamfi_envfrom(SMFICTX *ctx, char **argv); |
17 |
+sfsistat clamfi_envrcpt(SMFICTX *ctx, char **argv); |
|
17 | 18 |
int init_actions(struct cfgstruct *copt); |
18 | 19 |
|
19 | 20 |
#endif |
... | ... |
@@ -28,6 +28,7 @@ |
28 | 28 |
#include <arpa/inet.h> |
29 | 29 |
#include <sys/types.h> |
30 | 30 |
#include <sys/socket.h> |
31 |
+#include <sys/time.h> |
|
31 | 32 |
#include <sys/un.h> |
32 | 33 |
#include <netdb.h> |
33 | 34 |
#include <unistd.h> |
... | ... |
@@ -43,8 +44,16 @@ |
43 | 43 |
#define SETGAI(k, v) {(k)->gai = (void *)(v);} while(0) |
44 | 44 |
#define FREESRV(k) { if((k).gai) freeaddrinfo((k).gai); else if((k).server) free((k).server); } while(0) |
45 | 45 |
|
46 |
-struct CPOOL *cp = NULL; |
|
46 |
+#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) |
|
47 |
+#define _UNUSED_ __attribute__ ((__unused__)) |
|
48 |
+#else |
|
49 |
+#define _UNUSED_ |
|
50 |
+#endif |
|
47 | 51 |
|
52 |
+struct CPOOL *cp = NULL; |
|
53 |
+static pthread_cond_t mon_cond = PTHREAD_COND_INITIALIZER; |
|
54 |
+static int quitting = 1; |
|
55 |
+static pthread_t probe_th; |
|
48 | 56 |
|
49 | 57 |
static int cpool_addunix(char *path) { |
50 | 58 |
struct sockaddr_un *srv; |
... | ... |
@@ -132,15 +141,22 @@ int addslot(void) { |
132 | 132 |
cp->entries++; |
133 | 133 |
return 0; |
134 | 134 |
} |
135 |
- |
|
135 |
+ |
|
136 |
+ |
|
137 |
+/* Probe strategy: |
|
138 |
+- wake up every minute |
|
139 |
+- probe alive if last check > 15 min |
|
140 |
+- probe dead if (last check > 2 min || no clamd available) |
|
141 |
+*/ |
|
136 | 142 |
|
137 | 143 |
void cpool_probe(void) { |
138 | 144 |
unsigned int i, dead=0; |
139 | 145 |
struct CP_ENTRY *cpe = cp->pool; |
140 |
- time_t lastpoll = time(NULL) - 5*60; |
|
146 |
+ time_t now = time(NULL); |
|
141 | 147 |
|
142 | 148 |
for(i=1; i<=cp->entries; i++) { |
143 |
- if(cpe->dead && lastpoll > cpe->last_poll) { |
|
149 |
+ if((cpe->dead && (cpe->last_poll < now - 120 || !cp->alive)) || cpe->last_poll < now - 15*60*60) { |
|
150 |
+ cpe->last_poll = time(NULL); |
|
144 | 151 |
nc_ping_entry(cpe); |
145 | 152 |
logg("*Probe for slot %u returned: %s\n", i, cpe->dead ? "failed" : "success"); |
146 | 153 |
} |
... | ... |
@@ -148,8 +164,29 @@ void cpool_probe(void) { |
148 | 148 |
cpe++; |
149 | 149 |
} |
150 | 150 |
cp->alive = cp->entries - dead; |
151 |
+ |
|
151 | 152 |
if(!cp->alive) |
152 |
- logg("^No clamd server appears to be available, trying again in 5 minutes.\n"); |
|
153 |
+ logg("^No clamd server appears to be available\n"); |
|
154 |
+} |
|
155 |
+ |
|
156 |
+ |
|
157 |
+void *cpool_mon(_UNUSED_ void *v) { |
|
158 |
+ pthread_mutex_t conv; |
|
159 |
+ |
|
160 |
+ pthread_mutex_init(&conv, NULL); |
|
161 |
+ pthread_mutex_lock(&conv); |
|
162 |
+ |
|
163 |
+ while(!quitting) { |
|
164 |
+ struct timespec t; |
|
165 |
+ |
|
166 |
+ cpool_probe(); |
|
167 |
+ t.tv_sec = time(NULL) + 60; |
|
168 |
+ t.tv_nsec = 0; |
|
169 |
+ pthread_cond_timedwait(&mon_cond, &conv, &t); |
|
170 |
+ } |
|
171 |
+ pthread_mutex_unlock(&conv); |
|
172 |
+ pthread_mutex_destroy(&conv); |
|
173 |
+ return NULL; |
|
153 | 174 |
} |
154 | 175 |
|
155 | 176 |
|
... | ... |
@@ -196,13 +233,21 @@ void cpool_init(struct cfgstruct *copt) { |
196 | 196 |
cpool_free(); |
197 | 197 |
return; |
198 | 198 |
} |
199 |
- cpool_probe(); |
|
200 |
- srand(time(NULL)); /* FIXME: naive ? */ |
|
199 |
+ quitting = 0; |
|
200 |
+ pthread_create(&probe_th, NULL, cpool_mon, NULL); |
|
201 |
+ srand(time(NULL)); |
|
201 | 202 |
} |
202 | 203 |
|
203 | 204 |
|
204 | 205 |
void cpool_free(void) { |
205 | 206 |
unsigned int i; |
207 |
+ |
|
208 |
+ if(!quitting) { |
|
209 |
+ logg("*Killing the monitor and stopping\n"); |
|
210 |
+ pthread_cond_signal(&mon_cond); |
|
211 |
+ pthread_join(probe_th, NULL); |
|
212 |
+ } |
|
213 |
+ |
|
206 | 214 |
if(cp) { |
207 | 215 |
if(cp->pool) { |
208 | 216 |
for(i=0; i<cp->entries; i++) |
... | ... |
@@ -228,14 +273,12 @@ struct CP_ENTRY *cpool_get_rand(int *s) { |
228 | 228 |
cpe = cp->local_cpe; |
229 | 229 |
if((*s = nc_connect_entry(cpe)) == -1) { |
230 | 230 |
cpe->dead = 1; |
231 |
- cp->alive--; /* FIXME mutex */ |
|
232 | 231 |
continue; |
233 | 232 |
} |
234 | 233 |
return cpe; |
235 | 234 |
} |
236 | 235 |
} |
237 |
- logg("!No sockets are alive. Probe forced...\n"); |
|
238 |
- /* FIXME: yeah, actually do force smthng here */ |
|
236 |
+ pthread_cond_signal(&mon_cond); |
|
239 | 237 |
return NULL; |
240 | 238 |
} |
241 | 239 |
|
... | ... |
@@ -13,15 +13,13 @@ |
13 | 13 |
#include "shared/cfgparser.h" |
14 | 14 |
|
15 | 15 |
struct CP_ENTRY { |
16 |
+ struct sockaddr *server; |
|
17 |
+ void *gai; |
|
18 |
+ socklen_t socklen; |
|
19 |
+ time_t last_poll; |
|
16 | 20 |
uint8_t type; |
17 | 21 |
uint8_t dead; |
18 | 22 |
uint8_t local; |
19 |
- time_t last_poll; |
|
20 |
- struct sockaddr *server; |
|
21 |
- socklen_t socklen; |
|
22 |
-#ifdef HAVE_GETADDRINFO |
|
23 |
- void *gai; |
|
24 |
-#endif |
|
25 | 23 |
}; |
26 | 24 |
|
27 | 25 |
struct CPOOL { |
... | ... |
@@ -99,7 +99,7 @@ int nc_connect(int s, struct CP_ENTRY *cpe) { |
99 | 99 |
if (!res) return 0; |
100 | 100 |
if (errno != EINPROGRESS) { |
101 | 101 |
strerror_r(errno, er, sizeof(er)); |
102 |
- logg("!connect failed: %s\n", er); |
|
102 |
+ logg("*connect failed: %s\n", er); |
|
103 | 103 |
close(s); |
104 | 104 |
return -1; |
105 | 105 |
} |
... | ... |
@@ -122,12 +122,12 @@ int nc_connect(int s, struct CP_ENTRY *cpe) { |
122 | 122 |
tv.tv_usec = 0; |
123 | 123 |
continue; |
124 | 124 |
} |
125 |
- logg("!Failed to establish a connection to clamd\n"); |
|
125 |
+ logg("*Failed to establish a connection to clamd\n"); |
|
126 | 126 |
close(s); |
127 | 127 |
return -1; |
128 | 128 |
} |
129 | 129 |
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &s_err, &s_len) || s_err) { |
130 |
- logg("!Failed to establish a connection to clamd\n"); |
|
130 |
+ logg("*Failed to establish a connection to clamd\n"); |
|
131 | 131 |
close(s); |
132 | 132 |
return -1; |
133 | 133 |
} |
... | ... |
@@ -219,49 +219,56 @@ int nc_sendmsg(int s, int fd) { |
219 | 219 |
} |
220 | 220 |
|
221 | 221 |
char *nc_recv(int s) { |
222 |
- char buf[BUFSIZ], *ret=NULL; |
|
223 |
- time_t timeout = time(NULL) + readtimeout; |
|
222 |
+ char buf[128], *ret=NULL; |
|
223 |
+ time_t now, timeout = time(NULL) + readtimeout; |
|
224 | 224 |
struct timeval tv; |
225 | 225 |
fd_set fds; |
226 | 226 |
int res; |
227 |
+ unsigned int len = 0; |
|
227 | 228 |
|
228 |
- tv.tv_sec = readtimeout; |
|
229 |
- tv.tv_usec = 0; |
|
230 |
- |
|
231 |
- FD_ZERO(&fds); |
|
232 |
- FD_SET(s, &fds); |
|
233 | 229 |
while(1) { |
230 |
+ now = time(NULL); |
|
231 |
+ if(now >= timeout) { |
|
232 |
+ logg("!Timed out while reading clamd reply\n"); |
|
233 |
+ close(s); |
|
234 |
+ return NULL; |
|
235 |
+ } |
|
236 |
+ tv.tv_sec = timeout - now; |
|
237 |
+ tv.tv_usec = 0; |
|
238 |
+ |
|
239 |
+ FD_ZERO(&fds); |
|
240 |
+ FD_SET(s, &fds); |
|
241 |
+ |
|
234 | 242 |
res = select(s+1, &fds, NULL, NULL, &tv); |
235 | 243 |
if(res<1) { |
236 |
- time_t now; |
|
244 |
+ if (res != -1 || errno != EINTR) |
|
245 |
+ timeout = 0; |
|
246 |
+ continue; |
|
247 |
+ } |
|
237 | 248 |
|
238 |
- if (res == -1 && errno == EINTR && ((now = time(NULL)) < timeout)) { |
|
239 |
- tv.tv_sec = timeout - now; |
|
240 |
- tv.tv_usec = 0; |
|
241 |
- continue; |
|
242 |
- } |
|
243 |
- logg("!Failed to read clamd reply\n"); |
|
249 |
+ res = recv(s, &buf[len], sizeof(buf) - len, 0); |
|
250 |
+ if(res==-1) { |
|
251 |
+ char er[256]; |
|
252 |
+ strerror_r(errno, er, sizeof(er)); |
|
253 |
+ logg("!recv failed after successful select: %s\n", er); |
|
254 |
+ close(s); |
|
255 |
+ return NULL; |
|
256 |
+ } |
|
257 |
+ len += res; |
|
258 |
+ if(len && buf[len-1] == '\n') break; |
|
259 |
+ if(len >= sizeof(buf)) { |
|
260 |
+ logg("!Overlong reply from clamd\n"); |
|
244 | 261 |
close(s); |
245 | 262 |
return NULL; |
246 | 263 |
} |
247 |
- break; |
|
248 |
- } |
|
249 |
- /* FIXME: check for EOL@EObuf ? */ |
|
250 |
- res = recv(s, buf, sizeof(buf), 0); |
|
251 |
- if (res==-1) { |
|
252 |
- char er[256]; |
|
253 |
- strerror_r(errno, er, sizeof(er)); |
|
254 |
- logg("!recv failed after successful select: %s\n", er); |
|
255 |
- close(s); |
|
256 |
- return NULL; |
|
257 | 264 |
} |
258 |
- if(!(ret = (char *)malloc(res+1))) { |
|
259 |
- logg("!malloc(%d) failed\n", res+1); |
|
265 |
+ if(!(ret = (char *)malloc(len+1))) { |
|
266 |
+ logg("!malloc(%d) failed\n", len+1); |
|
260 | 267 |
close(s); |
261 | 268 |
return NULL; |
262 | 269 |
} |
263 |
- memcpy(ret, buf, res); |
|
264 |
- ret[res]='\0'; |
|
270 |
+ memcpy(ret, buf, len); |
|
271 |
+ ret[len]='\0'; |
|
265 | 272 |
return ret; |
266 | 273 |
} |
267 | 274 |
|
... | ... |
@@ -450,7 +457,7 @@ int islocalnet_name(char *name) { |
450 | 450 |
|
451 | 451 |
if(!lnet) return 0; |
452 | 452 |
if(resolve(name, &family, host)) { |
453 |
- logg("^Cannot resolv %s\n", name); |
|
453 |
+ logg("*Cannot resolv %s\n", name); |
|
454 | 454 |
return 0; |
455 | 455 |
} |
456 | 456 |
return islocalnet(family, host); |
... | ... |
@@ -481,7 +488,6 @@ int islocalnet_sock(struct sockaddr *sa) { |
481 | 481 |
} |
482 | 482 |
} |
483 | 483 |
} else return 0; |
484 |
- |
|
485 | 484 |
return islocalnet(family, host); |
486 | 485 |
} |
487 | 486 |
|