На главную
Классический MTA средствами qmail.Copyright (C) 2004 М. Альхименко. Содержание:
ВведениеЗдесь не ставилось целью дать полный перевод официальных руководств автора qmail — D. J. Bernstein'а (DJB) или написать "Книгу юных сурков" на все случаи жизни. Хотелось дать общее представление, как все устроено, а с частностями (например, с форматом запуска multilog) можно разобраться и самому. Imho основная цель этой статьи - помочь разобраться с классической доставкой почты в unix-системах (средствами qmail). Хотя, если строго следовать определению "классический", то изучать надо было бы sendmail, но imho не стоит привыкать к плохому с самого начала ;) . Все команды и пути даются из расчета на работу с RH-based Linux (RH9, ASP9) и FreeBSD 4.9, т.к. пока нет опыта работы с другим ОС. Если у вас другая система, и пути/команды не подходят, пишите — соответствующие поправки будут по возможности включены. На большинстве работающих серверов почта является едва ли не единственным средством обратной связи системы с администратором. По почте направляют отчеты о работе cron, системы вроде LIDS, различные средства мониторинга (smartd, logwatch) и пр. Многие распространенные дистрибутивы Linux (например RH9 и ASP9) ставят в качестве MTA или нечто дырявое (sendmail) или что-то, что тянет за собой несколько ненужных программ (postfix-xxx.i386.rpm требует MySQL + cyrus-sasl + ...), в данном случае совершенно ненужных. Поэтому было решено попробовать поставить MTA из исходников, и в был выбран qmail в его первоначальном варианте — без того множества дополнительных программ (и патчей вроде qmail-ldap), которые превращают его в нечто суперкрутое и суперсерьезное для обслуживания десятков доменов с тысячами пользователей. Только в роли классического unix'ового MTA. Для тех, кто не знаком с основами доставки почты в Unix я, к сожалению, не могу порекомендовать ничего полного, т.к. знания об этом приходилось собирать по частям из кучи руководств и подсказок знакомых. Самое приличное, что мне попадалось - "Руководство администратора Linux" Немет Э., Снайдер Г., Хейн Т. "Вильямс", 2003. Поэтому кратко изложу здесь то, что я понял. Может это поможет Вам разобраться, как все работает. Мы отправляем письмо по адресу user@host.domain.ru, то есть письмо предназначено пользователю "user", для которого есть учетная запись на хосте host.domain.ru. На первом этапе доставки программа, отправляющая почту (или мы сами из оболочки пользователя), вызывает MUA - Mail User Agent, клиента электронной почты передает ему адрес получателя и текст сообщения. (Обычно в качестве MUA в скриптах используется программа mail, в RH и ASP она входит в пакет mailx). Mail формирует сообщение и передает его MTA (Mail Transport Agent), который отвечает за доставку сообщений между системами или внутри системы между пользователями. Обычно все MUA при вызове MTA ищут бинарник sendmail (как интерфейс MUA -> MTA), а все MTA стараются его эмулировать, хотя некоторые MTA подменяют и саму программу mail, как это делает CGP. (Многие современные клиенты электронной почты частично реализуют функциональность MTA - передают сообщения по SMTP-протоколу настоящему MTA для дальнейшей пересылки). Далее MTA, если сообщение для локального пользователя, кладет его в соответствующие хранилище сообщений пользователя в системе (maildir или mailbox). Если сообщение отправлено для пользователя в другую систему, то MTA ищет в DNS MX-запись (Mail Exchanger), указывающую, какая машина принимает сообщения для пользователей нужного хоста или домена. Для каждого домена должна, а для хоста может сущеcтвовать в DNS соответствующая MX-запись, которая указывает на хост, принимающий почту для данной системы. Если для хоста нет записи MX, то MTA пытается передать сообщение напрямую на этот хост, основываясь только на записи типа A. Обычно для хоста запись MX используется в том случае, если он сам не принимает свою почту (в системе нет MTA или он не слушает 25 порт или он скрыт за firewall), а за него это делает другая система. Это очень упрощенная схема, но дает представления об основах работы MTA. Таким образом, в идеале на каждом хосте должен быть запущен MTA,
который принимает почту для пользователей своей системы
(в современном Internet слушая 25 порт TCP), осуществляет локальную доставку почты между пользователями
и занимается доставкой сообщений пользователям других систем (отправленную изнутри системы), направляя почту MTA в этой
системе, то есть занимается транспортом почты. MUA служит для просмотра пользователем своей почты в системе и передаче
MTA сообщений для доставки. Просматривать сообщения в системе MUA может или напрямую, просматривая хранилище сообщений,
или через демоны POP3 или IMAP, которые служат средством удаленного просмотра хранилища сообщений пользователем. Итак, в качестве MUA у нас есть mail, а как MTA мы будем использовать qmail. Он легкий, быстрый и в нем не было найдено ни одной дырки. Ставить qmail можно и по указанным ниже руководствам, но здесь будет описан процесс установки MTA, заточенный под определенную цель - без излишних наворотов (хотя, почитать эти мануалы безусловно стоит) и в том виде, каким его планировал DJB (imho, конечно). Запускать qmail можно из обычных стартовых скриптов, но imho лучше использовать для этого пакет daemontools, так же написанный DJB. Он является аналогом Service Manager'а в Win2k — предназначен для управлением сервисами. В числе прочих достоинств, описанных самим DJB на странице программы он имеет бесспорное преимущество - перезапускает демон в случае его падения. Если Вам не хочется ставить этот пакет, можете позаимствовать один из скриптов в указанных ниже руководствах для запуска qmail и запускать его или из rc.local (если у вас BSD-style система запуска) или с использованием runlevels, как в RH (система SysV) или еще как-нибудь. Краткое описание daemontools дается в отдельной статье. УстановкаИдем на http://cr.yp.to/qmail.html, выбираем ближайшее зеркало, скачиваем и распаковываем исходники:# cd /usr/src # wget ftp://ftp.eu.uu.net/pub/unix/mail/qmail/qmail-1.03.tar.gz # gunzip qmail-1.03.tar.gz # tar -xvf qmail-1.03.tar создаем каталог для патчей, скачиваем их и накладываем на исходники (Следует правильно понимать назначение этих патчей. Это не исправления безопасности, а добавление функциональности и совместимости. Т.к. весь софт DJB идет под немного ограничивающей лицензией, то все изменения и новые функции в нем доступны в виде пачей): # cd qmail-1.03 # mkdir patch # cd patch # wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/qmail-1.03.errno.patch (патч для совместимости с glibc 2.3.1 и выше) # wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/qmail-1.03.qmail_local.patch (разрешает использовать символ табуляции в началах строк в файлах .qmail) # wget http://www.jms1.net/qmail/qmail-date-localtime.patch (установка в заголовках локального времени, а не GMT) # wget http://www.flounder.net/qmail/qmail-dns-patch (патч для обрабтки записей в DNS, не соотвествующих RFC, которые имеют завышенные размеры (больше 512 байт). Не нужно накладывать, если вы используете dnscache из состава djbdns) # wget http://qmail.org/qmail-smtpd-relay-reject (патч для блокирования адресов типа user1%domain1@domain2 еще на стадии приема письма) # wget http://david.acz.org/software/sendmail-flagf.patch (патч для лучшей совместимости с sendmail при эмуляции его вызова при local-inject) # wget http://www.fehcom.de/qmail/qmail-smtpd.c.size.diff (патч для поддержки команды SIZE из RFC1870) # wget http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch (патч для распознавания адреса 0.0.0.0 как локального) # wget http://www-dt.e-technik.uni-dortmund.de/~ma/qmail/patch-qmail-1.03-rfc2821.diff (патч для совместимости с RFC2821; позволяет пропускать mx-сервера, отвечающие кодом от 400 до 499 и возвращать сообщение, если код ответа от 500 до 599.) Если вы хотите, чтобы qmail-remote пропускал хосты, отвечающие кодом 5XX и пробовал следующую mx-запись для реальной совместимости с RFC-2821 (как это делают Sendmail and Postfix), измените в последнем патче строку if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed"); на if (code >= 500 && code < 600) return; Вместо этого патча можно использовать патч http://www.qmail.org/accept-5xx.patch # cd .. # patch -p1 < patch/qmail-1.03.errno.patch # patch -p1 < patch/qmail-1.03.qmail_local.patch # patch -p1 < patch/qmail-date-localtime.patch # patch -p1 < patch/qmail-dns-patch # patch -p1 < patch/qmail-smtpd-relay-reject # patch -p0 < patch/sendmail-flagf.patch # patch -p1 < patch/qmail-0.0.0.0.patch # patch -p2 < patch/qmail-smtpd.c.size.diff # patch -p0 < patch/patch-qmail-1.03-rfc2821.diff Теперь внимательно читаем файл INSTALL в каталоге исходников и следуем инструкциям: Создаем каталог для qmail: # mkdir /var/qmail Создаем пользователей для qmail: # cp INSTALL.ids IDS # vi IDS Убираем из скрипта ненужные строки, оставляем только для своей системы, убираем с них комментарии и запускаем скрипт: # . IDS (не забудьте про пробел!) Проверяем, добавились ли новые пользователи и группы: # cat /etc/passwd # cat /etc/group Переходим в /var/qmail и удаляем оттуда все dot-файлы, добавленные туда из /etc/skel для нового пользователя. То же делаем и для /var/qmail/alias. В итоге каталог /var/qmail/ должен содержать только каталог alias - больше ничего. Собираем и устанавливаем qmail: # cd /usr/src/qmail-1.03 # make setup check Если все прошло без ошибок, значит qmail собран и установлен в /var/qmail. Свои man-страницы qmail устанавливает в /var/qmail/man, сделаем их доступными для команды man. Для этого нужно включить путь к man-страницам qmail в общесистемные пути к man'ам. Добавляем строку: MANPATH /var/qmail/man в файл /etc/man.config вручную или так: # echo "MANPATH /var/qmail/man" >> /etc/man.config К сожалению, мне так и не удалось во FreeBSD добавить пути к man-файлам qmail в общестистемные. Если кто знает как это сделать -- буду признателен за помощь. НастройкаТеперь нужно сделать первичную конфигурацию qmail. Все основные настройки хранятся в файлах в каталоге /var/qmail/control. В первую очередь это файлы:
Эти файлы автоматически создаются скриптом config, находящимся в каталоге исходников qmail. При запуске он пытается найти в DNS имя хоста, прописанное в /etc/sysconfig/network и, соответственно, в /proc/sys/kernel/hostname и переменной окружения HOSTNAME. Если ему это удается, он выполняет обратное преобразование и ищет FQDN для полученного ip-адреса. Это имя он кладет в me, имя домена в defaultdomain. Потом пытается найти PTR записи для всех локальных ip-адресов. Все найденные имена он также кладет в locals. Затем говорит нам, что если у нас еще есть доменные имена, ссылающиеся на наш хост, надо поместить их в locals. После этого копирует locals в rcpthosts (список хостов/доменов, для которых qmail будет принимать почту) и сообщает: Now qmail will refuse to accept SMTP messages except to those hosts.Make sure to change rcpthosts if you add hosts to locals or virtualdomains! Теперь qmail будет отвергать любые сообщения по SMTP кроме предназначенных для этого хоста. Убедитесь, что вы изменили rcpthosts, если вы добавили хост в locals или virtualdomains! Если ip-адрес, соответствующий вашему hostname невозможно найти в DNS, то скрипт выдает ошибку: Your hostname is gw. hard error Sorry, I couldn't find your host's canonical name in DNS. You will have to set up control/me yourself. Имя вашего хоста - gw серьезная ошибка Извините, не могу найти имя вашего хоста в DNS. Вам придется самому настроить control/me. и предлагает заполнить нужные файлы вручную. В таком случае выполняем: # ./config-fast полное_имя_вашего_хоста Этот скрипт не выполняет запросов в DNS, а просто заполняет файлы в control на основании переданного имени. Рекомендется посмотреть сами скрипты — там все достаточно ясно. Также, об этом написано в INSTALL.ctl. Узнать о назначении всех файлов в /var/qmail/control можно на http://www.ru.qmail.org/inform.html Теперь нужно создать псевдонимы для postmaster, MAILER-DAEMON и root (qmail не доставляет почту для root - для пущей безопасности), т.е. выбрать пользователя которому будут пересылаться сообщения, пришедшие на эти адреса. Пусть это будет пользователь max. (Помните, что это должен быть реальный пользователь системы!) Псевдонимы определяются файлами формата .qmail-user, лежащих в /var/qmail/alias. В каждом файле лежит имя пользователя, которому пересылается почта, пришедшая для user. # cd ~alias# touch .qmail-postmaster .qmail-mailer-daemon .qmail-root # chmod 644 ~alias/.qmail* # echo max > .qmail-postmaster # echo max > .qmail-mailer-daemon # echo max > .qmail-root Теперь нам нужно создать замену бинарнику sendmail, чтобы MUA могли отдавать почту qmail: Проверяем, нет ли у нас sendmail (если у вас не стоит пакет slocate воспользуйтесь find): # locate sendmail Если у вас что-то завалялось из состава других MTA, тщательно удалите их следы (бинарники, строки запуска в стартовых скриптах и inetd.conf и пр.), если, конечно, вы их не используете для каких-то целей. В таком случае, думайте сами, что делать. Создаем симлинк на бинарник sendmail из состава qmail (/var/qmail/bin/sendmail): # ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail Если у вы устанавливаете qmail на FreeBSD, то этого делать не надо — смотрите соотвутсвующий раздел. На этом установка закончена. MaildirТеперь нужно создать хранилища для пользовательских сообщений. Исторически, сообщения пользователей хранятся в формате Mailbox - один большой файл со всеми сообщениями пользователя в каталоге /var/spool/mail - по одному для каждого пользователя. DJB предложил новый формат: Maildir - каждое сообщение хранится в отдельном файле в специальной папке, которая обычно находится в домашнем каталоге пользователя. Это увеличивает сохранность сообщений и дает еще некоторое преимущества. Более развернуто почитать о достоинствах этого формата вы можете по указанным ниже ссылкам. О самом формате можно узнать набрав man maildir. Итак, мы выбираем Maildir. Для создания каталога Maildir служит программа maildirmake. О параметрах запуска вы можете почитать на её man-странице. Становимся пользователем, которого мы выбрали для псевдонимов root, postmaster и MAILER-DAEMON, чтобы сразу получить все файлы/каталоги с нужными разрешениями и создаем каталог maildir: # su max$ /var/qmail/bin/maildirmake /home/max/Maildir В каждом каталоге пользователя может лежать файл .qmail, в котором содержатся директивы о том, что делать с письмами для этого пользователя. Почитать о его формате можно на man-странице dot-qmail. Создадим этот файл: $ cd $ touch .qmail Добавим туда директиву "./Maildir/", которая будет говорит qmail о том, что сообщение надо хранить в нужном нам формате: $ echo "./Maildir/" > .qmail Нам нужно, чтобы сообщения уходили за переделы системы и пересылались на наш внешний ящик (например, liar@my.domain.ru). Для этого добавим строку "&liar@my.domain.ru": $ echo "&liar@my.domain.ru" >> .qmail Становимся опять root: $ exit Теперь нам нужно сделать так, чтобы у каждого вновь созданного пользователя автоматически создавался ящик в его homedir. Для этого дополним каталог /etc/skel нужными нам шаблонами: # /var/qmail/bin/maildirmake /etc/skel/Maildir # touch /etc/skel/.qmail # echo "./Maildir/" > /etc/skel/.qmail Все, теперь необходимые приготовления сделаны, можно приступать к запуску. Запуск qmail-start Примеры скриптов запуска лежат в /var/qmail/boot. Если посмотреть
их содержимое, то становится ясно, что общий принцип таков: Поскольку supervise, как только обнаружит у себя в /services новый каталог, сам запускает скрипт run из него, и перезапускает программу при её смерти, мы создадим в каталоге /var/qmail файл down, чтобы supervice не запускал qmail автоматом, пока нам этого не будет надо (см. документацию по daemontools): # touch /var/qmail/downСоздаем симлинк на /var/qmail в каталоге /services чтобы svscan мог узнать о существовании нового сервиса: # ln -s /var/qmail /service Если выполнить pstree, то можно увидеть новый процесс supervise в дереве процессов daemontools. Он обнаружил файл down и поэтому не запускает демон автоматически, а ждет команду на запуск. Теперь все готово к запуску qmail. Управление сервисами в daemontools производится с помощью программы svc. Запускаем qmail: # svc -u /service/qmail/ Смотрим, что получилось: # pstree -u Если все прошло нормально, то мы увидим: ...skip...
|-svscanboot-+-readproctitle
...skip...
В /var/log/maillog появится запись: Dec 22 14:41:55 gw qmail: 1072093315.662894 status: local 0/10 remote 0/20 (Возможно появление еще нескольких записей об отправке — в отсутствии MTA демоны накапливают некоторое количество писем для root). Обратите внимание на имена пользователей, под которыми работают программы. Они должны быть именно такими, иначе qmail откажется работать. Если у вас они не совпадают с приведенным выводом, проверьте, все ли вы сделали правильно. Теперь пробуем отправить сообщение: # mail -s "test 1" root (набираем текст сообщения)<Enter> .<Enter> cc:<Enter> Все, сообщение ушло. Смотрим логи. Там должны быть записи о старте демона и доставке сообщения. Dec 22 14:46:02 gw qmail: 1072093562.312652 new msg 131426 Dec 22 14:46:02 gw qmail: 1072093562.312773 info msg 131426: bytes 253 from <root@HOST.DOMAIN.RU> qp 10386 uid 0 Dec 22 14:46:02 gw qmail: 1072093562.318170 starting delivery 1: msg 131426 to local root@host.domain.ru Dec 22 14:46:02 gw qmail: 1072093562.318241 status: local 1/10 remote 0/20 Dec 22 14:46:02 gw qmail: 1072093562.355299 new msg 131429 Dec 22 14:46:02 gw qmail: 1072093562.355382 info msg 131429: bytes 359 from <root@HOST.DOMAIN.RU > qp 10389 uid 502 Dec 22 14:46:02 gw qmail: 1072093562.360645 starting delivery 2: msg 131429 to local max@host.domain.ru Dec 22 14:46:02 gw qmail: 1072093562.360716 status: local 2/10 remote 0/20 Dec 22 14:46:02 gw qmail: 1072093562.360741 delivery 1: success: did_0+1+0/qp_10389/ Dec 22 14:46:02 gw qmail: 1072093562.360760 status: local 1/10 remote 0/20 Dec 22 14:46:02 gw qmail: 1072093562.360776 end msg 131426 Dec 22 14:46:02 gw qmail: 1072093562.572414 new msg 131426 Dec 22 14:46:02 gw qmail: 1072093562.572490 info msg 131426: bytes 466 from <root@HOST.DOMAIN.RU > qp 10393 uid 500 Dec 22 14:46:02 gw qmail: 1072093562.577913 starting delivery 3: msg 131426 to remote liar@my.domain.ru Dec 22 14:46:02 gw qmail: 1072093562.577985 status: local 1/10 remote 1/20 Dec 22 14:46:02 gw qmail: 1072093562.578008 delivery 2: success: did_1+1+0/qp_10393/ Dec 22 14:46:02 gw qmail: 1072093562.578028 status: local 0/10 remote 1/20 Dec 22 14:46:02 gw qmail: 1072093562.578045 end msg 131429 Dec 22 14:46:02 gw qmail: 1072093562.590113 delivery 3: success: 81.26.136.2_accepted_message./Remote_host_said:_250_300014_message_accepted_for_delivery/ Dec 22 14:46:02 gw qmail: 1072093562.612473 status: local 0/10 remote 0/20 Dec 22 14:46:02 gw qmail: 1072093562.612544 end msg 131426 (сообщения удаленного хоста у вас могут быть другими) Через некоторое время проверяем почту в ящике, указанном в файле .qmail в каталоге пользователя, указанного в псеводонимах в каталоге ~alias. В каталоге исходников есть более развернутое описание тестов доставки - TEST.deliver, если будет желание, можете провести их все. Если все нормально, то удаляем файл down, чтобы daemontools перезапускал qmail в случае его падения: # rm /var/qmail/down Qmail-smtpdУстановка ucspi-tcp Чтобы ваш qmail отвечал высокому званию "MTA" он должен уметь не только доставлять почту локальным и удаленным клиентам
изнутри системы, но и принимать её снаружи. Этим занимается qmail-smtpd. Соединения он принимает через программы,
аналогичные inetd. Для замены tcpwrappers/inetd/xinetd DJB написал пакет ucspi-tcp,
его мы и будем использовать. Процесс tcpserver при старте начинает слушать указанный порт (в нашем случае 25) и передает входящие данные программе qmail-smtpd, которую он запускает при установке соединения. Qmail-smtpd в свою очередь передает пришедшую почту qmail-queue для дальнейшей доставки. Cкачиваем и распаковываем исходники:# cd /usr/src # wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz # gunzip ucspi-tcp-0.88.tar # tar -xf ucspi-tcp-0.88.tar # cd ucspi-tcp-0.88 Cоздаем каталог для патчей, скачиваем и накладываем их на исходники: # mkdir patch # cd patch # wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/ucspi-tcp-0.88.nobase.patch # wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/ucspi-tcp-0.88.errno.patch # wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/ucspi-tcp-0.88.a_record.patch # cd .. # patch -p1 < patch/ucspi-tcp-0.88.a_record.patch # patch -p1 < patch/ucspi-tcp-0.88.nobase.patch # patch -p1 < patch/ucspi-tcp-0.88.errno.patch компилируем и устанавливаем: # make # make setup check Запуск qmail-smtpdСоздаем в /var/qmail каталог smtpd (другого, более осмысленного размещения придумать не удалось):# mkdir /var/qmail/smtpd Создаем в /var/qmail/smtpd скрипт run (для запуска qmail-smtpd с помощью daemontools) и файл down: # cd /var/qmail/smtpd # touch run down открываем run в mc или vi и вставляем туда текст: #!/bin/sh exec envuidgid qmaild \ softlimit -m 2000000 \ tcpserver -UDHRQ 0 smtp \ /var/qmail/bin/qmail-smtpd # chmod 755 run здесь сначала запускается envuidgid (из состава daemontools), в качестве параметра запуска
передается имя учетной записи, с правами которой запустится tcpserver. Она устанавливет переменные окружения
$GID и $UID. Затем запускается программа softlimit, она устанавливает пределы на использование памяти (у нас - ~2MB).
Softlimit запускает tspserver, который переключается на работу с правами UID и GID, считанных из переменных окружения
$GID и $UID (параметр запуска "-U"). Tcpserver при коннекте на слушаемый порт запускает qmail-smtpd.
Подробнее - смотрите в документации на соотвествующие программы. Замечания относительно FreeeBSDПоскольку этот текст был написан в те времена, когда я работал только с Linux, некоторые моменты неприменимы к FreeBSD. Недавно появилась возможность установить qmail и на FreeBSD, в связи с чем наметились несколько дополнений, которые было решено вынести в отдельный раздел для экономии времени. Во-первых, во FreeBSD мне не удалось найти возможность полностью удалить sendmail из системы, поэтому чтобы его корректно отключить сделайте следующее:
Во-вторых, нам необходимо корректно заменить sendmail и системе.
Далее идет перевод какого-то из man'ов (никак не могу вспомнить какого): Cсылки
|