Русский язык SpamAssassin

Если использовать

/etc/spamassassin/local.cf
normalize_charset 0

по умолчанию, то писать свое правило на русском языке надо в 3-х кодировках - KOI8-R, WIN1251, UTF8.
то есть

body PORNO /порно_в_кодировке_koi8r|порно_в_кодировке_win|порно_в_кодировке_utf8/
score PORNO 1.0

Если

/etc/spamassassin/local.cf
normalize_charset 1

то достаточно

body PORNO /порно_в_кодировке_utf8/
score PORNO 1.0

Из коробки SpamAssassin не работает с normalize_charset 1
Исправил так:

/usr/lib/perl5/vendor_perl/5.8.8/Mail/SpamAssassin/Message.pm после use warnings;
#===========
use bytes;
#===========
/usr/lib/perl5/vendor_perl/5.8.8/Mail/SpamAssassin/Plugin/Check.pm после use warnings; добавил
#=====================
use utf8;
use POSIX qw (locale_h);
POSIX::setlocale(&POSIX::LC_CTYPE,'ru_RU.UTF-8');

взято с http://www.opennet.ru/openforum/vsluhforumID1/77201.html

таблица кодировок - http://www.utf8-chartable.de/unicode-utf8-table.pl
генератор правил - http://www.spamassassin.tu2.ru/index.php

Тесты:
utf8.msg

Return-Path: <1@1.ru>
Received: from localhost ([127.0.0.1])
To: "1@1.ru" <1@1.ru>
From: <1@1.ru>
Content-Type: text/plain; format=flowed; delsp=yes; charset=utf-8
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

порно

http://uralpress.ru/my/utf8.msg
То же в кодировке windows-1251:
http://uralpress.ru/my/win.msg
Правила:
http://uralpress.ru/my/russian.cf

normalize_charset=0
для win.msg срабатывает LOCAL_WIN
для utf8.msg срабатывает LOCAL_UTF

normalize_charset=1
для win.msg срабатывает LOCAL_UTF
для utf8.msg срабатывает LOCAL_UTF

Если не вносить исправления - то ничего не срабатывает.

/etc/spamassassin/russian.cf

body    LOCAL_TEST      /test/
score   LOCAL_TEST      1.0

body    LOCAL_WIN /\xEF\xEE\xF0\xED\xEE/
score   LOCAL_WIN 1.0

body    LOCAL_UTF /\xd0\xbf\xd0\xbe\xd1\x80\xd0\xbd\xd0\xbe/
score   LOCAL_UTF 1.0
spamassassin <utf8.msg
Return-Path: <1@1.ru>
X-Spam-Level: ****
X-Spam-Status: No, score=4.8 required=6.3 tests=AWL,LOCAL_UTF,MISSING_DATE,
        MISSING_MID,MISSING_SUBJECT,NO_DNS_FOR_FROM,UNPARSEABLE_RELAY autolearn=no
        version=3.2.5
X-Spam-Relay-Country:
Received: from localhost ([127.0.0.1])
To: "1@1.ru" <1@1.ru>
From: <1@1.ru>
Content-Type: text/plain; format=flowed; delsp=yes; charset=utf-8
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

порно

Что меня смутило до этого это TextCat.
Приношу свои извинения что неправильно понял.

http://spamassassin.apache.org/full/3.2.x/doc/Mail_SpamAssassin_Plugin_TextCat.html

DESCRIPTION

This plugin will try to guess the language used in the message text.

You can then specify which languages are considered okay for incoming
 mail and if the guessed language is not okay, UNWANTED_LANGUAGE_BODY is triggered

It will always add the results to a ``X-Language'' name-value pair in the message
 metadata data structure. This may be useful as Bayes tokens. The results can also
 be added to marked-up messages using ``add_header'', with the _LANGUAGES_ tag.
 See the Mail::SpamAssassin::Conf manpage for details.

Note: the language cannot always be recognized with sufficient confidence.
In that case, UNWANTED_LANGUAGE_BODY will not trigger.

Вот для чего он нужен.
Соответственно при normalize_charset=1 все переводится в UTF-8,
Сначала переводится, а потом запускается TextCat.
а там TextCat язык определяет
только для (Serbia and Montenegro) и Armenia.

cat /usr/share/spamassassin/languages | grep -a "^0 " | grep utf-8
0 am.utf-8
0 yi.utf-8

З.Ы. А баг который я отправил - это определение русского языка для UTF-8 TextCat.
То есть файл ru.utf-8.lm для сборки - feature request.

Теперь ответ на вопрос про

Теперь ответ на вопрос про базу GeoIP:

Меняем IP::Country::Fast на IP::Country::MaxMind

/usr/lib/perl5/vendor_perl/5.8.8/Mail/SpamAssassin/Plugin/RelayCountry.pm
68,70c68,70
<     require IP::Country::MaxMind;
<     $reg = IP::Country::MaxMind->new();
<     };
---
>     require IP::Country::Fast;
>     $reg = IP::Country::Fast->new();
>   };

Базу лучше брать свежую - http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
и класть ее в /usr/share/GeoIP/GeoIP.dat
Прогнал по всему архиву писем - последний релей всегда не XX!!!
Кстати пропали и непонятные EU - GeoIP точно лучше

However, you should note the circumstances where the country code returned by
IP::Country will deviate from those used by Geography::Countries:

  AP - non-specific Asia-Pacific location
  CS - Czechoslovakia (former)
  EU - non-specific European Union location
  FX - France, Metropolitan
  PS - Palestinian Territory, Occupied
  ** - intranet address
  undef - not in database

Ура!!!

Теперь ответ на вопрос почему

Теперь ответ на вопрос почему не ставятся заголовки:

http://www.ijs.si/software/amavisd/#faq-spam

Цитата:
SpamAssassin has configuration options to modify mail body and header, but they seem to be ignored.
amavisd-new does not modify mail body or lets SA do it (with the exception of defanging, introduced with amavisd-new-2.0). All mail (header) editing is done by amavisd-new and not by SA. Even though SA does observe options in its configuration file to rewrite mail body and modify mail header, the result is purposely not used by amavisd-new. There are two reasons for that: SA is only called once per message regardless of the number of recipients, and secondly, to be able to offer a guarantee the mail body will not be altered, This means the per-recipient handling of mail relaying and header editing needs to be done entirely in amavisd-new, as there are no provisions in SA to analyze mail once and then prepare different modifications for different recipients based on the same spam analysis. It is a tradeoff: speed for multi-recipient mail versus the full per-recipient flexibility. It would make no sense to fully duplicate the spamc/spamd functionality in amavisd-new. If you need such features, just disable calling SA from amavisd-new, and use the spamc/spamd or other back-end interface to SA.

План следующих действий.Из

План следующих действий.
Из нерешенных вопросов остается:
настройка фильтров
1. Relay-Country - пересчитать статистику и откнуть ненужные страны.
2. Language - возможно, добавить scores небольшой письмам на русском не из россии, на не русском добавить побольше.
Подбор оптимального значения засыпания:
smtpd_client_restriction = sleep 5

и включить проверку описанную http://www.spamhaus.org/effective_filtering.html URIBL_SBL
посмотреть что это даст.

И, конечно, написание русских фильтров.
За приближене можно взять эти темы -

score RU_2_SPAM_TRICKS 0.5
score RU_CLASSES 2.0
score RU_SPAM 2.5
score RU_SUSPECTED_SPAM 0.5
score RU_WEBSITE 1.5
score RU_PRINTING 1.0
score RU_REALTY 1.0
score RU_LOADERS 0.5
score RU_HOTELS 0.1
score RU_MMEDIA 1.0
score RU_PORN1 5.0
score RU_PORN2 5.0
score RU_PORN3 5.0
score RU_ACCOUNTING_OUTSOURCE 0.5
score RU_LAWYERS 0.4
score RU_BREED 0.4
score RU_PHONE_TARIFFS 0.5
score RU_IT 0.5
score RU_WATCH 0.5
score RU_DENTIST 0.5
score RU_CERTIFICATE 0.5

порно, ДВД, часы, вебсайты, рассылки и т.д.
для англйского языка этх тестов больше сотни - чем мы хуже?
В дальнейшем по настройке буду писать в эту тему.
Хочу ее закрыть до 1 февраля.

З.Ы. Большинство либо поднимает scores для Байеса, чтобы он ловил больше 6 с 80%, либо кушают спам.

Начнем со статистики. По

Начнем со статистики.
По странам:
ХАМ:

RU XX	371
RU RU	327
RU	141
US	21 = 2.3%
Итого	860
Всего	900

СПАМ, который просочился:

RU	127
RU RU	61
RU XX	39
Итого	227 = 31.4%
Всего	723
US	103 = 14.2%

IT	34
JP	22
CN	18
IE	11
US XX US 11
US US US 11
CZ CZ	10
UA UA	9
IN, RO, TR, AU, NL - 9
Всего	171 = 23.7%

По темам, пока приблизительно:

семинар - 45 = 6,3%
DVD (фильмы) - 51 = 7,1%
реклама (рассылки) - 77 = 10,7%
Порно (взрослые) - 220 = 30%
Всего - 720

Соответственно, пишу правила для Relay-Country и X-Language. Больше их трогать не буду.

#я все-таки добавил в languages определение русского языка в utf-8, работает отлично.
header          __LOCAL_LANG_RU X-Languages=~/ru.utf-8/

#самые хорошие страны
header          LOCAL_COUNTRY_RU X-Relay-Countries=~/(^RU XX)|(^RU RU)|(^RU)/
score           LOCAL_COUNTRY_RU -1

#США
header          __LOCAL_COUNTRY_US  X-Relay-Countries=~/^US$/

#плохие страны согласно статистике.
header          LOCAL_COUNTRY_SPAM X-Relay-Countries=~/(^CN)|(^JP)|(^IT)|(US XX US)|(US US US)|(UA UA)|(CZ CZ)|IE|IN|RO|TR|AU|NL/
score           LOCAL_COUNTRY_SPAM 10

#эл.адрес дотком или дотру
header          __LOCAL_FROM_COM From=~/\.(com|net)>?$/
header          __LOCAL_FROM_RU  From=~/\.ru>?$/

#адрес ком - страна ру
meta            LOCAL_REPLY_NOT_RU (__LOCAL_FROM_COM && LOCAL_COUNTRY_RU)
score           LOCAL_REPLY_NOT_RU 3

#Хостинг ру сайта в США
meta            LOCAL_US_HOSTING (__LOCAL_FROM_RU && __LOCAL_COUNTRY_US)
score           LOCAL_US_HOSTING -0.5

#адрес ком, страна США, язык письма - русский!
#очень хочется здесь порезать хорошо, думаю как исключить gmail и им подобные
meta            LOCAL_US_FROM_COM_RU (__LOCAL_FROM_COM && __LOCAL_COUNTRY_US && __LOCAL_LANG_RU)
score           LOCAL_US_FROM_COM_RU 1

#послабления кривым клиентам, тупым админам и корявым скриптам
score FROM_ILLEGAL_CHARS 1          #From: has too many raw illegal characters
score HEAD_ILLEGAL_CHARS 0.6        #Headers have too many raw illegal characters
score SUBJ_ILLEGAL_CHARS 0.6        #Subject: has too many raw illegal characters
score FORGED_MUA_OUTLOOK 1          #Forged mail pretending to be from MS Outlook

#то, что приходит только в спаме
score DATE_IN_PAST_06_12        3   #Date: is 6 to 12 hours before Received: date
score DIGEST_MULTIPLE           3   #Message hits more than one network digest check
score MIME_QP_LONG_LINE         3.5 #Quoted-printable line longer than 76 chars
score MIME_HEADER_CTYPE_ONLY    3.5 #'Content-Type' found without required MIME headers

А вот и мои первые русские

А вот и мои первые русские правила.
Идея гениальная.
Сначала отрезаем письма, в которых встречаются последовательно русские-нерусские буквы.
scores надо поставить побольше, чтобы в остальных правилах на этот казус не обращать внимания.
Таким образом, самые "умные" спамеры - веб-сайты, рассылки и т.д. отпадут сразу.
Почему не страшно писать об этом правиле вслух :
если им не будут пользоваться - оно будет отлично срабатывать у меня.
если им будут пользоваться - спамеры больше не будут так делать.
И то, и то хорошо.

Чтобы это по-нормальному сделать пришлось подумать.
В документации по SpamAssassin очень мало написано как писать правила, но смый лучший способ оказался плагин.
Чтобы не мучаться с трехэтажными regexp'ами, а писать нормальные правила на перле.

Вот первое правило:

#cat /etc/spamassassin/russian.cf

loadplugin     Mail::SpamAssassin::Plugin::RusEval

body LOCAL_RUS_LAT      eval:check_test()
score LOCAL_RUS_LAT 6

#body LOCAL_TEST        eval:check_count_regexp("кл")

LOCAL_RUS_LAT - это то самое правило.
LOCAL_TEST - это тест.
Следующие правила будут такие - куча тестов на вхождение определенного слова, написанного на русском языке, а не на корявых \xD0\xA1 в текст сообщения.
При проверке этого теста выявились ошибки:
если regexp = "123", то $body приходит нормально.
если regexp = "кл", то $body приходит абракадабра. Думаю как его раскодировать. Что-то я сделал неправильно.
Буква Р (Эр русская заглавная) - не понимается перлом как я не бился.
Можете не сомневаться, я проверил весь алфавит в обоих регистрах.
У других товарищей это тоже не получается - http://www.spamassassin.tu2.ru/index.php (выбрать UTF и поставить букву Р) причина непонятна.
Согласно http://www.utf8-chartable.de/unicode-utf8-table.pl

Unicode    character    UTF-8	name
code point		(hex.)

U+0420  	Р	d0 a0	CYRILLIC CAPITAL LETTER ER

Для тех, кто не согласен писать русские правила привожу кусок английских.

body            __KAM_LOTTO1    /(e-?mail address (have emerged a winner|has won|attached to (ticket|reference)|was one of the ten winners)|random selection in our computerized email selection system)/is
body            __KAM_LOTTO2    /((ticket|serial|lucky) number|secret pin ?code|batch number|reference number|promotion date)/is
body            __KAM_LOTTO3    /(won|claim|cash prize|pounds? sterling)/is
body            __KAM_LOTTO4    /(claims (officer|agent)|lottery coordinator|fiduciary (officer|agent)|fiduaciary claims)/is
body            __KAM_LOTTO5    /(freelotto group|Royal Heritage Lottery|UK National (Online)? Lottery|U\.?K\.? Grand Promotions|Lottery Department UK|Euromillion Loteria|Luckyday International Lottery|International Lottery)/is
body            __KAM_LOTTO6    /(Dear Lucky Winner|Winning Notification|Attention:Winner|Dear Winner)/is

Ну что - нужны они Вам?

Теперь листинг плагина:

# cat /usr/lib/perl5/vendor_perl/5.8.8/Mail/SpamAssassin/Plugin/RusEval.pm
# <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>

=head1 NAME

RusEval - RusEval plugin

=head1 SYNOPSIS

  loadplugin     Mail::SpamAssassin::Plugin::RusEval
  header         LOCAL_RUS_LAT eval:check_test()

=head1 DESCRIPTION

To try this plugin, write the above two lines in the synopsis to
C</etc/mail/spamassassin/russian.cf>.

=cut

package Mail::SpamAssassin::Plugin::RusEval;

use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Logger;

use strict;
use warnings;

use utf8;
use POSIX qw (locale_h);
POSIX::setlocale(&POSIX::LC_CTYPE,'ru_RU.UTF-8');

use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);

# constructor: register the eval rule
sub new {
  my $class = shift;
  my $mailsaobject = shift;

  # some boilerplate...
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsaobject);
  bless ($self, $class);

  # the important bit!
  $self->register_eval_rule ("check_test");
  $self->register_eval_rule ("check_count_regexp");

  return $self;
}

sub check_count_regexp {
  my ($self, $pms, $text, $regexp) = @_;
  my $subj = @{$text}[0];
  my $body = @{$text}[1];

  my $count = 0;

#  print "\ncheck: $body - $regexp \n";
#  $body = pack("U*", unpack("C*",$body));

  while($body =~ /($regexp)/g) {
    $count++;
#    print "$1 ";
  }

  return $count;
}

sub __check_count_regexp {
  my ($self, $text, $regexp) = @_;
  my $subj = @{$text}[0];
  my $body = @{$text}[1];

  my $count = 0;

#  print "\n__check: $body - $regexp \n";

  while($body =~ /($regexp)/g) {
    $count++;
#    print "$1 ";
  }

  return $count;
}


# and the eval rule itself
sub check_test {
  my ($self, $pms, $text) = @_;

  my $rus = "((\xD0[\x81\x90-\xBF])|(\xD1[\x80-\x8F\x91]))";
  my $eng = "[A-Za-z]";
  my $count = 0;

  $count = $self->__check_count_regexp($text,$rus.$eng);
  $count += $self->__check_count_regexp($text,$eng.$rus);
#  print "check_test: - $count\n";

  return ($count>3);
}

1;

Если все пойдет нормально, то будем писать regexp'ы на русском, еще хочу чтобы /i работало.
Вот это настоящая русификация!!!

Жду Ваших комментариев и конечно же, критики.

А вот и первый

А вот и первый клиент:
=C5-m=E0il pa=F1=F1=FB=EB=EAa = Е-mаil paссылкa
$count = 4.
O=D0=C5p=C1=D4u=D7=CE=C1=D1 =D0e=DE=C1=D4=D8 =D0o=CCu=C7=D2=C1=C6=C9u = Oпеpатuвная пeчать пoлuграфиu
$count = 82!!!

Следующее правило будет тоже

Следующее правило будет тоже общее - телефоны.

б в з о у ч ю
B I l o O
0123456789

Вот эти символы там встречаются, оставим только [:digit:].
а эти - выкинем:

767-З-7II, 77Ч-7-729
[495] б21-81-26, 627-О3-20

Вопрос - как написать на regexp правило вида
[xy]{7}, но не x{7} или, чтобы y встречался минимум 2 раза?

З.Ы.
Вместо

  my $subj = @{$text}[0];
  my $body = @{$text}[1];

читать

  my $body = join(" ",@{$text});

Иначе не проверит все части multipart. Сейчас столкнулся - в первой части (text) все ок, а во второй (html) обманывают :)
И еще какой-то перл там странный - пишу в my.pl - все ок.
Перетаскиваю в плагин - ошибка компиляции. - например @{$text} вместо @text пришлось писать.
Почему так? я перл вообще плохо знаю.

А Вы знаете что челябинские

А Вы знаете что челябинские спамеры самые суровые спамеры в мире?
Со вчерашнего числа стала приходить почта с домена зарегистрированного на адрес Челябинск с местным телефоном
Предлагают купить рассылки по челябинску и Уральскому регону.

Пересчитал статистику после

Пересчитал статистику после фильтров без учета Байеса, заодно перевел архив спама в utf-8 на русском для дальнейшего анализа. Отброшены письма по стране, языку, изменению базовых scores и с учетом 1 моего правила - стали СПАМом.

Было - 744
Всего осталось - 293
Итого отрезалось - 60%
Осталось:
На русском - 234 = 80%
На английском - 59 = 20%
Теперь приходит в среднем 1 письмо в день на одного пользователя СПАМ.

Так и не могу русский язык

Так и не могу русский язык получить.

Вот письмо utf8.msg

Received: from localhost ([127.0.0.1])
To: "1@1.ru" <1@1.ru>
From: <1@1.ru>
Content-Type: text/plain; format=flowed; delsp=yes; charset=utf-8
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
абвгдеёжзийклмнопрстуфхцчшщъыьэюя
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ

Русский алфавит.

Если тест сделать

body    LOCAL_TEST      eval:check_count_regexp("12")

то в функцию check_count_regexp приходит

 абвгдеёжзийклмнопрстуфхцчшщъыьэюя АБВГДЕЁЖЗИЙКЛМНОП▒ СТУФХЦЧШЩЪЫЬЭЮЯ

Про букву Р я уже писал.

Если же сделать

body    LOCAL_TEST      eval:check_count_regexp("ж")

то приходит

 абвгде�жзийклмноп���������������� �����������������РСТУФХЦЧШЩЪЫЬЭЮЯ

При этом body "портится" если печатать сразу $body и $regexp.
Видимо они в разных кодровках.
Если печатать только $body то результат одинаковый в обоих случаях. - алфавит.
Тем не менее regexp не дает ни одного срабатывания.
Если в функцию отправлять коды - \xd0\xa0, то они так и печатаются, срабатыванй тоже 0.
Если же эти коды посылать без функции

body LOCAL_TEST /\xd0\xa0/

то срабатывания есть.

Я так понимаю это связано с use bytes и use utf8;
Пробовал поставить use locales; в Conf.pm - не помогает.
Как сделать русский язык?

Не, не кузяво как-то..

Это ж, получается, после каждого обновления порта (у меня FreeBSD) снова .pm ручками править?
Муторно...

UTF-8 и TextCat

andribas написал(а):
З.Ы. А баг который я отправил - это определение русского языка для UTF-8 TextCat.
То есть файл ru.utf-8.lm для сборки - feature request.

Честно говоря не нашел багрепорта, поэтому сделал отдельный тикет:
https://issues.apache.org/SpamAssassin/show_bug.cgi?id=6364

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".