Browse code

Attempt to handle clamd quick timeout for slow remote sites

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@447 77e5149b-7576-45b1-b177-96237e5ba77b

Nigel Horne authored on 2004/03/28 06:46:03
Showing 3 changed files
... ...
@@ -1,3 +1,8 @@
1
+Sat Mar 27 21:55:33 GMT 2004 (njh)
2
+----------------------------------
3
+  * clamav-milter:	Delay connection to clamd to handle clamd's timeout
4
+	when the remote end (the end talking to sendmail) is slow
5
+
1 6
 Sat Mar 27 19:55:52 CET 2004 (tk)
2 7
 ---------------------------------
3 8
   * freshclam: remove timeout code; clean up return codes
... ...
@@ -293,6 +293,13 @@ Changes
293 293
 0.70b	26/3/04	Display errno information on write failure to clamd
294 294
 		Ensure errno is passed to strerror
295 295
 		Print fd in clamfi_send debug
296
+0.70c	27/3/04	Timestamp clamfi_send messages
297
+		Call cli_warnmsg if ERROR received
298
+		Minor code tidy
299
+		Delay connection to clamd to handle clamd's appetite for timing
300
+		out when the remote end (the end talking to
301
+		sendmail) is slow
302
+		Prefer cli_dbgmsg/cli_warnmsg over printf
296 303
 
297 304
 BUG REPORTS
298 305
 
... ...
@@ -292,9 +292,19 @@
292 292
  *	0.70b	26/3/04	Display errno information on write failure to clamd
293 293
  *			Ensure errno is passed to strerror
294 294
  *			Print fd in clamfi_send debug
295
+ *	0.70c	27/3/04	Timestamp clamfi_send messages
296
+ *			Call cli_warnmsg if ERROR received
297
+ *			Minor code tidy
298
+ *			Delay connection to clamd to handle clamd's appetite
299
+ *			for timing out when the remote end (the end talking to
300
+ *			sendmail) is slow
301
+ *			Prefer cli_dbgmsg/cli_warnmsg over printf
295 302
  *
296 303
  * Change History:
297 304
  * $Log: clamav-milter.c,v $
305
+ * Revision 1.65  2004/03/27 21:44:21  nigelhorne
306
+ * Attempt to handle clamd quick timeout for slow remote sites
307
+ *
298 308
  * Revision 1.64  2004/03/26 11:10:27  nigelhorne
299 309
  * Added debug information
300 310
  *
... ...
@@ -472,9 +482,9 @@
472 472
  * Revision 1.6  2003/09/28 16:37:23  nigelhorne
473 473
  * Added -f flag use MaxThreads if --max-children not set
474 474
  */
475
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.64 2004/03/26 11:10:27 nigelhorne Exp $";
475
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.65 2004/03/27 21:44:21 nigelhorne Exp $";
476 476
 
477
-#define	CM_VERSION	"0.70b"
477
+#define	CM_VERSION	"0.70c"
478 478
 
479 479
 /*#define	CONFDIR	"/usr/local/etc"*/
480 480
 
... ...
@@ -608,6 +618,7 @@ static	header_list_t	header_list_new(void);
608 608
 static	void	header_list_free(header_list_t list);
609 609
 static	void	header_list_add(header_list_t list, const char *headerf, const char *headerv);
610 610
 static	void	header_list_print(header_list_t list, FILE *fp);
611
+static	int	connect2clamd(struct privdata *privdata);
611 612
 static	void	checkClamd(void);
612 613
 
613 614
 static	char	clamav_version[128];
... ...
@@ -1254,6 +1265,7 @@ pingServer(int serverNumber)
1254 1254
 		checkClamd();
1255 1255
 		if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
1256 1256
 			perror(localSocket);
1257
+			close(sock);
1257 1258
 			return 0;
1258 1259
 		}
1259 1260
 	} else {
... ...
@@ -1380,6 +1392,7 @@ findServer(void)
1380 1380
 			if(use_syslog)
1381 1381
 				syslog(LOG_WARNING, "findServer: Check server %d - it may be down", i);
1382 1382
 			socks[i] = -1;
1383
+			close(sock);
1383 1384
 			continue;
1384 1385
 		}
1385 1386
 
... ...
@@ -1430,9 +1443,12 @@ findServer(void)
1430 1430
 	return 0;
1431 1431
 }
1432 1432
 
1433
+/*
1434
+ * Sendmail wants to establish a connection to us
1435
+ */
1433 1436
 static sfsistat
1434 1437
 clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1435
-
1438
+{
1436 1439
 	char ip[INET_ADDRSTRLEN];	/* IPv4 only */
1437 1440
 	char *remoteIP;
1438 1441
 
... ...
@@ -1563,20 +1579,14 @@ static sfsistat
1563 1563
 clamfi_envfrom(SMFICTX *ctx, char **argv)
1564 1564
 {
1565 1565
 	struct privdata *privdata;
1566
-	struct sockaddr_in reply;
1567
-	unsigned short port;
1568
-	int nbytes, rc, freeServer;
1569
-	char buf[64];
1570 1566
 
1571 1567
 	if(logVerbose)
1572 1568
 		syslog(LOG_DEBUG, "clamfi_envfrom: %s", argv[0]);
1573 1569
 
1574
-#ifdef	CL_DEBUG
1575
-	printf("clamfi_envfrom: %s\n", argv[0]);
1576
-#endif
1570
+	cli_dbgmsg("clamfi_envfrom: %s\n", argv[0]);
1577 1571
 
1578 1572
 	if(max_children > 0) {
1579
-		rc = 0;
1573
+		int rc = 0;
1580 1574
 
1581 1575
 		pthread_mutex_lock(&n_children_mutex);
1582 1576
 
... ...
@@ -1614,9 +1624,7 @@ clamfi_envfrom(SMFICTX *ctx, char **argv)
1614 1614
 		}
1615 1615
 		n_children++;
1616 1616
 
1617
-#ifdef	CL_DEBUG
1618
-		printf(">n_children = %d\n", n_children);
1619
-#endif
1617
+		cli_dbgmsg(">n_children = %d\n", n_children);
1620 1618
 		pthread_mutex_unlock(&n_children_mutex);
1621 1619
 
1622 1620
 		if(rc == ETIMEDOUT) {
... ...
@@ -1632,172 +1640,6 @@ clamfi_envfrom(SMFICTX *ctx, char **argv)
1632 1632
 	privdata->dataSocket = -1;	/* 0.4 */
1633 1633
 	privdata->cmdSocket = -1;	/* 0.4 */
1634 1634
 
1635
-	if(quarantine_dir) {
1636
-		/*
1637
-		 * quarantine_dir is specified
1638
-		 * store message in a temporary file
1639
-		 */
1640
-		int ntries = 5;
1641
-
1642
-		privdata->filename = (char *)cli_malloc(strlen(quarantine_dir) + 12);
1643
-
1644
-		do {
1645
-			sprintf(privdata->filename, "%s/msg.XXXXXX", quarantine_dir);
1646
-#if	defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS)
1647
-			privdata->dataSocket = mkstemp(privdata->filename);
1648
-#else
1649
-			if(mktemp(privdata->filename) == NULL) {
1650
-				if(use_syslog)
1651
-					syslog(LOG_ERR, "mktemp %s failed", privdata->filename);
1652
-				clamfi_free(privdata);
1653
-				return cl_error;
1654
-			}
1655
-			privdata->dataSocket = open(privdata->filename, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0600);
1656
-#endif
1657
-		} while((--ntries > 0) && (privdata->dataSocket < 0));
1658
-
1659
-		if(privdata->dataSocket < 0) {
1660
-			if(use_syslog)
1661
-				syslog(LOG_ERR, "tempfile %s creation failed", privdata->filename);
1662
-			clamfi_free(privdata);
1663
-			return cl_error;
1664
-		}
1665
-	} else {
1666
-		/*
1667
-		 * Create socket to talk to clamd. It will tell us the port to use
1668
-		 * to send the data. That will require another socket.
1669
-		 */
1670
-		if(localSocket) {
1671
-			struct sockaddr_un server;
1672
-
1673
-			memset((char *)&server, 0, sizeof(struct sockaddr_un));
1674
-			server.sun_family = AF_UNIX;
1675
-			strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
1676
-
1677
-			if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
1678
-				perror("socket");
1679
-				clamfi_free(privdata);
1680
-				return cl_error;
1681
-			}
1682
-			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
1683
-				perror(localSocket);
1684
-				clamfi_free(privdata);
1685
-				return cl_error;
1686
-			}
1687
-			freeServer = 0;
1688
-		} else {
1689
-			struct sockaddr_in server;
1690
-
1691
-			memset((char *)&server, 0, sizeof(struct sockaddr_in));
1692
-			server.sin_family = AF_INET;
1693
-			server.sin_port = (in_port_t)htons(tcpSocket);
1694
-
1695
-			assert(serverIPs != NULL);
1696
-
1697
-			freeServer = findServer();
1698
-			if(freeServer < 0) {
1699
-				clamfi_free(privdata);
1700
-				return cl_error;
1701
-			}
1702
-
1703
-			server.sin_addr.s_addr = serverIPs[freeServer];
1704
-
1705
-			if((privdata->cmdSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1706
-				perror("socket");
1707
-				clamfi_free(privdata);
1708
-				return cl_error;
1709
-			}
1710
-			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
1711
-				perror("connect");
1712
-				clamfi_free(privdata);
1713
-				return cl_error;
1714
-			}
1715
-		}
1716
-
1717
-		/*
1718
-		 * Create socket that we'll use to send the data to clamd
1719
-		 */
1720
-		if((privdata->dataSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1721
-			perror("socket");
1722
-			clamfi_free(privdata);
1723
-			if(use_syslog)
1724
-				syslog(LOG_ERR, "failed to create socket");
1725
-			return cl_error;
1726
-		}
1727
-
1728
-		shutdown(privdata->dataSocket, SHUT_RD);
1729
-
1730
-		if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
1731
-			perror("send");
1732
-			clamfi_free(privdata);
1733
-			if(use_syslog)
1734
-				syslog(LOG_ERR, "send failed to clamd");
1735
-			return cl_error;
1736
-		}
1737
-
1738
-		shutdown(privdata->cmdSocket, SHUT_WR);
1739
-
1740
-		nbytes = clamd_recv(privdata->cmdSocket, buf, sizeof(buf));
1741
-		if(nbytes < 0) {
1742
-			perror("recv");
1743
-			clamfi_free(privdata);
1744
-			if(use_syslog)
1745
-				syslog(LOG_ERR, "recv failed from clamd getting PORT");
1746
-			return cl_error;
1747
-		}
1748
-		buf[nbytes] = '\0';
1749
-#ifdef	CL_DEBUG
1750
-		if(debug_level >= 4)
1751
-			printf("Received: %s", buf);
1752
-#endif
1753
-		if(sscanf(buf, "PORT %hu\n", &port) != 1) {
1754
-			clamfi_free(privdata);
1755
-			if(use_syslog)
1756
-				syslog(LOG_ERR, "Expected port information from clamd, got '%s'",
1757
-					buf);
1758
-			else
1759
-				fprintf(stderr, "Expected port information from clamd, got '%s'\n",
1760
-					buf);
1761
-			return cl_error;
1762
-		}
1763
-
1764
-		memset((char *)&reply, 0, sizeof(struct sockaddr_in));
1765
-		reply.sin_family = AF_INET;
1766
-		reply.sin_port = (in_port_t)htons(port);
1767
-
1768
-		assert(serverIPs != NULL);
1769
-
1770
-		reply.sin_addr.s_addr = serverIPs[freeServer];
1771
-
1772
-#ifdef	CL_DEBUG
1773
-		if(debug_level >= 4)
1774
-			printf("Connecting to local port %d\n", port);
1775
-#endif
1776
-
1777
-		rc = connect(privdata->dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in));
1778
-
1779
-		if(rc < 0) {
1780
-			perror("connect");
1781
-
1782
-			/* 0.4 - use better error message */
1783
-			if(use_syslog) {
1784
-#ifdef HAVE_STRERROR_R
1785
-				strerror_r(errno, buf, sizeof(buf));
1786
-				syslog(LOG_ERR,
1787
-					"Failed to connect to port %d given by clamd: %s",
1788
-					port, buf);
1789
-#else
1790
-				syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, strerror(errno));
1791
-#endif
1792
-			}
1793
-			clamfi_free(privdata);
1794
-
1795
-			return cl_error;
1796
-		}
1797
-	}
1798
-
1799
-	clamfi_send(privdata, 0, "Received: by clamav-milter\nFrom: %s\n", argv[0]);
1800
-
1801 1635
 	privdata->from = strdup(argv[0]);
1802 1636
 	privdata->to = NULL;
1803 1637
 
... ...
@@ -1819,11 +1661,7 @@ clamfi_envrcpt(SMFICTX *ctx, char **argv)
1819 1819
 	if(logVerbose)
1820 1820
 		syslog(LOG_DEBUG, "clamfi_envrcpt: %s", argv[0]);
1821 1821
 
1822
-#ifdef	CL_DEBUG
1823
-	printf("clamfi_envrcpt: %s\n", argv[0]);
1824
-#endif
1825
-
1826
-	clamfi_send(privdata, 0, "To: %s\n", argv[0]);
1822
+	cli_dbgmsg("clamfi_envrcpt: %s\n", argv[0]);
1827 1823
 
1828 1824
 	if(privdata->to == NULL) {
1829 1825
 		privdata->to = cli_malloc(sizeof(char *) * 2);
... ...
@@ -1847,11 +1685,20 @@ clamfi_header(SMFICTX *ctx, char *headerf, char *headerv)
1847 1847
 		syslog(LOG_DEBUG, "clamfi_header: %s: %s", headerf, headerv);
1848 1848
 #ifdef	CL_DEBUG
1849 1849
 	if(debug_level >= 9)
1850
-		printf("clamfi_header: %s: %s\n", headerf, headerv);
1850
+		cli_dbgmsg("clamfi_header: %s: %s\n", headerf, headerv);
1851 1851
 	else
1852 1852
 		cli_dbgmsg("clamfi_header\n");
1853 1853
 #endif
1854 1854
 
1855
+	if(privdata->dataSocket == -1)
1856
+		/*
1857
+		 * First header - make connection with clamd
1858
+		 */
1859
+		if(!connect2clamd(privdata)) {
1860
+			clamfi_cleanup(ctx);
1861
+			return cl_error;
1862
+		}
1863
+
1855 1864
 	if(clamfi_send(privdata, 0, "%s: %s\n", headerf, headerv) < 0) {
1856 1865
 		clamfi_cleanup(ctx);
1857 1866
 		return cl_error;
... ...
@@ -1872,9 +1719,19 @@ clamfi_eoh(SMFICTX *ctx)
1872 1872
 	if(logVerbose)
1873 1873
 		syslog(LOG_DEBUG, "clamfi_eoh");
1874 1874
 #ifdef	CL_DEBUG
1875
-	cli_dbgmsg("clamfi_eoh\n");
1875
+	if(debug_level >= 4)
1876
+		cli_dbgmsg("clamfi_eoh\n");
1876 1877
 #endif
1877 1878
 
1879
+	if(privdata->dataSocket == -1)
1880
+		/*
1881
+		 * No headers - make connection with clamd
1882
+		 */
1883
+		if(!connect2clamd(privdata)) {
1884
+			clamfi_cleanup(ctx);
1885
+			return cl_error;
1886
+		}
1887
+
1878 1888
 	if(clamfi_send(privdata, 1, "\n") < 0) {
1879 1889
 		clamfi_cleanup(ctx);
1880 1890
 		return cl_error;
... ...
@@ -1932,7 +1789,7 @@ clamfi_body(SMFICTX *ctx, u_char *bodyp, size_t len)
1932 1932
 	if(logVerbose)
1933 1933
 		syslog(LOG_DEBUG, "clamfi_envbody: %u bytes", len);
1934 1934
 #ifdef	CL_DEBUG
1935
-	printf("clamfi_envbody: %u bytes\n", len);
1935
+	cli_dbgmsg("clamfi_envbody: %u bytes\n", len);
1936 1936
 #endif
1937 1937
 
1938 1938
 	if(clamfi_send(privdata, len, (char *)bodyp) < 0) {
... ...
@@ -2022,9 +1879,7 @@ clamfi_eom(SMFICTX *ctx)
2022 2022
 
2023 2023
 		if(logVerbose)
2024 2024
 			syslog(LOG_DEBUG, "clamfi_eom: read %s", mess);
2025
-#ifdef	CL_DEBUG
2026
-		printf("clamfi_eom: read %s\n", mess);
2027
-#endif
2025
+		cli_dbgmsg("clamfi_eom: read %s\n", mess);
2028 2026
 	} else {
2029 2027
 		clamfi_cleanup(ctx);
2030 2028
 		syslog(LOG_NOTICE, "clamfi_eom: read nothing from clamd");
... ...
@@ -2038,8 +1893,12 @@ clamfi_eom(SMFICTX *ctx)
2038 2038
 	privdata->cmdSocket = -1;
2039 2039
 
2040 2040
 	if(strstr(mess, "ERROR") != NULL) {
2041
+
2042
+		ptr = smfi_getsymval(ctx, "i");
2043
+
2044
+		cli_warnmsg("%s: %s\n", ptr, mess);
2041 2045
 		if(use_syslog)
2042
-			syslog(LOG_ERR, "%s: %s\n", smfi_getsymval(ctx, "i"), mess);
2046
+			syslog(LOG_ERR, "%s: %s\n", ptr, mess);
2043 2047
 		clamfi_cleanup(ctx);
2044 2048
 		return cl_error;
2045 2049
 	}
... ...
@@ -2217,7 +2076,7 @@ clamfi_eom(SMFICTX *ctx)
2217 2217
 				if(use_syslog)
2218 2218
 					syslog(LOG_DEBUG, "Can't set quarantine user %s", quarantine);
2219 2219
 				else
2220
-					fprintf(stderr, "Can't set quarantine user %s\n", quarantine);
2220
+					cli_warnmsg("Can't set quarantine user %s\n", quarantine);
2221 2221
 			} else
2222 2222
 				/*
2223 2223
 				 * FIXME: doesn't work if there's no subject
... ...
@@ -2268,7 +2127,7 @@ clamfi_close(SMFICTX *ctx)
2268 2268
 		if(use_syslog)
2269 2269
 			syslog(LOG_DEBUG, "clamfi_close, privdata != NULL");
2270 2270
 		else
2271
-			puts("clamfi_close, privdata != NULL");
2271
+			cli_warnmsg("clamfi_close, privdata != NULL");
2272 2272
 	}
2273 2273
 #endif
2274 2274
 
... ...
@@ -2374,6 +2233,9 @@ clamfi_free(struct privdata *privdata)
2374 2374
 	}
2375 2375
 }
2376 2376
 
2377
+/*
2378
+ * Returns < 0 for failure
2379
+ */
2377 2380
 static int
2378 2381
 clamfi_send(const struct privdata *privdata, size_t len, const char *format, ...)
2379 2382
 {
... ...
@@ -2399,9 +2261,17 @@ clamfi_send(const struct privdata *privdata, size_t len, const char *format, ...
2399 2399
 		ptr = output;
2400 2400
 	}
2401 2401
 #ifdef	CL_DEBUG
2402
-	if(debug_level >= 9)
2403
-		printf("clamfi_send: len=%u bufsiz=%u, fd=%d\n",
2404
-			len, sizeof(output), privdata->dataSocket);
2402
+	if(debug_level >= 9) {
2403
+		time_t t;
2404
+		const struct tm *tm;
2405
+
2406
+		time(&t);
2407
+		tm = localtime(&t);
2408
+
2409
+		cli_dbgmsg("%d:%d:%d clamfi_send: len=%u bufsiz=%u, fd=%d\n",
2410
+			tm->tm_hour, tm->tm_min, tm->tm_sec, len,
2411
+			sizeof(output), privdata->dataSocket);
2412
+	}
2405 2413
 #endif
2406 2414
 
2407 2415
 	while(len > 0) {
... ...
@@ -2579,6 +2449,199 @@ header_list_print(header_list_t list, FILE *fp)
2579 2579
 	for(iter = list->first; iter; iter = iter->next)
2580 2580
 		fprintf(fp, "%s\n", iter->header);
2581 2581
 }
2582
+ 
2583
+/*
2584
+ * Establish a connection to clamd
2585
+ *	Returns success (1) or failure (0)
2586
+ */
2587
+static int
2588
+connect2clamd(struct privdata *privdata)
2589
+{
2590
+	char **to;
2591
+
2592
+	assert(privdata->dataSocket == -1);
2593
+	assert(privdata->from != NULL);
2594
+	assert(privdata->to != NULL);
2595
+
2596
+#ifdef	CL_DEBUG
2597
+	if((debug_level > 0) && use_syslog)
2598
+		syslog(LOG_DEBUG, "connect2clamd");
2599
+	if(debug_level >= 4)
2600
+		cli_dbgmsg("connect2clamd\n");
2601
+#endif
2602
+
2603
+	if(quarantine_dir) {
2604
+		/*
2605
+		 * quarantine_dir is specified
2606
+		 * store message in a temporary file
2607
+		 */
2608
+		int ntries = 5;
2609
+
2610
+		privdata->filename = (char *)cli_malloc(strlen(quarantine_dir) + 12);
2611
+
2612
+		do {
2613
+			sprintf(privdata->filename, "%s/msg.XXXXXX", quarantine_dir);
2614
+#if	defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS)
2615
+			privdata->dataSocket = mkstemp(privdata->filename);
2616
+#else
2617
+			if(mktemp(privdata->filename) == NULL) {
2618
+				if(use_syslog)
2619
+					syslog(LOG_ERR, "mktemp %s failed", privdata->filename);
2620
+				return 0;
2621
+			}
2622
+			privdata->dataSocket = open(privdata->filename, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0600);
2623
+#endif
2624
+		} while((--ntries > 0) && (privdata->dataSocket < 0));
2625
+
2626
+		if(privdata->dataSocket < 0) {
2627
+			if(use_syslog)
2628
+				syslog(LOG_ERR, "tempfile %s creation failed", privdata->filename);
2629
+			return 0;
2630
+		}
2631
+	} else {
2632
+		int freeServer, nbytes;
2633
+		struct sockaddr_in reply;
2634
+		unsigned short port;
2635
+		char buf[64];
2636
+
2637
+		assert(privdata->cmdSocket == -1);
2638
+
2639
+		/*
2640
+		 * Create socket to talk to clamd. It will tell us the port to
2641
+		 * use to send the data. That will require another socket.
2642
+		 */
2643
+		if(localSocket) {
2644
+			struct sockaddr_un server;
2645
+
2646
+			memset((char *)&server, 0, sizeof(struct sockaddr_un));
2647
+			server.sun_family = AF_UNIX;
2648
+			strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
2649
+
2650
+			if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
2651
+				perror("socket");
2652
+				return 0;
2653
+			}
2654
+			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
2655
+				perror(localSocket);
2656
+				return 0;
2657
+			}
2658
+			freeServer = 0;
2659
+		} else {
2660
+			struct sockaddr_in server;
2661
+
2662
+			memset((char *)&server, 0, sizeof(struct sockaddr_in));
2663
+			server.sin_family = AF_INET;
2664
+			server.sin_port = (in_port_t)htons(tcpSocket);
2665
+
2666
+			assert(serverIPs != NULL);
2667
+
2668
+			freeServer = findServer();
2669
+			if(freeServer < 0)
2670
+				return 0;
2671
+
2672
+			server.sin_addr.s_addr = serverIPs[freeServer];
2673
+
2674
+			if((privdata->cmdSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2675
+				perror("socket");
2676
+				return 0;
2677
+			}
2678
+			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
2679
+				perror("connect");
2680
+				return 0;
2681
+			}
2682
+		}
2683
+
2684
+		/*
2685
+		 * Create socket that we'll use to send the data to clamd
2686
+		 */
2687
+		if((privdata->dataSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2688
+			perror("socket");
2689
+			if(use_syslog)
2690
+				syslog(LOG_ERR, "failed to create socket");
2691
+			return 0;
2692
+		}
2693
+
2694
+		shutdown(privdata->dataSocket, SHUT_RD);
2695
+
2696
+		if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
2697
+			perror("send");
2698
+			if(use_syslog)
2699
+				syslog(LOG_ERR, "send failed to clamd");
2700
+			return 0;
2701
+		}
2702
+
2703
+		shutdown(privdata->cmdSocket, SHUT_WR);
2704
+
2705
+		nbytes = clamd_recv(privdata->cmdSocket, buf, sizeof(buf));
2706
+		if(nbytes < 0) {
2707
+			perror("recv");
2708
+			if(use_syslog)
2709
+				syslog(LOG_ERR, "recv failed from clamd getting PORT");
2710
+			return 0;
2711
+		}
2712
+		buf[nbytes] = '\0';
2713
+#ifdef	CL_DEBUG
2714
+		if(debug_level >= 4)
2715
+			cli_dbgmsg("Received: %s", buf);
2716
+#endif
2717
+		if(sscanf(buf, "PORT %hu\n", &port) != 1) {
2718
+			if(use_syslog)
2719
+				syslog(LOG_ERR, "Expected port information from clamd, got '%s'",
2720
+					buf);
2721
+			else
2722
+				cli_warnmsg("Expected port information from clamd, got '%s'\n",
2723
+					buf);
2724
+			return 0;
2725
+		}
2726
+
2727
+		memset((char *)&reply, 0, sizeof(struct sockaddr_in));
2728
+		reply.sin_family = AF_INET;
2729
+		reply.sin_port = (in_port_t)htons(port);
2730
+
2731
+		assert(serverIPs != NULL);
2732
+
2733
+		reply.sin_addr.s_addr = serverIPs[freeServer];
2734
+
2735
+#ifdef	CL_DEBUG
2736
+		if(debug_level >= 4)
2737
+			cli_dbgmsg("Connecting to local port %d\n", port);
2738
+#endif
2739
+
2740
+		if(connect(privdata->dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in)) < 0) {
2741
+			perror("connect");
2742
+
2743
+			/* 0.4 - use better error message */
2744
+			if(use_syslog) {
2745
+#ifdef HAVE_STRERROR_R
2746
+				strerror_r(errno, buf, sizeof(buf));
2747
+				syslog(LOG_ERR,
2748
+					"Failed to connect to port %d given by clamd: %s",
2749
+					port, buf);
2750
+#else
2751
+				syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, strerror(errno));
2752
+#endif
2753
+			}
2754
+			return 0;
2755
+		}
2756
+	}
2757
+
2758
+	/*
2759
+	 * TODO:
2760
+	 *	Put from and to data into a buffer and call clamfi_send once
2761
+	 * to save bandwidth when using TCP/IP to connect with a remote clamd
2762
+	 */
2763
+	clamfi_send(privdata, 0,
2764
+		"Received: by clamav-milter\nFrom: %s\n",
2765
+		privdata->from);
2766
+
2767
+	for(to = privdata->to; *to; to++)
2768
+		if(clamfi_send(privdata, 0, "To: %s\n", *to) < 0)
2769
+			return 0;
2770
+
2771
+	cli_dbgmsg("connect2clamd OK\n");
2772
+
2773
+	return 1;
2774
+}
2582 2775
 
2583 2776
 /*
2584 2777
  * If possible, check if clamd has died, and report if it has