Отслеживание спама Теперь когда


На некоторых сайтах ведутся локальные черные списки узлов, известных как распространители спама. Такая тактика была взята на вооружение, когда спам только начал появляться, и некоторые провайдеры отказывались принимать меры даже против самых закоренелых клиентов-спамеров. В ответ на это в основных агентах передачи почты появились механизмы, отвергающие соединения от узлов и доменов, входящих в список антисоциальных.

Можно использовать такой черный список, чтобы разобраться, проходило ли сообщение через узлы, известные своим спамерством. Ясно, что в черном списке нет сервера, передавшего нам почту (иначе с ним просто не было бы установлено соединение), но любой из остальных почтовых серверов, указанный в заголовках Received:, вполне может там быть.

Не существует способа написать одну программу, проверяющую все возможные черные списки агентов передачи почты, поскольку разные агенты хранят эту информацию в различных форматах. Большая часть узлов в Интернете в настоящее время применяет в качестве агента передачи почты sendmail, так что в нашем примере будет применяться его формат черного списка. В новых версиях sendmail черный спи- сок хранится в базе данных при помощи библиотек Berkeley DB 2.X, доступных на http://www.sleepycat.com.

Поль Маркес (Paul Marquess) написал модуль BerkeleyDB, специально предназначенный для работы с библиотеками Berkeley 2.x/3.x. Это может сбить с толку, поскольку в документации по DB_File, еще одному известному модулю Маркеса, входящему в состав дистрибутива Perl, также рекомендуется применять библиотеки 2.х/З.х. DB_File использует библиотеки Berkeley DB 2.х/З.х в «режиме совместимости» (в частности, библиотека собирается с ключом --enable-compat185, так что доступен API версии 1.x API). Модуль BerkeleyDB позволяет программисту на Perl применять расширенные возможности из API версии 2.х/З.х.

Агент передачи sendmail использует формат BerkeleyDB 2.х/З.х, так что нужно включить модуль BerkeleyDB. Вот пример, который выводит содержимое локального черного списка:

Sblacklist = "/etc/mail/blacklist.db"; use BerkeleyDB;

Ясвяжем хэш %blist с черным списком, используя Berkeley DB

# для получения значений

tie %blist, 'BerkeleyDB::Hash', -Filename => Sblacklist or die

"Невозможно открыть файл $filenane: $! SBerkeleyDB::Error\n" ;

# обходим в цикле каждый ключ и значение из этого файла, и

выводя только записи REJECT while(($key,$value) = each %blist){

в списке также могут быть записи "OK", "RELAY" и др. next

if ($value ne "REJECT");

print "$key\n": }

Принимая за основу этот код, можно написать подпрограмму, проверяющую, находится ли данный узел или домен (содержащий этот узел) в черном списке. Если нужно узнать об узле mallserver.spam-mer.com, следует обойти в цикле все записи из черного списка (в котором могут находиться mailserver.spammer.com, spammer.com или даже просто spammer), чтобы проверить, содержатся ли в имени узла какие-либо записи из него.

Существует много способов написать на Perl программу, сравнивающую список значений с какими-либо данными. Но для того чтобы программа была эффективной и интересной, мы будем использовать две продвинутые технологии. Они созданы для уменьшения числа компиляций регулярных выражений, которые применяются в ходе выполнения программы. Каждый раз, когда программа использует «новое» регулярное выражение, Perl должен компилировать его заново. Например, в этом отрывке кода Perl вынужден обрабатывать новое значение на каждой итерации:



вообразите себе внешний цикл, в котором этот код вызывается

множество раз

foreach Smatch (qw(alewife davis porter harvard central кепааН park))

{

Sstation =" /Smatch/ and print "found our station stop'": }

Этот процесс требует больших вычислительных затрат, так что если бы можно было сократить количество вычислений, программа стала бы намного эффективней. Время, потраченное на компиляцию регулярных выражений, становится значительным в программах, где в цикле рассматривается список различных регулярных выражений.

Вот пример первой технологии, созданной для решения указанной проблемы:

use BerkeleyDB;

Sblacklist = "/etc/mail/blacklist.db";

&loadblist;

и принимаем имя узла в качестве аргумента командной строки и

сообщаем, если оно есть в черном списке

if (defined &checkblist($ARGV[0])){

print "*** $found найден в черном списке \п"; }

И

загружаем черный список в массив анонимных подпрограмм sub loadblist{

tie %blist, 'BerkeleyDB::Hash', -Filename => Sblacklist or die

"Невозможно открыть Sfilename:

$! $BerkeleyDB::ErrorXn" ;

while(my($key,$value) = each %blist){

# в черном списке могут быть "OK", "RELAY" и пр. next if ($value ne "REJECT");

push(@blisttests, eval 'sub {$_[0] =~ \Q$key/o and $key}'); } }

sub checkblist{

my($line) = shift:

foreach Ssubref (@blisttests){

return Sfound if (Sfound = &$subref($line)); }

return undef: } В этом примере используются анонимные подпрограммы - технология, продемонстрированная в книге Джозефа Хола (Joseph Hall) «Effective Perl Programming» (Эффективное программирование на Perl) (Addison Wesley). Для каждой записи из черного списка создается анонимная подпрограмма. Каждая подпрограмма сверяет переданные ей данные с одним из элементов черного списка. Если они совпадают, такая запись возвращается. Ссылки на эти подпрограммы хранятся в списке. Вот строка, в которой создается подпрограмма и ссылка на нее добавляется к списку:

push(@blisttests, eval 'sub <$_[0] =" /\0$key/o and $key}');

Так что, если в черном списке есть запись spammer, ссылка на код, добавленная в массив, будет указывать на подпрограмму, по сути эквивалентную следующей:

sub {

$_[0] =" /\Qspammer/o and "spammer"; }

в начале регулярного выражения присутствует для того, чтобы точки (как в .сот) или другие зарезервированные знаки пунктуации не считались бы метасимволами регулярных выражений.

Позже в программе будет обойден в цикле список ссылок на код и выполнена каждая маленькая подпрограмма для переданных данных. Если результатом каких-либо из этих вычислений окажется значение «истина», мы вернем код возврата подпрограммы:

return $found if (Sfound = &$subref($line));

Компиляция регулярного выражения, которая нас так беспокоит, происходит всего один раз - при создании ссылки на подпрограмму. Можно вызывать каждую подпрограмму столько раз, сколько надо, не теряя время на компиляцию регулярного выражения.

Существует и другой, чуть менее продвинутый подход, который можно применять, если у вас Perl версии 5.005 или выше. В Perl 5.005 была введена новая синтаксическая конструкция, названная «прекомпи-лируемым регулярным выражением», которая делает подобную задачу несколько проще. Переписать код, используя эту новую конструкцию, можно было бы примерно так:

sub loadblist{

tie %blist, 'BerkeleyDB::Hash', -Filename => $blacklist or die

"Невозможно открыть файл $Шегше:

$BerkeleyDB: :Error\n" ;

while(my($key,$vaiue) = eac^- %blist){

# в черном списке могут бьть запис/ "OK". "RELAY" и пр. next

(Svalue ne "PEJECT") push('SDlisttests, [qr/\Q$i<ey/. $кеу]): }

sub checkblisu

my($iine) = shift;

foreach my Stest (§blisttests){

my($re,$kr;v) = a{$test}

return $key i* ($line =" /$re/): }

return undef; }

На этот раз ссылка была перенесена на анонимный массив в@blist test. Первый элемент этого массива - скомпилированное регулярное выражение, созданное с применением нового синтаксиса qr/Y. Это позволяет сохранить регулярное выражение после его компиляции. Такая форма обработки значительно увеличивает скорость выполнения программы при дальнейшем поиске соответствия. Второй элемент анонимного массива - сама запись из черного списка, которая будет возвращена при найденном соответствии скомпилированному регулярному выражению.



Содержание раздела