Почтовый модуль#

Реализует почтовый прокси: Angie обслуживает подключения IMAP-, POP3- и SMTP-клиентов и, когда внешний сервер аутентификации принимает клиента и выбирает для него бэкенд, передает сессию клиента на этот бэкенд. Остальные модули этого раздела добавляют поддержку протоколов, обмен с сервером аутентификации, SSL/TLS и настройки проксирования.

При сборке из исходного кода модуль не собирается по умолчанию; его необходимо включить с помощью параметра сборки --with-mail.

В пакетах и образах из наших репозиториев модуль включен в сборку.

Принцип работы#

Angie работает посредником между почтовыми клиентами и бэкендами и обрабатывает каждую сессию в четыре этапа:

  1. Клиент подключается к Angie, а не к бэкенду. Angie сам отправляет приветствие, отвечает на запросы о возможностях сервера, выполняет STARTTLS и получает учетные данные клиента одним из методов, заданных директивами imap_auth, pop3_auth или smtp_auth.

  2. Angie передает учетные данные серверу аутентификации, заданному директивой auth_http, в заголовках HTTP-запроса. Если SMTP-клиент отправляет почту без аутентификации, этот запрос уходит после его команды RCPT TO.

  3. Сервер аутентификации принимает или отклоняет клиента. Принимая клиента, сервер аутентификации возвращает IP-адрес и порт бэкенда в заголовках ответа Auth-Server и Auth-Port, а также может вернуть имя пользователя и пароль для входа на бэкенд.

  4. Angie открывает TCP-соединение с бэкендом, без TLS, и входит на него от имени клиента IMAP-командой LOGIN или POP3-командами USER и PASS. SMTP-бэкенду Angie передает сведения о клиенте командой XCLIENT, если включена директива xclient (по умолчанию включена), и аутентифицируется командой AUTH PLAIN, если включена директива proxy_smtp_auth. После этого Angie передает данные между клиентом и бэкендом.

В блоке mail нет ни proxy_pass, ни групп upstream: ответ сервера аутентификации — единственный способ, которым Angie узнает, куда проксировать сессию. Поэтому директива auth_http нужна каждому server в блоке mail, даже если он принимает SMTP-почту без аутентификации. Заголовки запроса и ответа описаны в модуле Auth HTTP.

Пример конфигурации#

Минимальная конфигурация проксирует IMAP- и POP3-сессии на один бэкенд по адресу 192.0.2.10. Сервер аутентификации — это location в том же Angie: он принимает любого клиента и оставляет проверку пароля бэкенду, что подходит для включенных по умолчанию методов входа с паролем в открытом виде. Блок mail поместите на верхний уровень angie.conf, а блоки map и server — внутрь существующего блока http:

mail {
    auth_http                127.0.0.1:9000/mail-auth;
    proxy_pass_error_message on;

    server {
        listen   143;
        protocol imap;
    }

    server {
        listen   110;
        protocol pop3;
    }
}

http {
    map $http_auth_protocol $mail_backend_port {
        imap 143;
        pop3 110;
    }

    server {
        listen 127.0.0.1:9000;

        location = /mail-auth {
            add_header Auth-Status OK;
            add_header Auth-Server 192.0.2.10;
            add_header Auth-Port   $mail_backend_port;

            return 204;
        }
    }
}

Поскольку бэкенд сам проверяет пароль, включена директива proxy_pass_error_message: клиент с неверным паролем получает ответ бэкенда с ошибкой, а не сообщение о внутренней ошибке, после чего Angie закрывает соединение. Сервер аутентификации получает пароли клиентов в незашифрованном виде, поэтому он должен слушать локальный или другой доверенный адрес.

Более полная конфигурация также проксирует SMTP и включает дополнительные методы аутентификации. Ее сервер аутентификации, в данном случае CGI-скрипт, должен сам проверять дайджесты APOP и CRAM-MD5 и возвращать пароль пользователя в Auth-Pass, как описано в модуле Auth HTTP:

worker_processes auto;

error_log /var/log/angie/error.log info;

events {
    worker_connections  1024;
}

mail {
    server_name       mail.example.com;
    auth_http         localhost:9000/cgi-bin/auth.cgi;

    imap_capabilities IMAP4rev1 UIDPLUS IDLE LITERAL+ QUOTA;

    pop3_auth         plain apop cram-md5;
    pop3_capabilities LAST TOP USER PIPELINING UIDL;

    smtp_auth         login plain cram-md5;
    smtp_capabilities "SIZE 10485760" ENHANCEDSTATUSCODES 8BITMIME DSN;
    xclient           off;

    server {
        listen   25;
        protocol smtp;
    }
    server {
        listen   110;
        protocol pop3;
        proxy_pass_error_message on;
    }
    server {
        listen   143;
        protocol imap;
    }
    server {
        listen   587;
        protocol smtp;
    }
}

Директивы#

error_log_user_tag#

Добавлено в версии 1.12.0.

Синтаксис

error_log_user_tag значение;

По умолчанию

—

Контекст

mail, server

Добавляет тег к записям error_log каждой сессии, которую обслуживает сервер. В отличие от одноименных директив модулей http и stream, значение — статическая строка, переменные в ней не поддерживаются. Директива может задаваться несколько раз для добавления нескольких тегов. Директивы наследуются с предыдущего уровня конфигурации при условии, что на данном уровне не описаны свои директивы error_log_user_tag.

Теги выводятся в виде списка tags только в логах error_log с format=json; фильтр filter=tag: находит их при любом формате.

listen#

Синтаксис

listen адрес[:порт] [ssl] [proxy_protocol] [backlog=число] [rcvbuf=размер] [sndbuf=размер] [bind] [ipv6only=on | off] [multipath] [so_keepalive=on | off | [keepidle]:[keepintvl]:[keepcnt]];

По умолчанию

—

Контекст

server

Задает адрес и порт для сокета, на котором сервер будет принимать соединения. Можно указать только порт, и тогда Angie будет слушать на всех доступных IPv4-интерфейсах (и IPv6, если он включен). Кроме того, адрес может быть именем хоста, например:

listen 127.0.0.1:110;
listen *:110;
listen 110;     # то же, что и *:110
listen localhost:110;

IPv6-адреса задаются в квадратных скобках:

listen [::1]:110;
listen [::]:110;

UNIX-сокеты задаются префиксом unix:

listen unix:/var/run/angie.sock;

Примечание

Разные серверы должны слушать на разных парах адрес:порт.

ssl

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

proxy_protocol

указывает на то, что все соединения, принимаемые на данном порту, должны использовать протокол PROXY. Полученная информация передается серверу аутентификации и может быть использована для изменения адреса клиента.

В директиве listen можно также указать несколько дополнительных параметров, специфичных для связанных с сокетами системных вызовов.

backlog=число

задает параметр backlog в вызове listen(), который ограничивает максимальный размер очереди ожидающих приема соединений. По умолчанию backlog устанавливается равным -1 для FreeBSD, DragonFly BSD и macOS, и 511 для других платформ.

rcvbuf=размер

задает размер буфера приема (параметр SO_RCVBUF) для слушающего сокета.

sndbuf=размер

задает размер буфера передачи (параметр SO_SNDBUF) для слушающего сокета.

bind

указывает, что для данной пары адрес:порт нужно делать отдельный вызов bind(). Без этого параметра, если несколько директив listen используют один порт с разными адресами и одна из них слушает на всех адресах этого порта, Angie вызывает bind() только для wildcard-сокета, а адрес, на который пришло соединение, определяет системным вызовом getsockname(). Параметры backlog, rcvbuf, sndbuf, ipv6only, multipath и so_keepalive всегда влекут за собой отдельный вызов bind().

ipv6only=on | off

определяет (через параметр сокета IPV6_V6ONLY), будет ли слушающий на wildcard-адресе [::] IPv6-сокет принимать только IPv6-соединения, или же одновременно IPv6- и IPv4-соединения. По умолчанию параметр включен. Установить его можно только один раз на старте.

multipath

включает прием соединений по протоколу Multipath TCP (MPTCP), поддерживаемому в ядре Linux с версии 5.6.

so_keepalive=on | off | [keepidle]:[keepintvl]:[keepcnt]

Конфигурирует для слушающего сокета поведение "TCP keepalive".

''

если параметр опущен, для сокета будут действовать настройки операционной системы

on

для сокета включается параметр SO_KEEPALIVE

off

для сокета параметр SO_KEEPALIVE выключается

Некоторые операционные системы позволяют настраивать "TCP keepalive" для отдельного сокета с помощью параметров сокета TCP_KEEPIDLE, TCP_KEEPINTVL и TCP_KEEPCNT. На таких системах (в настоящее время это Linux, NetBSD, DragonFly, FreeBSD и macOS) значения этих параметров сокета задаются параметрами keepidle, keepintvl и keepcnt. Один или два параметра могут быть опущены, в таком случае для соответствующего параметра сокета будут действовать стандартные системные настройки. В macOS параметр keepidle задает вместо TCP_KEEPIDLE параметр сокета TCP_KEEPALIVE.

Например,

so_keepalive=30m::10

установит таймаут бездействия (TCP_KEEPIDLE) в 30 минут, для интервала проб (TCP_KEEPINTVL) будет действовать стандартная системная настройка, а счетчик проб (TCP_KEEPCNT) будет равен 10.

mail#

Синтаксис

mail { ... }

По умолчанию

—

Контекст

main

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

max_commands#

Синтаксис

max_commands число;

По умолчанию

max_commands 1000;

Контекст

mail, server

Задает максимальное количество команд, отправляемых во время аутентификации, для усиления защиты от DoS-атак.

max_errors#

Синтаксис

max_errors число;

По умолчанию

max_errors 5;

Контекст

mail, server

Задает число ошибок протокола, по достижении которого соединение закрывается.

protocol#

Синтаксис

protocol imap | pop3 | smtp;

По умолчанию

—

Контекст

server

Задает протокол проксируемого сервера. Поддерживаются протоколы IMAP, POP3 и SMTP.

Если директива не указана, то протокол может быть определен автоматически по общеизвестному порту, указанному в директиве listen:

imap: 143, 993
pop3: 110, 995
smtp: 25, 587, 465

При сборке из исходного кода поддержку ненужных протоколов можно отключить с помощью параметров сборки --without-mail_imap_module, --without-mail_pop3_module и --without-mail_smtp_module.

resolver#

Синтаксис

resolver [адрес ...] [conf [=файл]] [valid=время] [ipv4=on | off] [ipv6=on | off] [status_zone=зона] | off;

По умолчанию

resolver off;

Контекст

mail, server

Задает серверы DNS, с помощью которых Angie определяет имя хоста SMTP-клиента, чтобы передать его серверу аутентификации в заголовке запроса Client-Host, а SMTP-бэкенду — в команде XCLIENT, например:

resolver 127.0.0.53 [::1]:5353;

Адрес может быть указан в виде доменного имени или IP-адреса, и необязательного порта. Если порт не указан, используется порт 53. Серверы DNS опрашиваются циклически.

Необходимо указать хотя бы один адрес DNS-сервера или параметр conf, кроме формы resolver off;.

Помимо явно заданных адресов серверов директива распознает:

off

отключает преобразование имени хоста клиента и отменяет унаследованное значение директивы

conf [=файл]

считывает адреса DNS-серверов из указанного файла или из /etc/resolv.conf, если файл не указан

Файл может содержать строки nameserver в том же формате, что использует системный резолвер:

nameserver 127.0.1.4
nameserver 127.0.1.5

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

В процессе работы Angie перечитывает файл при его изменении, обновляя набор DNS-серверов.

Примечание

Рекомендуется использовать локальный доверенный резолвер, например 127.0.0.53 (systemd-resolved), а не публичный (например, 8.8.8.8). Публичные резолверы раскрывают DNS-запросы третьим сторонам и повышают риск атак с подменой кэша.

Примечание

Значение директивы наследуется вложенными блоками и может быть переопределено в них при необходимости. В пределах одного блока директиву допустимо указывать только один раз; повторное указание является ошибкой конфигурации.

При поиске имени хоста клиента Angie кэширует каждый DNS-ответ на время, заданное его TTL. Необязательный параметр valid позволяет переопределить этот срок:

valid

необязательный параметр, позволяет переопределить срок кэширования ответа

resolver 127.0.0.53 [::1]:5353 valid=30s;

По умолчанию Angie будет искать как IPv4-, так и IPv6-адреса при преобразовании имен в адреса.

ipv4=off

запрещает поиск IPv4-адресов

ipv6=off

запрещает поиск IPv6-адресов

status_zone

необязательный параметр, включает сбор информации о запросах и ответах сервера DNS в указанной зоне

Совет

Для предотвращения DNS-спуфинга рекомендуется использовать DNS-серверы в защищенной доверенной локальной сети.

Совет

При запуске в Docker используйте соответствующий внутренний адрес DNS-сервера, например 127.0.0.11.

resolver_timeout#

Синтаксис

resolver_timeout время;

По умолчанию

resolver_timeout 30s;

Контекст

mail, server

Задает таймаут для преобразования имени в адрес, например:

resolver_timeout 5s;

server#

Синтаксис

server { ... }

По умолчанию

—

Контекст

mail

Задает конфигурацию для сервера.

server_name#

Синтаксис

server_name имя;

По умолчанию

server_name hostname;

Контекст

mail, server

Задает имя сервера, используемое:

  • в начальном приветствии POP3/SMTP-сервера;

  • в salt при аутентификации SASL-методом CRAM-MD5;

  • в команде EHLO при подключении к SMTP-бэкенду, если разрешена передача команды XCLIENT.

Если директива не указана, используется имя хоста машины.

timeout#

Синтаксис

timeout время;

По умолчанию

timeout 60s;

Контекст

mail, server

Задает таймаут, который используется до начала проксирования на бэкенд.