calum.org:~#

Postfix Antispam

Tags: linux, email, spam, howto,

Added: 2006-08-12T09:45

Postfix Antispam

Like everyone, spam (or UCE - unsolicited commercial email) is the bane of my life.

If you run your own Postfix SMTP server however, there are lots of things you can do to stop it. This is a little crib sheet of what I do on most of my servers (as much for my ease-of-access as for other people).

Why do I use Postfix?
It's securely designed, has human-readable config, and is kept up to date.
I avoid Sendmail as much as I can, and I tried to like Qmail, I really did. But it's just far too conservative, and presumes that you're not trying to do anything even vaguely unusual.

The main premise here is to a:, avoid unnecessary server load (i.e. put the cpu-intensive checks such as SpamAssassin last), and b:, try and get rid of as many spams as possible as early on as possible. We're trying to avoid any ending up on the client.

So how are we intending on doing it?

Overview



  • Reject anyone that doesn't "EHLO/HELO" with a valid FQDN. This stops many of the "HELO localhost, HELO friend, or EHLO -10221740411" style mass-senders. (I'm aware that this is controversial. However, if you're drowning in spam, you'll do whatever it takes.)

  • Reject anyone that EHLO/HELOs with a FQDN that doesn't exist (see comment below though for possible problems!)

  • Reject anyone that is sending from networks/addresses that you've manually added to a blocked list.

  • Reject anyone that seems to be doing something weird.

  • Reject any sender that comes from an IP address in the Spamhaus blacklists.

  • Use Greylisting

  • Finally, run SpamAssassin on any mails that get this far, and use Procmail to move any identified as Spam into a separate mailbox.

  • Optionally, drop mails with .exe/.pif/.whatever files attached



So. The first thing I do after configuring a Postfix server on Gentoo is add a chunk at the bottom of main.cf with these goodies:


smtpd_helo_required = yes
smtpd_delay_reject = no
disable_vrfy_command = yes



These mean that a client has to say EHLO, Postfix won't delay in telling them to get lost, and they can't try and enumerate which usernames are valid on the system - bad for Spam, and bad for system security.

Then I add something to make sure that clients are saying EHLO nicely:

HELO/EHLO restrictions



smtpd_helo_restrictions =
permit_mynetworks,
reject_invalid_hostname,
reject_unknown_helo_hostname,
reject_non_fqdn_hostname



This alone stops 98% of my Spam, which runs at 1 Spam every 3 to 10 seconds.
(I actually think that some malware has my mailserver hardcoded as an SMTP server - I don't know why, as I've never been used to send Spam in the past. )

DNS/IP checks



I then check the client IP/reverse DNS against a list I keep of networks that seem to cause most of the trouble.
It also includes a whitelist section so that you can, say, whitelist a specific .ru domain, but block all other .ru servers.

(The TrendMicro list can give you ideas of the networks producing the most traffic, but it's probably just best to look at your logs, and tailor it for you.)


# The smtpd_client_restrictions parameter restricts what clients this
# system accepts SMTP connections from.
smtpd_client_restrictions =
permit_mynetworks,
check_client_access hash:/etc/postfix/client_restrictions,
reject_rbl_client sbl-xbl.spamhaus.org,
reject_rbl_client cn.countries.nerd.dk,
reject_rbl_client kr.countries.nerd.dk,
reject_rbl_client pl.countries.nerd.dk,
reject_rbl_client sa.countries.nerd.dk



(Note: I include the following configuration:


default_rbl_reply = $rbl_code Service unavailable; $rbl_class [$rbl_what] blocked using $rbl_domain${rbl_reason?; $rbl_reason}. For whitelisting, contact via http://mydomain.dom/blocked.php

which links to a page where people can contact me if they need a netblock/domain whitelisting.)

/etc/postfix/client_restrictions contains the following:


# After changing, run postmap /etc/postfix/client_restrictions
# Whitelisted
my.home.ip OK
.google.com OK
55.66.77.0/24 OK



# Blacklisted
.cn 554 Too much spam from China. For whitelisting, contact at http://mydomain.dom/blocked.php
.kr 554 Too much spam from Korea. For whitelisting, contact at http://mydomain.dom/blocked.php
.br 554 Too much spam from Brazil. For whitelisting, contact at http://mydomain.dom/blocked.php
.pe 554 Too much spam from Peru. For whitelisting, contact at http://mydomain.dom/blocked.php
.pl 554 Too much spam from Poland. For whitelisting, contact at http://mydomain.dom/blocked.php
.gr 554 Too much spam from Greece. For whitelisting, contact at http://mydomain.dom/blocked.php
.tr 554 Too much spam from Turkey. For whitelisting, contact at http://mydomain.dom/blocked.php
.mx 554 Too much spam from Mexico. For whitelisting, contact at http://mydomain.dom/blocked.php
.jp 554 Too much spam from Japan. For whitelisting, contact at http://mydomain.dom/blocked.php
.my 554 Too much spam from Malaysia. For whitelisting, contact at http://mydomain.dom/blocked.php
.ma 554 Too much spam from Morroco. For whitelisting, contact at http://mydomain.dom/blocked.php



.verizon.net 554 Too much spam from verizon.net. For whitelisting, contact at http://mydomain.dom/blocked.php
.rr.com 554 Too much spam from rr.com. For whitelisting, contact at http://mydomain.dom/blocked.php
.comcast.net 554 Too much spam from comcast.net. For whitelisting, contact at http://mydomain.dom/blocked.php
.rima-tde.net 554 Too much spam from rima-tde.net. For whitelisting, contact at http://mydomain.dom/blocked.php
.shawcable.net 554 Too much spam from shawcable.net. For whitelisting, contact at http://mydomain.dom/blocked.php
.user.ono.com 554 Too much spam from user.ono.com. For whitelisting, contact at http://mydomain.dom/blocked.php
.wanadoo.fr 554 Too much spam from wanadoo.fr. For whitelisting, contact at http://mydomain.dom/blocked.php
.cable.ntl.com 554 Too much spam from cable.ntl.com. For whitelisting, contact at http://mydomain.dom/blocked.php
.blueyonder.co.uk 554 Too much spam from blueyonder.co.uk. For whitelisting, contact at http://mydomain.dom/blocked.php
.telecomitalia.it 554 Too much spam from telecomitalia.it. For whitelisting, contact at http://mydomain.dom/blocked.php



130.117.0.0/16 554 Too much spam from 130.117.0.0/16. For whitelisting, contact at http://mydomain.dom/blocked.php
88.235.128.0/17 554 Too much spam from TurkTelecom. For whitelisting, contact at http://mydomain.dom/blocked.php
88.227.0.0/17 554 Too much spam from TurkTelecom. For whitelisting, contact at http://mydomain.dom/blocked.php



It's important to understand that these TLDs/domain names are what my DNS server returns for the reverse DNS look-up - it doesn't take any notice of what the client says in the transaction.

We could also perform the same checks against the HELO/EHLO FQDN, but these are more often than not fake/invalid when coming from spammers, so we don't bother.

Now it's time to add in a few more restrictions, and use the excellent Spamhaus black list.


smtpd_recipient_restrictions =
permit_mynetworks,
reject_invalid_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unauth_pipelining,
reject_unauth_destination,
reject_rbl_client sbl-xbl.spamhaus.org,
permit



(Note: I don't enable options that require that hosts have a reverse DNS entry, such as reject_unknown_reverse_client_hostname, or the stronger reject_unknown_client_hostname - as I have been in situations before where, although I am running a completely decent, locked down mail server, I haven't been able to control the reverse DNS for various reasons - political, technical, etc - and I don't want to block people running well-behaved home SMTP servers, etc.)

We need to make sure that hosts, when they are told "Go away", they don't bother retrying:


unknown_local_recipient_reject_code = 550
unknown_hostname_reject_code = 550




Now, should a spammer connect from an IP range that isn't in the Spamhaus blacklist, nor in a network that I've manually blocked, they identify themselves correctly in the EHLO stage, and they are actually trying to send to a valid user on the system, we need to make them just through a few more hoops.

Greylisting



Greylisting is a system whereby, unless you have had an email from that particular email address/sender IP combination in the last 30 days, the mail server issues a reply that basically says "Hold on, temporary error, try again in 300 seconds".
Most spammers are blasting out millions of emails an hour and as such, they can't be bothered to wait and tie up their resources for 5 minutes to try and get one through. So they drop the connection.
"Real" mail servers should see this as a legitimate, temporary error, and hold on, trying again for up to (usually) 7 days until the mail is delivered.

Note: The downside of greylisting is that you may have to wait 300 seconds (or whatever you configure) for the first email from a new sender. In actual fact, you might have to wait longer - Postfix for example tries to redeliver deferred mails every 1000 seconds by default.
I can't imagine when this would be much of a problem, but it's worth mentioning - I don't pretend to know everything every mail server in the world is used for.. Perhaps email alerts for hosts going down from something like Nagios would need to be exempt from the greylisting.


emerge -v postgrey

installs Postgrey.
I edit the /etc/conf.d/postgrey file, and change POSTGREY_TYPE from inet to unix (as the fewer network sockets open on my machine, the better).
I then add in, just under the "permit_my_networks" line in smtpd_recipient_restrictions


check_policy_service unix:private/postgrey,

, before starting it up, and making it run at bootup:


# /etc/init.d/postgrey start && rc-update add postgrey default
* Starting Postgrey ... [ ok ]
* postgrey added to runlevel default
* rc-update complete.
#



We're almost there. Hardly anything unsolicited should be getting through now. The final thing is to use the SpamAssassin program to check anything that does get through.

SpamAssassin




emerge -v spamassassin


Edit /etc/mail/spamassassin/local.cf, and enable the things you want. I always make sure that the subject header re-writing is enabled - this makes it easy to filter in the client. I choose not to use Vipul's Razor.
Make sure SpamAssassing (spamd) runs at bootup:


# /etc/init.d/spamd start && rc-update add spamd default
* Starting spamd ... [ ok ]
* spamd added to runlevel default
#



And finally, make sure that Postfix sends email through it:

In /etc/postfix/master.cf, add the line "-o content_filter=spamassassin" as shown below:


smtp inet n - - - - smtpd
-o content_filter=spamassassin


Restart Postfix, and you should be good.


Procmail



If you have procmail installed, you can automatically drop any "Spam" tagged email messages into a directory of your choice:
In ~/.procmailrc


DROPPRIVS=yes



:0
* ^Subject:.*\*SPAM\*
.maildir/.Trash/


Warning: Only do this when you are sure it's all working fine, so you don't end up binning good messages.

It is possible to train SpamAssassin to be able for it to better sort your mail. After all, you might work for Pfizer, and receive legitimate emails about Viagra all day long.
You do this by telling the system about spam that has slipped though as legitimate, and about "ham" - valid emails that have been incorrectly identified as spam.
I don't bother with this as not enough gets through to make it worthwhile. However, if I did, I'd set up two aliases (spam@, and ham@), and forward mails onto the appropriate address, and then pipe it through to SpamAssassin.

Attachments


If you want to block all mails with, say, exe attachments, you can do so like this. Add this to/uncomment it in /etc/postfix/main.cf:


header_checks = regexp:/etc/postfix/header_checks



Then, put your rules in the header_checks file - here is an example to get you going:


# After editing, run postmap /etc/postfix/header_checks
/^content-(type|disposition):.*name[[:space:]]*=.*\.(exe|vbs|pif)/
REJECT Bad attachment file name extension: $2



You can change the REJECT to DISCARD if you just want to silently throw it away - most viruses will spread with faked "from" addresses - however, if you ditch emails silently, you can almost guarantee that someone will moan at you in a few weeks that you've ignored an email they've sent you.
This is a very crude way of protecting your system and users from viruses/trojans etc - if you're looking for a free antivirus scanner for Linux, investigate ClamAV.


For a third party test of your mail server, you can use http://www.abuse.net/relay.html for quite a thorough bunch of tests.

Todo: Add in SPF checking.

Hopefully, you should see very few Spams make it through this maze. I don't. If you have any suggestions, comments, flames, please add them as a comment below.
If you would like someone to come along, and set you up an SMTP server, please get in touch.

posted by Calum on 2006-08-12T09:45 under

Comments

Comment

Of course, there'll always be some mail servers that don't follow the RFCs properly. Checking the logs, I noticed the following: Sep 26 03:11:47 hosting postfix/smtpd[19263]: connect from mail7.exchange.microsoft.com[131.107.1.27] Sep 26 03:11:49 hosting postfix/smtpd[19263]: NOQUEUE: reject: RCPT from mail7.exchange.microsoft.com[131.107.1.27]: 450 4.7.1 <df-gwy-07.exchange.corp.microsoft.com>: Helo command rejected: Host not found; from=<a.user@exchange.microsoft.com> to=<a.user@a.domain> proto=ESMTP helo=<df-gwy-07.exchange.corp.microsoft.com> Sep 26 03:11:49 hosting postfix/smtpd[19263]: disconnect from mail7.exchange.microsoft.com[131.107.1.27] Now, according to the SMTP RFC (http://www.ietf.org/rfc/rfc2821.txt): The domain name given in the EHLO command MUST BE either a primary host name (a domain name that resolves to an A RR) or, if the host has no name, an address literal as described in section 4.1.1.1. So why isn't there a DNS entry for df-gwy-07.exchange.corp.microsoft.com? Anyway, to allow these broken setups to skip the "reject_unknown_hostname" in "smtpd_helo_restrictions", (as I don't want to disable it - it catches 95% of the spam) - you need to do the following: * In main.cf, add parent_domain_matches_subdomains = yes * In the smtpd_helo_restrictions section, add "check_helo_access hash:/etc/postfix/helo_access" * In that helo_access file, list the offending "HELO/EHLOs" - in this case: .exchange.corp.microsoft.com OK * Finally, run postmap /etc/postfix/helo_access to build the DB file, and restart postfix. It does appear to be a problem more with some mail server admins than others. (https://www.nearlyfreespeech.net/about/email.php#software)

Comment

Here is a slightly old but still useful presentation from Ohio LinuxFest 2004 about dealing with spam in Postfix. http://www.potentialtech.com/wmoran/spam.pdf
Add a comment

Your IP:
Please enter 2568326 here: