Spam filtering with OpenBSD and making spamming a little harder

Spam is the most annoying thing I have to deal with every day on my servers. Only 3-4 spams make it daily all the way to my inbox, but I got tired of thinking about all the energy wasted by sysadmins blocking unwanted messages, so I decided to do something about it. It is too easy and cheap for spammers to send unwanted messages via email right now, and they might even make money from it. Recipients on the other hand must bear the cost of managing incoming spams. To make spamming a little more difficult, I set up tarpits to increase usage of spammers' resources.

Whenever a bot is busy wasting time on one of my tarpits, it is not sending spam. Spammers get payed by volume and every time someone slows them down they are losing revenue. On my spamtrap machine, by holding connections open for as long as possible, I am wasting more than 720 hours (30 hours per day) worth of spammer connection time. The spamtrap also helps me to build my blacklist and therefore improves my spam filter.

To annoy the spammers I use spamd. Spamd is a lightweight spam-deferral daemon. Spamd is a fake SMTP-like daemon designed to work in conjunction with pf(4). It runs on any machine with OpenBSD, NetBSD, FreeBSD or any BSD Like system.

Spamd works by sitting between the sender and the MTA, blocking all the undesired connections before they reach the SMTP server. Spamd offers features such as Blacklisting, Tarpitting, Greylisting and SpamTrapping. It doesn't replace a mail filter but greatly limits the number of connections reaching the real mail server.

In this post I am going to explain how I have configured spamd on my network. Once the sender IP address has been cleared by spamd, the mail is then handled by my real SMTP server. Please refer to your documentation to setup an SMTP server.

Spamtrap and tarpit, how it works

I am luckyto have 2 machines in 2 different locations, but this configuration can also be done with one machine or two machines in the same location. The machine in Location 1 is hosting my MTA. The MX record for my domain name points to that machine. This machine also runs spamd to greylist all the incoming SMTP connections, before they are sent to my SMTP server.

The machine in Location 2 is a spamtrap and doesn't handle any real email. I have a few domain names that were popular a long time ago but that haven't beeng in use for a dozen of years. In theory ---in a world without spammers--- these domain names shouldn't receive any email. Unfortunately spam bots are sending an average of 25,000 emails per hour to these domain names. Once a spammer connects to that machine its connection is slowed down to one character per second, holding the connection for as long as possible. Its IP address is also put in a blacklist. That blacklist is then synchronized with the main mail server. The main mail server will benefit from the bad IP addresses learned by the spamtrap.

The main mail server is a simple rack mount PC hosting several services. It is noteworthy that the spamtrap is running on a small 1GHz machine with 256MB of ram and no disk, (see picture on the right). That box only consumes 14 Watts of energy and can gather many spambot IP addresses with little impact on your electric bill. The operating system is an embedded version of OpenBSD. The system is booted from a 2GB flash. This machine is powerful enough to handle several hundred simultaneous connections from mail bots. While I am writing this post the spamd is handling 1600 simultaneous SMTP connections and I have enough resources to easily have 4 to 5 times more connections.

In this graph you can see the number of IP addresses trapped and blacklisted by the SMTP server.

trapped addresses

Spamtrap and Tarpit configuration

Location 1

The Location 1 runs spamd and exim on my main mail server.

If an SMTP server connects to the machine for the first time, pf checks if the IP address is in the whitelist. If the IP address of the sender is whitelisted, pf sends the connection directly to exim for normal email processing. If the address is not in the whitelist, the connection is sent to spamd on the port 8025. Spamd emulates an SMTP server, but cuts the connection with a temporary error (error 450), forcing the sender to resend the mail later. The IP address is then placed in the greylist. Next time the SMTP sever will connect to try to send the same email, the IP address will be placed in the whitelist and pf will let that connection go through and reach the SMTP server.

For more details on how greylists works, you can read the Wikipedia page.

Here is the part of my /etc/pf.conf file that blocks the IP addresses that are blacklisted, sends the new connections to spamd and lets the whitelisted IP addresses go to the SMTP server.

# spamd-sync
pass in quick log on $out_if inet proto udp from $spamtrap to $mainserver \
    port spamd-sync

# spamd tables definitions
table <spamd-white> persist
table <nospamd> persist file "/var/db/whitelist.txt"
table <localtmp> persist
table <localblack> persist file "/var/db/local-black.txt"

# block all the ip addresses that are blacklisted
block in quick log on $out_if proto tcp from <localtmp> to any port smtp
block in quick log on $out_if proto tcp from <localblack> to any port smtp

# Incoming connections that are whitelisted goes directly
# to the smtp server
pass in on $out_if proto tcp from <nospamd> to any port smtp
pass in on $out_if proto tcp from <spamd-white> to any port smtp

# send the new incoming connections to spamd
pass in on $out_if proto tcp from any to any port smtp rdr-to 127.0.0.1 \
    port spamd

On lines 2 to 3 you can see the rule allowing the incoming UDP spamd-sync connections from the machine in the Location 2. This allows the machine running the spamtrap to send the list of the IP addresses that have been blacklisted.

The following file is the configuration file for spamd /etc/mail/spand.conf, containing my personal whitelist and personal blacklist. I usually don't use blacklist found on the internet because I don't trust them. Sometimes they are too restrictive or out of date. The good lists are usually not free and are too expensive for a personal use. I simply rely on the greylisting mechanism provided by spamd and my own spamtrap to block the majority of the bots. I also use SpamAssassin on the mail server to classify the spam for the remaining emails that reach the server. The greylist blocks about 98% of the illegitimate connection to my MTA.

# spamd(8) configuration file, read by spamd-setup(8).
# See also spamd.conf(5).
#
# Configures lists for spamd(8).
all:\
        :override:localblack:

override:\
        :white:\
        :method=file:\
        :file=/var/db/override.txt:

localblack:\
        :black:\
        :msg="SPAM. Your address %A appears to be in our local blacklist":\
        :method=file:\
        :file=/var/db/local-black.txt:

The following lines need to be added to your /etc/rc.conf.local file to automatically start spamd at boot time.

spamd_flags="-5 -G8:4:864 -y xx.xx.xx.xx -S 16 -n \"Postfix (Debian/GNU)\""
spamlogd_flags="-i em0"
  • -5 For blacklisted entries, return error code 550.
  • -G8:4:864 passtime:greyexp:whiteexp Adjust greylisting timeouts.
  • -y xx.xx.xx.xx allow spamd receive synchronization messages from the spamtrap server xx.xx.xx.xx should be replaced by the IP address of the spamtrap machine.
  • -S 16 Stutter at greylisted connections for 16 seconds
  • -n "Postfix (Debian/GNU)" Name shown in the SMTP banner. (I know... I am lying here)

Location 2 (Spamtrap)

The Location 2 runs on a tiny client described earlier in this post running an embedded version of OpenBSD. This machine does not handle any real email. All the emails coming to this machine are sent to expired domain names, and email addresses that have never existed.

OpenBSD's pf sends all the connections to the SMTP port to spamd listening on its default port 8025. I could have spamd directly run on the SMTP port, but this configuration allows me to change the pf rules to do DoS mitigation in case of an attack. For example, in the following rule I only accept 2000 connections at a rate of 50 connections per minutes (line 5). Once the threshold is reached the ip address of the offender is placed in the smtpforce for one hour.

table <smtpforce> persist

pass in on $out_if inet proto tcp from any to ($out_if) port smtp \
        flags S/SA synproxy state \
        (max-src-conn 2000, max-src-conn-rate 50/60, \
        overload <smtpforce> flush global) rdr-to lo0 port spamd

Don't forget to add the following line to your root crontab to expire the IP addresses that are in the smtpforce table after an hour.

0   *   *   *   *   /sbin/pfctl -t smtpforce -T expire 3600

The following lines from the file /etc/rc.conf.local containing the flags for starting spamd.

spamd_flags="-5 -c 1600 -h mytrap.com -l 127.0.0.1 \
    -n 'Postfix (Debian/GNU)' -S 60 -Y yy.yy.yy.yy"
spamlogd_flags="-i rl0"
  • -5 For blacklisted entries, return error code 550. I could return an error 450, but I want to give a chance to a legitimate SMTP servers to unsubscribe this email address from its lists, or to a real person to get a bounce message as soon as possible.
  • -c 1600 The maximum number of concurrent incoming connections.
  • -h mytrap.com The hostname that is reported in the SMTP banner.
  • -l 127.0.0.1 Specify the local address to which spamd is listening to.
  • -n "Postfix (Debian/GNU)" Name shown in the SMTP banner.
  • -S 60 Stutter at greylisted connections for 60 seconds.
  • -Y yy.yy.yy.yy This is the IP address of the machine to send the blacklist notifications.

The spamd configuration file located in /etc/mail/spamd.conf contain the following lines.

#
all:\
        ::

The most important file is the file /etc/mail/spamd.alloweddomains. This file lists the domain names allowed to receive email from the outside. All email sent to any other domain than the ones listed in that file will be tarpitted and then blacklisted.

fred$ cat /etc/mail/spamd.alloweddomains
randomfakedomain.com

All imcoming SMTP connections to that machine will be tarppited and their IP addresses will be blacklisted. The blacklisted IP addresses will be sent to my real SMTP server, allowing it to block spammers.

It is also important that you maintain a good whitelist. You'll need to create a whitelist containing the IP addresses of all the majors mail services such as yahoo, gmail, hotmail, etc. Since these services are also used by small spammers, you may end up completely blocking them. By whitelisting these big providers you ensure that their emails will be delivered without delay and they will be not get blocked.


Comments !