Putting the Spamhaus DROP list in FreeBSD’s ipfw
Are you aware of the Spamhaus DROP list? According to the ladies and gentlemen of Spamhaus:
DROP (Don’t Route Or Peer) is an advisory “drop all traffic” list, consisting of stolen ‘zombie’ netblocks and netblocks controlled entirely by professional spammers. DROP is a tiny sub-set of the SBL designed for use by firewalls and routing equipment.
So DROP is simply a short-ish list of CIDR numbers and Spamhaus SBL references, and that we can definitely use in our FreeBSD ipfw rules. There’s a couple of perl scripts in the DROP FAQ, but none of them is suitable for generating ipfw rules, so I went ahead and made my own script. Yup, a good old-fashioned shell script. I don’t speak perl (not very well, anyway), and a shell script can be made equally no-nonsense and portable in my opinion. I operate several internet-facing FreeBSD servers, and they all use this script to generate ipfw rules.
You obviously need ipfw set up and operating on your FreeBSD server or workstation. How you deploy ipfw is up to you, but all “my” servers are already behind other types of firewalls, which means the open mode ipfw is purely a second line of defense set up to block unwanted traffic on common, open ports.
The basic idea behind the script is this:
1. Download the DROP list once a day
2. Compare today’s version to yesterday’s version. Exit if no change
3. Strip out all unneccessary info and generate ipfw syntax around the CIDR blocks
4. Write the converted DROP list to a file
5. Include the file in /etc/rc.firewall (or whatever script your ipfw rules are in)
6. Flush the ruleset and load it again
Here’s the script (comments and all). I try to not be a smartass while scripting, so please excuse the lack of finesse and obscure commands. If you want to fetch the script directly, use this link.
#!/bin/sh # Generates an IPFW-format deny list based on the Spamhaus DROP list # http://www.spamhaus.org/drop/ # # Example ipfw rule: # ipfw add [nnnn] deny log tcp from 63.148.99.0/24 to 192.168.1.1 # # Released into the public domain by Break Left Outings # 20070724/twa ############################################ # Change these to suit your installation ############################################ # The starting ipfw rule number I=50000 # The interface you want protected. IFACE=192.168.1.1 # Rules will be written to this file. Remember to include it near the end # in your "real" ipfw rules script with ". /filename" IPFWSCRIPT=/usr/local/etc/ipfw.DROPlist REALIPFWRULES=/etc/rc.firewall ############################################ # No need to change anything below here! # Vars DROPLIST=http://www.spamhaus.org/drop/drop.lasso LOCALNEWFILE=/tmp/droplist.new LOCALOLDFILE=/tmp/droplist.old TMP=`mktemp -t tmpdroplist` TMP1=`mktemp -t tmpdroplist` TMP2=`mktemp -t tmpdroplist` # fetch the list fetch -q -o $LOCALNEWFILE $DROPLIST if [ $? -ne 0 ] ; then echo "`date`: makedroplist failed to fetch $DROPLIST. Aborting" exit 0 fi # # Compare the old and new file # No need to generate new rules if nothing have changed # # if old DROP list have disappeared, create a dummy if [ ! -f $LOCALOLDFILE ] ; then echo "Spamhaus DROP List" > $LOCALOLDFILE fi # Remove first line from both files to ensure a real comparison # Spamhaus seems to change the first line every day, even if there are no changes grep -v "Spamhaus DROP List" $LOCALOLDFILE >$TMP cp $TMP $LOCALOLDFILE grep -v "Spamhaus DROP List" $LOCALNEWFILE >$TMP cp $TMP $LOCALNEWFILE # # Use diff to see if they are different. We don't need to know WHAT has been changed # /usr/bin/diff -q $LOCALNEWFILE $LOCALOLDFILE >/dev/null if [ $? -eq 0 ] ; then # Be quiet when nothing has changed. Uncomment next line if you need to know #echo "`date`: makedroplist: DROP list not changed. Exiting" rm -f $TMP $TMP1 $TMP2 $LOCALNEWFILE exit 0 fi # Clean up the file. We only want the CIDR blocks for ipfw #echo "cleaning up" cat -s $LOCALNEWFILE | cut -f 1 -d ";" | tr -d " " >$TMP # Get rid of blank lines in file sed '/./,$!d' $TMP >$TMP1 sed -e :a -e '/^n*$/{$d;N;};/n$/ba' $TMP1 >$TMP2 # Write a comment header etc, to the script echo "#!/bin/sh" >$IPFWSCRIPT echo "# The Spamhaus DROP list in IPFW format" >>$IPFWSCRIPT echo "# See http://www.spamhaus.org/drop/ for details" >>$IPFWSCRIPT echo "# This file was generated on `hostname`, `date`" >>$IPFWSCRIPT # Generate the ipfw rules while read line ;do echo "/sbin/ipfw -q add $I deny log all from $line to $IFACE" >>$IPFWSCRIPT I=`expr $I + 1` done < $TMP2 # Load the rules sh $REALIPFWRULES # Clean up and exit rm -f $TMP $TMP1 $TMP2 $LOCALOLDFILE mv -f $LOCALNEWFILE $LOCALOLDFILE echo "`date`: ipfw rules successfully generated from $DROPLIST" # End of script
To have the DROP rules included in your regular ipfw rules, use the following lines near the end of your regular rule set (e.g. /etc/rc.firewall):
# Load the generated rules from the Spamhaus DROP list . /usr/local/etc/ipfw.DROPlist
Basically, that’s it. Put in crontab and run it once a day or every other day. If a new list is loaded, you’ll get a mail telling you so. If you don’t want to be notified, comment out the final echo statement. The DROP list changes no more than once a week in my experience, so there’s no need to hammer Spamhaus with hourly cronjobs!
Please use the comments if you have any questions or suggestions.
august 5th, 2009 at 8:21
I have modified your script to generate rules for the OpenBSD PF.
http://blog.devnull.ro/node/138
oktober 3rd, 2009 at 2:28
too more sed / awk ?
fetch http://www.spamhaus.org/drop/drop.lasso
grep SBL drop.lasso | awk -F ” ” ‘{print $1}’ |while read m;do ${fwcmd} add reject ip from `echo $m` to me;done
for cleaning file try:
curl -s http://www.spamhaus.org/drop/drop.lasso | grep SBL | awk -F ” ” ‘{print $1}’
or
curl -s http://www.spamhaus.org/drop/drop.lasso | grep SBL | awk -F ” ” ‘{print $1}’ >> clean-drop-file
oktober 3rd, 2009 at 22:42
[…] Sugerør […]
august 13th, 2012 at 7:02
Another script for *BSD with pf, using a table: http://www.neant.ro/2012/07/script-to-add-spamhaus-drop-list-to-pf/ . Written on OpenBSD, should work just fine on any BSD.