Browse code

Check remote servers in parallel

git-svn: trunk@2207

Nigel Horne authored on 2006/08/25 19:23:51
Showing 2 changed files
... ...
@@ -1,3 +1,11 @@
1
+Fri Aug 25 11:22:24 BST 2006 (njh)
2
+----------------------------------
3
+  * clamav-milter:	Start a separate thread for each load balancing server
4
+				that is being queried
5
+			When not in internal mode, don't send headers to clamd
6
+				that it will discard (cf usefulHeaders() in
7
+				libclamav/mbox.c)
8
+
1 9
 Wed Aug 23 07:54:15 BST 2006 (njh)
2 10
 ----------------------------------
3 11
   * clamav-milter:	--report-phish didn't work with --quarantine-dir
... ...
@@ -23,9 +23,9 @@
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.280 2006/08/23 06:52:53 njh Exp $";
26
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.281 2006/08/25 10:21:54 njh Exp $";
27 27
 
28
-#define	CM_VERSION	"devel-230806"
28
+#define	CM_VERSION	"devel-250806"
29 29
 
30 30
 #if HAVE_CONFIG_H
31 31
 #include "clamav-config.h"
... ...
@@ -252,6 +252,13 @@ struct	privdata {
252 252
 static	int		createSession(unsigned int s);
253 253
 #else
254 254
 static	int		pingServer(int serverNumber);
255
+static	void		*try_server(void *var);
256
+struct	try_server_struct {
257
+	int	sock;
258
+	int	rc;
259
+	struct	sockaddr_in *server;
260
+	int	server_index;
261
+};
255 262
 #endif
256 263
 static	int		findServer(void);
257 264
 static	sfsistat	clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr);
... ...
@@ -520,6 +527,7 @@ static	void	mx(void);
520 520
 static	void	resolve(const char *host);
521 521
 #endif
522 522
 static	sfsistat	black_hole(const struct privdata *privdata);
523
+static	int	useful_header(const char *cmd);
523 524
 
524 525
 extern	short	logg_time, logg_lock, logg_verbose, logg_foreground;
525 526
 extern	int	logg_size;
... ...
@@ -2105,9 +2113,11 @@ static int
2105 2105
 findServer(void)
2106 2106
 {
2107 2107
 	struct sockaddr_in *servers, *server;
2108
-	int *socks, maxsock = -1, i, j;
2108
+	int maxsock, i, j;
2109 2109
 	fd_set rfds;
2110 2110
 	int retval;
2111
+	pthread_t *tids;
2112
+	struct try_server_struct *socks;
2111 2113
 
2112 2114
 	assert(tcpSocket != 0);
2113 2115
 	assert(numServers > 0);
... ...
@@ -2118,9 +2128,7 @@ findServer(void)
2118 2118
 	servers = (struct sockaddr_in *)cli_calloc(numServers, sizeof(struct sockaddr_in));
2119 2119
 	if(servers == NULL)
2120 2120
 		return 0;
2121
-	socks = (int *)cli_malloc(numServers * sizeof(int));
2122
-
2123
-	FD_ZERO(&rfds);
2121
+	socks = (struct try_server_struct *)cli_malloc(numServers * sizeof(struct try_server_struct));
2124 2122
 
2125 2123
 	if(max_children > 0) {
2126 2124
 		assert(n_children > 0);
... ...
@@ -2139,6 +2147,11 @@ findServer(void)
2139 2139
 		 */
2140 2140
 		j = cli_rndnum(numServers);
2141 2141
 
2142
+	tids = cli_malloc(numServers * sizeof(pthread_t));
2143
+
2144
+	for(i = 0; i < numServers; i++)
2145
+		socks[i].sock = -1;
2146
+
2142 2147
 	for(i = 0, server = servers; i < numServers; i++, server++) {
2143 2148
 		int sock;
2144 2149
 		int server_index = (i + j) % numServers;
... ...
@@ -2149,45 +2162,53 @@ findServer(void)
2149 2149
 
2150 2150
 		logg("*findServer: try server %d\n", server_index);
2151 2151
 
2152
-		sock = socks[i] = socket(AF_INET, SOCK_STREAM, 0);
2152
+		sock = socks[i].sock = socket(AF_INET, SOCK_STREAM, 0);
2153 2153
 
2154 2154
 		if(sock < 0) {
2155 2155
 			perror("socket");
2156
-			do
2157
-				if(socks[i] >= 0)
2158
-					close(socks[i]);
2159
-			while(--i >= 0);
2156
+			do {
2157
+				if(socks[i].sock >= 0)
2158
+					close(socks[i].sock);
2159
+				pthread_join(tids[i], NULL);
2160
+			} while(--i >= 0);
2160 2161
 			free(socks);
2161 2162
 			free(servers);
2162 2163
 			return 0;	/* Use the first server on failure */
2163 2164
 		}
2164 2165
 
2165
-		if((connect(sock, (struct sockaddr *)server, sizeof(struct sockaddr)) < 0) ||
2166
-		   (send(sock, "PING\n", 5, 0) < 5)) {
2167
-#ifdef	MAXHOSTNAMELEN
2168
-			char hostname[MAXHOSTNAMELEN + 1];
2166
+		socks[i].server = server;
2167
+		socks[i].server_index = server_index;
2169 2168
 
2170
-			cli_strtokbuf(serverHostNames, server_index, ":", hostname);
2171
-			if(strcmp(hostname, "127.0.0.1") == 0)
2172
-				gethostname(hostname, sizeof(hostname));
2173
-#else
2174
-			char *hostname = cli_strtok(serverHostNames, server_index, ":");
2175
-#endif
2176
-			logg(_("^Check clamd server %s - it may be down\n"), hostname);
2177
-			close(sock);
2178
-#ifndef	MAXHOSTNAMELEN
2179
-			free(hostname);
2180
-#endif
2181
-			broadcast(_("Check clamd server - it may be down\n"));
2182
-			socks[i] = -1;
2183
-			continue;
2169
+		if(pthread_create(&tids[i], NULL, try_server, &socks[i]) != 0) {
2170
+			perror("pthread_create");
2171
+			do {
2172
+				if(socks[i].sock >= 0)
2173
+					close(socks[i].sock);
2174
+				pthread_join(tids[i], NULL);
2175
+			} while(--i >= 0);
2176
+			free(socks);
2177
+			free(servers);
2178
+			return 0;	/* Use the first server on failure */
2184 2179
 		}
2180
+	}
2181
+
2182
+	maxsock = -1;
2183
+	FD_ZERO(&rfds);
2185 2184
 
2186
-		shutdown(sock, SHUT_WR);
2185
+	for(i = 0; i < numServers; i++) {
2186
+		struct try_server_struct *rc;
2187 2187
 
2188
-		FD_SET(sock, &rfds);
2189
-		if(sock > maxsock)
2190
-			maxsock = sock;
2188
+		pthread_join(tids[i], &rc);
2189
+		assert(rc->sock == socks[i].sock);
2190
+		if(rc->rc == 0) {
2191
+			close(rc->sock);
2192
+			socks[i].sock = -1;
2193
+		} else {
2194
+			shutdown(rc->sock, SHUT_WR);
2195
+			FD_SET(rc->sock, &rfds);
2196
+			if(rc->sock > maxsock)
2197
+				maxsock = rc->sock;
2198
+		}
2191 2199
 	}
2192 2200
 
2193 2201
 	free(servers);
... ...
@@ -2208,8 +2229,8 @@ findServer(void)
2208 2208
 		perror("select");
2209 2209
 
2210 2210
 	for(i = 0; i < numServers; i++)
2211
-		if(socks[i] >= 0)
2212
-			close(socks[i]);
2211
+		if(socks[i].sock >= 0)
2212
+			close(socks[i].sock);
2213 2213
 
2214 2214
 	if(retval == 0) {
2215 2215
 		free(socks);
... ...
@@ -2217,13 +2238,12 @@ findServer(void)
2217 2217
 		return 0;
2218 2218
 	} else if(retval < 0) {
2219 2219
 		free(socks);
2220
-		if(use_syslog)
2221
-			syslog(LOG_ERR, _("findServer: select failed"));
2220
+		logg(_("^findServer: select failed (maxsock = %d)\n"), maxsock);
2222 2221
 		return 0;
2223 2222
 	}
2224 2223
 
2225 2224
 	for(i = 0; i < numServers; i++)
2226
-		if((socks[i] >= 0) && (FD_ISSET(socks[i], &rfds))) {
2225
+		if((socks[i].sock >= 0) && (FD_ISSET(socks[i].sock, &rfds))) {
2227 2226
 			const int s = (i + j) % numServers;
2228 2227
 
2229 2228
 			free(socks);
... ...
@@ -2235,6 +2255,49 @@ findServer(void)
2235 2235
 	logg(_("^findServer: No response from any server\n"));
2236 2236
 	return 0;
2237 2237
 }
2238
+
2239
+/*
2240
+ * Connecting to remote servers can take some time, so let's connect to
2241
+ *	them in parallel. This routine is started as a thread
2242
+ */
2243
+static void *
2244
+try_server(void *var)
2245
+{
2246
+	struct try_server_struct *s = (struct try_server_struct *)var;
2247
+	int sock = s->sock;
2248
+	struct sockaddr *server = (struct sockaddr *)s->server;
2249
+	int server_index = s->server_index;
2250
+
2251
+	logg("*try_server: sock %d\n", sock);
2252
+
2253
+	if(connect(sock, server, sizeof(struct sockaddr)) < 0) {
2254
+		perror("connect");
2255
+		s->rc = 0;
2256
+	} else if(send(sock, "PING\n", 5, 0) < 5) {
2257
+		perror("send");
2258
+		s->rc = 0;
2259
+	} else
2260
+		s->rc = 1;
2261
+
2262
+	if(s->rc == 0) {
2263
+#ifdef	MAXHOSTNAMELEN
2264
+		char hostname[MAXHOSTNAMELEN + 1];
2265
+
2266
+		cli_strtokbuf(serverHostNames, server_index, ":", hostname);
2267
+		if(strcmp(hostname, "127.0.0.1") == 0)
2268
+			gethostname(hostname, sizeof(hostname));
2269
+#else
2270
+		char *hostname = cli_strtok(serverHostNames, server_index, ":");
2271
+#endif
2272
+		logg(_("^Check clamd server %s - it may be down\n"), hostname);
2273
+#ifndef	MAXHOSTNAMELEN
2274
+		free(hostname);
2275
+#endif
2276
+		broadcast(_("Check clamd server - it may be down\n"));
2277
+	}
2278
+
2279
+	return var;
2280
+}
2238 2281
 #endif
2239 2282
 
2240 2283
 /*
... ...
@@ -2472,7 +2535,7 @@ clamfi_envfrom(SMFICTX *ctx, char **argv)
2472 2472
 	struct privdata *privdata;
2473 2473
 	const char *mailaddr = argv[0];
2474 2474
 
2475
-	logg("*clamfi_envfrom: %s", argv[0]);
2475
+	logg("*clamfi_envfrom: %s\n", argv[0]);
2476 2476
 
2477 2477
 	if(strcmp(argv[0], "<>") == 0) {
2478 2478
 		mailaddr = smfi_getsymval(ctx, "{mail_addr}");
... ...
@@ -2657,9 +2720,9 @@ clamfi_header(SMFICTX *ctx, char *headerf, char *headerv)
2657 2657
 	if(debug_level >= 9)
2658 2658
 		logg("*clamfi_header: %s: %s\n", headerf, headerv);
2659 2659
 	else
2660
-		logg("*clamfi_header\n");
2660
+		logg("*clamfi_header: %s\n", headerf);
2661 2661
 #else
2662
-	logg("*clamfi_header\n");
2662
+	logg("*clamfi_header: %s\n", headerf);
2663 2663
 #endif
2664 2664
 
2665 2665
 	/*
... ...
@@ -2667,20 +2730,6 @@ clamfi_header(SMFICTX *ctx, char *headerf, char *headerv)
2667 2667
 	 */
2668 2668
 	privdata->rejectCode = "554";
2669 2669
 
2670
-	if(privdata->dataSocket == -1)
2671
-		/*
2672
-		 * First header - make connection with clamd
2673
-		 */
2674
-		if(!connect2clamd(privdata)) {
2675
-			clamfi_cleanup(ctx);
2676
-			return cl_error;
2677
-		}
2678
-
2679
-	if(clamfi_send(privdata, 0, "%s: %s\n", headerf, headerv) <= 0) {
2680
-		clamfi_cleanup(ctx);
2681
-		return cl_error;
2682
-	}
2683
-
2684 2670
 	if(hflag)
2685 2671
 		header_list_add(privdata->headers, headerf, headerv);
2686 2672
 	else if((strcasecmp(headerf, "Received") == 0) &&
... ...
@@ -2708,6 +2757,25 @@ clamfi_header(SMFICTX *ctx, char *headerf, char *headerv)
2708 2708
 			privdata->sender = strdup(headerv);
2709 2709
 	}
2710 2710
 
2711
+	if(!useful_header(headerf)) {
2712
+		logg("*Discarded the header\n");
2713
+		return SMFIS_CONTINUE;
2714
+	}
2715
+
2716
+	if(privdata->dataSocket == -1)
2717
+		/*
2718
+		 * First header - make connection with clamd
2719
+		 */
2720
+		if(!connect2clamd(privdata)) {
2721
+			clamfi_cleanup(ctx);
2722
+			return cl_error;
2723
+		}
2724
+
2725
+	if(clamfi_send(privdata, 0, "%s: %s\n", headerf, headerv) <= 0) {
2726
+		clamfi_cleanup(ctx);
2727
+		return cl_error;
2728
+	}
2729
+
2711 2730
 	return SMFIS_CONTINUE;
2712 2731
 }
2713 2732
 
... ...
@@ -5443,6 +5511,7 @@ verifyIncomingSocketName(const char *sockName)
5443 5443
  * TODO: Allow regular expressions in the addresses
5444 5444
  * TODO: Syntax check the contents of the files
5445 5445
  * TODO: Allow emails of the form "name <address>"
5446
+ * TODO: Allow emails not of the form "<address>"
5446 5447
  * TODO: Assume that if a '@' is missing from the address, that all emails
5447 5448
  *	to that domain are to be whitelisted
5448 5449
  */
... ...
@@ -5793,3 +5862,23 @@ black_hole(const struct privdata *privdata)
5793 5793
 	}
5794 5794
 	return SMFIS_CONTINUE;
5795 5795
 }
5796
+
5797
+/* See also libclamav/mbox.c */
5798
+static int
5799
+useful_header(const char *cmd)
5800
+{
5801
+	if(strcasecmp(cmd, "From") == 0)
5802
+		return 1;
5803
+	if(strcasecmp(cmd, "Received") == 0)
5804
+		return 1;
5805
+	if(strcasecmp(cmd, "Content-Type") == 0)
5806
+		return 1;
5807
+	if(strcasecmp(cmd, "Content-Transfer-Encoding") == 0)
5808
+		return 1;
5809
+	if(strcasecmp(cmd, "Content-Disposition") == 0)
5810
+		return 1;
5811
+	if(strcasecmp(cmd, "De") == 0)
5812
+		return 1;
5813
+
5814
+	return 0;
5815
+}