Spam Filtering with Port Forwarding and Geo-Location
This page is a work in progress (started on February 25, 2010)
The procedures outlined in this document should work with any mail server software.
For several years I have been running a small ISP. We regularly receive approximately 20,000 legit emails per day. We use several servers running postfix and amavisd-new. We have servers setup for our MX Records which forward to our mail storage server. We have been using greylisting (policyd v1) until recently when I concluded that it's effectiveness had diminished significantly.
We recently moved all of our servers behind a trusty power-router (mikrotik x86) firewall and I was determined to find a way to use it effectively. With all of the servers having an internal address scheme, I now have control over which mail server handles incoming mail. To this end I added a couple of extra MX records to our primary domain to fool spammers.
First off I wanted to load balance the inbound mail. My two inbound MX Records point to the router's IP's of 199.60.237.4 and 199.60.237.6 which point to the respective inbound mail servers which are behind the firewall. So I created the following nat rules:
add action=dst-nat chain=dstnat comment="Port forward for incoming mail" disabled=no\ dst-address=199.60.237.4 dst-port=25 protocol=tcp src-address=0.0.0.0/1 to-addresses=10.100.100.4 to-ports=25
add action=dst-nat chain=dstnat comment="Port forward for incoming mail" disabled=no\ dst-address=199.60.237.4 dst-port=25 protocol=tcp src-address=128.0.0.0/1 to-addresses=10.100.100.5 to-ports=25 add action=dst-nat chain=dstnat comment="Port forward for incoming mail" disabled=no\ dst-address=199.60.237.6 dst-port=25 protocol=tcp src-address=0.0.0.0/1 to-addresses=10.100.100.5 to-ports=25 add action=dst-nat chain=dstnat comment="Port forward for incoming mail" disabled=no\ dst-address=199.60.237.6 dst-port=25 protocol=tcp src-address=128.0.0.0/1 to-addresses=10.100.100.4 to-ports=25
If you look at the rules you will see that I am directing mail based on the source addresses. If you are in the top half of IPV4 address space then you will hit one server, if you are in the bottom half you will hit the other mail server. This essentially makes both my primary and secondary mx records load balanced, since they are both receiving inbound mail based on the location of the sender. MX Failover continues to work properly in the event that one mail server goes down.
Now here is where it get's interesting. Being that I am in Canada, 97% of legit mail hitting our servers is coming from English speaking countries. A few google searches of SPAM from different regions, reveals that large quantities of SPAM are originating in China, Korea, Brazil, and Russia etc.
So in the interest of fighting SPAM I was curious how I could filter by country. First off I setup a postfix server with some additional rules that I don't normally get away with. Things like reverse-dns helo checks and additional blacklists. I also setup policyd (Version 2) greylisting with a 35 minute window.
So I found the following website and generated a list of english speaking countries IP addresses. [1]
Now I ended up with a list of IP Blocks on the order of 28,000 long. I though that was a bit much and wondered if someone had written a CIDR Compressor and stumbled onto this program. [2] It's linux so you'll have to figure that bit out yourself. Once I had a working file I dumped it into OpenOffice spreadsheet and added the necessary tags to create a mikrotik.rsc file so that I could generate an address list. Due to mikrotik's file size limits that may not work. Instead open up an ssh session to your router and paste the contents into the router. It worked fine, took about five minutes and I had a complete list of all 20,000 english speaking IP Blocks.
Okay now for the fun part. One rule to rule them all!!!
add action=dst-nat chain=dstnat comment="Non-English speaking countries - go to third smtp machine" disabled=no dst-port=25 protocol=tcp src-address-list=!english \
to-addresses=10.100.100.3 to-ports=25
Notice the not (!) symbol in the src-address-list. Put this rule above the other rules. So now you have all inbound foreign mail going to a special server.
Here are some graphs of it's effectiveness. While I don't have before and after graphs it is definitely impressive. The amount of mail/mail attempts reaching my main inbound mail servers has plummeted. The foreign server now receives the majority of the mail attempts. Normal greylisting is about five minutes delay, with a thirty plus minute delay you greatly increase the chance that the sender will have moved on. Also you greatly increase the chance that the sender will have been blocked by some sort of blacklist. Pay careful attention to the rejection levels in these graphs.
First MX Record Server [3]
Second MX Record Server [4]
SPAM (Foreign) Server [5]
The received levels show all of the mail that was accepted for delivery, the sent is the mail that was sent on to our customers. Messages that have a Spam Assassin score of 13+ are automatically discarded. We have never had any false hits.
You will have a massive reduction in the level of attempted traffic hitting your primary mail servers, all of the incoming connection load is transferred off to the Foreign Spam Server. Your maillogs are actually readable again.
You can use this method to target specific countries, depending on where you live. Targeting Asian and South American countries will make a big difference.