postfix 2, cyrus-sasl 2, kaspersky antivirus, spamassassin,

courier-imap, tls, mysql how-to (FreeBSD4 STABLE)


Дмитрий Суходоев

Прелюдия.
Всё, что описано в данном how-to вы используете на свой страх и риск. я, как автор за ваши действия и любые потери, связанные с ними ответственности не несу. кое-что для этого how-to я взял из how-to mysql+cyrus-sasl+courier-imap+postfix+openssl Вячеслава Калошина, пусть не обижается - я не присваиваю авторство, а information must be free.

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

кроме того, всё, что здесь описано - описано исключительно для операционной системы FreeBSD 4-STABLE и для других unix-like ОС это очень и очень вряд ли подойдёт. особенно для пингинуксов. ну не символично ли: птица которая не умеет летать.

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

postfix 2
вообще, до некоторого времени стандартным решением был sendmail. но когда я начал заниматься *nix системами, то postfix существовал уже как достаточно стабильный проект (только появилась версия 1) с нормальным конфигурированием, в котором не нужно было изучать жестокий язык sendmail а также непонятно зачем нужный язык макросов m4. собственно postfix и был выбран за внятное конфигурирование, до которого sendmail'у как пешком до луны.

cyrus-sasl 2
собственно, другого SASL (модуля авторизации для SMTP) я не нашёл. да и этот очень неплохо выполняет свои функции.

kaspersky antivirus
вот это уже всего лишь моё личное предпочтение. лаборатория Касперского™ прекрасно разбирает вирусы, регулярно пополняет антивирусную базу, да и что уж скромничать: антивирус у них прекрасный. но всё это справедливо для их windows-продуктов, а под *nix они программировать совершенно не умеют. именно поэтому я не стал использовать в своей конструкции их kavdaemon и kav/postfix, ибо их надо запускать с привилегиями root, а этого мне совсем не хочется делать :-)

spamassassin
великолепный инструмент для борьбы со спамом. содержит большое количество критериев отбора спама и письма спамеров, которые не знают о существовании spamassassin, очень хорошо ловит.

courier-imap
простой и понятный pop3/imap сервер, работает с maildir, что нам и нужно. умеет брать данные о пользователях из mysql/postgresql чем и отличен. больше ничего хорошего, как, собственно, и плохого про него сказать не могу :)

mysql
записная книжка с sql интерфейсом. может выдать данные из базы по запросу, а может положить данные в базу по запросу. больше ничего не умеет, но от неё ничего и не требуется.


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

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

create database mail;
use mail;

создаём таблицы с необходимыми индексами. первая таблица transport - описания транспортов для наших виртуальных доменов. сразу добавляем туда наш единственный домен - raven.elk.ru с транспортом virtual.

create table transport(
domain varchar(255) not null default '',
transport varchar(255) not null default '',
comment text,
primary key(domain)
);

insert into transport(domain, transport)
values('raven.elk.ru','virtual:');

следующая таблица - алиасы адресов. смысл её в том, что если postfix увидит письмо на адрес указанный в поле alias, то это письмо будет переправлено на адрес в соответствующем поле rcpt. адреса в полях могут принадлежать одинаковым доменам, разным доменам, а так же там могут быть адреса, которые не принадлежат нашим доменам ;) просто если, вдруг, письма с такими адресами получателя будут проходить через наш MTA (например от наших пользователей), то postfix изменит их адреса получателя и письма уйдут туда, куда мы их отправим.

create table aliases(
alias varchar(255) not null default '',
rcpt varchar(255) not null default '',
comment text,
primary key(alias)
);

insert into aliases(alias, rcpt)
values('root@raven.elk.ru', 'iam@raven.elk.ru');

insert into aliases(alias, rcpt)
values('abuse@raven.elk.ru', 'iam@raven.elk.ru');

insert into aliases(alias, rcpt)
values('mailer-daemon@raven.elk.ru', 'iam@raven.elk.ru');

insert into aliases(alias, rcpt)
values('postmaster@raven.elk.ru', 'iam@raven.elk.ru');

insert into aliases(alias, rcpt)
values('hostmaster@raven.elk.ru', 'iam@raven.elk.ru');

insert into aliases(alias, rcpt)
values('iam@raven.elk.ru', 'me@raven.elk.ru');

далее идёт таблица - список наших логинов. поля login, password и maildir очевидны, можете посмотреть на примере в insert. единственное, хотелось бы подчеркнуть, что значения поля maildir обязательно должны заканчиваться знаком '/' (slash) иначе virtual (транспорт) почту будет валить в обычный unix mailbox с соответствующим именем, а нам нужен именно maildir. если бы не тупой mysql в качестве sql сервера, то можно было бы установить rule и trigger, которые бы самостоятельно заполняли поля исходя из логина, но в mysql такого без порядочного геморроя не сделать.

поля expired, antivirus и antispam соответственно обозначают expired ли логин, нужно ли проверять его антивирусом и антиспамом. подобные услуги для пользователей стоит делать платными, так как всё таки они откушивают очень много ресурсов у почтового сервера по сравнением с обычной доставкой почты. а антивирус вообще стоит денег, хоть тут мы его и будем использовать бесплатно, пользуясь дыркой в системе работы с ключами ;-) что совершенно законно, между прочим.

create table users(
login varchar(255) not null default '',
password varchar(255) not null default '',
maildir varchar(255) not null default '',
expired char default '0',
antivirus char default '1',
antispam char default '1',
comment text,
primary key(login),
key login_expired(login, expired),
key login_antivirus(login, antivirus),
key login_antispam(login, antispam)
);

insert into users(login, password, maildir)
values('me@raven.elk.ru', encrypt('password:)'), 'raven.elk.ru/me/');

insert into users(login, password, maildir)
values('test@raven.elk.ru', encrypt('password1:)'), 'raven.elk.ru/test/');

insert into users(login, password, maildir)
values('test1@raven.elk.ru', encrypt('password2:)'), 'raven.elk.ru/test1/');

казалось бы это всё, но нет. следующая таблица решает проблему 'старшего брата'. здесь мы не будем обсуждать моральную сторону этого вопроса, но ни для кого не секрет, что очень многие гендиры корпораций желают (и получают) копии всех писем сотрудникам на свой ящик. опция always_bcc в postfix решает этот вопрос, но мы же крутые админы и не хотим, чтобы начальник читал нашу личную почту, верно? да и не только нашу. всегда существуют исключения в виде симпатичных секретарш или других особей женского пола которые рады отблагодарить админа за его доброту. шутка ;-)

примеры insert'ов демонстрируют систему работы скрипта, который обрабатывает эту таблицу. первое правило:

поле type 'delivered-to'. этим правилом будут ловится все письма, у которых в служебной строке delivered-to встретился адрес, попавший под маску в регулярных выражениях, соответствующую полю mask (персонально для mysql не забываем экранировать знак back slash '' им же самим, а для перловых регэкспов служебные символы). в поле forward_addr хранится адрес, на который нужно копировать письмо, если оно подошло под условия. поле what установлено в буковку 'i', что значит (i)nclude, т.е. включающее правило. таким образом в первом примере будет ловится вся почта для домена raven.elk.ru и копироваться на адрес me@raven.elk.ru.

второе правило - это исключение из первого примера адреса test1@raven.elk.ru. т.о. в комплексе этих двух правил на адрес me@raven.elk.ru будет копироваться вся почта для домена raven.elk.ru, исключая адрес test1@raven.elk.ru.

create table forward(
id int(10) unsigned not null auto_increment,
type varchar(50) not null default 'delivered-to',
mask varchar(255) not null default '.+',
forward_addr varchar(255) not null default 'root',
what char not null default 'i',
comment text,
primary key(id),
key what(what),
key type_mask(type, mask)
);

insert into forward(type, mask, forward_addr, what, comment)
values('delivered-to', '[a-z0-9- _]+\@raven\.elk\.ru',
'me@raven.elk.ru', 'i', 'forwarding all mail for raven.elk.ru');

insert into forward(type, mask, forward_addr, what, comment)
values('delivered-to', 'test1\@raven\.elk\.ru',
'me@raven.elk.ru', 'e', 'exclude forward test1 mail');

теперь осталось создать пользователей в mysql и выдать им соответствующие права на доступ к нашим таблицам. пользователь mailer - это наши демоны, в числе которых будет postfix, courier-imap и cyrus-sasl2 в лице pam-mysql :-) а пользователь mail_admin - это эникейщик в нашей конторе, которого можно допустить до базы через phpMyAdmin и заставить его самого делать почтовые эккаунты юзерам, а самим расслабляться и пить пиво ;)

grant select on mail.* to mailer@localhost
identified by 'mailer_password';

grant select, insert, update on mail.* to mail_admin@localhost
identified by 'mail_admin_password';



Настройка MTA/MDA
в этом разделе мы начнём с конца и поставим сначала то, что нужно основному "виновнику торжества" - postfix'у.

cyrus-sasl2

для начала поставим cyrus-sasl2. в зависимости от свежести вашего дерева портов может быть два варианта. для более старого дерева портов вы можете просто сделать:

cd /usr/ports/security/cyrus-sasl2
make -DWITHOUT_OTP -DWITHOUT_CRAM -DWITHOUT_DIGEST -DWITHOUT_NTLM

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

[X] SASLAUTHD

после того, как cyrus-sasl2 собрался, то стандартно:

make install clean

ежели красивого окошечка не выскакивало, то, значит, у вас свежие порты и после всех этих действий у вас все ещё не хватает нужного нам saslauthd. его можно поставить вот таким образом:

cd /usr/ports/security/cyrus-sasl2-saslauthd
make install clean

но повторяю, что данный порт есть только в новых портах, в старых портах он включён в порт cyrus-sasl2 и не нужен. теперь поправим конфиг для активации этого самого saslauthd в postfix. редактируем /usr/local/lib/sasl2/smtpd.conf:

pwcheck_method: saslauthd

теперь надо поставить pam-mysql. это делается стандартно:

cd /usr/ports/security/pam-mysql
make install clean

после прочтения и осмысливания /usr/local/share/doc/pam_mysql/Readme добавим в /etc/pam.conf следующие строчки:

smtp auth sufficient pam_mysql.so user=mailer passwd=mailer_password db=mail
table=users usercolumn=login passwdcolumn=password crypt=1 where=expired=0
smtp account sufficient pam_mysql.so user=mailer passwd=mailer_password db=mail
table=users usercolumn=login passwdcolumn=password crypt=1 where=expired=0

не забудем запустить saslauthd:

/usr/local/etc/rc.d/saslauthd.sh start
ps ax|grep sasl
363 ?? IWs 0:00,00 /usr/local/sbin/saslauthd -a pam
367 ?? IW 0:00,00 /usr/local/sbin/saslauthd -a pam
368 ?? IW 0:00,00 /usr/local/sbin/saslauthd -a pam
369 ?? IW 0:00,00 /usr/local/sbin/saslauthd -a pam
370 ?? IW 0:00,00 /usr/local/sbin/saslauthd -a pam

если результат примерно такой, то значит всё прошло нормально, cyrus-sasl2 поставлен и теперь можно перейти к настройке postfix.


postfix2

как обычно:

/usr/ports/mail/postfix
make install clean

должна вылезти красивая и совсем не юниксоидная ;) менюшка, в которой нам надо выбрать следующие опции:

[X] SASL2
[X] TLS
[X] MySQL

если какой-то из опций у вас не обнаружилось, поздравляю, у вас ну очень старые порты и надо обновлять. как это делать - не в этом how-to да и вообще ни в каком, читайте handbook - там всё написано. после установки порт должен сказать, что делать дальше это мы сразу и сделаем. в /etc/rc.conf исправим:

sendmail_enable="NONE"

в /etc/periodic.conf:

daily_clean_hoststat_enable="NO"
daily_status_mail_rejects_enable="NO"
daily_status_include_submit_mailq="NO"
daily_submit_queuerun="NO"

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

cd /usr/local/etc/rc.d
ln -s /usr/local/sbin/postfix postfix.sh

откроем /usr/local/etc/postfix/main.cf в каком-нибудь текстовом редакторе, найдём в его теле и исправим следующие параметры:

default_privs = nobody
mynetworks = 127.0.0.0/8
alias_maps = hash:/etc/mail/aliases
alias_database = hash:/etc/mail/aliases
mail_spool_directory = /var/mail
smtpd_banner = $myhostname mail sterver

не торопимся сохранять и закрывать /usr/local/etc/postfix/main.cf, а допишем туда:

# с каким кодом отшивать письма от open relays:
maps_rbl_reject_code = 554

# принимать письма от:
# авторизованных клиентов
# от сетей, указанных в параметре mynetworks
# отшивать письма от:
# не для наших доменов и пользователей
# для хостов, который есть в списках open relays
# (подробности на www.ordb.org)
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
reject_rbl_client list.dsbl.org,
reject_rbl_client relays.ordb.org,
reject_rbl_client dynablock.wirehub.net,
reject_rbl_client blackholes.wirehub.net,
reject_rbl_client dnsbl.njabl.org

# списки транспортов:
transport_maps = mysql:/usr/local/etc/postfix/sql/transport.cf

# куда складывать почту транспорту virtual:
virtual_mailbox_base = /var/mail/virtual

# списки почтовых ящиков:
virtual_mailbox_maps = mysql:/usr/local/etc/postfix/sql/users.cf

# списки алиасов:
virtual_alias_maps = mysql:/usr/local/etc/postfix/sql/aliases.cf

# списки uid и gid пользователей:
virtual_uid_maps = mysql:/usr/local/etc/postfix/sql/uids.cf
virtual_gid_maps = mysql:/usr/local/etc/postfix/sql/gids.cf

# списки наших доменов, для которых мы принимаем почту
relay_domains = $transport_maps

# списки наших пользователей:
local_recipient_maps = $virtual_mailbox_maps $virtual_maps $transport_maps

# включаем плагин sasl2 для smtpd авторизации
smtpd_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes

# использовать transport layer security для отправки почты
# (пока все оставляем закомментаренным, ибо ключей у нас ещё нет)
#smtp_use_tls = yes

# наши ключи. генерируются с помощью courier-imap (далее)
#smtp_tls_key_file = /usr/local/share/courier-imap/pop3d.pem
#smtp_tls_cert_file = $smtp_tls_key_file
#smtp_tls_CAfile = $smtp_tls_key_file
#smtp_tls_note_starttls_offer = yes

# включать возможность авторизации только в режиме tls
#smtpd_tls_auth_only = yes

# использовать tls для приёма почты
#smtpd_use_tls = yes
#smtpd_tls_loglevel = 1
#smtpd_tls_received_header = yes
#smtpd_tls_session_cache_timeout = 3600s
#tls_random_source = dev:/dev/urandom

# наши ключи. генерируются с помощью courier-imap (далее)
#smtpd_tls_key_file = /usr/local/share/courier-imap/pop3d.pem
#smtpd_tls_cert_file = $smtpd_tls_key_file
#smtpd_tls_CAfile = $smtpd_tls_key_file

сохраняем /usr/local/etc/postfix/main.cf и напишем maps файлы для mysql:

/usr/local/etc/postfix/sql/transport.cf:
user = mailer
password = mailer_password
dbname = mail
table = transport
select_field = transport
where_field = domain
hosts = localhost

/usr/local/etc/postfix/sql/users.cf
user = mailer
password = mailer_password
dbname = mail
table = users
select_field = maildir
where_field = login
additional_conditions = and expired = '0'
hosts = localhost

/usr/local/etc/postfix/sql/aliases.cf:
user = mailer
password = mailer_password
dbname = mail
table = aliases
select_field = rcpt
where_field = alias
hosts = localhost

/usr/local/etc/postfix/sql/gids.cf:
user = mailer
password = mailer_password
dbname = mail
table = users
select_field = 6
where_field = login
additional_conditions = and expired = '0'
hosts = localhost

/usr/local/etc/postfix/sql/uids.cf:
user = mailer
password = mailer_password
dbname = mail
table = users
select_field = 1009
where_field = login
additional_conditions = and expired = '0'
hosts = localhost

по поводу последних двух файлов нужно заметить, что реально полей для gid и uid в таблицах нет, ибо они все одинаковые и прописаны прямо в параметре select_field. чтобы узнать значения gid и uid для вашей системы, вам нужно посмотреть в /etc/passwd и /etc/group какие uid и gid принадлежат пользователю postfix (которого добавляет порт /usr/ports/mail/postfix) и группе mail. и прописать соответствующие значения в последних двух sql файлах.

если вы всё сделали правильно, то ваш MTA и MDA успешно настроен. теперь нужно создать каталог virtual mailbox base и выставить ему атрибутов:

mkdir -pv /var/mail/virtual
chown postfix:mail /var/mail/virtual
chmod 770 /var/mail/virtual

теперь можно запускать postfix. запускаем для начала 'postfix check' и смотрим, что он скажет на свою конфигурацию. если всё нормально, то запускаем: 'postfix start'. если postfix на что-то ругнулся, то надо это что-то исправить, к тому же postfix он не настолько злобный и на всякую ерунду не ругается.

ну что ж, настала пора проверить SMTP часть нашего MTA:

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 raven.elk.ru mail sterver
mail from: user@aol.com
250 Ok
rcpt to: me@raven.elk.ru
250 Ok
data
354 End data with <CR><LF>.<CR><LF>
test message
.
250 Ok: queued as AB11E334F2
quit
221 Bye
Connection closed by foreign host.

если у вас в консоли всё примерно так же, как и выше, то SMTP часть у вас работает нормально.

теперь проверим возможность авторизации:

telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 raven.elk.ru mail sterver
ehlo aol.com
250-raven.elk.ru
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-XVERP
250 8BITMIME
AUTH PLAIN bWVAcmF2ZW4uZWxrLnJ1AG1lQHJhdmVuLmVsay5ydQBwYXNzd29yZDop
235 Authentication successful

строка 'bWVAcmF2ZW4uZWxrLnJ1AG1lQHJhdmVuLmVsay5ydQBwYXNzd29yZDop' справедлива для логина 'me@raven.elk.ru' и пароля 'password:)'. генерируется эта строчка следующим образом:

perl -MMIME::Base64 -e
'print encode_base64("логинлогинпароль");'

если диалог с почтовым сервером прошёл как показано выше, то значит авторизация работает. если же нет, то, читайте /var/log/maillog. вероятно, вы что-то не так сделали и очень вероятно, что чтение данного лога поможет выяснить что же конкретно неправильно.



Настройка POP3 сервера
роль POP3 сервера в нашей системе играет courier-imap. хоть он и называется -imap, но умеет работать на двух разных протоколах: IMAP и POP3. первый лично мне совсем-совсем не нужен, поэтому я использую только второй. вот его-то мы сейчас и настроим. для начала поставим этот самый courier-imap:

cd /usr/ports/mail/courier-imap
make -DWITH_MYSQL install clean
cd /usr/local/etc/courier-imap
cp authdaemonrc.dist authdaemonrc
cp authmysqlrc.dist authmysqlrc
cp authdaemonrc.dist authdaemonrc
cp authmysqlrc.dist authmysqlrc
cp pop3d.dist pop3d
cp pop3d-ssl.dist pop3d-ssl
cp pop3d.cnf.dist pop3d.cnf
cd /usr/local/etc/rc.d
rm courier-imap-imapd.sh.sample
rm courier-imap-pop3d.sh.sample
ln -s /usr/local/libexec/courier-imap/pop3d.rc pop3d.sh
ln -s /usr/local/libexec/courier-imap/pop3d-ssl.rc pop3d-ssl.sh

редактируем /usr/local/etc/courier-imap/authdaemonrc:

authmodulelistorig="authmysql"
daemons=5
version=""
authdaemonvar=/usr/local/var/authdaemon

редактируем /usr/local/etc/courier-imap/authmysqlrc:

MYSQL_SERVER localhost
MYSQL_USERNAME mailer
MYSQL_PASSWORD mailer_password
MYSQL_SOCKET /var/tmp/mysql.sock
MYSQL_PORT 3306
MYSQL_OPT 0
MYSQL_DATABASE mail
MYSQL_USER_TABLE users
MYSQL_CRYPT_PWFIELD password
MYSQL_UID_FIELD 1009
MYSQL_GID_FIELD 6
MYSQL_LOGIN_FIELD login
MYSQL_HOME_FIELD '/var/mail/virtual/'
MYSQL_MAILDIR_FIELD maildir
MYSQL_WHERE_CLAUSE expired = '0'

редактируем /usr/local/etc/courier-imap/pop3d:

prefix=/usr/local
exec_prefix=/usr/local
sbindir="/usr/local/sbin"
PIDFILE=/var/run/pop3d.pid
MAXDAEMONS=11
MAXPERIP=3
AUTHMODULES="authdaemon"
AUTHMODULES_ORIG="authdaemon"
POP3AUTH="LOGIN PLAIN"
POP3AUTH_ORIG="LOGIN PLAIN"
POP3AUTH_TLS="LOGIN PLAIN"
POP3AUTH_TLS_ORIG="LOGIN PLAIN"
PORT=110
ADDRESS=0
TCPDOPTS="-nodnslookup -noidentlookup"
POP3DSTART=YES

редактируем /usr/local/etc/courier-imap/pop3d-ssl:

prefix=/usr/local
exec_prefix=/usr/local
SSLPORT=995
SSLADDRESS=0
SSLPIDFILE=/var/run/pop3d-ssl.pid
POP3DSSLSTART=YES
POP3DSTARTTLS=YES
POP3_TLS_REQUIRED=0
COURIERTLS=/usr/local/bin/couriertls
TLS_PROTOCOL=SSL3
TLS_STARTTLS_PROTOCOL=TLS1
TLS_CERTFILE=/usr/local/share/courier-imap/pop3d.pem
TLS_VERIFYPEER=NONE

теперь сгенерируем сертификат для нашего почтового сервера. для этого сначала нужно отредактировать /usr/local/etc/courier-imap/pop3d.cnf:

RANDFILE = /usr/local/share/courier-imap/pop3d.rand

[ req ]
default_bits = 4096
encrypt_key = yes
distinguished_name = req_dn
x509_extensions = cert_type
prompt = no

[ req_dn ]
C=ru
ST=ch
L=chicaginsk
O=raVen's mail sterver
OU=raVen's ssl key
CN=mail.raven.elk.ru
emailAddress=postmaster@raven.elk.ru

[ cert_type ]
nsCertType = server

запустим генерилку сертификатов:

rm /usr/local/share/courier-imap/pop3d.pem
/usr/local/share/courier-imap/mkpop3dcert

оно будет очень долго возиться с генерацией случайных значений, вы в это время можете поделать чего-нибудь своё, либо пойти попить кофе. после готовности сертификата можно запускать courier-imap:

/usr/local/etc/rc.d/pop3d.sh start
/usr/local/etc/rc.d/pop3d-ssl.sh start

ну и как обычно, проверим его:

telnet localhost 110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK Hello there.
user me@raven.elk.ru
+OK Password required.
pass password:)
+OK logged in.
list
+OK POP3 clients that break here, they violate STD53.
1 623
.
quit
+OK Bye-bye.
Connection closed by foreign host

так как наш сертификат готов теперь можно раскомментировать tls часть main.cf у postfix, и перезапустить его: 'postfix reload'. теперь на ehlo он кроме всего прочего будет предлагать ещё и опцию STARTTLS и доставлять письма на удалённые smtp тоже будет по TLS, если удалённый сервер на ehlo среди прочего отвечает STARTTLS.


Настройка фильтров (антивирус, антиспам и форвардер)
я сразу хотел бы заметить, что все фильтры в данном how-to представляют собой perl скрипты со всеми вытекающими последствиями. отсюда следует, что вам стоит сопоставить конфигурацию своего почтового сервера с нагрузкой на него, что бы не получилось так, что в результате работы фильтров пропускная способность сервера оказалась меньше средней почтовой нагрузки. например, spamassasin даже на очень хорошей машине (в моём случае это p3-866/256ram) обычное письмо обрабатывает более 10 секунд. а если письмо большое, то и того больше.

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


Kaspersky antivirus

поставим его, родного. живёт package для BSD систем где-то в районе ftp://ftp.avp.ru/patches/. качнём и поставим его:

cd /var/tmp
wget -c ftp://ftp.avp.ru/patches/KAVUnix4.0.3.0_UrgentUpdate1/FreeBSD
/4.x/kav-WorkStationSuit-4.0.3.1-FreeBSD-4.x.tgz
pkg_add kav-WorkStationSuit-4.0.3.1-FreeBSD-4.x.tgz

нефиг ему запускаться под рутом:

rm -f /usr/local/etc/rc.d/kavd.sh

теперь, если вы хотите использовать kavscanner совершенно законно и нахаляву, то вам необходимо скачать вот этот файлик. внутри архива находится старая версия kavscanner, которая глючит при работе со своими же ключами и при комбинации двух определённых ключей всегда считает себя зарегистрированной. как вы правильно догадались, эти два ключа лежат в том же архиве ;-) вам нужно заменить kavscanner из дистрибутива бинарником из архива и положить два ключа в /etc/AVP.

теперь нам надо подкорректировать конфиги Касперского. идём в /etc/AVP и правим. описание конфигов есть на том же ftp://ftp.avp.ru где-то в районе документации. там такой здоровый pdf метров на 10, в котором подробное описание всего пакета. среди него есть и описания конфигов. я просто привожу здесь свои варианты конфигов. они у меня работают на нескольких серверах.
/etc/AVP/AvpUnix.ini:

[AVP32]
DefaultProfile=/etc/AVP/defUnix.prf

[Configuration]
KeysPath=/etc/AVP
SetFile=avp.set
BasePath=/var/AVP/Bases
SearchInSubDir=No
UpdatePath=ftp://ftp.kasperskylab.ru/updates

/etc/AVP/defUnix.prf

[Object]
Names=*/var/tmp;*/tmp
Memory=No
Sectors=No
ScanAllSectors=No
Files=Yes
FileMask=2
UserMask=*.tar.gz
ExcludeFiles=0
ExcludeMask=*.txt *.cmd
ExcludeDir=
Packed=Yes
Archives=Yes
SelfExtArchives=Yes
MailBases=Yes
MailPlain=Yes
Embedded=Yes
InfectedAction=0
BackupInfected=No
IfDisinfImpossible=0
DeleteInfectedArch=No
Warnings=Yes
CodeAnalyser=Yes
RedundantScan=No
SubDirectories=Yes
CrossFs=Yes

[Options]
ScanRemovable=No
ScanSubDirAtEnd=No
ParallelScan=No
LimitForProcess=16
EndlesslyScan=No
ScanDelay=-1
Symlinks=0

[Report]
Report=Yes
UseSysLog=No
ReportFileName=/var/log/kavscan.log
Append=Yes
ReportFileLimit=Yes
ReportFileSize=1024
RepCreateFlag=644
ExtReport=Yes
WriteTime=Yes
WriteExtInfo=No
UseCR=No
RepForEachDisk=Yes
LongStrings=Yes
UserReport=No
UserReportName=~/.AVP/userreport.log
ShowOK=No
ShowPack=Yes
ShowPassworded=Yes
ShowSuspision=Yes
ShowWarning=Yes
ShowCorrupted=Yes
ShowUnknown=Yes

[ActionWithInfected]
InfectedCopy=No
InfectedFolder=~/.AVP/infected
CopyWithPath=Yes
ChangeExt=None
NewExtension=Virs
ChownTo=None
ChModTo=No

[ActionWithSuspicion]
SuspiciousCopy=No
SuspiciousFolder=~/.AVP/suspicious
CopyWithPath=Yes
ChangeExt=None
NewExtension=Susp
ChownTo=None
ChModTo=No

[ActionWithCorrupted]
CorruptedCopy=No
CorruptedFolder=~/.AVP/corrupted
CopyWithPath=Yes
ChangeExt=None
NewExtension=Corr
ChownTo=None
ChModTo=No

[TempFiles]
UseMemoryFiles=Yes
LimitForMemFiles=6000
MemFilesMaxSize=20000
TempPath=/var/tmp

[Priority]
Father=0
Child=0

[Customize]
Sound=No
UpdateCheck=No
UpdateInterval=90
OtherMessages=Yes
RedundantMessage=No
DeleteAllMessage=Yes
ExitOnBadBases=Yes
UseExtendedExitCode=Yes

так же в пакете kav-scanner идёт утилита и скрипт для обновления антивирусных баз. утилита вроде бы нормальная, хоть и требует wget :) а вот вот скрипт дико кривой. я не помню, что я там уже правил, а правил, видимо всё таки много, так как отличий от стандартного нашлось целая куча. в общем вот он этот скрипт /etc/periodic/daily/900.kavupdater:

#!/bin/sh

KAV_PATH=/usr/local/share/AVP
PATH=$PATH:/usr/local/bin

if [ ! -x /usr/local/bin/wget ]; then
echo "$0: wget must be installed for the updater to run" >&2
exit 1
fi

DESC="kaspersky anti-virus updater"

if [ -r ~.AVP/AvpUnix.ini ]; then
INIFILE=~.AVP/AvpUnix.ini
else if [ -r /etc/AVP/AvpUnix.ini ]; then
INIFILE=/etc/AVP/AvpUnix.ini
fi
fi

if [ -r $INIFILE ]; then
eval `egrep '^[A-Za-z]*=' $INIFILE | perl -pe 's/ //g'`
fi

if [ -n "$UpdatePath" ]; then
DPARMS="$UpdatePath"
else
if [ -n $1 ]; then
echo "warning! add updatepath in your config file AvpUnix.ini"
exit 1
fi
DPARMS=$1
fi

echo
echo
echo run kaspersky antivirus updating:
echo checking parameters "$DPARMS"

if [ $? -eq 0 ]; then
$KAV_PATH/kavupdater -uik="$DPARMS" -o -y -kb
exitCode=$?
case $exitCode in
8)
echo 8 - new antiviral bases not found.
;;
6)
echo 6 - found corrupted file and process stoped on it.
;;
4)
echo 4 - found corrupted file.
;;
2)
echo 2 - process stoped on corrupted file.
;;
0)
echo 0 - antiviral bases correctly loaded.
;;
*)
echo $exitCode - i dont know this exit code!
esac
else
echo "$0: network connection error." >&2
exit 1
fi

exit 0

запустите обновлялку /etc/periodic/daily/900.kavupdater. оно должно скачать и установить все базы для kav. после этого запуск kavscanner должен запустится проверить /tmp и ни на что не ругаться.



spamassassin

как обычно:

cd /usr/ports/lang/perl5
make install clean
use.perl port
cd /usr/ports/mail/p5-Mail-SpamAssassin
make install clean

потянет за собой кучу байды, но она, видимо, нужна, так что потерпите уж. perl 5.6.1 тоже нужен для фильтровых скриптов. отредактируем конфиг spamassassin. /usr/local/etc/mail/spamassassin/local.cf:

# подробный отчёт
clear_report_template
report тут, похоже, привалило спама, но я его узнал и отловил. письмо, которое пришло
report находится в приложении и его можно поглядеть, вдруг я облажался и на самом деле
report это не спам.
report
report вот что там внутри: _PREVIEW_
report
report детали анализа текста письма: (набрано _HITS_ очков, _REQD_ необходимо)
report _SUMMARY_

# краткий отчёт
clear_terse_report_template
terse_report --- результаты борьбы со спамом
terse_report набрано _HITS_ очков, _REQD_ требуется;
terse_report _SUMMARY_
terse_report --- конец результатов борьбы со спамом

# если нет текста
clear_unsafe_report_template
unsafe_report а вообще это письмо не содержит текста, так что лучше его не открывать, так как
unsafe_report там может быть вирус или подтверждение, что Ваш адрес может получать спам ;)
unsafe_report если Вы всё таки хотите поглядеть что там такое, то лучше сохранить это письмо
unsafe_report как файл и поглядеть его какой-нибудь внешней безопасной программой.

# переписывать поле subject
rewrite_subject 1
subject_tag new spam received:

# эти рассылки я читаю и они умудряются определяться спамом ;)
# поэтому эти адреса добавим в whitelist
whitelist_from subscribe@74.ru
whitelist_from info@suct.uu.ru
whitelist_from suct@suct.uu.ru
whitelist_from subscribe@udaff.com
whitelist_from genocide@raven.elk.ru

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

filter:*:1025:1025::0:0:mail filter:/var/spool/filter:/sbin/nologin

напишем и запустим скрипт для запуска и останова spamd - демона, который значительно ускоряет работу spamassassin, правда отжирает много памяти, но он того стоит. /usr/local/etc/rc.d/spammerdaemon.sh:

#!/bin/sh
if ! PREFIX=$(expr $0 : "(/.*)/etc/rc.d/$(basename $0)$"); then
echo "$0: Cannot determine the PREFIX" >&2
exit 1
fi
case "$1" in
start)
kill `ps ax | grep spamd | grep -v grep | awk '{print $1}'
| head -1` >/dev/null 2>/dev/null && echo -n ' spamd'
[ -x ${PREFIX}/bin/spamd ]
&& ${PREFIX}/bin/spamd -d -a -c -u filter && echo -n ' spamd'
;;
stop)
kill `ps ax | grep spamd | grep -v grep | awk '{print $1}'
| head -1` >/dev/null 2>/dev/null && echo -n ' spamd'
;;
*)
echo "Usage: `basename $0` {start|stop}" >&2
;;
esac
exit 0

запустим его и проверим, запущен ли он. результат должен быть примерно такой:

/usr/local/etc/rc.d/spammerdaemon.sh start
ps ax | grep spam
338 ?? Is 0:07,50 /usr/local/bin/spamd -d -a -c -u filter (perl)

опять postfix

теперь вернёмся к postfix добавлять фильтры. открываем /usr/local/etc/postfix/master.cf и дописываем туда следующие строчки. обратите внимание, что для каждого фильтра (он же транспорт) указано количество максимальных процессов - 10. вам стоит поменять это на своё значение в зависимости от количества свободной памяти на вашем сервере. в принципе если её много, то можно оставить и 10. если мало, то лучше поставить значения поменьше вплоть до 1.

# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
# forwarder
forwarder
unix - n n - 10 pipe
flags=RD
user=filter
argv=/usr/local/raven/mail/forwarder.pl "localhost:10025" "${sender}" "${recipient}"

# from forwarder
localhost:10025
inet n - n - - smtpd
-o content_filter=genocide
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_helo_restrictions=
-o smtpd_client_restrictions=
-o smtpd_sender_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o myhostname=localhost

# antivirus
genocide unix - n n - 10 pipe
flags=R
user=filter
argv=/usr/local/raven/mail/antikav.pl "localhost:10026" "${sender}" "${recipient}"

# from antivirus
localhost:10026
inet n - n - - smtpd
-o content_filter=spamfilter
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_helo_restrictions=
-o smtpd_client_restrictions=
-o smtpd_sender_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o myhostname=localhost

# spamfilter
spamfilter
unix - n n - 10 pipe
flags=R
user=filter
argv=/usr/local/raven/mail/std2lmtp.pl "localhost:10027" "antispam" "
${sender}" "${recipient}" "/usr/local/bin/spamc"

# from spamfilter to smtpd:10026
localhost:10027
inet n - n - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_helo_restrictions=
-o smtpd_client_restrictions=
-o smtpd_sender_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o myhostname=localhost

а к /usr/local/etc/postfix/main.cf добавляем вот это:

# первый из цепочки фильтров:
content_filter = forwarder

# необходимо для корректной работы скриптов!
forwarder_destination_recipient_limit = 1
genocide_destination_recipient_limit = 1
spamfilter_destination_recipient_limit = 1

forwarder.pl, antikav.pl и std2lmtp.pl можно найти вот в этом архиве. в каждом скрипте вначале есть мини конфигурация, в которой необходимо как минимум прописать логин и пароль для mysql.

forwarder.pl - помощник 'старшего брата'. копирует письмо на нужный адрес в случае необходимости. если нужного адреса нет, то просто прокидывает письмо к следующему элементу в цепочке.

antikav.pl - антивирусный фильтр. с помощью модуля MIME::Tools разбирает письмо на файлы, которые кладёт в /tmp, напускает на эти файлы kavscanner и, парся его вывод, определяет что из этих файлов заражено. заражённые файлы вычленяет из письма, собирает письмо обратно с помощью всё того же MIME::Tools и отправляет следующему фильтру в цепочке.

std2lmtp.pl - вообще это мелкий скрипт, который переправляет содержимое stdin в на указанный адрес по smtp протоколу. в нашем случае этот скрипт кроме простого перенаправления, на письмо ещё и напускает указанную программу (spamc), которая в свою очередь соединяется со spamd, который является самом spamassassin, проверяет письмо на спамность и в случае необходимости помечает его. ну а наш скрипт потом результат отправляет в smtpd, который последний в цепочке фильтров и дальше уже идёт раскладка по почтовым ящикам.

todo, хотелки, благодарности и всё остальное...
postgresql
как я уже упоминал в начале, mysql представляет из себя записную книжку с sql интерфейсом. он, конечно, быстр, удобен для определённых задач, но держать лишний sql сервер на машине ради почты не очень хочется. сам я сейчас работаю исключительно с postgresql и хотел сделать данную связку не на основе mysql, а на основе postgresql. хотел - сделал и даже начал писать how-to по нему, но есть одна большая проблема.

почему-то после соединений postfix или courier-imap с postgresql сервером, в памяти от них остаются процессы postmaster в состоянии idle, которые потом закрываются и сообщают в лог о том, что пришёл неожиданный eof от клиента. причем происходит это только в случае, если клиентами выступают postfix или courier-imap. pam_pgsql и мои перловые тесты отрабатывают нормально.

если у кого-то получилось настроить postfix и courier-imap в связке с postgresql, то, пожалуйста, расскажите мне, как вы это делали, я сделаю ещё один how-to, где вместо mysql будет postgresql со всеми его фичами и, естественно обязательно упомяну вас. очень уж хочется снести mysql со своих серверов! он хоть и простой и быстрый, но память-то всё равно жрёт ;)

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

поэтому я говорю спасибо только себе, за то, что ещё не сошёл с ума от всего безумства жизни, за то, что ещё жив, по прежнему быстр и рационален, хоть и постоянно занят :-(

http://raven.elk.ru

Обновлено: 12.03.2015