Mail filtering examples

Taken from Track T1 of the AfNOG 2004 Network Workshop

These are snippets of configuration for an Exim-based MTA. They have had some simple testing but are intended mainly as a starting point for building your own customised configurations. Test them for yourself, and read the related parts of the documentation.


1. RBL blacklists with opt-in/opt-out

Here we will configure Exim to check incoming mail against DNS RBLs, but individual users can have a different set of RBLs which apply to their account (which can be empty, in which case they have opted out of filtering altogether).

Customised RBLs can help improve the accuracy of your filtering. For example, if a particular user knows that they will never receive any legitimate mail from a particular country, then they can use an RBL which lists all IP addresses in that country (see http://blackholes.us/), without affecting any other users on your system.

Firstly, create a file /usr/exim/dnslists containing E-mail addresses (one per line), followed by a space or tab and the list of RBLs to use for that user. If you want a default policy to apply to all other users, put a line starting "*". For a policy which applies to all users in at domain.com, use "*@domain.com". If someone wants no RBL filtering at all, leave the right-hand side blank.

fred@flintstone.org	korea.blackholes.us : china.blackholes.us
wilma@flintstone.org
*			sbl.spamhaus.org : ordb.relay.org : bl.spamcop.net

Now edit the configuration file /usr/exim/configure. In the section 'begin acl' locate the following lines:

  # deny    message       = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
  #         dnslists      = black.list.example

Uncomment these two lines and change the second line as shown here:

  deny    message       = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
          dnslists      = ${lookup{${lc:$local_part@$domain}}lsearch*@{/usr/exim/dnslists}}

How does this work? Instead of having a static list of dnslists, which is the same for everyone, we perform a file lookup to decide which dnslists to use for this particular recipient. This is using Exim's "string expansion" facility.

${lookup{key}lsearch*@{file}}
Lookup the value "key" in the file "file". The result of the expansion is the rest of the line in the file.
lsearch*@
We perform a linear search (top to bottom) through a plain text file. If the key "foo@bar" is not found, then we look a second time for "*@bar", and if still not found, look a third time for "*".
${lc:some-string}
Expands "some-string" and converts it to Lower Case. This is because incoming mail might be using uppercase characters for some or all of the address, so we need to convert to all lower-case to find the key.
$local_part@$domain
The E-mail address which we are currently processing

You can test and debug string expansions like this using exim's -be (expression testing) mode.

# /usr/exim/bin/exim -be '${lookup{fred@flintstone.org}lsearch*@{/usr/exim/dnslists}}'
korea.blackholes.us : china.blackholes.us

To test whether the policy works use exim's -bh mode which simulates an SMTP connection from a particular IP address. The address 61.32.0.1 is included in the korea.blackholes.us list, so:

# /usr/exim/bin/exim -bh 61.32.0.1

**** SMTP testing session as if from host 61.32.0.1
**** This is not for real!
220 noc.t1.ws.afnog.org ESMTP Exim 4.34 Wed, 19 May 2004 15:18:30 +0000
mail from:<>
250 OK
rcpt to:<wilma@flintstone.org>
250 Accepted
rcpt to:<fred@flintstone.org>
550-rejected because 61.32.0.1 is in a black list at korea.blackholes.us
550 Korea blocked by korea.blackholes.us
quit
221 noc.t1.ws.afnog.org closing connection

If the /usr/exim/dnslist file gets big, then it will be slow to search. In this case, you can convert it into an indexed .db file:

# /usr/exim/bin/exim_dbmbuild /usr/exim/dnslists /usr/exim/dnslists.db

You'll have to run this command every time you change dnslists. Then make another change to the configure file:

change          ....lsearch*@{/usr/exim/dnslists}}
to              ....dbm*@{/usr/exim/dnslists.db}}

For more information read the Exim manual, which is doc/spec.txt inside the source directory, or online at www.exim.org


2. Content filtering: exiscan-acl

Exim has some hooks which allow other people to write extensions which perform content scanning. One of these is "exiscan-acl". You need to apply the exiscan-acl patch before you compile exim. Assuming you have already downloaded and unpacked the exim source in /usr/exim:

$ cd /usr/exim
$ ftp noc.ws.afnog.org

Log in as 'anonymous'
ftp> cd /pub/t1
ftp> get exiscan-acl-4.34-21.patch
ftp> bye

$ cd /usr/exim/exim-4.34
$ patch -p1 <../exiscan-acl-4.34-21.patch

Now continue to build exim as instructed before (create and edit Local/Makefile and Local/eximon.conf). If you have built exim already, before you applied the exiscan-acl patch, then clean out the source tree by

$ rm -rf build-FreeBSD-i386

before continuing as before:
... set up Local/Makefile and Local/eximon.conf ...
$ make
$ su
# make install

Check the exim binary now includes exiscan:
# /usr/exim/bin/exim -bV
Exim version 4.34 #1 built 19-May-2004 15:47:58
...
Contains exiscan-acl patch revision 21 (c) Tom Kistner [http://duncanthrax.net/exiscan/]

Exiscan needs options in the configure file to enable it; until this is done, exim will continue to work just as it did before. To do useful filtering you will need to install SpamAssassin and/or clamav first. The Exiscan documentation is in doc/exiscan-acl-spec.txt and doc/exiscan-acl-examples.txt in the source directory once you've applied the exiscan patch.