Postfix — Amavisd-New Без Локального Хоста Или Нового Почтового Сервера

Инструкций по настройке почтового сервера с помощью связки postfix — amavisd-new — dovecot очень много.

И подавляющее большинство из них практически дословно повторяют друг друга, включая ошибки и неточности.

Мне кажется скучным бездумное нажатие кнопок, поэтому я решил оптимизировать стандартную конфигурацию: а что, если построить взаимодействие postfix и amavisd-new не через localhost, а на unix-сокете? Как оказалось, это не так просто, но я это сделал! Инструкция и патч под катом.

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

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

Более того, таким образом можно организовать защиту (посредством прав на файловую систему) даже там, где она отсутствует на уровне приложения или протокола.

Итак, путь почты в обсуждаемом соединении выглядит так:

Postfix — amavisd-new без локального хоста или нового почтового сервера

Получается, что нам нужно организовать два соединения: при переходе на фильтрацию и при возврате обратно в MTA. Поскольку сокет создается слушателем, то в первом случае это будет amavisd, а во втором — постфикс.

Начнем со второго, потому что он проще и лучше описан.

Чтобы постфикс создал сокет прослушивания, вам просто нужно указать unix, а не inet, во втором столбце master.cf (столбец типа).

В этом случае в первом столбце указывается путь и имя файла сокета.

Поскольку постфиксные процессы выполняются в chroot (это можно отключить для конкретного процесса, но не следует этого делать), папку необходимо создать внутри домашнего каталога постфикса: /var/spool/postfix. Он будет содержать оба сокета:

  
  
  
  
  
  
  
  
  
   

mkdir /var/spool/postfix/amavis chown amavis:postfix /var/spool/postfix/amavis chmod 770 /var/spool/postfix/amavis

Итак, конфигурация постфикса:

amavis/postfix-in unix y - y - - smtpd -o smtpd_client_restrictions=$local_clients_only -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions= -o smtpd_milters=

Точные параметры зависят от ваших настроек, это мой вариант. Здесь есть две проблемы:
  1. Путь будет относительным к /var/spool/postfix/private, у которого очень строгие права.

  2. Я не уверен, верно ли это для всех дистрибутивов, но для Ubuntu это верно.

    Права на папку лучше не трогать (сокеты всех постфиксных сервисов там есть), лучше просто создать симлинк.

  3. Помимо сокета, postfix также создает для процесса pid-файл, имя которого автоматически генерируется с использованием маски $type.$name. Где тип будет равен unix, а имя берется из первого столбца master.cf. Получается unux.amavis/postfix-in т.е.

    файл в подпапке.

    Сам он его не создаст и завершится с ошибкой.

Итак, заменим костыли:

cd /var/spool/postfix/private ln -s .

/amavis .

mkdir /var/spool/postfix/pid/unix.amavis

Не очень красиво, но и не разрушительно для стандартной структуры папок пакета.

Перезапускаем постфикс и убеждаемся, что файл сокета появился в папке amavis, а файл pid — в pid/unix.amavis. К сожалению, права на сокет 666, но права на папку, которую вы создали ранее, защитят файл от посторонних глаз.

Проверить работу можно командой:

netcat -U /var/spool/postfix/amavis/postfix-in 220 mail.example.ru ESMTP Postfix

Отлично, мы справились.

Теперь о восторге.

Во-первых, давайте настроим обратный путь почты через сокет unix, принадлежащий postfix. Это работает из коробки:

$forward_method = 'smtp:/var/spool/postfix/amavis/postfix-in'; $notify_method = \$forward_method;

Ну а теперь самое сложное — настройка сокетов в amavisd. Решение можно найти в Интернет , но предлагает использовать один сокет, указанный в параметре $unix_socketname. Я хотел, чтобы мой собственный протокол amavisd-new (AM.PDP) и прием почты происходили через сокеты.

В файле конфигурации по умолчанию упоминается директива @listen_sockets, но для нее нет описания.

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

Вот что произошло:

$unix_socketname = undef; $inet_socket_bind = undef; $inet_socket_port = undef; @listen_sockets = ('/var/lib/amavis/amavisd.sock', '/var/spool/postfix/amavis/amavis-in.sock'); $unix_socket_mode = 0660; %interface_policy = ( '/var/lib/amavis/amavisd.sock' => 'AM.PDP-SOCK', '/var/spool/postfix/amavis/amavis-in.sock' => 'LMTP-SOCK' ); $policy_bank{'LMTP-SOCK'} = { protocol => 'LMTP' }; $policy_bank{'AM.PDP-SOCK'} = { protocol => 'AM.PDP', auth_required_release => 0, # don't require secret-id for release };

Перезапускаю и проверяю — действительно, оба сокета созданы! Победа? Не совсем, при попытке подключиться к сокету ничего не происходит, а в журнал пишется ошибка, что протокол для него не определен.

Получается, что политика банков к ним не применяется.

Как же так? Мне пришлось зайти в код. Эта поездка принесла две новости – как обычно, хорошую и плохую.

Хорошей новостью является то, что предположение относительно %interface_policy было верным:

# load policy banks according to my socket (destination), # then check for allowed access from the peer (client/source) # sub access_is_allowed($;$$$$) { my($unix_socket_path, $src_addr, $src_port, $dst_addr, $dst_port) = @_; my(@bank_names); if (defined $unix_socket_path) { push(@bank_names, $interface_policy{"SOCK"}); push(@bank_names, $interface_policy{$unix_socket_path}); } elsif (defined $dst_addr && defined $dst_port) { $dst_addr = '['.

lc($dst_addr).

']' if $dst_addr =~ /:[0-9a-f]*:/i; # IPv6? push(@bank_names, $interface_policy{$dst_port}); push(@bank_names, $interface_policy{"$dst_addr:$dst_port"}); } load_policy_bank($_) for @bank_names;

Плохо то, что $unix_socket_path приходит в эту функцию пустым.

Заполняется следующим образом:

my $is_ux = $sock && $sock->UNIVERSAL::can('NS_proto') && $sock->NS_proto eq 'UNIX';

И оба объекта там пусты.

Изучение документация предложил такой вариант:

my $unix_socket_path = $sock->hostpath();

И это сработало! Готовый .

патч можно сказать Здесь .

Остается последний штрих.

Поскольку amavisd создает свой сокет с правами только себе, а доступ другим мы запретили (что верно), то нужно добавить постфикс в группу amavis, чтобы она могла писать в сокет:

gpasswd -a postfix amavis

Готовый.

P.S. Патч и описание проблемы я отправил Марку Мартинеку по почте, так как на сайте нет упоминания о баг-трекере.

Веб-сайт Не нашел.

Ответа я до сих пор не получил, но особо на него не рассчитываю — проект выглядит заброшенным (последний релиз был более двух лет назад).

Теги: #*nix #Администрирование сервера #почтовый сервер #postfix #amavisd-new #unix-сокет

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.