Recently I've been seeing an awful lot more bounced mail addressed to my domains, to the extent that I now wonder whether they are deliberate "attacks".
Over the past four or five years I'd expect to receive one joe-job attack every six months. Over the past two that's risen to once every two months. For the past two months its been once a week.
I run several domains on my Xen guest, and most of those domains rarely have mail received, so there are only a few localparts. (A "localpart" is the bit before the @ sign in an email address.)
My main domain is steve.org.uk and unfortunately this was historically setup with "catchall" behaviour. I used that wildcard expansion pretty seriously so I had localparts such as "slashdot.org", "lwn.net", etc. Over time I've stopped making up new addresses and just stuck with "steve".
Still I'd never quite gotten round to enumerating all valid localparts, instead I tried to mitigate against these rare bounce storms with various simple hacks. For example the following procmail recipe to file away bounces:
However this doesn't work as well as it used to - too many
idiots people are using challenge/response systems so I'll receive a reply to a mail I didn't send which doesn't look like a bounce (ie. There is a real envelope sender.)
In short blocking bounces by detecting an empty envelope sender is not a complete strategy these days. I started down the heuristic path blocking mail to "unlikely" localparts via patterns such as:
[0-9]@ DENY Localparts never end in digits
, DENY Localparts never contain a comma
| DENY Localparts never contain PIPES.
^([^a-zA-Z]) DENY Localparts start with a-z/A-Z
" DENY Quotes are never used in accounts on this system:
' DENY Quotes are never used in accounts on this system:
That was actually a simple change to make, via the addition of a new QPSMTPD plugin and it managed to block a lot of the bounceback spam - regardless of the envelope sender. For example:
IP:188.8.131.52 sender:<> Recipient:firstname.lastname@example.org
IP:184.108.40.206 sender:<> Recipient:email@example.com
Blocking "unlikely" localparts wasn't perfect, but without implementing BATV or enumerating valid localparts there wasn't too much else that I could do. In terms of numbers yesterday I blocked just over 18,500 messages with these six rules.
I also wrote a couple of cronjobs to look at the contents of the Automated.bonces folder so that I could add per-user rejections on the specific addresses being received - with some whitelisting.
(For example if I received 20+ bounces to firstname.lastname@example.org within the space of ten minutes I'd drop further mails to that address automatically.)
Anyway enough is enough. Today I woke up to just over 40,000 replies to mails I didn't send. I've now scanned my mail directories for all the email addresses I've ever used and will now only accept mail destined to those localparts.
Thankfully it turned out that since 1999 (when steve.org.uk was registered) I've only used about 150 distinct localparts, and many of those are now obsolete. So hopefully I'll now have less of a problem.
It seems to be paying off already:
220.127.116.11 wpc0505.host7x24.com <> virtual_rcpt_ok
901 mail to email@example.com not accepted here (#5.1.1)
18.104.22.168 cobra.compukey.net <> virtual_rcpt_ok
901 mail to firstname.lastname@example.org not accepted here (#5.1.1)
22.214.171.124 box19.fuitadnet.com <> virtual_rcpt_ok
901 mail to email@example.com not accepted here (#5.1.1)
In the future this means I could still get flooded with bounces, but there will be two outcomes:
- The bounces will not hit valid localparts and will be dropped easily, quickly, and cheaply.
- The bounces will hit valid localparts:
- Real bounces will end up in Automated.bounces/
- Challenge/Response things will still reach me. Sigh.
Still this is progress and I can steal some ideas from this great spam filtering service (ahem) to improve the handling of those! (I explicitly chose to use a similar but different system for my personal mails. Even though my support system is on another box I want to avoid problems where failures requiring human intervention are swallowed in the same way that the original one was. Those kind of reasons mandate a similar system but different implementation.)
I guess I could publish some of the qpsmtpd plugins I use locally virtual_rcpt_ok, virtual_badusers, rcpt_pattern_test, etc. Then again most people who do funky things with qpsmtpd will have plenty of choice already.
ObFilm: Monty Python's Flying Circus. (OK technically not a film. Sums up my mood though.)