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_maps
hash 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_restrictions
the line
check_recipient_access hash:/etc/postfix/maps/access_recipient
and created the file
/etc/postfix/access_recipient
containingpostmaster@domain.ie REJECT MAILER-DAEMON@domain.ie REJECT
and then ran
postmap access_recipient
as root. I should note I did not put a line likedomain.ie OK
which would have let all other mail for the domain go through—but usurped any other rules thatsmtpd_recipient_restrictions
may try to do after my access_recipients entry. - I created a
/etc/postfix/access_sender
file 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_sender
as root. Inmain.cf
, forsmtpd_sender_restrictions
I addedcheck_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-pcre
Debian package, I created a new file/etc/postfix/access_sender.pcre
with the lines
/.*bounces\@/ REJECT /confirm-return.*\@/ REJECT
and in
main.cf
gavesmtpd_sender_restrictions
yet another entry ofcheck_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_checks
and 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.cf
I gave thesmtpd_sender_restrictions
list the new entry ofhash:/etc/postfix/null_sender
and also added a new line defining
header_checks
asheader_checks = regexp:/etc/postfix/header_checks
Finally I had to run
postmap null_sender
as root. - In
master.cf
I had to adjust thesmtp unix
andrelay unix
entries 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/transport
file 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 transport
as root. Intomain.cf
I addedtransport_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_senderheader_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)'