Implementing nolisting in cPanel using exim

by brian on October 31, 2011

Nolisting is a spam-avoidance scheme which tricks the spammers into giving up when trying to send us spam.  It can result in 50-60% spam reduction on heavily spammed domains and does not use any server load as the spammers don’t even get to connect. [ The 60% figure was measured in 2008 but the technique is expected to be less effective these days (2011).]

More specifically, nolisting tricks the spammers into talking to IPs that ignore traffic, whereas normal mailers go on to talk to the real mail system.

NoListing works through MX records, by listing pseudo mail servers that reject email as the lowest and highest priority MX mail servers.  A normal server will connect to the lowest MX, get an immediate failure, then retry the second MX (which works) and successfully send email.  A spammer will connect to the highest record (as they often have the weakest anti-spam) and get a slow deny (as we want to annoy them).

When setting up MX records for nolisting, we propose the use of a set of 3 MX records where the middle one works, and the lowest rejects connection attempts quickly (to help real mailers) and the highest rejects slowly (as only spammers connect to it).  Some other examples on the net use only one extra fake MX (as a high MX) but it’s not as effective as the high/low double whammy we are using.

For a sample domain with nolisting active, look at whitedoggreenfrog.com.  We’ve been using this setup since approximately 2007 on multiple high-volume domains.

I don’t recommend using this on every domain, we only use it on high-spam domains.  Also, we’ve only used this on cPanel servers but it would work just as well on non-cPanel systems.

NOTE: remember the rule that you must use A records only for MX records, do not ever use a CNAME as some emailers may not work with it (it’s against the official rules, God knows why; IP addresses are also forbidden).  Breaking this rule can lead to weird and untraceable email failures.

Nolisting IPs are defined in /etc/csf/csfpost.sh at this point and the scripts check the active firewall rules to find active nolisting IPs.

Technical details

We had to develop what appear to be industry firsts to get this to work reliably.  We had to deallocate an IP from exim (which by defauilt listens on all IPs) and also get CSF to reliably block the IPs correctly (ie fast and slow blocking, reliably).

Exim delisting

The exim delisting is done through a script /usr/local/sbin/build.exim.iplist which when run regenerates a small file /etc/exim.iplist listing the valid email listening IPs on the server – ie all the server IPs with the nolisting IPs removed.

The script finds the nolisting IPs by using “csf -l” (same as iptables  -l, roughly) to list the IPs refusing port 25 connections.  The build.exim.iplist script is called from /scripts/posteximup which is run after every exim update.  It is also called from /etc/csf/csfpost.sh which is run every time the CSF firewall restarts.  Perhaps it could be called from elsewhere (like cron, for example) but what’s there now is sufficient to be pretty stable over some years.  If you are running this without cPanel you’ll need to ensure that exim.iplist is rebuilt regularly in similar fashion.

The small file generated by the build script is /etc/exim.iplist and it is included from exim by a line in the exim config:

.include_if_exists /etc/exim.iplist

This means that exim will work even if the file is not present.

To insert this line, go into WHM Exim Configuration Editor – Advanced Editor (at bottom) – put it in the very first block visible, at the top under “cPanel Exim 4 Config” and save.  Do not manually edit this in, as it will then be removed when the file is next edited or when cPanel is in the mood.

The reason for the need for this is that when routing email between multiple servers exim will get upset when you share nolisting IPs between servers, as it won’t be able to work out why it is trying to send email to itself.  That is, if we use one of our server’s nolisting IPs on a domain on another server, and try to send email to it, our server will think it is trying to send email to itself and will refuse unless this trick is used to remove the IP from the list that exim thinks it owns.

CSF blocking

CSF calls a script /etc/csf/csfpost.sh after every reboot and restart.  This script exists on the servers providing nolisting IPs (not all servers have them setup, or need to, as they can be shared around servers).  This script has the IPs for blocking hardcoded into it for now, although eventually they should go in a small config file (currently this script is the only place they are defined, the exim script uses csf -l to work them out).

The csfpost.sh file uses an iptables call to apply either fast blocking (REJECT, instantaneous deny with TCP RST) or slow blocking (DROP – packet silently ignored, sender takes 45s or more to timeout).

You can easily test this by connecting to an IP with nolisting active on port 25 – you get an immediate reject on the fast port and a slower reject on the slow port:

 [minka:/etc]# telnet 203.88.12.11 25
Trying 203.88.12.11...
telnet: connect to address 203.88.12.11: Connection refused
telnet: Unable to connect to remote host: Connection refused

Needless to say, don’t host domains on these IPs as they will not get their email!  (or, if you do, use their MX records to channel their incoming email through another IP).

The download below contains the three files – /etc/csf/csfpost.sh, /usr/local/sbin/build.exim.iplist and a sample one-line /scripts/posteximup in a tar.gz file.  They’ll need to be installed in the appropriate directories.  The scripts require CSF, though as mentioned they could run without it, and similarly for cPanel.

Download exim_nolisting.tar.gz [537 downloads] gz

Previous post:

Next post: