Quick Links    
Quick hacks
Contact me

Greg's Obsolete Exim Virus Filter

One of Exim's more interesting features is its built-in filtering language. It's certainly not a general-purpose programming language, but for simple mail-filtering tasks it's a hell of a lot easier to use than (shudder) procmail. It's also easier on your server than spawning a Python or Perl script, since you don't have to fork() and you don't have to startup a big hairy interpreter. (And you don't have to write the script and worry about all the niggling little details of how to handle email.)

One obvious application of Exim's "system filter" feature is to inspect every email message for viruses. The original idea is due to Nigel Metheringham; he created a generic Windows executable content filter and put it on the Exim web site. This is not an all-singing, all-dancing, industrial-strength, super-powered email virus filter. However, it's Good Enough for a lot of people.

I started using Nigel's filter in July 2001, and expanded/improved it over the following months. In particular, I added the following features:

I also made the rejection messages a tad nicer-looking (IMHO).

I stopped using this virus filter in June/July of 2002, because Exim 4 provides a much better solution in the form of its local_scan() API. I wrote elspy to let me write local_scan() functions in Python, and that's how I do virus detection now. So this page is largely of historical interest.

Without further ado, here is my email virus filter for Exim. You will almost certainly need to edit it as follows before using it on your system:

Of course, you'll also have to edit Exim's configuation file to enable the filter. For Exim 3.x, you'll need to add the following:

# Virus filtering, using a filter descended from Nigel Metheringham's
# filter for rejecting mail that looks like a Windows e-mail virus.
message_filter = /etc/exim/system_filter 
message_body_visible = 5000 
# These are needed so we can save, pipe, or send mail from the  
# system filter. 
message_filter_file_transport = address_file 
message_filter_reply_transport = address_reply 

# Viruses can be big, and it's not really necessary to return
# every last byte.
return_size_limit = 30k
Of course, make sure that message_filter refers to where you put the filter. Also, make sure that the two transports -- address_file and address_reply -- exist; they should look something like this:
  driver = appendfile
  # these three options are not necessary, but I like them

  driver = autoreply

Once you've got virus-filtering working, there are a few things to consider: