Using postfix to block spam botnet traffic
A friend of mine is set up with a satellite Internet connection to his home in a not-all-that-rural part of Ireland. He’s been hosting his domain from there, with all email traffic and such going to his local server. Until recently, it was a perfectly workable solution, even with the normal supply of spam, virus, and other junk mail arriving.
But nearly two weeks ago, his domain came under attack from a bunch of spam botnets. Uncountable messages were forged to various places, all of which set up with the Sender: header to be totally random addresses @domain.ie. Unfortunately his ISP said they would not help block the traffic. (As opposed to could not.)
The workaround we came up with pushed his traffic through a virtual-hosted system I have set up over in the US with johncompanies.com (yes, a blatant plug, but I really like their service). There were a few steps I had to take in configuring Postfix before they added the MX record for his domain to reroute everything. (This is on a system running Debian GNU/Linux version 4.0, codenamed etch, using postfix 2.3.7.)
- In
main.cf, add his domain torelay_domains(which already existed for other domains I MX with). - Since he uses a lot of different email addresses (to make it easy to catch re-use and selling of them), I didn’t set up a
relay_recipient_mapshash table. That would have been even cooler with its ability to block every single address except for the few that are in fact valid. In this case, however, he had a number of variants of addresses he used so it wasn’t a practical choice. - Add to
smtpd_recipient_restrictionsthe line
check_recipient_access hash:/etc/postfix/maps/access_recipient
and created the file
/etc/postfix/access_recipientcontaining
postmaster@domain.ie REJECT MAILER-DAEMON@domain.ie REJECT
and then ran
postmap access_recipientas root. I should note I did not put a line likedomain.ie OKwhich would have let all other mail for the domain go through—but usurped any other rules thatsmtpd_recipient_restrictionsmay try to do after my access_recipients entry. - I created a
/etc/postfix/access_senderfile with the lines below. The first was used because his server will never receive mail from someone in his domain.
domain.ie REJECT MAILER-DAEMON@ REJECT MailerDaemon@ REJECT abuse@ REJECT admin@ REJECT Administrator@ REJECT autoresponder@ REJECT bounce@ REJECT info@ REJECT majordomo@ REJECT Majordomo-Owner@ REJECT nobody@ REJECT postmaster@ REJECT savrequest@ REJECT senderchallenge@ REJECT spam@ REJECT vacation@ REJECT
Then I had to run
postmap access_senderas root. Inmain.cf, forsmtpd_sender_restrictionsI added
check_sender_access hash:/etc/postfix/access_sender
as well.
- I found I wanted to add some rules that used regular expressions. After installing the
postfix-pcreDebian package, I created a new file/etc/postfix/access_sender.pcrewith the lines
/.*bounces\@/ REJECT /confirm-return.*\@/ REJECT
and in
main.cfgavesmtpd_sender_restrictionsyet another entry of
check_sender_access pcre:/etc/postfix/access_sender.pcre
- Following the hints from a post by Justin Mason, I created a new file
/etc/postfix/header_checksand gave it the lines
/^Content-Type: multipart\/report; report-type=delivery-status\;/ REJECT no third-party DSNs /^Content-Type: message\/delivery-status; / REJECT no third-party DSNs
A second file,
/etc/postfix/null_sender, had
<> 550 no third-party DSNs
In
main.cfI gave thesmtpd_sender_restrictionslist the new entry of
hash:/etc/postfix/null_sender
and also added a new line defining
header_checksas
header_checks = regexp:/etc/postfix/header_checks
Finally I had to run
postmap null_senderas root. - In
master.cfI had to adjust thesmtp unixandrelay unixentries to only do 2 processes, not the default of 20, since having my machine try 20 simultaneous connections to his machine wouldn’t help. Under each, respectively, I had to add
-o smtp_destination_concurrency_limit=2
and
-o relay_destination_concurrency_limit=2
I’m still not positive if the maximum of 2 processes would make these options necessary. I should note that this particular system I was setting up did no other mail delivery, so this change was okay. If you’re doing this on a fully production-level host, you might find a different way to throttle the delivery connections going to a specific host, instead of this change which makes all outgoing mail connections happen only two-at-a-time.
- He’s closed port 25 on his router to try to at least stop the flood. Instead, he’s opening a random port number (like 1767) and having it listen there for new mail. I’ve made postfix deliver it by creating a
/etc/postfix/transportfile with the lines
# 20080327 help fight the flood, tunnel the mail to its real destination, e.g., his server is 1.2.3.4 domain.ie :[1.2.3.4]:1767 .domain.ie :[1.2.3.4]:1767
and ran
postmap transportas root. Intomain.cfI added
transport_maps = hash:/etc/postfix/transport
- After all of this was done, I had to do
postfix restart
The end result, with Justin’s rules in particular, has had thousands and thousands of attempts get blocked trying to get through the door. Some still trickle through, even after the amavis/clamav/spamassassin content filter has processed them.
This is the final accumulation (with a few I already had):
smtpd_sender_restrictions = check_sender_access hash:/etc/postfix/access_sender,
check_sender_access pcre:/etc/postfix/access_sender.pcre,
hash:/etc/postfix/null_sender
header_checks = regexp:/etc/postfix/header_checks
## Steps from http://www.akadia.com/services/postfix_spamassassin.html
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks,
reject_unauth_destination,
reject_unauth_pipelining,
reject_invalid_hostname,
reject_non_fqdn_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
check_recipient_access hash:/etc/postfix/access_recipient,
check_recipient_access pcre:/etc/postfix/access_recipient.pcre,
check_policy_service inet:127.0.0.1:60000,
permit
(The check_policy_service line is for my use of postgrey, another simple step which drastically reduced the amount of spam my own server was getting.)
Please let me know if any of the instructions above prove to not work out properly for you.
P.S. A command I found handy watching the logs to see what was getting through for attempted delivery, even after everything above:
sudo tail -f /var/log/mail.log | egrep -v '((RCPT|connect(ion)?).* from |smtpd_peer_init)'
4 Comments »
RSS feed for comments on this post.
Leave a comment
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
I am not 100% sure but I think many HowTos are mixing some postfix directives in wrong context.
For example reject_non_fqdn_sender is listed in smtpd_sender_restrictions (in man postconf(5)) and not in smtpd_recipient_restrictions (as stated in your and many others HowTos)
I think the following is more appropriate:
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
# warn_if_reject,
reject_non_fqdn_helo_hostname,
reject_invalid_helo_hostname,
permit
smtpd_sender_restrictions =
check_sender_access hash:/etc/postfix/access
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
permit
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_recipient,
reject_unauth_destination,
reject_unauth_pipelining,
reject_unknown_recipient_domain,
permit
Comment by bspinner — April 22, 2008 @ 14:12 GMT
Just wanted to thank you for this. I only needed a very very simplified version (adding a few of the addresses to access to be rejected) and this worked perfectly for me.
Comment by Scott — May 3, 2008 @ 02:51 GMT
I am reading this and having trouble filtering the information I need, but I suspect it is here. I have a domain running dual servers, inbound (FreeBSD, Postfix, Amavisd, ClamAV) and outbound (Qmail on Freebsd). Mail is delivered to inbound, cleaned and passed to user mailboxes on outbound. Users pick up mail from outbound. My problem is that someone decided we hae an account henryxxx@domain.com and we get thousands of spam messages to variants on henry@. henry is almost always the beginning of the recipient address. We do not have a Henry in the system. Can I add a filter to incoming (Postfix) to reject any email addressed to henryx@domain.com where x is any number of random characters? I do not want to bounce or do any processing on them, just get rid of them as quickly and simply as possible.
Comment by Paul Rotenberg — May 14, 2008 @ 18:51 GMT
I think you could add
check_recipient_access pcre:/etc/postfix/maps/access_recipient.pcre
and in that file, put
/^henryxxx@/ ACCEPT
/^henry.*@/ REJECT
or something similar, letting the regular expression block all possible sequences after ‘henry’ except for ‘xxx’, which is accepted initially.
Comment by brendan — May 16, 2008 @ 10:47 GMT