Настройка OpenBSD Spamd


Spamd - это sendmail-подобный демон, задачей которого является отсеивание спама. Если пакетный фильтр PF сконфигурирован таким образом, что бы переадресовать порт 25 (SMTP) на этот демон, то он постарается потратить впустую время и ресурсы отправителя спама. Spamd спроектирован специально для того, что бы не загружать почтовый сервер, для чего обнаруженный спам отклоняется с сообщениями об ошибке 450 или 550. До сего момента борьба со спамом заключалась в том, что мы принимали и отбрасывали такую почту или напрямую блокировали отправителя, spamd же, сконфигурированный на сообщение об ошибке 450, отправит спам обратно отправителю. Spamd лучше всего запускать из rc.

В моей сети нет почтового сервера, поэтому я использую spamd на каждой машине, которая напрямую получает почту. Другими словами, если вы соединяетесь с 25-м портом машины из моей сети, то попадаете в цепкие руки spamd. Не рекомендую этого делать!

Настройка осуществляется следующим образом:
Отредактируйте /etc/spamd.conf таким образом, чтобы получилось нечто, похожее на нижеприведенное:

# $OpenBSD: spamd.conf,v 1.9 2004/01/21 08:07:39 deraadt Exp $

all:
::
Это позволит обрабатывать все соединения.
В /etc/rc.conf добавляем строку:

spamd_flags="-b127.0.0.1 -v -s5 -nWelcome_To_The_Pit"
Для перенаправления трафика spamd, добавьте следущие строки в /etc/pf.conf:

rdr on $ext_if proto tcp from any to port smtp -> 127.0.0.1 port spamd
pass in quick on $ext_if inet proto tcp from any to lo0 port spamd synproxy state flags S/SA
Запускаем spamd:

/usr/libexec/spamd -b127.0.0.1 -v -s5 -nWelcome_To_The_Pit
По умолчанию, логи складываются в /var/log/deamon. Ниже представлен сценарий на Perl, складывающий всю статистику в html файл. В задания cron прописана строка 50 23 * * * /var/www/cgi-bin/PantzSpamdStats.pl >>/dev/null 2>&1, позволяющая запускать этот сценарий периодически.

#!/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.html";

##############################
# 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"> ";
print SPAMDHTMLSTATS "<b><font size="4">Pantz Spamdlog Stats</font></b><br> ";
print SPAMDHTMLSTATS "Script run on: $Month-$Day-$Year $Hour:$Minute:$Second <br><br> ";
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> ";

# 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> ";
$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);

Обновлено: 13.03.2015