Spamd is a fake sendmail-like daemon which rejects false mail. If the pf packet filter is configured to redirect port 25 (SMTP) to this daemon, it will attempt to waste the time and resources of the spam sender. spamd is designed to be very efficient so that it does not slow down the receiving machine. Spam is never accepted, but always rejected with either a 450 or 550 error message. The normal way that spam has been dealt with in the past is to either accept and drop, or outright block. When configured to use 450 responses, spamd takes neither of these actions: it rejects the mail back to the senders' queue. Spamd is best started from rc.
In this config I use spamd on the machine as a straight tarpit. I have no MTA running to do mail transfer. If you want to know how to setup spamd with an MTA like postfix see my spamd configuration page on setting this up. In this configuration if you touch the server on port 25 you get pitted. Don't touch my 25! If your touching a port that has not been advertised to be open your usually up to no good. To lure in spammers if you don't have an static ip signup at dyndns.org for a free dynamic host name that changes with your ip. Run the ddclient software in OpenBSD packages that watches for an ip address to change and updates dyndns if it does. Then post fake e-mail addresses around the net using the dyndns or static hostnames in the e-mail address. Post on places like test newsgroups and free webpages where spammers like to scrape up e-mail addresses. But to be sure your passive about this on webpages do the text in the href mailto: tag but don't put it in the text area so the text will not show up on the webpage. This way you know the mailto: link was scraped from the page by a bot not a human. This way you can put it on webpages and it won't show up as text and will not effect the layout of the page. Some fun example e-mail addresses to post with your new host name (dyndns has a big list of host names) are things like: [email protected] or [email protected]
1. Open /etc/spamd.conf and make it look like the one below. Save it. This will pit all connecitons.
# $OpenBSD: spamd.conf,v 1.9 2004/01/21 08:07:39 deraadt Exp $ all:\ ::
2. Open /etc/rc.conf find the line spamd_flags= and put in "-b127.0.0.1 -v -s5 -nWelcome_To_The_Pit"
3. Put lines below in /etc/pf.conf to redirect to spamd. Put the rdr line at the top before the pass rule. Then save the file and restart pf (pfctl -f /etc/pf.conf).
#Replace any $ext_if with your external interface name. Ex. fxp0. # redirect any connection from the outside to localhost port 8025 (spamd). rdr on $ext_if proto tcp from any to port smtp -> 127.0.0.1 port spamd # allow the access to spamd port on localhost. pass in quick on $ext_if inet proto tcp from any to lo0 port spamd synproxy state flags S/SA
4. Start spamd up with the command "/usr/libexec/spamd -b127.0.0.1 -v -s5 -nWelcome_To_The_Pit"
5. The logs are in /var/log/deamon by default. I've made a Perl script (below) that adds up all the stats and ouputs them to an html file. I have a webserver running on the internal interface and a cronjob set up (50 23 * * * /var/www/cgi-bin/PantzSpamdStats.pl >>/dev/null 2>&1) to run the script every night and dump it to the website directory. Then I can browse to it every day and check out how many spammers are trying to send mail to my fake passive e-mail addresses.
#!/usr/bin/perl ################################ # Start Configuration Settings # ################################ # Set to "all" of you want all files (compressed also) read. # Set to "one" if you just want the one file named "spamd" read. $oneorallfiles = "all"; # Path to spamd logfile(s). No "/" after last dir name. Ex. "/var/log". $spamdpath = "/var/log"; # Spamd log file (daemon by default) $spamdfile = "daemon"; # Path to output html file $spamdhtmlfile = "/var/www/htdocs/spamdstats.shtml"; ############################## # End Configuration Settings # ############################## #####Begin: Assembling date code.##### ($Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay, $DayOfYear, $IsDaylightSavings) = localtime(time); $Month += 1; $Year += 1900; if ($Month < 10) { $Month = "0" . $Month; } if ($Hour < 10) { $Hour = "0" . $Hour; } if ($Minute < 10) { $Minute = "0" . $Minute; } if ($Second < 10) { $Second = "0" . $Second; } if ($Day < 10) { $Day = "0" . $Day; } #####End: Assembling date code.##### #####Begin: Get one or all spamd filenames.##### if ($oneorallfiles eq "all") { @spamdfilenames = <$spamdpath/$spamdfile*>; @spamdfilenames = sort { $b cmp $a } @spamdfilenames; } else { push(@spamdfilenames, "$spamdpath/$spamdfile"); } #####End: Get one or all spamd filenames.##### #####Begin: Read spamd file(s) and input data into a hash of arrays for sorting.##### foreach $spamdlogfile (@spamdfilenames) { open(IN, "gzcat -f $spamdlogfile |") or die ("Can't open file. Permissions?. UserID?"); while( <IN> ) { if ((/spamd/) && (/disconnected after/)) { ($date,$hostname,$daemonandid,$ipaddress,$seconds) = ($_ =~ /(\w+\s{1,2}\d+ \d+:.\d:.\d+) (.*) (.*)\: (\d+\.\d+\.\d+\.\d+)\: disconnected after (\d+)/); # Ipaddress is hash key. Update the 1st value in the array with seconds count calling old seconds count and # adding it to the new count. Update the 2nd value in the array by 1. Count is per unique ip address hit. $spamd_hash{$ipaddress} = [$spamd_hash{$ipaddress}[0] + $seconds,$spamd_hash{$ipaddress}[1] + 1]; } } close(IN); } #####End: Read spamd file(s) and input data into a hash of arrays for sorting.##### #####Begin: Output of HTML file.##### open(SPAMDHTMLSTATS, ">$spamdhtmlfile") or die ("Can't create file"); print SPAMDHTMLSTATS "<html><HEAD><TITLE>Pantz Spamdlog Stats</TITLE></HEAD><div align=\"center\">\n"; print SPAMDHTMLSTATS "<b><font size=\"4\">Pantz Spamdlog Stats</font></b><br>\n"; print SPAMDHTMLSTATS "Script run on: $Month-$Day-$Year $Hour:$Minute:$Second <br><br>\n"; print SPAMDHTMLSTATS "<TABLE BORDER=\"1\"><tr><td align=\"center\"><b>IP Address</b></td> <td align=\"center\"><b>Hits</b></td><td align=\"center\"><b>Seconds</b></td></tr>\n"; # Loop thru the hash of arrays. Sort on the second value in the arrays. Print it. for $ips ( sort { $spamd_hash {$b}[1] <=> $spamd_hash{$a}[1] } keys %spamd_hash ) { print SPAMDHTMLSTATS "<tr><td align=\"center\">$ips</td> <td align=\"center\">$spamd_hash{$ips}[1]</td> <td align=\"center\">$spamd_hash{$ips}[0]</td></tr>\n"; $totalseconds += $spamd_hash{$ips}[0]; $totalhitcount += $spamd_hash{$ips}[1]; $totaluniquehosts++; } $avgpitmin = sprintf("%4.1f",($totalseconds/60)/$totalhitcount); $avgnumhits = sprintf("%4.1f",$totalhitcount/($totaluniquehosts)); $totalpitmin = sprintf("%4.1f",$totalseconds/60); $totalpithr = sprintf("%4.1f",($totalseconds/60)/60); print SPAMDHTMLSTATS "<tr><td align=\"center\"><b>Totals:</b></td> <td align=\"center\"><b>$totalhitcount</b></td><td align=\"center\"> <b>$totalpitmin Mins<br>$totalpithr Hrs</b></td></tr>"; print SPAMDHTMLSTATS "<tr><td align=\"center\"><b>Averages:</b></td> <td align=\"center\"><b>$avgnumhits</b></td> <td align=\"center\"><b>$avgpitmin Mins</b></td></tr>"; print SPAMDHTMLSTATS "</html>"; close(SPAMDHTMLSTATS);