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

Reply via email to