Ключевые слова:spam, ocr, filter, image, postfix, freebsd, samba, (найти похожие документы)
From: Enfogar <enfogar@gala.net.>
Newsgroups: email
Date: Mon, 4 May 2007 14:31:37 +0000 (UTC)
Subject: Борьба со спамом в картинках при помощи OCR
Предисловие
-----------
Рассмотрев на досуге статистику своего сервера я осознал, что основная
масса обычного спама осталась за бортом, но письма, содержащие рекламу в
картинках проходят.
Выбрав немного свободного времени, решил заняться этим вопросом плотнее.
Наперед скажу, что на загруженных серверах данное решение необходимо
продумать более детально, т.к. процесс распознавания картинок - не
очень быстрый.
Ориентировочная моя суточная нагрузка выглядит так:
940 received
1476 delivered
1398 rejected (48%) - без image spam
Источники размышлений и информации
1. Большое спасибо Oles Hnatkevych, don_oles at able.com.ua за
http://able.com.ua/~gnut/fighting-spam.html
Основная конфигурация построена именно по такой схеме за исключением TLS/SSL/SASL.
2. К этому всему подключен Spamassassin
http://spamassassin.apache.org/
3. С плагином FuzzyOCR
http://fuzzyocr.own-hero.net/
4. И поправкой к нему
http://fuzzyocr.own-hero.net/ticket/201
5. SAMBA в ActiveDirectory
http://turbogaz.kharkov-ua.com/unix/www/squid.php
6. Microsoft Office Document Imaging
http://msdn2.microsoft.com/en-us/library/aa167607(office.11).aspx
Как это работает:
Общая схема построена на FreeBSD с postfix+etc хорошо описана в
able.com.ua/~gnut/fighting-spam.html , единственно к ней
добавляется Spamassassin, задача которого - пометить письма с картинками
непотребного содержания.
Подключается spamassassin к postfix обычным smtp proxy (демон spampd)
как и clamav. Единственно у меня получилось его подключить только перед
clamav и dkfilter, а хотелось последним.
Spamassassin использует плагин FuzzyOCR (который в свою очередь
использует gocr или ocrad) в качестве распознавателя.
Т.к. FuzzyOCR (с gocr) нацелен на англоязычное население, да и качество
распознавания посредственное, пришлось думать над дальнейшей обработкой.
FuzzyOCR готовит .pnm файл и передает его в gocr, который отдает обратно текст.
Вот вместо gocr мы и будем цеплять Microsoft Office Document Imaging (MODI)
Думал, про ABBY http://www.abbyy.ru/sdk/?param=60343 , но стоимость
Developer лицензии моментально уничтожило всякое желание использовать
FineReader.
Perl Скрипт (вместо gocr) полученный .pnm файл конвертирует в tif и
кладет на Win (через самбу)
Заходит telnet'ом на Win и запускает там VisualBasic приложение,
которое через API MODI распознает tif , а результат складывает в .txt
файл.
Perl Скрипт отдает содержимое полученного .txt файла обратно в FuzzyOCR.
Раскроем ключевые моменты
SAMBA
На рабочей станции делаем ресурс (для отладки можнос правами Все:Change + на NTFS
тоже самое), дальше - для пользователя, прописанного в /etc/nsmb.conf
В файле /etc/nsmb.conf прописываем
[WKSTNAME]
addr=10.0.0.10
[WKSTNAME:USERNAME]
password=mypassword
Содаем /mnt/incoming с правами для демона spamd (у меня uid:spamd)
Подключаем
mount_smbfs // USERNAME@WKSTNAME/INCOMING /mnt/incoming/
Для автомаунта можно прописать в /etc/fstab
//USERNAME@WKSTNAME/INCOMING /mnt/incoming/ smbfs rw,auto,noexec 0 0
FuzzyOCR
1. По умолчанию не понимает цифр и большие (или маленькие) буквы в
FuzzyOCR.words и соответственно не работает нормально.
Для этого воспользуемся предложением fuzzyocr.own-hero.net/ticket/201 и закомментируем строки
в FuzzyOcr.pm под номерами 1137 и 1144.
2. В конфигурационном файле FuzzyOCR.cf меняем focr_bin_gocr на наш скрипт:
focr_bin_gocr /usr/local/scripts/modi
Проверяем
focr_scansets $gocr -i $pfile
Остальные параметры - на свое усмотрение.
Perl скрипт: /usr/local/scripts/modi
#!/usr/bin/perl
use strict;
use warnings;
use Net::Telnet ();
use Getopt::Std;
use File::Basename;
my $hostname="WKSTNAME"; # имя Win рабочей станции
my $username="domain\\username"; # Имя пользователя Win
my $password="userpassword";
my $RMT_dir="/mnt/incoming/";
my $drive="Z:"; #Имя локального Win диска с tif файлами
#Имя локальной папки Win с tif файлами
my $Files="Z:\\!SPAM_imaged\\PRJ\\console\\Console OCR\\Console OCR\\INCOMING\\";
my $OCR_cmd="\"Z:\\!SPAM_imaged\\PRJ\\console\\Console OCR\\Console OCR\\bin\\Release\\Console OCR.exe\""; # Путь к VB программе использующей MODI
my $pnmimage="";
my $tifimage="";
my @lines="";
my $textfile="";
my $secs=120;
my $systring="";
our($opt_i);
getopt('i:');
if ($opt_i eq "") { exit };
$pnmimage=$opt_i; # берем имя pnm файла
$tifimage=basename($pnmimage) . ".tif";
# Преобразуем pnm в tif
$systring="pnmtotiff -packbits ".$opt_i." > ".$RMT_dir.$tifimage." 2>/dev/null";
system($systring); # Для меня - загадка,
system($systring); # Необходимо выполнить pnmtotiff 2 раза для того, что бы MODI понял tiff, возможно из-за Кеша самбы или Win
my $image=$tifimage;
# Коннектимся телнетом на винду и логинимя
my $t = new Net::Telnet ();
$t ->open(Host => $hostname, Timeout => $secs);
$t->waitfor('/login:/');
$t->print($username);
$t->waitfor('/password:/');
$t->print($password);
$t->waitfor ('/system32>/');
# Переходим в папку с файлами
$t->print($drive);
$t->waitfor("/$drive/");
$t->print("cd $Files");
$t->waitfor("/>/");
my $cmdstring=$OCR_cmd." ".$image;
# Запускаем VB программу, параметр - имя tif файла
$t->print("$OCR_cmd $image");
$t->waitfor(Match => "/OCR of $tifimage COMPLETE in seconds/",Timeout => $secs);
# Дождавшись завершения - выводим содержимое txt файла в STDOUT
$textfile=$RMT_dir.$tifimage.".txt";
system("cat $textfile");
# Удаляем созданные файлы
system ("rm $textfile");
system ("rm /mnt/incoming/$tifimage");
Программа на VB (Console OCR.exe)
Воспользовался MS Visual Basic 2005 Express Edition для создания "Console application"
Необходимо добавить reference на COM библиотеку MODI
(%ProgramFiles%\Common Files\Microsoft Shared\MODI\11.0\MDIVWCTL.DLL)
Подходит от MS Office 2003 и, возможно, дальше (В Office XP у MODI
отсутствовало API). Подробное описание в
msdn2.microsoft.com/en-us/library/aa167607(office.11).aspx.
Текст:
Module Module1
Dim MiDOC As MODI.Document = Nothing
Dim MiLayout As MODI.Layout = Nothing
Dim strLayoutInfo As String = ""
Dim Myerr As Integer = 0
Dim CMD_Args As String = ""
Dim TIFF_File As String = ""
Dim INCOMING As String = "Z:\!SPAM_imaged\PRJ\console\Console OCR\Console OCR\INCOMING\" 'Must end with \
Dim OCR_File As String = ""
'CodePage получаемого txt файл
Dim OUT_File_ENC As String = "windows-1251" ' koi8-r koi8-u windows-1251
Sub Main()
If (My.Application.CommandLineArgs.Count > 0) Then
TIFF_File = My.Application.CommandLineArgs(0)
Console.Write(My.Application.CommandLineArgs(0))
OCR_File = INCOMING + TIFF_File
Console.Write(OCR_File)
If (My.Computer.FileSystem.FileExists(OCR_File) = True) Then
MiDOC = New MODI.Document
' Load an existing TIFF file.
MiDOC.Create(OCR_File)
' Perform OCR на русском.
MiDOC.OCR(MODI.MiLANGUAGES.miLANG_RUSSIAN)
MiLayout = MiDOC.Images(0).Layout
Console.Write(MiLayout.Text) ' Можно опустить
TXT_File = OCR_File + ".txt"
My.Computer.FileSystem.WriteAllText(TXT_File, MiLayout.Text, False, System.Text.Encoding.GetEncoding(OUT_File_ENC))
' Perform OCR на английском, т.к. попадаются слова типа VIAGRA, CIALIS и т.д.
MiDOC.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, True, True)
MiLayout = MiDOC.Images(0).Layout
My.Computer.FileSystem.WriteAllText(TXT_File, MiLayout.Text, True, System.Text.Encoding.GetEncoding(OUT_File_ENC))
Console.Write(MiLayout.Text) ' Можно опустить
MiLayout = Nothing
MiDOC = Nothing
End If
End If
Dim errorWriter As IO.TextWriter = Console.Error
errorWriter.WriteLine("OCR of " + TIFF_File + " COMPLETE in seconds.")
End Sub
End Module
Заключение
Задача выполнена подручными средствами и без особого контроля над
происходящим в Perlе и VB, но даже если что-то в них не срабатывает -
почта проходит, но не помечается как спам.
В дальнейшем хочется перевести с телнета - на сокеты, вполне возможно
произвести распределение нагрузки по рабочим станциям - пусть каждый
распознает свой спам :).