FreeBSD - статьи

         

Настройка фильтров (антивирус, антиспам и форвардер)


я сразу хотел бы заметить, что все фильтры в данном 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/\r//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, который последний в цепочке фильтров и дальше уже идёт раскладка по почтовым ящикам.




Настройка 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("логин\0логин\0пароль");'

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




Настройка 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';






Настройка 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 вы используете на свой страх и риск. я, как автор за ваши действия и любые потери, связанные с ними ответственности не несу. кое-что для этого how-to я взял из how-to mysql+cyrus-sasl+courier-imap+postfix+openssl , пусть не обижается - я не присваиваю авторство, а information must be free.

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

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



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 со своих серверов! он хоть и простой и быстрый, но память-то всё равно жрёт ;)

благодарности

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

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



для чего всё это нужно.


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