mod_clamav 0.23

An Apache virus scanning filter

Apache 2 introduces filters, which allow to modify content generated by some other module. mod_clamav is an Apache 2 filter which scans the content delivered by the proxy module (mod_proxy) for viruses using the Clamav virus scanning engine.

mod_clamav was written and is currently maintained by Andreas Müller, it is distributed under the GNU General Public License, see the file COPYING in the distribution for details.

This document describes Version 0.23 of mod_clamav. This version can be downloaded from http://software.othello.ch/mod_clamav/mod_clamav-0.23.tar.gz. The most current version will always be available at http://software.othello.ch/mod_clamav/.

This version (0.23) is an update of mod_clamav for the current Clamav API (0.95.1) and for Apache 2.2.x.

Installation

Before installing mod_clamav, make sure you have Clamav properly installed. The module is of only limited use if the proxy module is not available to apache, which is not built by default. So you may want to go back to your Apache compilation and adjust the options to configure so that the proxy module is built.

The only configuration option necessary for mod_clamav is --with-apache=/your/apache2/directory. So installing the module usually takes the familiar steps

# ./configure --with-apache=/usr/local/apache2
# make
# make install

mod_clamav can produce extensive log messages, but as they may slow down the module, log messages at debug level are only produced if the module is compiled with debugging enabled. Add -DCLAMAV_DEBUG to your CFLAGS environment variable to enable debuggin:

CFLAGS="-DCLAMAV_DEBUG"
export CFLAGS

mod_clamav has so far been tested on Linux, Solaris and Mac OS X (the latter only in local mode on Jaguar, Clamav 0.70 on Panther finds a suitable pthreads implementation and compiles the daemon, and mod_clamav seems to work in daemon mode on Panter, but I have not fully tested it). If you succeed to install the module on some other platform, please keep the maintainer updated.

Some initial testing on FreeBSD revealed some permission problems, but mod_clamav seems to work if the apache server and clamd run with the same uid.

Configuration

The distribution includes a sample configuration file sample.conf, which should get you started.

Here is a configuration for an Apache proxy that scans everything except some image types for viruses, using the database files in /usr/local/share/clamav. While downloading files, mod_clamav will write a copy of the file it will later scan for viruses in /tmp/clamav.

ClamavTmpdir    /tmp/clamav
ClamavDbdir     /usr/local/share/clamav
ClamavSafetypes image/gif image/jpeg image/png
<Proxy *>
    SetOutputFilter CLAMAV
</Proxy>

The status page can be enabled with the Location

<Location /clamav>
        SetHandler clamav
</Location>
Please note that not restricting access to this location may reveal sensitive information.

mod_clamav can write a detailed log of what it finds, by enabling the ClamavExtendedLogging directive. Please check the reference below for details.

Best security is obtained if the temporary files have as strict permissions as necessary for the virus scanner to read them. Use the ClamavPermissions directive to set the permissions of the temporary files.

The contents status of the status page depend on the configuration: in daemon mode there is no way to measure the CPU time spent checking viruses, so not CPU time is displayed.

Interaction with mod_dnsbl

This module can be used in combination with mod_dnsbl, a module that allows to selectively block are pass requests based on a url database in the DNS, similar to the real time spam blacklists. mod_dnsbl records the action configured for an IP address, and mod_clamav checks it. If noscan is among the options, then the response is not scanned for viruses. If scan is among the options, all responses are scanned, even those that are considere safe. This version of mod_clamav needs at least version 0.7 of mod_dnsbl

How it works

mod_clamav is an Apache 2 filter, so there is no hope that it will ever be usable with Apache 1. Filters were introduced in Apache 2 to inspect and modify content delivered by some other module.

mod_clamav takes the output of the proxy module, and scans it for viruses using the Clamav library (local mode) or the Clamav daemon (daemon mode). This means that in local mode, the virus scanning engine is part of the apache process, thus virus scanning does not take an extra round-trip to a virus scanning proxy, as with many other virus scanning products.

The clamav library could work entirely inside main memory, but this would cause a problem for large downloads: they could eat up all memory starving the machine in the process. Hence mod_clamav writes the data to a file, the location is configurable with the ClamavTmpdir directive. If file IO is a problem, the temporary files can be placed on a ramdisk.

Long downloads create a special dilemma for a virus scanning proxy: the proxy should not send anything to the browser before it has made sure the object is virus free, but the browser may think the server has a problem if no data is transmitted for a long time. mod_clamav therefore sends one byte every minute (or less if you prefer) of the file being downloaded to the browser. This is enough to keep the browser happy.

Some platforms do not support daemon mode, because the Clamav daemon (which uses pthreads), is not available for them. One example is Mac OS X, on which mod_clamav can only be used in local mode.

One problem with browsers is that the decide to time out if the proxy does not send any data to them. So mod_clamav sends a single byte every minute, even before anything has been checked for viruses. This has the side effect that no HTML error message can be displayed to the client if a byte has been sent already. If the transfer from the server completes within the first minute, i.e. before the first trickle byte is sent to the browser, mod_clamav sends an HTML error message (new in 0.9).

Debugging

mod_clamav provides very verbose logging, if enabled at compile time. If the preprocessor flag CLAMAV_DEBUG is set to 1 instead of the default 0, additional messages are generated at run time. If you meet a problem running mod_clamav, please try to compile with debugging enabled and run the server with DebugLevel set to debug.

Reference

All the available directives are described below

ClamavMode

Syntax: ClamavMode local | daemon
Default: local
Context: server config, virtual host, directory

If the module is supposed to use the clamav library directly, use local mode. In daemon mode, the module queries a remote clamd (on the same machine, of course) for virus checking. The connection to the daemon must be configured using the ClamavSocket or ClamavPort directives


ClamavSocket

Syntax: ClamavSocket unix-domain-socket
Default: none
Context: server config, virtual host, directory

Specifies the path where the Clamav daemon clamd is listening. If this directive is not set, the daemon mode of the module assumes a TCP connection to the Clamav daemon.


ClamavPort

Syntax: ClamavPort port
Default: none
Context: server config, virtual host, directory

Specifies the port number on which the clamav daemon is listening. Not that this directive only has any effect if ClamavSocket is not specified.


ClamavTmpdir

Syntax: ClamavTmpdir tmp-dir
Default: /tmp
Context: server config, virtual host, directory

This directive defines the directory where temporary files should be stored until the can be scanned for viruses.


ClamavDbdir

Syntax: ClamavDbdir virus-pattern-dir
Default: same as that of your clamav installation
Context: server config, virtual host, directory

This directive defines the directory from which virus patterns are loaded.


ClamavReloadInterval

Syntax: ClamavReloadInterval interval
Default: 0
Context: server config, virtual host, directory

The pattern database is reloaded if the last request is more then interval seconds in the past. A value of 0 means that the pattern database is never reloaded, to update patterns, the server must be gracefully restarted. Reloading is only necessary in local mode, in daemon mode its the daemon's business to keep the pattern matching engine up-to-date.


ClamavTrickleInterval

Syntax: ClamavTrickleInterval interval
Default: 60
Context: server config, virtual host, directory

This directive sets the interval at which a block (normaly one byte, but configurable with the ClamavTrickleSize directive) of the incoming data is sent to the browser to keep it happy. If your browsers are tolerant of long delays, this value can be increased.

Note that the trickle interval has a side effect that can affect your link load considerably: only when the trickle is sent to the client will the module be able to detect that the client has aborted the connection. A long trickle interval means that the server will continue downloading the file, although the client is no longer interested. This can fill up you link with downloads still going on no user is interested in.

Browsers behave quite differently with respect to timeouts. For some browsers, a single byte is not good enough, so you will want to increase the trickle size to a larger value. Download speeds below 1 byte/sec seem to be a problem for browsers. Apple's Safari browser times out after 60 seconds (Mozilla seems to be more patient), so you will have do make the trickle interval smaller than 60. Note also that the trickle interval is a minimum value, if a packet arrives from the remote server after that interval, then a trickle block is sent to the browser client. If no packets arrive from the remote server, no trickle blocks are sent to client either.


ClamavTrickleSize

Syntax: ClamavTrickleSize size
Default: 1
Context: server config, virtual host, directory

This directive sets the size of the block sent after each trickle interval. See the description of the ClamavTrickleInterval directive for details.


ClamavMaxfiles

Syntax: ClamavMaxfiles number-of-files
Default: none
Context: server config, virtual host, directory

This directive sets the maxfiles limit variable in Clamav, please read the Clamav for the exact implications of this.


ClamavMaxfilesize

Syntax: ClamavMaxfilesize filesize
Default: none
Context: server config, virtual host, directory

This directive sets the maxfilesize limit variable in Clamav, please read the Clamav documentation for the exact implications of this.


ClamavRecursion

Syntax: ClamavRecursion depth
Default: none
Context: server config, virtual host, directory

This directive sets the recursion depth limit variable in Clamav, please read the Clamav for the exact implications of this.


ClamavSafetypes

Syntax: ClamavSafetypes safe-mime-type ...
Default: none
Context: server config, virtual host, directory

Use this directive to specify a list of mime types that can safely be bypassed.


ClamavSafeURI

Syntax: ClamavSafetypes [ host | uri ] pattern
Default: none
Context: server config, virtual host, directory

If a host or some URIs can safely be bypassed, use this directive to exclude them from virus scanning. With host as the first argument, all hosts matching the pattern are bypassed. With uri, the complete URI is matched against the pattern and virus scanning bypassed in case of a match. Example:

  ClamavSafeuri uri  ^(f|ht)tp://safe-site\.net/safe-dir/.*\.gz$
  ClamavSafeuri host ^safe\.site\.net$
  ClamavSafeuri host safe-domain\.net$

ClamavSafepattern

Syntax: ClamavSafepattern tag [ pattern [ mask ] ]
Default: none
Context: server config, virtual host, directory

This directive adds an object pattern which will be not scanned for viruses. The advantage of this directive is that even if a web server sends the wrong MIME type the object delivered by the web server will be properly classified. 'tag' is an identifier that is output when debugging is enabled. It needs not to be unique. If no pattern is given the first 16 bytes of the object must consist only of printable ASCII characters or TAB, CR and LF. A 'pattern' may consist of up to 16 bytes. Each byte may be given as a printable character or as a '\x' encoded hexadecimal value. The 'mask' is a bitmask which is applied to the object data before comparing the data with the 'pattern'. If not given the 'mask' defaults to '\xff' for all 'pattern' bytes. If a mask is given it may be shorter than the 'pattern', in this case the missing 'mask' bytes are '\xff'. A mask must consist of no more bytes than the 'pattern' has. Each byte may be given as a printable character or as a '\x' encoded hexadecimal value. A usable set of ClamavSafepattern directives is included in the file safepatterns.conf in the mod_clamav distribution.


ClamavSizelimit

Syntax: ClamavSizelimit size
Default: 0
Context: server config, virtual host, directory

This directive sets the size of the largest part of a file that will be checked. By default, its value is 0, meaning the a file is scanned in its entirety. For a positive value, a chunk of at least size bytes is downloaded and checked for viruses. If nothing is found, the rest of the file is downloaded without checking.


ClamavAcceptDaemonproblem

Syntax: ClamavAcceptDaemonproblem on | off
Default: off
Context: server config, virtual host, directory

Setting this to on causes the daemon to accept files as OK if the daemon had a problem checking the file, and returned a bad reply.


ClamavPermissions

Syntax: ClamavPermissions perms
Default: 0640
Context: server config, virtual host, directory

Set the file permissions for temporary files to this value. perms must be an octal value encoding the permissions.


ClamavShm

Syntax: ClamavShm shmfilename
Default: /var/tmp/clamav.shm
Context: server config, virtual host, directory

Shared memory uses a filename to identify the shared memory segment. Since different instances of Apache should use different shared memory segments, the filename must be configurable.


ClamavMutex

Syntax: ClamavMutex mutexfilename
Default: /var/tmp/clamav.lock
Context: server config, virtual host, directory

This directive specifies the file name to be used for mutex locking.


ClamavMessage

Syntax: ClamavMessage message text
Default: none
Context: server config, virtual host, directory

Sets a custom virus notification message. The following replacements are possible: '%%' is replaced by '%', '%i' is replaced by information about mod_clamav, '%u' is replaced by the requested URI and '%v' is replaced by the name of the virus detected. See the example given in the file message.conf included in the mod_clamav distribution.


ClamavExtendedLogging

Syntax: ClamavExtendedLogging on | off
Default: off
Context: server config, virtual host, directory

If turned on, mod_clamav writes four additional notes to the request table, namely clamav:status with possible values passed, bypassed, aborted, INFECTED or failed, clamav:details, clamav:virusname and clamav:longstatus (a string built out of the other notes). These notes can then be used to output detailed logs with mod_logconfig, e.g. using the following log configuration:

LogFormat "%t %!304{clamav:status}n %{clamav:virusname}n request=\"%r\", status=%>s, sent=%!304b, delay=%!304D" clamav_stats
CustomLog logs/scan_log clamav_stats

Common problems

Bad charset info

Hervé Guehl points out that you should not have any AddDefaultCharset settings in your apache configuration file, as the charset info generated may interfere with the info sent by the remote server, causing pages to display badly.

Windows update through mod_clamav

Users have reported that Windows Update does not work with mod_clamav. It turns out that this is not mod_clamav's fault, but rather a bug in the apache2 proxy code. Please see Apache Bug 21348 for details. There is a simple fix (also described in the Apache bugzilla) by applying this patch to server/protocol.c in the apache distribution:

diff -u -r1.121.2.2 protocol.c
--- protocol.c	3 Feb 2003 17:32:00 -0000	1.121.2.2
+++ protocol.c	24 Mar 2003 10:10:49 -0000
@@ -1290,7 +1290,7 @@
      * We can only set a C-L in the response header if we haven't already
      * sent any buckets on to the next output filter for this request.
      */
-    if (ctx->data_sent == 0 && eos) {
+    if (ctx->data_sent == 0 && eos && !r->header_only) {
         ap_set_content_length(r, r->bytes_sent);
     }

It seems the bug is not resolved yet in the new httpd-2.0.49.


© 2003-2009 Prof. Dr. Andreas Müller, Beratung und Entwicklung and Prof. Dr. Andreas Müller
$Id: mod_clamav.html.in,v 1.22 2009/04/10 23:37:29 afm Exp $