Implementing Greylisting on FreeBSD

There are a number of ways of tackling spam coming into an ISPs mail servers each with it’s own issues.

1. Sender Verification.

Prior to an email being allowed to enter your mail server; the mail server associated with the senders domain is looked up and a “ring back” is attempted to see if the mail server would accept a reply. The idea here being that if a you receive and email and need to bounce it, you need to know that the sender really exists on the service they say they exist on.

2. Dropping protocol violators

When a connection is made to your mail server you would expect connections to follow the SMTP protocol in a way you would expect. So for example if a connection came in from a mail server to one of you inbound only MX’s and it advised you it was one of your own servers then it’s likely to be bogus. You can be very pedantic ensuring for example that the dns forward and reverse entries match. Or you can ensure that a correctly formatted HELO/EHLO message is found for example. The problem with these is that you cannot afford too many false possitives if you have paying customers expecting to receive their email.

3. Realtime black lists

One of the most successful solutions we have deployed is RBL’s particularly SPAMHaus and SpamCop. Unfortunately we were still allowing a considerable amount of spam through.

4. SpamAssassin

We found SpamAssissin to be problematic on two fronts. Firstly you had to teach it by receiving spam in the first place and secondly it hasn’t been very scaleable. I have looked at slowing the queues down so as not to overwhelm the Spam Assissin processes but this just delays email too much.

Whilst looking around for a solution to this issue I started to investigate GreyListing which appears to have two flavours.

1. Trusting a mail server to send email unless it sends too much in which case start delaying it.

2. Initially advise the inbound mail server you are too busy. Then if they come back between 5mins and 12 hours later assume they are okay and then let them in.

Since spam is really only successful by sending literally thousands (if not more) messages through in the shortest possible time. Then it doesn’t match the normal pattern of an email server. Which will try to send some email and if not successful will be more that happy to try again say every 15 mins, expanding to several hours.

Due to the robustness of the I/O in the BSD kernel I had elected to go with FreeBSD instead of Linux. And I managed to piece together a very simple Grey Listing solution that is exceptionally scaleable 2 – 4 millions inbound connections per server per day, and has proven to be very effective.

The solution consists of a number of quite simple steps:

1. Edit the /etc/rc.conf adding the following lines :

pf_enable="YES"
pflog_enable="YES"
pf_rules="/etc/pf.conf"

obspamd_enable="YES"
# options em1 in this case refers to the interface used to allow multiple boxes to communicate.
obspamd_flags="-v -G5:13:864 -y em1 -Y em1"
obspamlogd_enable="YES"

2. Install the application spamd from /usr/ports/mail/spamd as follows :

cd /usr/ports/mail/spamd
make install distclean

3. Create the file /etc/pf.conf – this is the firewall config to contain the following :

## MACROS
EXT_IF="em0"
PUBLIC_TCP_PORTS="{ 25 }"

## TABLES
table <spamd-white> persist
table <spamd-mywhite> persist file "/var/db/spamd_whitelist.txt"
## GLOBAL OPTIONS
set skip on lo0
set skip on em1  - change this to your internal interface if you have one
## TRAFFIC NORMALISATION
scrub in on $EXT_IF all fragment reassemble
scrub out on $EXT_IF all fragment reassemble random-id no-df

## TRANSLATION RULES
rdr pass inet proto tcp from <spamd-mywhite> to $EXT_IF port smtp -> 127.0.0.1 port smtp
rdr pass inet proto tcp from <spamd-white> to $EXT_IF port smtp -> 127.0.0.1 port smtp
rdr pass inet proto tcp from any to $EXT_IF port smtp -> 127.0.0.1 port spamd

## FILTER RULES
block in log on $EXT_IF all
pass in quick on $EXT_IF proto tcp from any to $EXT_IF port $PUBLIC_TCP_PORTS synproxy state
pass in quick on $EXT_IF proto icmp to $EXT_IF keep state
pass out quick on $EXT_IF proto { tcp udp icmp } all modulate state

4. Create the file /var/db/spamd_whitelist.txt to contain safe senders :

#eg:
10.0.0.0/8
172.168.0.0/12
192.168.0.0/16

5. Edit /usr/local/etc/spamd/spamd.conf adding fixed white and blacklists :

all:
:uatraps:nixspam:whitelist:

# University of Alberta greytrap hits
# Addresses stay in it for 24 hours from time they misbehave.
uatraps:
:black:
:msg="Your address %A has sent mail to a ualberta.ca spamtrapn
within the last 24 hours":
:method=http:
:file=www.openbsd.org/spamd/traplist.gz

# Nixspam recent sources list.
# Mirrored from http://www.heise.de/ix/nixspam
nixspam:
:black:
:msg="Your address %A is in the nixspam listn
See http://www.heise.de/ix/nixspam/dnsbl_en/ for details":
:method=http:
:file=www.openbsd.org/spamd/nixspam.gz
# Whitelists are done like this, and must be added to "all" after each
# blacklist from which you want the addresses in the whitelist removed.
#
whitelist:
:white:
:method=file:
:file=/var/db/spamd_whitelist.txt:

6. Add cronjob to update spamd :

crontab -e

38 * * * *    /usr/local/sbin/spamd-setup > /dev/null 2>&1

(each server is configured at a slightly different hourly offset)

7. Amend your mail software to only listen on ip address 127.0.0.1

8. Reboot the server.

Ensure you have access to the console of the server just in case you have got you pf.conf file wrong and there by locking yourself out.

To monitor how things are going spamdb is your friend. Without parameters is will dump the current list of GREY/WHITELISTED entries and with the -a parameter it will add another address (I haven’t managed to add a network range this way to do that I needed to edit the whitelist file in /var/db).

To see how things are going :

mymx1# spamdb | cut -b 1-4 | sort | uniq -c
1200642 GREY
200318 WHIT

This shows you how many addresses are grey and how many are whitelisted.

The other command to know if pfctl a few examples of command options are as follows but it is a whole subject in it’s own right.

pfctl -t spamd-white -T show

will list the addresses in the whitelist table.

pfctl -sa

will list all the current information on what the packet filter is up to.

pfctl -sr

will list the rules

Good luck

Mick