Hi
We are setting up a cluster of clamd-servers which will be load-balanced
by a TCP-loadbalancer in front of the servers.
We want all clamdscan-clients to connect to the load-balancers IP and
the connections to be evenly distributed across the cluster.
Since we use stream-scanning and the clamd STREAM-command responds with
only a port to which clamdscan then tries to connect for sending the
data, this setup means that clamdscan will try to connect to the
selected port on the load-balancer instead of on the selected server..
We want to avoid having to use different port-ranges for the
clamd-servers in the cluster and mapping them on the load-balancer to
the corresponding server, so instead we have created a patch which makes
clamd implement a new command called "NEWSTREAM" to which it responds
with "PORT portnumber ip_of_control_connection" instead of just "PORT
portnumber".
With this patch clamdscan first connects to the load-balancer which
selects a clamd-server to forward the connection to, then use NEWSTREAM
for scanning, and connects directly to the chosen port on the selected
server for sending the stream (since the stream should always go to the
same server as the main clamd-connection). This lets us have the same
clamd-config on all clamd-servers in the cluster (and on all clamdscan
clients as well).
The reason for using a new command instead of just changing STREAM is to
allow old clamdscan-clients to connect to the new clamd without getting
confused by the additional info in the PORT-response, but the patch
could easily be modified to instead change STREAM if you consider that a
better solution.
What do you guys think of this method? Would it be possible to get the
patch included in some future version of clamav (I'm more than happy to
do any changes deemed neccesary for that to happen)?
The patch is attached, and any comments would be greatly appreciated.
Best regards,
Jimmy Mäkelä
diff -ur clamav-0.88.5.orig/clamd/scanner.c clamav-0.88.5/clamd/scanner.c
--- clamav-0.88.5.orig/clamd/scanner.c Sun Mar 26 21:37:19 2006
+++ clamav-0.88.5/clamd/scanner.c Tue Oct 17 12:22:29 2006
@@ -295,15 +295,16 @@
return ret;
}
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_node
*root, const struct cl_limits *limits, int options, const struct cfgstruct
*copt)
+int scanstream(int odesc, unsigned long int *scanned, const struct cl_node
*root, const struct cl_limits *limits, int options, const struct cfgstruct
*copt, int compat)
{
int ret, portscan = CL_DEFAULT_MAXPORTSCAN, sockfd, port = 0, acceptd;
int tmpd, bread, retval, timeout, btread, min_port, max_port;
long int size = 0, maxsize = 0;
+ int namelen = sizeof(struct sockaddr_in);
short bound = 0, rnd_port_first = 1;
const char *virname;
- char buff[FILEBUFF];
- struct sockaddr_in server;
+ char buff[FILEBUFF], ip[16] = { 0 };
+ struct sockaddr_in server, bound_ip;
struct hostent *he;
struct cfgstruct *cpt;
FILE *tmp = NULL;
@@ -380,7 +381,22 @@
return -1;
} else {
listen(sockfd, 1);
- mdprintf(odesc, "PORT %d\n", port);
+
+ if (compat) {
+ mdprintf(odesc, "PORT %d\n", port);
+ } else {
+ if (getsockname(odesc, (struct sockaddr *) &bound_ip, &namelen) !=
-1) {
+ if (inet_ntop(AF_INET, &bound_ip.sin_addr, ip, 16) == NULL) {
+ *ip = 0;
+ }
+ }
+
+ if (*ip != 0) {
+ mdprintf(odesc, "PORT %d %s\n", port, ip);
+ } else {
+ mdprintf(odesc, "PORT %d\n", port, ip);
+ }
+ }
}
switch(retval = poll_fd(sockfd, timeout)) {
diff -ur clamav-0.88.5.orig/clamd/scanner.h clamav-0.88.5/clamd/scanner.h
--- clamav-0.88.5.orig/clamd/scanner.h Thu Jun 23 22:03:05 2005
+++ clamav-0.88.5/clamd/scanner.h Tue Oct 17 12:22:29 2006
@@ -29,6 +29,6 @@
int scanfd(const int fd, unsigned long int *scanned, const struct cl_node
*root, const struct cl_limits *limits, int options, const struct cfgstruct
*copt, int odesc, short contscan);
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_node
*root, const struct cl_limits *limits, int options, const struct cfgstruct
*copt);
+int scanstream(int odesc, unsigned long int *scanned, const struct cl_node
*root, const struct cl_limits *limits, int options, const struct cfgstruct
*copt, int compat);
#endif
diff -ur clamav-0.88.5.orig/clamd/session.c clamav-0.88.5/clamd/session.c
--- clamav-0.88.5.orig/clamd/session.c Sun Oct 30 17:00:52 2005
+++ clamav-0.88.5/clamd/session.c Tue Oct 17 12:22:29 2006
@@ -137,10 +137,13 @@
free(path);
} else if(!strncmp(buff, CMD8, strlen(CMD8))) { /* STREAM */
- if(scanstream(desc, NULL, root, limits, options, copt) == CL_EMEM)
+ if(scanstream(desc, NULL, root, limits, options, copt, 1) == CL_EMEM)
+ if(cfgopt(copt, "ExitOnOOM"))
+ return COMMAND_SHUTDOWN;
+ } else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* NEWSTREAM */
+ if(scanstream(desc, NULL, root, limits, options, copt, 0) == CL_EMEM)
if(cfgopt(copt, "ExitOnOOM"))
return COMMAND_SHUTDOWN;
-
} else if(!strncmp(buff, CMD9, strlen(CMD9))) { /* SESSION */
return COMMAND_SESSION;
diff -ur clamav-0.88.5.orig/clamd/session.h clamav-0.88.5/clamd/session.h
--- clamav-0.88.5.orig/clamd/session.h Sun Oct 30 17:00:43 2005
+++ clamav-0.88.5/clamd/session.h Tue Oct 17 12:22:29 2006
@@ -36,6 +36,7 @@
#define CMD10 "END"
#define CMD11 "SHUTDOWN"
#define CMD12 "FD"
+#define CMD13 "NEWSTREAM"
#include <clamav.h>
#include "cfgparser.h"
diff -ur clamav-0.88.5.orig/clamdscan/client.c clamav-0.88.5/clamdscan/client.c
--- clamav-0.88.5.orig/clamdscan/client.c Thu Apr 20 18:52:19 2006
+++ clamav-0.88.5/clamdscan/client.c Tue Oct 17 12:22:29 2006
@@ -204,10 +204,10 @@
#else
int peer_size;
#endif
- char buff[4096], *pt;
+ char buff[4096], ip[16] = { 0 }, *pt;
- if(write(sockd, "STREAM", 6) <= 0) {
+ if(write(sockd, "NEWSTREAM", 9) <= 0) {
mprintf("@Can't write to the socket.\n");
return 2;
}
@@ -217,7 +217,7 @@
read(sockd, buff, sizeof(buff));
if((pt = strstr(buff, "PORT"))) {
pt += 5;
- sscanf(pt, "%d", &port);
+ sscanf(pt, "%d %15s", &port, &ip);
break;
}
loopw--;
@@ -251,7 +251,9 @@
server.sin_addr.s_addr = inet_addr("127.0.0.1");
break;
case AF_INET:
- server.sin_addr.s_addr = peer.sin_addr.s_addr;
+ if (*ip == 0 || inet_aton(ip, (struct in_addr *) &server.sin_addr)
!= 1) {
+ server.sin_addr.s_addr = peer.sin_addr.s_addr;
+ }
break;
default:
mprintf("@Unexpected socket type: %d.\n", peer.sin_family);
_______________________________________________
http://lurker.clamav.net/list/clamav-devel.html