1 diff -uNr snort-2.6.0.2/autojunk.sh snort-2.6.0.2.clam/autojunk.sh
2 --- snort-2.6.0.2/autojunk.sh 1970-01-01 01:00:00.000000000 +0100
3 +++ snort-2.6.0.2.clam/autojunk.sh 2006-11-06 08:24:08.000000000 +0100
6 +# the list of commands that need to run before we do a compile
9 +automake --add-missing --copy
12 diff -uNr snort-2.6.0.2/configure.in snort-2.6.0.2.clam/configure.in
13 --- snort-2.6.0.2/configure.in 2006-08-29 21:22:16.000000000 +0200
14 +++ snort-2.6.0.2.clam/configure.in 2006-11-06 08:24:08.000000000 +0100
15 @@ -1033,6 +1033,59 @@
19 +AC_ARG_ENABLE(clamav,
20 +[ --enable-clamav Enable the clamav preprocessor],
21 + enable_clamav="$enableval", enable_clamav="no")
22 +if test "$enable_clamav" = "yes"; then
23 + CFLAGS="$CFLAGS -DCLAMAV"
25 + AC_ARG_WITH(clamav_includes,
26 + [ --with-clamav-includes=DIR clamav include directory],
27 + [with_clamav_includes="$withval"],[with_clamav_includes=no])
29 + AC_ARG_WITH(clamav_defdir,
30 + [ --with-clamav-defdir=DIR clamav virusdefinitions directory],
31 + [with_clamav_defdir="$withval"],[with_clamav_defdir=no])
34 + if test "$with_clamav_defdir" != "no"; then
35 + echo "Virusdefs: $with_clamav_defdir"
36 + CFLAGS="$CFLAGS -DCLAMAV_DEFDIR=\"$with_clamav_defdir\""
39 + if test "$with_clamav_includes" != "no"; then
40 + CPPFLAGS="${CPPFLAGS} -I${with_clamav_includes}"
44 + AC_CHECK_HEADERS(clamav.h,, LCLAM="no")
45 + if test "$LCLAM" = "no"; then
47 + echo " ERROR! clamav.h header not found, go get it from"
48 + echo " http://www.clamav.net/ or use the --with-clamav-includes"
49 + echo " options, if you have it installed in an unusual place"
54 + AC_CHECK_LIB(clamav,cl_scanbuff,, LCLAM="no")
55 + if test "$LCLAM" = "no"; then
57 + echo " ERROR! libclamav library not found, go get it from"
58 + echo " http://www.clamav.net/ or make sure that the place"
59 + echo " you installed it is in the library path."
63 + # in 0.80 cl_buildtrie is renamed to cl_build
65 + AC_CHECK_LIB(clamav, cl_build,, LCLAM="no")
66 + if test "$LCLAM" != "no"; then
67 + CFLAGS="$CFLAGS -DCLAMAV_HAVE_CL_BUILD"
70 + LIBS="${LIBS} -lclamav"
73 # let's make some fixes..
75 diff -uNr snort-2.6.0.2/doc/README.clamav snort-2.6.0.2.clam/doc/README.clamav
76 --- snort-2.6.0.2/doc/README.clamav 1970-01-01 01:00:00.000000000 +0100
77 +++ snort-2.6.0.2.clam/doc/README.clamav 2006-11-06 08:24:08.000000000 +0100
81 +- Please note that detection depends on ClamAV. If clam doesn't know a virus, it will not be detected. So keep your defs up-to-date.
82 +- Archives are not scanned, unless so small that it fits in one packet/uber-packet.
83 +- OLE2 virusses are not detected.
84 +- Attachments to email that are in some way encoded are not scanned.
85 +- As the clam guy's make there detection more specific it is harder for us to detect viri in on the fly packets. Much work needs to be done to create application layer decoders - i.e. strip out actual packet payload and remove things such as http headers from packets.
86 +- turn on clamav by going into snort_inline.conf
87 +- If you don't configure an action and we detect a vrius, the virus is logged and detection is disabled for the rest of snort, and we flush the stream containing the packet in stream4. We have to do this due to logging restrictions and stream4 reassembly.
91 +This turns on the defaults for clamav which are to listen on ports 21 25 80 81 110 119 139 445 143
92 +uses the default database location of /var/lib/clamav unless another dbdir was specified at ./configure
93 +Alerts are written to alert logs no packets are rejected or dropped.
97 +preprocessor clamav: ports {portlist separated by " "}, {flow can be toclientonly or toserveronly or defaults to both} {action can be action-drop or action-reset otherwise default to writing to alert file},{dbdir},{dbreload-time time in seconds to refresh the read of the AV signatures}, {tmpdir for fd mode}
101 +preprocessor clamav: ports all !25 !443 !22, action-reset
104 +will turn on clamav will listen for virus activity on all ports except 25 443 22 and send a reset and drop the packet if a virus is detected.
107 +preprocessor clamav: ports 139 445 21, toclientonly, action-drop, dbdir /var/lib2/clamav
109 +will turn on clamav, will listen for virus activity on ports 129 445 21 will only watch traffic that flows to the client, will drop the packet, sets the virus-sig database path to /var/lib2/clamav
111 +to scan uberpackets from stream4 reassembly make sure that stream4 is initialized before ClamAV in your snort_inline.conf
113 diff -uNr snort-2.6.0.2/src/generators.h snort-2.6.0.2.clam/src/generators.h
114 --- snort-2.6.0.2/src/generators.h 2006-08-29 18:59:37.000000000 +0200
115 +++ snort-2.6.0.2.clam/src/generators.h 2006-11-06 08:24:08.000000000 +0100
118 #define GENERATOR_DNS 131
120 +#define GENERATOR_SPP_CLAMAV 132
121 +#define CLAMAV_VIRUSFOUND 1
123 /* This is where all the alert messages will be archived for each
128 #define PSNG_OPEN_PORT_STR "(portscan) Open Port"
130 +#define CLAMAV_VIRUSFOUND_STR "(spp_clamav) Virus Found:"
132 #endif /* __GENERATORS_H__ */
133 diff -uNr snort-2.6.0.2/src/plugbase.c snort-2.6.0.2.clam/src/plugbase.c
134 --- snort-2.6.0.2/src/plugbase.c 2006-02-20 20:02:35.000000000 +0100
135 +++ snort-2.6.0.2.clam/src/plugbase.c 2006-11-06 08:24:08.000000000 +0100
137 #include "preprocessors/spp_sfportscan.h"
138 #include "preprocessors/spp_frag3.h"
141 +#include "preprocessors/spp_clamav.h"
144 /* built-in detection plugins */
145 #include "detection-plugins/sp_pattern_match.h"
146 #include "detection-plugins/sp_tcp_flag_check.h"
156 void CheckPreprocessorsConfig()
157 diff -uNr snort-2.6.0.2/src/preprocessors/Makefile.am snort-2.6.0.2.clam/src/preprocessors/Makefile.am
158 --- snort-2.6.0.2/src/preprocessors/Makefile.am 2006-02-03 15:11:46.000000000 +0100
159 +++ snort-2.6.0.2.clam/src/preprocessors/Makefile.am 2006-11-06 08:24:08.000000000 +0100
161 spp_frag2.c spp_frag2.h \
162 spp_frag3.c spp_frag3.h \
163 str_search.c str_search.h \
164 -stream_api.c stream_api.h
165 +stream_api.c stream_api.h \
166 +spp_clamav.c spp_clamav.h
169 INCLUDES = @INCLUDES@
170 diff -uNr snort-2.6.0.2/src/preprocessors/spp_clamav.c snort-2.6.0.2.clam/src/preprocessors/spp_clamav.c
171 --- snort-2.6.0.2/src/preprocessors/spp_clamav.c 1970-01-01 01:00:00.000000000 +0100
172 +++ snort-2.6.0.2.clam/src/preprocessors/spp_clamav.c 2006-11-06 08:53:57.000000000 +0100
175 +/* Snort Preprocessor for Antivirus Checking with ClamAV */
178 +** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
179 +** Copyright (C) 2003 Sourcefire, Inc.
180 +** Copyright (C) 2004 William Metcalf <William_Metcalf@kcmo.org> and
181 +** Victor Julien <victor@nk.nl>
183 +** This program is free software; you can redistribute it and/or modify
184 +** it under the terms of the GNU General Public License as published by
185 +** the Free Software Foundation; either version 2 of the License, or
186 +** (at your option) any later version.
188 +** This program is distributed in the hope that it will be useful,
189 +** but WITHOUT ANY WARRANTY; without even the implied warranty of
190 +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
191 +** GNU General Public License for more details.
193 +** You should have received a copy of the GNU General Public License
194 +** along with this program; if not, write to the Free Software
195 +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
202 + * Purpose: Sends packet p to ClamAV for Antivirus checking.
206 + * Effect: Who needs virus.rules??? :-)
213 + * - are the defaultports in ParseClamAVArgs ok?
214 + * - options structure like s4data in Stream4 for cl_root, VirusScanPorts, drop/reject/alert, defs dirlocation **IN PROGRESS**
215 + * - maybe more protocol specific support for less false negatives?
220 + * 2004/11/10: added code for the automatic reloading of the virusdefs
221 + * added support for ClamAV 0.80
222 + * 2006/02/03: added check for http traffic so we better handle http downloads
223 + * removed cl_scanbuf since it was broken anyway
224 + * cleanups and comments added.
225 + * added 8080 to the default ports
228 +#ifdef HAVE_CONFIG_H
234 + #define INLINE inline
243 +// enable if this is included in the Snort_inline project as opposed to normal Snort
244 +//#define SNORTINLINE_SF_NET
245 +#ifdef SNORTINLINE_SF_NET
249 +#include <sys/types.h>
252 +#include <rpc/types.h>
254 +#include "generators.h"
255 +#include "event_wrapper.h"
257 +#include "plugbase.h"
261 +#include "mstring.h"
263 +#include "spp_clamav.h"
264 +#include "stream_api.h"
265 +#include "preprocessors/spp_stream4.h"
268 +#include "preprocessors/spp_stickydrop.h"
276 +#ifdef HAVE_STRINGS_H
277 +#include <strings.h>
283 +extern SDtimeout sdt;
284 +//extern Stream4Data s4data;
285 +#endif /* STICKYDROP */
288 +/* we need this to stringify the CLAMAV_DEFDIR which is supplied at compiletime see:
289 + http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */
290 +#define xstr(s) str(s)
293 +/* the config struct */
296 + /* scan limitations */
297 + char toclientonly; /* if set to 1 scan only traffic to the client */
298 + char toserveronly; /* if set to 1 scan only traffic to the server */
299 + char VirusScanPorts[65536/8]; /* array containing info about which ports we care about */
304 +#ifdef SNORTINLINE_SF_NET
306 +#endif /* SNORTINLINE_SF_NET */
311 + /* temp dir for file descriptors */
312 + char desctmpdir[255];
314 + /* reload time in seconds */
315 + u_int16_t reloadtime;
316 + u_int32_t next_reload_time;
320 +/* pointer to ClamAV's in-memory virusdatabase */
321 +struct cl_node *cl_root;
322 +/* scanner limits */
323 +struct cl_limits clam_limits;
324 +static void ClamAVInit(u_char *);
325 +extern void SetupClamAV();
326 +static int VirusInPacket(Packet *);
327 +int check_4_http_headers(u_int8_t *, int);
328 +static void VirusChecker(Packet *, void *);
329 +extern u_int32_t event_id;
332 +struct cl_stat dbstat;
336 + * Function: SetupClamAV()
338 + * Purpose: Registers the preprocessor.
342 + * Returns: void function
347 + RegisterPreprocessor("ClamAV", ClamAVInit);
352 + * Function: ProcessPorts(u_char *)
354 + * Purpose: Sets the port limits
356 + * Arguments: pointer to string with portlist.
358 + * Returns: void function
361 +static void ProcessPorts(u_char *portlist)
370 + /* reset the ports array */
371 + bzero(&clamcnf.VirusScanPorts, sizeof(clamcnf.VirusScanPorts));
373 + ports = mSplit(portlist, " ", 40, &num_ports, 0);
375 + /* run through the ports */
376 + for(j = 0; j < num_ports; j++)
380 + /* we need to set this port */
381 + if(isdigit((int)port[0]))
383 + portnum = atoi(port);
384 + if(portnum > 65535)
386 + FatalError("%s(%d) => Bad port list to scan: "
387 + "port '%d' out of range\n", portnum, file_name, file_line);
390 + /* mark this port as being interesting using some portscan2-type voodoo,
391 + and also add it to the port list string while we're at it so we can
392 + later print out all the ports with a single LogMessage() */
393 + clamcnf.VirusScanPorts[(portnum/8)] |= 1<<(portnum%8);
395 + /* we need to unset this port */
396 + else if(port[0] == '!')
398 + for(i = 0; i < strlen(port) && port[i+1] != '\0'; i++)
400 + port[i] = port[i+1];
404 + if(isdigit((int)port[0]))
406 + portnum = atoi(port);
407 + if(portnum > 65535)
409 + FatalError("%s(%d) => Bad port list to scan: "
410 + "port '%d' out of range\n", portnum, file_name, file_line);
413 + /* clear the bit - this removes the port from the array */
414 + clamcnf.VirusScanPorts[(portnum/8)] &= ~(1<<(portnum%8));
418 + FatalError("%s(%d) => Bad port list to scan: "
419 + "bad port\n", file_name, file_line);
422 + /* we need to set all ports */
423 + else if(!strncasecmp(port, "all", 3))
425 + /* enable all ports */
426 + for(portnum = 0; portnum <= 65535; portnum++)
427 + clamcnf.VirusScanPorts[(portnum/8)] |= 1<<(portnum%8);
429 + else if(!strncasecmp(port, "ports", 5));
432 + FatalError("%s(%d) => Bad port list to scan: "
433 + "bad port\n", file_name, file_line);
437 + mSplitFree(&ports, num_ports);
439 + /* some pretty printing */
442 + /* print the portlist */
443 + LogMessage(" Ports: ");
445 + for(portnum = 0, j = 0; portnum <= 65535; portnum++)
447 + if((clamcnf.VirusScanPorts[(portnum/8)] & (1<<(portnum%8))))
449 + LogMessage("%d ", portnum);
455 + LogMessage("...\n");
464 + * Function: ParseClamAVArgs(u_char *)
466 + * Purpose: reads the options and sets the defaults.
468 + * Arguments: pointer to string with options
470 + * Returns: void function
472 +void ParseClamAVArgs(u_char *args)
478 + int ports_done = 0;
480 + int num_dbdirtoks = 0;
482 + int num_dbtimetoks = 0;
483 + char **desctmptoks;
484 + int num_desctmptoks = 0;
487 + /* ftp, smtp, http, pop3, nntp, samba (2x), imap */
488 + u_char *default_ports = "21 25 80 81 110 119 139 445 143 8080";
493 +#ifdef SNORTINLINE_SF_NET
495 +#endif /* SNORTINLINE_SF_NET */
497 + clamcnf.toclientonly = 0;
498 + clamcnf.toserveronly = 0;
500 + /* default tmp dir */
501 + if(strlcpy(clamcnf.desctmpdir, "/tmp", sizeof(clamcnf.desctmpdir)) >= sizeof(clamcnf.desctmpdir))
503 + FatalError("The tempdir supplied at compile time is too long\n");
506 +#ifdef CLAMAV_DEFDIR
507 + /* copy the default that was set at compile time, if any */
508 + if(strlcpy(clamcnf.dbdir, xstr(CLAMAV_DEFDIR), sizeof(clamcnf.dbdir)) >= sizeof(clamcnf.dbdir))
510 + /* otherwise a buildin default */
511 + if(strlcpy(clamcnf.dbdir, "/var/lib/clamav/", sizeof(clamcnf.dbdir)) >= sizeof(clamcnf.dbdir))
514 + FatalError("The defdir supplied at compile time is too long\n");
518 + /* reload time default to 10 minutes */
519 + clamcnf.reloadtime = 600;
524 + LogMessage("ClamAV config:\n");
528 + /* if no args, load the default config */
533 + LogMessage(" no options, using defaults.\n");
536 + /* process the args */
539 + toks = mSplit(args, ",", 12, &num_toks, 0);
541 + for(i = 0; i < num_toks; i++)
544 + while(isspace((int)*index)) index++;
546 + if(!strncasecmp(index, "ports", 5))
548 + ProcessPorts(toks[i]);
552 + else if(!strncasecmp(index, "action-reset", 12))
556 +#ifdef SNORTINLINE_SF_NET
557 + else if(!strncasecmp(index, "action-rboth", 12))
561 +#endif /* SNORTINLINE_SF_NET */
562 + else if(!strncasecmp(index, "action-drop", 11))
567 + else if(!strncasecmp(index, "toclientonly", 12))
569 + clamcnf.toclientonly = 1;
571 + else if(!strncasecmp(index, "toserveronly", 12))
573 + clamcnf.toserveronly = 1;
575 + else if(!strncasecmp(index, "dbdir", 5))
577 + /* get the argument for the option */
578 + dbdirtoks = mSplit(index, " ", 1, &num_dbdirtoks, 0);
580 + /* copy it to the clamcnf */
581 + if(strlcpy(clamcnf.dbdir, dbdirtoks[1], sizeof(clamcnf.dbdir)) >= sizeof(clamcnf.dbdir))
583 + FatalError("The defdir supplied in the config is too long\n");
585 + mSplitFree(&dbdirtoks, num_dbdirtoks);
587 + else if(!strncasecmp(index, "dbreload-time", 13))
589 + /* get the argument for the option */
590 + dbtimetoks = mSplit(index, " ", 1, &num_dbtimetoks, 0);
592 + if(isdigit((int)dbtimetoks[1][0]))
594 + clamcnf.reloadtime = atoi(dbtimetoks[1]);
598 + FatalError("We need an integer in seconds for dbreload interval\n");
600 + mSplitFree(&dbtimetoks, num_dbtimetoks);
602 + else if((!strncasecmp(index, "descriptor-temp-dir", 19)))
604 + /* get the argument for the option */
605 + desctmptoks = mSplit(index, " ", 1, &num_desctmptoks, 0);
607 + /* copy it to the clamcnf */
608 + if(strlcpy(clamcnf.desctmpdir, desctmptoks[1], sizeof(clamcnf.desctmpdir)) >= sizeof(clamcnf.desctmpdir))
610 + FatalError("The tmpdir supplied in the config is too long\n");
612 + mSplitFree(&desctmptoks, num_desctmptoks);
616 + FatalError("%s(%d) => Bad ClamAV option specified: "
617 + "\"%s\"\n", file_name, file_line, toks[i]);
621 + mSplitFree(&toks, num_toks);
625 + /* sanety checks */
626 + if(clamcnf.drop && clamcnf.reset)
628 + FatalError("Can't set action-drop and action-reset together!\n");
631 + if(clamcnf.toclientonly && clamcnf.toserveronly)
633 + FatalError("Can't set toclientonly and toserveronly together!\n");
637 + /* if at this stage the ports are not yet done, load the default ports */
639 + ProcessPorts(default_ports);
642 + /* some pretty printing */
647 + if(clamcnf.drop == 1)
648 + LogMessage(" Virus found action: DROP\n");
649 + else if(clamcnf.reset == 1)
650 + LogMessage(" Virus found action: RESET\n");
651 +#ifdef SNORTINLINE_SF_NET
652 + else if(clamcnf.rboth == 1)
653 + LogMessage(" Virus found action: RESET-BOTH\n");
654 +#endif /* SNORTINLINE_SF_NET */
656 + LogMessage(" Virus found action: ALERT\n");
659 + LogMessage(" Virus definitions dir: '%s'\n", clamcnf.dbdir);
661 + LogMessage(" Virus DB reload time: '%i'\n", clamcnf.reloadtime);
662 + if(clamcnf.toclientonly == 1)
663 + LogMessage(" Scan only traffic to the client\n");
664 + else if(clamcnf.toserveronly == 1)
665 + LogMessage(" Scan only traffic to the server\n");
666 + LogMessage(" Directory for tempfiles (file descriptor mode): '%s'\n",
667 + clamcnf.desctmpdir);
673 + * Function: ClamAVInit(u_char *)
675 + * All it does right now is register the plugin, eventually we will take port args
677 +void ClamAVInit(u_char *args)
684 + /* first parse the commandline args */
685 + ParseClamAVArgs(args);
688 + /* get the current time for the reloading */
689 + memset(&t, 0, sizeof(struct timeval));
690 + gettimeofday(&t, NULL);
691 + clamcnf.next_reload_time = t.tv_sec + clamcnf.reloadtime;
693 + /* setup for check */
694 + memset(&dbstat, 0, sizeof(struct cl_stat));
695 + cl_statinidir(clamcnf.dbdir, &dbstat);
697 + /* open the defs dir */
698 + ret = cl_loaddbdir(clamcnf.dbdir, &cl_root, &n);
701 + FatalError("ClamAV: cl_loaddbdir() %s\n", cl_strerror(ret));
704 + /* run buildtrie */
705 +#ifdef CLAMAV_HAVE_CL_BUILD
706 + if((ret = cl_build(cl_root)))
708 + if((ret = cl_buildtrie(cl_root)))
709 +#endif /* CLAMAV_HAVE_CL_BUILD */
711 + FatalError("ClamAV: cl_build() %s\n", cl_strerror(ret));
714 + /* set the limits */
715 + memset(&clam_limits, 0, sizeof(clam_limits));
716 + /* maximal number of files in archive */;
717 + clam_limits.maxfiles = 1000;
718 + /* maximal archived file size */
719 + clam_limits.maxfilesize = 10 * 1048576; /* 10 MB */
720 + /* maximal recursion level */
721 + clam_limits.maxreclevel = 5;
722 + /* maximal compression ratio */
723 + clam_limits.maxratio = 200;
724 + /* disable memory limit for bzip2 scanner */
725 + clam_limits.archivememlim = 0;
727 + /* register the VirusChecker */
728 + AddFuncToPreprocList(VirusChecker, PRIORITY_SCANNER, PP_CLAMAV);
733 + * Function: ClamAVReloadDB(void)
735 + * Purpose: Determines if the virus definition files need
736 + * to be reloaded. If so, reload them.
738 + * Arguments: pointer to Packet *p, for the time only
740 + * Returns: none, void function
743 +static void ClamAVReloadDB(Packet *p)
748 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"going to Reload ClamAV Database\n"););
749 + clamcnf.next_reload_time = p->pkth->ts.tv_sec + clamcnf.reloadtime;
751 + /* now really check */
752 + if(cl_statchkdir(&dbstat) == 1)
754 + /* okay, we are going to reload the db */
755 +#ifdef CLAMAV_HAVE_CL_BUILD
758 + cl_freetrie(cl_root);
759 +#endif /* CLAMAV_HAVE_CL_BUILD */
762 + /* open the defs dir */
763 + ret = cl_loaddbdir(clamcnf.dbdir, &cl_root, &n);
766 + FatalError("ClamAV: cl_loaddbdir() %s\n", cl_strerror(ret));
769 + /* run buildtrie */
770 +#ifdef CLAMAV_HAVE_CL_BUILD
771 + if((ret = cl_build(cl_root)))
773 + if((ret = cl_buildtrie(cl_root)))
774 +#endif /* CLAMAV_HAVE_CL_BUILD */
776 + FatalError("ClamAV: cl_build() %s\n", cl_strerror(ret));
779 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"New ClamAV Database loaded\n"););
781 + /* re-init the dbstat */
782 + cl_statfree(&dbstat);
784 + memset(&dbstat, 0, sizeof(struct cl_stat));
785 + cl_statinidir(clamcnf.dbdir, &dbstat);
789 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"Database is up2date\n"););
797 + * Function: check_for_http(Packet *p, u_int8_t **data, int *dsize)
799 + * Purpose: Determines if the packet is a HTTP response. We are interested
800 + * in those because we want to cut off the header from the
801 + * response, so ClamAV has less trouble detecting virusses.
803 + * It doesn't actually modify any buffer, it only returns (through
804 + * the **data argument) the start of the buffer after the header.
805 + * *dsize is the size of the buffer without the header.
807 + * The check for HTTP should be very cheap, so we do it on all
808 + * traffic. Later we can change this if there is a need to.
810 + * Arguments: pointer to the packet, pointer to a data pointer, pointer to
813 + * Returns: nothing, void function
816 +strip_http_headers_p(Packet *p, u_int8_t **data, int *dsize)
818 + u_int8_t *needle = NULL;
822 + u_int8_t *newbuf = NULL;
824 + /* set needle to past the HTTP keyword */
825 + needle = p->data + 5;
827 + /* search the http headers for Transfer-Encoding */
828 + needle = strstr(needle, "Transfer-Encoding: chunked");
832 + /* chunked encoding used */
837 + /* needle is NULL set the pointer back */
838 + needle = p->data + 5;
840 + /* search for the end of the http header string */
841 + needle = strstr(needle, "\r\n\r\n");
846 + /* set newbuf past the http headers */
847 + newbuf = needle + 4;
848 + /* size of packet minus headers */
849 + offset = newbuf - p->data;
851 + /* point the new buf to the beginning of the payload */
854 + /* chunked encoding used put needle past */
855 + needle = needle + 4;
856 + needle = strstr(needle, "\r\n");
859 + /* chunked but couldn't return after chunksize */
862 + /* just get us past the first chunksize */
863 + newbuf = needle + 2;
865 + /* size of packet minus headers and chunksize */
866 + offset = newbuf - p->data;
869 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"p->data %p, needle %p, newbuf %p, offset %d, p->dsize %u\n",
870 + p->data, needle, newbuf, offset, p->dsize););
872 + /* some sanity checks */
873 + if(offset >= p->dsize)
878 + tmpsize = p->dsize - offset;
880 + while(check_4_http_headers(newbuf,tmpsize))
882 + needle = newbuf + 5;
883 + /* stripping http headers from buffer */
884 + needle = strstr(needle, "\r\n\r\n");
890 + /* point the new buf to the beginning of the payload */
891 + newbuf = needle + 4;
892 + offset = newbuf - p->data;
893 + tmpsize = p->dsize - offset;
896 + /* some sanity checks */
897 + if(offset >= p->dsize)
902 + /* finally pass the new buf ptr and size back to the caller */
904 + *dsize = p->dsize - offset;
910 +check_4_http_headers(u_int8_t *buf, int dsize)
913 + (buf[0] == 'H' || buf[1] == 'T' ||
914 + buf[2] == 'T' || buf[3] == 'P'))
916 + /* http headers found */
920 + //printf("no http headers found\n");
926 + * Function: ScanPort(Packet *p)
928 + * Purpose: Determines if a packet needs to be scanned based
929 + * on the source and destination ports, and for tcp
930 + * packets also if we want to scan only toclient or
931 + * toserver packets.
933 + * Arguments: pointer to the packet
935 + * Returns: returns 1 if the packet needs to be scanned,
938 +static INLINE int ScanPort(Packet *p)
943 + if(p->packet_flags & PKT_FROM_SERVER && !clamcnf.toserveronly)
945 + /* server to client packet: check sp */
946 + if(!(clamcnf.VirusScanPorts[(p->sp/8)] & (1<<(p->sp%8))))
951 + else if(p->packet_flags & PKT_FROM_CLIENT && !clamcnf.toclientonly)
953 + /* client to server packet: check dp */
954 + if(!(clamcnf.VirusScanPorts[(p->dp/8)] & (1<<(p->dp%8))))
961 + /* if we get here the packet was FROM_SERVER while in toserveronly mode
962 + or vice-versa. So we don't scan. */
966 + /* if the packet is not tcp we have no idea about the direction of the
967 + * packet. So we check both the dp and the sp. */
968 + else if(!(clamcnf.VirusScanPorts[(p->dp/8)] & (1<<(p->dp%8))) && /* destination ports */
969 + !(clamcnf.VirusScanPorts[(p->sp/8)] & (1<<(p->sp%8)))) /* source ports */
980 +static ssize_t writepacket(int fd, const void *pbuffer, size_t psize)
982 + ssize_t pdwritten = 0, pd;
985 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"we have written %i of %i bytes in writepacket loop\n",pdwritten,psize););
987 + if((pd = write(fd, &((const char *)pbuffer)[pdwritten], psize - pdwritten)) == -1)
991 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"we wrote %i of %i bytes to disk and got a signal interrupt looping\n",pdwritten,psize););
1000 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"we have written %i of %i bytes in writepacket loop\n",pdwritten,psize););
1001 + } while (pdwritten < psize);
1008 + 1: virus or error, so not scanned
1011 +static INLINE int StoreAndScan(Packet *p)
1014 + char tempfilename[256]="";
1016 + int ret = 0, retval = 0;
1018 + char outstring[255];
1019 + const char *cl_virusname = NULL;
1020 + u_int8_t *buf = p->data;
1021 + int dsize = p->dsize;
1023 + /* create a secure temp file */
1024 + size = snprintf(tempfilename, sizeof(tempfilename), "%s/snort_inline-clamav-XXXXXX", clamcnf.desctmpdir);
1025 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"tempfilename is %s\n",tempfilename););
1026 + if(size >= sizeof(tempfilename))
1028 + FatalError("buffer too small");
1030 + fd = mkstemp(tempfilename);
1033 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"mkstemp error: %s.\n", strerror(errno)););
1037 + /* check if this is a HTTP response, if it is, the buffer
1038 + and buffer size will be adjusted */
1039 + if(check_4_http_headers(buf,dsize))
1041 + if(strip_http_headers_p(p, &buf, &dsize))
1043 + //printf("headers stripped\n");
1047 + /* writing the data to the tempfile */
1048 + ret = writepacket(fd, buf, dsize);
1051 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"tmpfile too small\n"););
1054 + /* scan the descriptor */
1055 + ret = cl_scandesc(fd, &cl_virusname, NULL, cl_root, &clam_limits, CL_SCAN_STDOPT);
1056 + if(ret == CL_CLEAN)
1058 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"Packet is clean\n"););
1060 + else if(ret == CL_VIRUS)
1062 + snprintf(outstring, sizeof(outstring), "%s %s", CLAMAV_VIRUSFOUND_STR, cl_virusname);
1064 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"tempfile and or packet is infected: '%s'.\n", outstring););
1067 + SetEvent(&event, GENERATOR_SPP_CLAMAV, CLAMAV_VIRUSFOUND, 1, 0, 0, 0);
1068 + CallAlertFuncs(p, outstring, NULL, &event);
1069 + CallLogFuncs(p, outstring, NULL, &event);
1077 + /* close the fd */
1079 + /* remove the file */
1080 + unlink(tempfilename);
1081 + /* ret < 0 is very serious, bail out */
1082 + FatalError("ClamAV scan error: %s.\n", cl_strerror(ret));
1085 + /* error, but dont bail out (like we did before), because
1086 + * we dont want to be DoS-ed because of a clamav bug.
1088 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"ClamAV scan error: %s.\n", cl_strerror(ret)););
1091 + /* close the fd */
1094 + unlink(tempfilename);
1101 + * Function: VirusInPacket(Packet *)
1103 + * Purpose: Perform Virusscanning on the payload of a packet.
1105 + * Arguments: p => pointer to the current packet data struct
1107 + * Returns: 1: is a virus was found
1108 + * 0: if the packet is clean
1111 +static int VirusInPacket(Packet *p)
1113 + /* check if we need to reload the virus db */
1114 + if(p->pkth->ts.tv_sec >= clamcnf.next_reload_time)
1116 + ClamAVReloadDB(p);
1120 + /* virus scanning requires data, so check if we have any */
1127 + /* check the port list to see if we need to scan this port */
1134 + /* if cl_root is NULL we return */
1141 + /* do the actual scanning */
1142 + return(StoreAndScan(p));
1147 + * Function: PreprocFunction(Packet *)
1149 + * Purpose: Perform the preprocessor's intended function. This can be
1150 + * simple (statistics collection) or complex (IP defragmentation)
1151 + * as you like. Try not to destroy the performance of the whole
1152 + * system by trying to do too much....
1154 + * Arguments: p => pointer to the current packet data struct
1156 + * Returns: void function
1159 +static void VirusChecker(Packet *p, void *context)
1161 + if(VirusInPacket(p))
1166 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"ClamAV virus found sending Reject\n"););
1169 +#ifdef SNORTINLINE_SF_NET
1170 + else if(clamcnf.rboth)
1172 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"ClamAV virus found sending Reject\n"););
1173 + InlineRejectBoth(p);
1175 +#endif /* SNORTINLINE_SF_NET */
1176 + else if(clamcnf.drop)
1178 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"ClamAV virus found sending Drop\n"););
1183 + /* we only call AlertFlushStream when we are in alert mode
1184 + because if the packet stays in our reassembled buffer
1185 + (in stream4inline mode) we might keep alerting on it. */
1186 + stream_api->alert_flush_stream(p);
1187 + /* we also disable detection because if snort alerts it will
1188 + try to access the reassebled session, which is already gone.
1189 + This will cause us to SEGV. */
1193 + if((SppStickydIsRunning()) && sdt.clamav)
1195 + DEBUG_WRAP(DebugMessage(DEBUG_CLAMAV,"ClamAV adding ip to StickyDrop treei\n"););
1196 + AddIpToBlockTree(p, 0, sdt.clamav);
1198 +#endif /* STICKYDROP */
1204 +#endif /* CLAMAV */
1205 diff -uNr snort-2.6.0.2/src/preprocessors/spp_clamav.h snort-2.6.0.2.clam/src/preprocessors/spp_clamav.h
1206 --- snort-2.6.0.2/src/preprocessors/spp_clamav.h 1970-01-01 01:00:00.000000000 +0100
1207 +++ snort-2.6.0.2.clam/src/preprocessors/spp_clamav.h 2006-11-06 08:24:08.000000000 +0100
1210 +/* Snort Preprocessor Plugin Header File Template */
1212 +/* This file gets included in plugbase.h when it is integrated into the rest
1215 +#ifndef __SPP_CLAMAV_H__
1216 +#define __SPP_CLAMAV_H__
1220 + * list of function prototypes to export for this preprocessor
1222 +void SetupClamAV();
1224 +#endif /* CLAMAV */
1226 +#endif /* __SPP_CLAMAV_H__ */
1228 diff -uNr snort-2.6.0.2/src/preprocids.h snort-2.6.0.2.clam/src/preprocids.h
1229 --- snort-2.6.0.2/src/preprocids.h 2006-02-17 22:39:35.000000000 +0100
1230 +++ snort-2.6.0.2.clam/src/preprocids.h 2006-11-06 08:24:08.000000000 +0100
1234 #define PP_STREAM5 26
1235 +#define PP_CLAMAV 28
1237 #define PRIORITY_FIRST 0x0
1238 #define PRIORITY_NETWORK 0x10