20 Декабрь 2017

Управление выбором исходящих IP адресов в Exim

Outgoing IP addresses management in Exim

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

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

1. Стандартный выбор IP-адреса

На протяжении последних 15 лет стандартная политика выбора IP адреса регулируется стандартом RFC3484. Вкратце, операционная система всегда должна отдавать приоритет соединениям с использованием IPv6 адресов над IPv4. Приоритет за IPv4 может быть в ряде случаев лишь при использовании трансляции 6to4 (сеть 2002::0/16) или Teredo / 6in4 туннелей (сеть 2001::0/32).

На уровне системы этот приоритет можно изменить при помощи специальных настроек. В случае с FreeBSD за это отвечает специальная утилита ip6addrctl которая может производить как глобальное изменение предпочтений выбора версий IP протокола, так и более тонкий тюнинг по подсетям.

В общем случае для включения этого механизма достаточно добавить в файл стартовой конфигурации /etc/rc.conf следующие параметры

root@beta:~ # uname -v
FreeBSD 11.1-RELEASE-p4 #0: Tue Nov 14 06:12:40 UTC 2017     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC
root@beta:~ # grep ip6addrctl /etc/rc.conf
ip6addrctl_enable="YES"         # Enable selection
ip6addrctl_verbose="NO"         # Or YES to enable verbose configuration messages
ip6addrctl_policy="AUTO"        # RFC address selection policy (or set to ipv4_prefer, ipv6_prefer)

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

Дополнительную информацию о тонкой настройке приоритета при выборе IP-адреса см. документацию.

2. Выбор IP-адреса в Exim

Exim, как известно, является наиболее популярным на сегодня сервером SMTP в мире с долей свыше 50% видимых в сети почтовых узлов. Столь широкой популярности он обязан, не в последнюю очередь своим чрезвычайно гибким возможностям по настройке. Эта особенность в равной степени относится и к случаю управления выбором исходящих IP-адресов.

Касаемо приоритета при выборе версии IP протокола в общем случае Exim, как и любой другой софт работающий в рамках операционной системы, будет руководствоваться стандартной политикой, описанной в предыдущем разделе. Однако, вышеупомянутая гибкость конфигурирования позволяет определять свои приоритеты.

Список доступных IP-адресов для отправки исходящей почты определяется параметром interface в транспорте smtp.

root@beta:~ # cd /usr/local/etc/exim/
root@beta:/usr/local/etc/exim # cat configure
...
begin transports
...
remote_smtp:
  driver                = smtp
  interface             = <; 1.2.3.4 ; 2000:4:3:2::1
...

По умолчанию он не задан, что означает указание использовать все доступные в данной системе. В данном случае используется два адреса — один IPv4 и один IPv6.

Вызов данного транспорта с именем remote_smtp производится из роутера типа dnslookup.

root@beta:/usr/local/etc/exim # cat configure
...
begin routers

dnslookup:
  driver        = dnslookup
  domains       = !+local_domains
  transport     = remote_smtp
  no_more
...

Данные роутер, как правило, идёт первым в списке и служит для доставки почты внешним адресатам.

Он разрешает имя узла из записи MX в DNS в IP-адрес или их список и исходя из общей политики приоритета выбора в данной системе передаёт один из этих адресов в качестве адреса назначения транспорту smtp. При этом интересным является тот факт, что при стандартных настройках системы в случае, если для получателя был выбран IPv6 адрес, а в списке интерфейсов транспорта в качестве исходящего IPv6 отсутствует, то несмотря на это будет выбран любой из доступных внешних IPv6 адресов.

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

...
dnslookup:
...
  ignore_target_hosts = <; 0::0/0
...

К примеру, если вы имеете список доменов-получателей, для которых вы желаете использовать исключительно лишь IPv4 адреса, можно написать следующую конфигурацию.

...
begin routers

dnslookup_ipv4:
  driver        = dnslookup
  domains       = first.domain : second.domain : third.domain
  transport     = remote_smtp_ipv4
  ignore_target_hosts = <; 0::0/0  

dnslookup:
  driver        = dnslookup
  domains       = !+local_domains
  transport     = remote_smtp
  no_more
...
begin transports
...
remote_smtp_ipv4:
  driver                = smtp
  interface             = 1.2.3.4

remote_smtp:
  driver                = smtp
  interface             = <; 1.2.3.4 ; 2000:4:3:2::1
...

В данном случае, доставка для доменов из списка в параметре domains будет производиться используя IPv4 и лишь в случае отсутствия у хоста-получателя IPv4 адреса будет производиться попытка доставки на IPv6 адрес.

Из списка IP-адресов, которых перечислены в параметре interface транспорта smtp выбирается первый доступный, соответствующий необходимой для отправки на удалённых хост версии IP. При наличии более чем одного IP адреса одного типа, может сложиться ситуация, когда вся исходящая почта направляется только через первый по списку адрес. Для избежания такой неразумной политики использования адресного пространства можно воспользоваться механизмом ротации.

Например, у нас имеется подсеть IPv4 1.2.3.240/28, что даёт нам 14 свободных IP-адресов c 1.2.3.241 по 1.2.3.254 для использования. Тогда для случайной ротации этого набора можно использовать следующее выражение в параметре interface транспорта smtp.

...
remote_smtp:
  driver                = smtp
  interface             = 1.2.3.${eval:${randint:14}+241}
...

Аналогично, можно ротировать адреса по времени. К примеру, последовательно один раз в секунду.

...
remote_smtp:
  driver                = smtp
  interface             = 1.2.3.${eval:$tod_epoch%14+241} 
...

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

...
remote_smtp:
  driver                = smtp
  interface             = <;${extract{${eval:${randint:4}+1}}{;}{1.2.3.4;5.6.7.8;9.0.1.2;3.4.5.6}}
...

Можно также задать свой набор IP-адресов для каждого из доменов-отправителей, перечислив их соответствие в списке в отдельном файле.

root@beta:/usr/local/etc/exim # cat ifaces
"first.domain"  1.2.3.4;2000:1:2:3::4
"second.domain" 5.6.7.8;2000:5:6:7::8
...
root@beta:/usr/local/etc/exim # cat configure
...
begin transports
...
remote_smtp:
  driver                = smtp
  interface             = <;${lookup{$sender_address_domain}lsearch{/usr/local/etc/exim/ifaces}{$value}{1.2.3.4;5.6.7.8;2000:1:2:3::4;2000:5:6:7::8}} 
...

В этом примере в файле ifaces производится поиск соответствующего домену-отправителю списка IP-адресов, а в случае их отсутствия используется общий их список.

Помимо вышеперечисленных базовых приёмов можно использовать их всевозможные комбинации.

3. PROFIT!

Статья была полезной? Тогда прошу не стесняться и деньгами, биткоинами или через замечательную систему Patreon.


antispam  FreeBSD  security  exim