Hi,

just wrote a small programm to replace SquidClamAV_Redirector.py 
Reason for doing that:
- I manage RPM based servers which don't have pylibclam
  (with my own program I only need one alien rpm not three)
- maybe C is faster as pyhton (not proven yet ;)
- I was in the mood doing that.

nevertheless squidclam should behave like SquidClamAV_Redirector.py
I like SCAVR's technic to save bandwidth and performance.

At the moment the following code is a PoC showing what I'm going to
do. Please have a look at it and post me some comments/opinions.
If this is usefull for some more people I'll think of maintaining
it at sf.net

To compile, you need libcurl and libclamav *surprise* ;)

Make sure you set ERROR and MY_PROXY to something usefull.

in squid just set
 redirect_program /usr/local/bin/squidclam
and an acl
 redirector_access deny localhost
to prevent loops.

for an example ERROR Page have a look at Michael Lang's page. 
http://www.jackal-net.at/tiki-read_article.php?articleId=1

TODO:
- clean infected buffer properly
- kick tmpfile usage out (use big buffer in memory)

Greetings Daniel

/*********************************************************************
 * Squid 2 ClamAV redirector                                         *
 *********************************************************************/

/*********************************************************************
 * ---------+-------------------------------------+--------+-------- *
 *  Version | Changes                             | Datum  | Author  *
 * ---------+-------------------------------------+--------+-------- *
 *   0.1    | Program build                       |11.01.05| me      *
 *          |                                     |        |         *
 * ---------+-------------------------------------+--------+-------- *
 *********************************************************************/

/*********************************************************************
 * Copyright (C) 2005 Daniel Lord (d_lord At gmx DoT de)             *
 *                                                                   *
 * This is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published *
 * by the Free Software Foundation; either version 2 of the License, *
 * or (at your option) any later version.                            *
 *                                                                   *
 * This software is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
 * GNU General Public License for more details.                      *
 *                                                                   *
 * You should have received a copy of the GNU General Public License *
 * along with this software; if not, write to the Free Software      *
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,            *
 * MA  02111-1307, USA.                                              *
 *********************************************************************/

/* some lines are stolen from Tomas Kojms clamav example ex1.c file */
/* credits also go to [EMAIL PROTECTED] for having the
 * great idea to this program */

/* to compile use something like the following */

/* gcc -Wall -s -O2 -march=i586 -mcpu=i586 -L/usr/lib -lcurl \
 * -lcrypto -ldl -lssl -lcrypto -ldl -lz -lbz2 -lgmp -lpthread \
 * -lclamav -o squidclam squidclam.c
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <clamav.h>
#include <curl/curl.h>

#define MAX (10000)            /* url length */
#define LM (MAX+600)           /* squid line */

#define ERROR "http://url.withantivir.com/infected.php";
#define MY_PROXY "http://127.0.0.1:3128";

/* I'd like to maintain a whitelist instead of a blacklist */
#define EXT   "txt "           /* extension to ignore */
#define TRUE  1
#define FALSE 0
#define FSIZE (102400)         /* scan max 100kb */

struct request {
    char line[LM];
    char url[MAX];
    char src[255];
    char ident[255];
    char method[31];
} rq;

/* one bloated main for the moment */
int main (int argc, char *argv[])
{   
    FILE *tf;
    CURL *eh;
    double dsize=0;
    
    int ret=0;
    int ft;
    const char *dbdir;
    const char *virname;
    unsigned long int size = 0;
    
    struct cl_node *root = NULL;
    struct cl_limits limits;

    /* start sysloging */
    openlog("squidclam", LOG_PID, LOG_DAEMON);
    
    /* make stdout line buffered */
    if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) {
        syslog(LOG_ERR, "stdout not line buffered exiting");
        usleep(1000000); /* don't do DoS */
        return 1;
    }

    /* clamav init (load database) */
    dbdir = cl_retdbdir();
    if ((ret=cl_loaddbdir(dbdir, &root, NULL))) {
        syslog(LOG_ERR, "libclamav: %s", cl_strerror(ret));
        usleep(1000000); /* don't do DoS */
        return 1;
    }
    /* build database */
    if((ret = cl_build(root))) {
        syslog(LOG_ERR,"Database initialization error: %s", cl_strerror(ret));
        usleep(1000000); /* don't do DoS */
        return 2;
    }

    /* set up archive limits */
    memset(&limits, 0, sizeof(struct cl_limits));
    limits.maxfiles = 2;              /* max files */
    limits.maxfilesize = 2 * 1048576; /* maximal archived file size == 2 Mb */
    limits.maxreclevel = 2;           /* maximal recursion level */
    limits.maxratio = 100;            /* maximal compression ratio */
    limits.archivememlim = 0;         /* disable memory limit for bzip2 scanner 
*/
    
    /* get a tempfile handle */
    if ((tf=tmpfile()) == NULL) {
        syslog(LOG_ERR,"could not open tempfile()");
        usleep(1000000); /* don't do DoS */
        return 2;
    }

    /* curl init */
    curl_global_init(CURL_GLOBAL_ALL);

    /* get an easy handle */
    eh = curl_easy_init();

    /* set the proxy */
    curl_easy_setopt(eh, CURLOPT_PROXY, MY_PROXY);

    /* set the file curl to write to (tmpfile) */
    curl_easy_setopt(eh, CURLOPT_WRITEDATA, tf);

    /* info that we go up */
    syslog(LOG_INFO,"squidclam starting up");

    /* loop to parse the given URLs */
    while (fgets(rq.line, LM, stdin) != NULL) {
        /* show which url we're handling */
        /* syslog(LOG_INFO,"handle URL (%s)\n", rq.line); */
       
        /* ignore some extensions completly */
        if (strstr(rq.line, EXT) != NULL) {
            /* output clean url */
            putchar('\n');
            continue;
        }
        
        /* get the first part from the URL */
        /* and store it in the tmp buffer */
        sscanf(rq.line, "%10000s %255s %255s %31s", rq.url, rq.src, rq.ident, 
rq.method);
        
        /* set the url to retrive */
        curl_easy_setopt(eh, CURLOPT_URL, rq.url);

        /* only get the head */
        curl_easy_setopt(eh, CURLOPT_NOBODY, TRUE);
        
        /* actually get the header */
        if (curl_easy_perform(eh) != 0) {
            /* no header so just go back to squid */
            putchar('\n');
            rewind(tf);
            continue;
        }
        
        /* get the CONTENT_LENGTH out of the header */
        if (curl_easy_getinfo(eh, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dsize) != 
CURLE_OK) {
            /* not ok --> squid should handle this */
            putchar('\n');
            rewind(tf);
            continue;
        }

        /* file too big --> don't scan */
        if (dsize > FSIZE) {
            putchar('\n');
            rewind(tf);
            continue;
        }
        
    /* now get the complete file (header is there two times but who cares) */
        curl_easy_setopt(eh, CURLOPT_NOBODY, FALSE);

        /* get the file */
        if (curl_easy_perform(eh) != 0) {
            /* if error, give back to squid */
            putchar('\n');
            /* position file handle at the beginning */
            rewind(tf);
            continue;
        }

        /* scan the file with clamav */
        rewind(tf);
        ft = fileno(tf);
        
        /* virus detection */
        if((ret = cl_scandesc(ft, &virname, &size, root, &limits, 
CL_SCAN_STDOPT)) == CL_VIRUS) {
            fprintf(stdout,"%s?url=%s&virus=%s %s %s %s\n", ERROR, rq.url, 
virname, rq.src, rq.ident, rq.method);
            syslog(LOG_WARNING, "url=%s virus=%s", rq.url, virname);
        }
        else {
            /* file was clean */
            putchar('\n');
            if(ret != CL_CLEAN) {
                syslog(LOG_ERR, "%s\n", cl_perror(ret));
            }
        }
        /* (re)position file handle at the beginning */
        rewind(tf);
    }
    
    /* clean up */
    fclose(tf);
    closelog();
    curl_global_cleanup();
    cl_free(root);
    return 0;
}
-- 
"Those who desire to give up Freedom in order to gain Security, 
will not have, nor do they deserve, either one."
       --Thomas Jefferson

_______________________________________________
http://lists.clamav.net/cgi-bin/mailman/listinfo/clamav-users

Reply via email to