top image
home  /  pages  /  tech tips  /  contact about

Prevent spam with Mail Avenger, exim, SpamAssassin, bogofilter, procmail, and DNS

Problem

You receive too much spam.

Keywords

spam, mailavenger, Mail Avenger, exim, DNS, procmail, SpamAssassin, bogofilter, Ubuntu, Debian.

Solution

It's not really a solution. It's a half-hearted attempt.

The attempt breaks down into several categories: making it hard to find you, making it hard to mail you, and then using the obvious tools to flag mail as spam.

Obviously, I'm not the first one to take a crack at this problem. Pretty much everything you read here I stole from other places.

Making it hard to find you: DNS

This is taken from the Spamassassin / OtherTricks wiki page. Instead of configuring a single MX, configure many, most of them fake:
  domain.com.   28800   IN      MX   10 fake0.domain.com.
  domain.com.   28800   IN      MX   20 realmx.domain.com.
  domain.com.   28800   IN      MX   30 fake1.domain.com.
  domain.com.   28800   IN      MX   40 fake2.domain.com.
  domain.com.   28800   IN      MX   50 fake3.domain.com.
  domain.com.   28800   IN      MX   60 fake4.domain.com.
  domain.com.   28800   IN      MX   70 fake5.domain.com.
  domain.com.   28800   IN      MX   80 fake6.domain.com.
  domain.com.   28800   IN      MX   90 fake7.domain.com.
Most spam / zombie software will give up after trying (and failing) on the first MX (fake0.domain.com). However, RFC compatible mail servers will move on to realmx.domain.com. Also, zombies that pick an MX at random have a reduced chance of picking the correct MX.

I strongly advise you to configure the lowest numbered MX to immediately reject TCP connections (by letting the operating system send a TCP RST packet, for example using an iptables REJECT rule) rather than having clients time out.

Preparation: configuring exim to work with Mail Avenger

First, it is likely you'll want to support virtual domains. This document assumes you followed the instructions for handling mail for multiple virtual domains with exim4.

The changes you need to make to exim are to (among other things) allow emails with a '+' in them to work properly, which is one of the neat things you can do with Mail Avenger.

Create an avenger transport file /etc/exim4/conf.d/transport/30_exim4-config_avenger_pipe.

# /etc/exim4/conf.d/transport/30_exim4-config_avenger_pipe
avenger_pipe:
  debug_print = "T: avenger_pipe for $local_part@$domain"
  driver = pipe
  path = "/bin:/usr/bin:/usr/local/bin"
  command = "/usr/local/libexec/avenger.local -D $local_part@$domain -d $local_part"
  return_path_add
  delivery_date_add
  envelope_to_add
Secondly, create an avenger router /etc/exim4/conf.d/router/650_exim4-config_avenger.
# /etc/exim4/conf.d/router/650_exim4-config_avenger
avenger:
  debug_print = "R: avenger for $local_part@$domain"
  driver = accept
  domains = +local_domains
  check_local_user
  transport = avenger_pipe
  require_files = /usr/local/libexec/avenger.local
  no_verify
  no_expn
Finally, modify /etc/exim4/conf.d/router/350_exim4-config_vdom_aliases to accept '+' in email addresses.
# /etc/exim4/conf.d/router/350_exim4-config_vdom_aliases
vdom_aliases:
  driver = redirect
  allow_defer
  allow_fail
  local_part_suffix = +*
  local_part_suffix_optional
  domains = dsearch;/etc/exim4/conf.d/virtual
  data = ${expand:${lookup{$local_part}lsearch*@{/etc/exim4/conf.d/virtual/$domain}}}
  retry_use_local_part
  pipe_transport   = address_pipe
  file_transport   = address_file
  no_more
Finally, you need to make sure exim only listens on localhost port 25. On Debian and Ubuntu, edit /etc/exim4/update-exim4.conf.conf and make sure that:
[...]
dc_local_interfaces='127.0.0.1'
[...]
This frees up port 25 for Mail Avenger. Restart exim.
sudo /etc/init.d/exim4 restart
It is a good idea to keep an eye on /var/log/exim4/mainlog and /var/log/exim4/paniclog.

Making it hard to mail you: Mail Avenger

Mail Avenger is an elegant SMTP server that allows intended recipients to verify mail even before the mail has been accepted. Simply put, Mail Avenger picks up the phone, asks who's talking, puts the caller on hold, then talks to you, and hangs up on the caller should you decide you're not interested. You can decide this based on the sender address, based on the actual body of the message, and even on things like the TCP SYN fingerprint of the client SMTP server.

Mail Avenger does a number of standard checks for you. First, it verifies that the sender can receive bounce messages (without actually sending one), which weeds out bogus senders. Secondly, it performs SPF checks on the sender, and, optionally, it can perform greylisting: deferring the sender, telling it to try again in a few minutes. This will, in some cases, slow down email a little bit, but it discourages most spammers, while RFC compliant senders will keep trying to deliver the message every few minutes.

There is no Ubuntu / Debian package for Mail Avenger (yet), so you have to compile and install it by hand. Follow the steps outlined in the Mail Avenger installation instructions. I remember having to install quite a few packages before being able to compile and build Mail Avenger. I configured and installed Mail Avenger as follows.

sudo ./configure --enable-sasl --enable-ssl
sudo make install
After step 5 from the Mail Avenger installation instructions (when you create /etc/avenger), make sure the directory is readable to the newly created avenger user:
sudo chmod 755 /etc/avenger/
Here is my /etc/avenger/asmtpd.conf.
# /etc/avenger/asmtpd.conf

# replace with your real IP
BindAddr 123.123.123.123

Separator +
Sendmail /usr/sbin/rmail

AvengerUser Debian-exim

SPFfail include:spf.trusted-forwarder.org

MaxClients 60
MaxConPerIP 10
MaxRcpts 5
MaxMsgSize 104857600
SMTPTimeout 300

# see the smtpd.conf man page
# SMTPFilter /etc/avenger/smtp-filter

MXLocalRcpt 1

RBL zen.spamhaus.org
RBL cbl.abuseat.org
RBL combined.njabl.org
RBL bl.spamcop.net
RBL list.dsbl.org
RBL dnsbl.sorbs.net
RBL dul.dnsbl.sorbs.net

DebugSMTP 1
DebugSMTPc 1
DebugAvenger 1

NoCheck postmaster
NoCheck abuse
Obviously, you need to set the BindAddr variable. See also the asmtpd.conf(5) man page.

Make sure you fill the /etc/domains file with domains that you want Mail Avenger to accept mail for, or make sure MXLocalRcpt is set to 1 (and the BindAddr is the same IP as the MX for the domain(s) you want Mail Avenger to receive mail for). Here is an example /etc/avenger/domains file:

# /etc/avenger/domains
domain1.com:
domain2.com:
domain3.com:
Here is my /etc/avenger/default file (which happens to be also my /etc/avenger/unknown through a symbolic link: I am relying on exim to discard email to non-existent addresses).
# /etc/avenger/default and /etc/avenger/unknown
errcheck
case "$SPF0" in
    error)
        defer "Temporary error in SPF record processing"
        ;;
    pass)
        accept "SPF sender PASS"
        ;;
esac

greylist_delay=10m
greylist_ttl1=5h
greylist_ttl2=30D
greylist "${CLIENT_IP%.*} $RECIPIENT $SENDER"

bodytest /etc/avenger/clam

accept
See also the avenger(1) manual page.

This default file discards email that Mail Avenger has flagged as coming from a non-existent sender (errcheck). Then it immediately accepts email that comes from a SPF-verified sender (accept "SPF sender PASS"). Otherwise it greylists the sender's IP address (in fact, the /24) by telling it to send the email again in 10 minutes (greylist "${CLIENT_IP%.*} $RECIPIENT $SENDER"). Then (when the email comes a few minutes later), it gets scanned on viruses (bodytest) and, finally, provided it is clean, gets accepted and handed to exim (which is responsible for delivering it to the user).

Here is the /etc/avenger/clam file (which should probably be executable).

#!/bin/sh

# this is /etc/avenger/clam

edinplace
out="`/usr/bin/clamdscan --no-summary - 2>&1`"
if test "$?" = 1; then
    echo This message appears to be infected with a virus
    printf "%s\n" "$out" \
        | sed -e '/Warning:/d' -e 's/^[^:]*: //' | sort -u
    exit 100
fi
exit 0
Notice that this relies on the clamav-daemon package being installed.

Make sure asmtpd starts on reboot by adding a @reboot root crontab entry or by adding it to rc.local! I opted for the former.

sudo crontab -e
Add a @reboot entry:
@reboot         /usr/local/sbin/asmtpd
Fire up Mail Avenger.
sudo /usr/local/sbin/asmtpd
You can follow Mail Avenger's output by tailing /var/log/mail.info. It's probably a good idea to do that for a while.
sudo tail -f /var/log/mail.info

Train bogofilter

Plenty has been written about bogofilter already.

My ~/.bogofilter.cf file.

bogofilter_dir=~/.bogofilter
spam_header_name=X-Bogosity
spamicity_tags = Yes, No, Unsure
header_format = %h: %c, spamicity=%p
ham_cutoff = 0.10
spam_cutoff= 0.90
I train bogofilter on my email as follows (this assumes you created a file, ~/ham with non-spam, and a file, ~/spam with spam). Make sure the files contain roughly the same number of messages.
perl /usr/share/doc/bogofilter-common/examples/contrib/bogominitrain.pl -fnv \
    ~/.bogofilter ~/ham ~/spam '-o 0.99,0.01'
One thing I always get confused about is the following.

To tell bogofilter that a piece of mail is spam, where it wasn't sure yet:

/usr/bin/bogofilter -s
To tell bogofilter that a piece of mail is ham, where it wasn't sure yet:
/usr/bin/bogofilter -n
To tell bogofilter that a piece of mail is spam, where it wrongly classified and registered it as ham:
/usr/bin/bogofilter -N -s
To tell bogofilter that a piece of mail is ham, where it wrongly classified and registered it as spam:
/usr/bin/bogofilter -n -S

Configure SpamAssassin

Plenty has been written about SpamAssassin already.

My ~/.spamassassin/user_prefs file, generated using the SpamAssassin Configuration Generator. (This file assumes you're OK with Dutch, English, German, and Hebrew mail!)

required_score    5.0
report_safe       0
use_bayes         0
bayes_auto_learn  1
skip_rbl_checks   0
use_razor2        1
use_dcc           1
use_pyzor         1

# OK with Dutch, English, German, and Hebrew
ok_languages             nl en de he

ok_locales               en 
add_header all Status  _YESNO_, _HITS_, _TESTS(,)_
Notice that, first of all, I disabled bayes learning because bogofilter does that already. One might argue that I should also disable RBL checks since Mail Avenger is doing it already. Secondly, this config relies on several Debian / Ubuntu packages being installed: razor, pyzor, and dcc-client.

I had to add the following lines to /etc/spamassassin/v320.pre.

loadplugin Mail::SpamAssassin::Plugin::TextCat
loadplugin Mail::SpamAssassin::Plugin::DCC
Now verify your configuration.
spamassassin --lint

Configure procmail

Plenty has been written about procmail already.

Here are the relevant parts from my ~/.procmailrc file. This procmailrc assumes you're using Maildir and it assumes you have a spam/ folder and an unsure/ folder.

MAILDIR=$HOME/Maildir/
DEFAULT=$MAILDIR/

# Uncomment for debugging; set to no if you want minimal logging
VERBOSE=yes
LOGABSTRACT=all
PMDIR=$HOME/.procmail
LOGFILE=$PMDIR/log

LINEBUF=32768

# ...

# score it with bogofilter
:0wf
| /usr/bin/bogofilter -e -p -u -c ~/.bogofilter.cf

# bogofilter says it's spam
:0:
* ^X-Bogosity: Yes
spam/

# bogofilter says it's not spam.  see what SpamAssassin thinks.
:0fw
|/usr/bin/spamassassin

# If bogofilter isn't sure, but SpamAssassin is really sure, train
# bogofilter and mark it as spam.
:0
* ^X-Spam-Status: Yes
* ^X-Bogosity: Unsure
{
    :0wf
    | /usr/bin/bogofilter -e -s -c ~/.bogofilter.cf

    :0:
    spam/
}

# bogofilter isn't sure, and SpamAssassin didn't say an outright yes
:0:
* ^X-Bogosity: Unsure
unsure/

# ...
It's a good idea to keep an eye on ~/.procmail/log while you're debugging this.

Acknowledgements

Many thanks to David Mazières for writing Mail Avenger and for helping me understand it.
URL: http://thomer.com/howtos/fight_spam.html
Copyright © 1994-2011 by Thomer M. Gil
Updated: 2007/06/20