Полезные скрипты/настройки для exim.

EXIM, sendmail, postfix, Dovecot и прочие. Решение проблем связанных с работой электронной почты

Модератор: xM

Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Полезные скрипты/настройки для exim.

Непрочитанное сообщение dikens3 » 2007-05-22 8:33:29

auto_whitelist для E-Mail адресов получателей. Т.е. когда Exim отправляет сообщение удалённому адресату, то в mysql таблицу заносится соответствующая запись для последующего беспрепятственного приёма сообщения от этого E-Mail'a. (Без проверок HELO, RBL и т.п.) Разрешено примать сообщения от E-Mail'ов получателей в течение 10 дней.

Таблица для Mysql:

Код: Выделить всё

# Создаём таблицу для запоминания E-Mail'ов получателей.
DROP TABLE IF EXISTS `mylist`;
CREATE TABLE `mylist` (
  `src_email` varchar(50) default NULL,
  `dst_email` varchar(50) default NULL,
  `record_expires` datetime NOT NULL,
  PRIMARY KEY  (`src_email`,`dst_email`)
) ENGINE=InnoDB DEFAULT CHARSET=koi8r COMMENT='Таблица E-Mail-ов получателей';
Определяем макросы в основном конфиге:

Код: Выделить всё

# Список наших доменов у меня хранится в базе mysql (себе можете делать что угодно)
MYSQL_DOMAINS           = SELECT domain FROM domains WHERE domain='${quote_mysql:$domain}' AND active='Y' LIMIT 1

# Белый список E-Mail'ов
MYSQL_MYLIST            = INSERT INTO mylist(src_email,dst_email,record_expires) VALUES ('$sender_address','$acl_m4@$acl_m5',DATE_ADD(now(), INTERVAL 10 DAY))
MYSQL_UPDATEMYLIST      = UPDATE mylist SET record_expires=DATE_ADD(now(), INTERVAL 10 DAY) WHERE src_email='$sender_address' AND dst_email='$acl_m4@$acl_m5'
MYSQL_DELMYLISTEXPIRED  = DELETE FROM mylist WHERE record_expires < now()
MYSQL_TESTMYLIST        = SELECT CASE WHEN now() - record_expires > 0 THEN 2 ELSE 1 END FROM mylist WHERE src_email='$sender_address' AND dst_email='$acl_m4@$acl_m5'
MYSQL_TESTCLIENTMYLIST  = SELECT CASE WHEN now() - record_expires > 0 THEN 2 ELSE 1 END FROM mylist WHERE dst_email='$sender_address' AND src_email='$local_part@$domain'
Добавить в acl_smtp_rcpt перед тем, как принять во внешний мир.
Должно получиться следующее:

Код: Выделить всё

warn      set acl_m3    = ${lookup mysql{MYSQL_DOMAINS}}
      set acl_m4    = $local_part
      set acl_m5    = $domain
...
...
...
# Принимаем аутентифицированных для нашего домена
  accept    authenticated = *
            domains       = +local_domains
            endpass
            message       = "Unknown user"
            verify        = recipient

# Проверяем, существует ли домен получателя
  deny     log_message   = Recipient verify failed
           authenticated = *
           !verify        = recipient

# Для наших пользователей записываем наш $sender_address и адрес получателя($local_part@$domain).
# Существуют записи для данной пары src-dst email? Если нет, вернёт 0.
warn
          authenticated = *
          set acl_m19   = ${lookup mysql{MYSQL_TESTMYLIST}{$value}{0}}

# Если существует, изменяем поле record_expire
warn
          authenticated = *
          condition     = ${if and {{eq{$acl_m3}{}}{!eq{$acl_m19}{0}}}{yes}{no}}
          set acl_m19   = ${lookup mysql{MYSQL_UPDATEMYLIST}}

# Если не существует такой записи, добавляем в базу.
warn
          authenticated = *
          condition     = ${if and {{eq{$acl_m3}{}}{eq{$acl_m19}{0}}}{yes}{no}}
          set acl_m19   = ${lookup mysql{MYSQL_MYLIST}}
...
...
И правим acl_smtp_rcpt для принятия от клиентов в auto_whitelist:

Код: Выделить всё

# Белые списки
# Принимаем от пользователей (E-Mail'ов), которым мы посылали сообщения (10 дней максимум) 0 - Нет записи, 1 - Принимаем, 2 - Срок истёк.
  warn      set acl_m19  = ${lookup mysql{MYSQL_TESTCLIENTMYLIST}{$value}{0}}

  accept    domains       = +local_domains
            condition     = ${if eq{$acl_m19}{1}{yes}{no}}
            endpass
            message       = "Unknown user"
            verify        = recipient
Я сделал очистку с помощью exim(acl_smtp_rcpt - В конец):

Код: Выделить всё

# Очищаем в 12 часов список mylist c устаревшими записями каждого 1-го числа месяца
warn
          set acl_m19   = ${substr{6}{4}{$tod_zulu}}
          condition     = ${if eq{$acl_m19}{0112}{yes}{no}}
          set acl_m19   = ${lookup mysql{MYSQL_DELMYLISTEXPIRED}}

# Остальных прибиваем
  deny     message       = relay not permitted
Остальное выше.

P.S. Делал так, т.к. не знал как делать поиск в поле datetime. Можно сделать лучше. Руки не доходят.
Последний раз редактировалось dikens3 2007-06-03 10:30:32, всего редактировалось 3 раза.
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-05-22 8:45:22

Проверка корректного поля from от аутентифицированных клиентов. (У меня только аутентифицированные)

Есть несколько доменов и проверятся будут все:

Код: Выделить всё

# Прибиваем всех, у кого домен отправителя не тот, что при аутентификации
  deny    message       = "Sender only $authenticated_id@domain1.ru or $authenticated_id@domain2.ru"
          authenticated = *
          condition     = ${if and{{!eq{$authenticated_id@domain1.ru}{$sender_address}}{!eq{$authenticated_id@domain2.ru}{$sender_address}}}{yes}{no}}
В $authenticated_id у меня $local_part без домена.
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-05-22 14:31:22

Существует ли получатель?

Код: Выделить всё

# Проверяем, существует ли домен получателя
  deny     log_message   = Recipient verify failed
           authenticated = *
           !verify        = recipient/callout
P.S. При таком раскладе в фильтры acl_smtp_data никогда не попадёт несуществующий адресат. Включите фантазию, exim безграничен. (Данный фильтр не идеален и тормозит отправку, мне не нравится, я сделал проверку без callout)
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-06-01 9:04:07

Разрешение проверки наших получателей:
Зачем это нужно? Как правило при отправке письма современные почтовики (Exim к примеру) соединяются с почтовым сервером отправителя и проверяют существование E-Mail отправителя. Если в ваших фильтрах сработает блокировка, то ваше же сообщение доставлено не будет.

Проверка Exim осуществляется с пустым E-Mail отправителем (ENVELOPE-FROM: <>)
Необходимо сделать разрешения для такого отправителя:
Для всех условий с блокировками необходимо добавить:

Код: Выделить всё

!senders = :
Т.е. пустого отправителя.
Условия примут вид:

Код: Выделить всё

# Прибиваем, если нет приветствия HELO/EHLO
  deny    message       = HELO/EHLO required by SMTP RFC
          !senders      = :
          condition     = ${if eq{$sender_helo_name}{}{yes}{no}}
Далее в основном конфиге определяем:

Код: Выделить всё

acl_smtp_predata=acl_check_predata

И в самом фильтре (Не забываем в конце сделать accept):

Код: Выделить всё

# Проверки после команды DATA, но до приёма письма
# Прибиваем mailer-daemon
  deny    message       = "Unknown user"
          condition     = ${if match{$recipients}{mailer-daemon}{yes}{no}}

# Прибиваем с пустым отправителями (<>) используется для проверки существования E-Mail'а
  deny    message       = "Unknown user"
          senders       = : postmaster@rambler.ru
accept
Тут я добавил ещё блокировку писем для mailer-daemon.
postmaster@rambler.ru используется rambler'ом для проверки E-Mail'ов. Прибиваем в predata и, если есть Greylist, то ещё и там добавляем.

И в заключении хочу показать как работает следующий фильтр:

Код: Выделить всё

# Проверка существования E-Mail'a отправителя для внешних клиентов
deny      log_message   = Отправитель неправильный
          !authenticated = *
          !verify       = sender/callout=20s,defer_ok,maxwait=30s
Предположим что отправитель dmitry@mail.ru , тогда проверка exim'ом будет выглядеть так:

Код: Выделить всё

>>> Connecting to mxs.mail.ru [194.67.23.20]:25 ... connected
>>>   SMTP<< 220 Mail.Ru ESMTP
>>>   SMTP>> HELO mail.МОЙДОМЕН.ru
>>>   SMTP<< 250 mx21.mail.ru ready to serve
>>>   SMTP>> MAIL FROM:<>
>>>   SMTP<< 250 OK
>>>   SMTP>> RCPT TO:<dmitry@mail.ru>
>>>   SMTP<< 250 OK
>>>   SMTP>> QUIT
Т.к. на mail.ru не блокируются сообщения на этапе rcpt, пришлось использовать yandex для примера, когда проверка неудачна.
Отправителем сделал dsaasdkljhaslkdlkajsdlkj@yandex.ru и проверка exim'ом будет выглядеть так:

Код: Выделить всё

>>> Connecting to mx1.yandex.ru [213.180.200.11]:25 ... connected
>>>   SMTP<< 220 Yandex ESMTP (NO UCE)(NO UBE) server ready at Fri, 1 Jun 2007 10:21:29 +0400
>>>   SMTP>> HELO mail.МОЙДОМЕН.ru
>>>   SMTP<< 250 mxfront6.yandex.ru Hello mail.МОЙДОМЕН.ru
>>>   SMTP>> MAIL FROM:<>
>>>   SMTP<< 250 2.1.0 Sender syntax Ok;
>>>   SMTP>> RCPT TO:<dsaasdkljhaslkdlkajsdlkj@yandex.ru>
>>>   SMTP<< 550 5.1.1 <dsaasdkljhaslkdlkajsdlkj@yandex.ru> user unknown
>>>   SMTP>> QUIT
В случае если будут превышены интервалы подключения и т.п. (вобщем всё что не выдаёт ответ от сервера 5xx) сообщение будет пропущено через фильтр.
Собственно это всё. :-)
Последний раз редактировалось dikens3 2007-06-09 16:48:59, всего редактировалось 1 раз.
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-06-06 13:47:35

SPAMTRAP:
Пример создания блокировки всего письма, если хотя бы один из получателей наш spamtrap (E-mail который нигде не афишируется и замаскирован на сайте для чтения только ботами, собирающими E-mail адреса)

Вот к примеру root можно использовать как spamtrap, чем мы и займёмся:

Код: Выделить всё

acl_smtp_rcpt:
...
...
# Проверяем, получатель root?.
  warn    local_parts   = root
          set acl_m18   = 2
...
...
Далее в acl_smtp_predata: (До получения письма, но после команды DATA)

Код: Выделить всё

# Прибиваем всё сообщение для любых получателей, если есть получатель root(acl_m18 = 2)
  deny    message       = "Temporary error, unknown user(s)"
          condition     = ${if eq{$acl_m18}{2}{yes}{no}}

accept
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-06-06 13:57:05

Блокировка с помощью SPF: (Собирать exim с поддержкой SPF)

Код: Выделить всё

# Проверка SPF
  deny    message       = "$sender_host_address is not allowed to send mail from $sender_address_domain"
          !authenticated = *
          spf           = fail

# Добавляем SPF-Received в заголовки
  warn    message       = $spf_received
Последний раз редактировалось dikens3 2007-06-07 12:00:29, всего редактировалось 1 раз.
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Непрочитанное сообщение dikens3 » 2007-06-27 14:03:33

Исправление неправильной MX записи в DNS средствами exim:
Иногда бывает, что некоторые админы прописывают в DNS для MX записи IP-Адрес и при отправке письма в логах пишется следующее:

Код: Выделить всё

all relevant MX records point to non-existent hosts or (invalidly) to IP addresses
MX запись выглядит так:

Код: Выделить всё

dig mx vp.kis.ru
;; ANSWER SECTION:
vp.kis.ru.              308     IN      MX      10 195.98.60.250.
Если же взять любой другой почтовый сервер, то увидим корректную MX запись:

Код: Выделить всё

dig mx mail.ru
;; ANSWER SECTION:
mail.ru.                17099   IN      MX      10 mxs.mail.ru.

В exim есть решение и на этот случай.
В документации у лиссяры:
allow_mx_to_ip - разрешить MX указывать на IP-адрес

Попутно раскопал ещё тут .

Вот ещё почти аналогичный вариант:
Запись в логе exim при проверке адресата:

Код: Выделить всё

2008-09-09 13:11:50 [24628] H=comp1.mydomain.ru.local [192.168.222.22]:2822 F=<myuser1@mydomain.ru> rejected RCPT <gtrk@nnov.ru>: Recipient verify failed: all relevant MX records point to non-existent hosts
Проверяем наличие MX записи:

Код: Выделить всё

# host nnov.ru
nnov.ru has address 195.98.32.114
nnov.ru mail is handled by 10 not-for-mail.bca.ru.
Пробуем соединиться с сервером:

Код: Выделить всё

# telnet not-for-mail.bca.ru 25
not-for-mail.bca.ru: hostname nor servname provided, or not known
Не существует такого хоста, о чём и сказано в ошибке. (all relevant MX records point to non-existent hosts)
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 34889
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

Непрочитанное сообщение Alex Keda » 2007-07-10 12:09:12

Прибиваем спам, отправляемый как рикошет:
(когда спамеры подставляют адрес юзера в обратный адрес - сам огрёб позавчера несколько сотен писем :)) Вариант примитивный - но должен работать.
в ACL data:

Код: Выделить всё

# bounce test
        deny    message         = Message that generate bounce not coming from main hosts
                condition       = ${if !match{$message_body}{X-Bounce-ID}{yes}{no}}
                condition       = ${if eq{$sender_address}{}{yes}{no}}

в транспорте:

Код: Выделить всё

remote_smtp:
        driver                  = smtp
        headers_add             = "X-Bounce-ID: $primary_hostname"

вроде пашет, но тестирование пока не завершено :)

Комментарий участника gmn:
Да, вариант. Но будет работать если сервер-отправитель NDR будет включать часть исходного сообщения.
А не все включают хотя бы заголовки исходного сообщения.
Да и в таком случае отлупы на письма, отправленные с сайтов на хостинге не будут приняты.
Подробнее о моем вопросе здесь - viewtopic.php?f=20&t=4168
Убей их всех! Бог потом рассортирует...

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 34889
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение Alex Keda » 2007-08-24 9:37:49

Пример условий для проверки тела сообщения. (acl_smtp_mime)
Cмысл - проверка тела сообщения и накидывание балов спамерам.
Основа - белые списки, без них начнут считаться спамом легальные сообщения.

$acl_m0 - очки насчитанные за спам
$acl_m2 - находится ли хост в белых списках - если да, там единичка.

Код: Выделить всё

# if message < 80k and contain picture
  warn  message         = "added 20 ball for message size = $message_size; with file = $mime_filename"
        log_message     = "added 20 ball for message size = $message_size; with file = $mime_filename"
        condition       = ${if !eq{$acl_m2}{1} {yes}{no}}
        condition       = ${if match {${lc:$mime_filename}} \
                                {\N(\.gif|\.jpg|\.jpeg|\.tif|\.tiff|\.png|\.pdf)$\N} {yes}{no}}
        condition       = ${if <{$message_size}{80k} {yes}{no}}
        set     acl_m0  = ${eval:$acl_m0+20}

# if message small and contains url links $message_body_end
  warn  message         = "added 20 balls - found url links in small ($message_size) message"
        log_message     = "added 20 balls - found url links in small ($message_size) message"
        condition       = ${if !eq{$acl_m2}{1} {yes}{no}}
        condition       = ${if <{$message_size}{30k} {yes}{no}}
        condition       = ${if match {${lc:$message_body}}{\Nhttp://\N} {yes}{no}}
        set     acl_m0  = ${eval:$acl_m0+20}

  warn  message         = "added 20 balls - $h_Reply-To: != $h_Return-path:"
        log_message     = "added 20 balls - $h_Reply-To: != $h_Return-path:"
        condition       = ${if !eq{$acl_m2}{1} {yes}{no}}
        condition       = ${if <{$message_size}{30k} {yes}{no}}
        condition       = ${if !match{$h_Reply-To:}{$h_Return-path:} {yes}{no}}
        # длинна заголовка больше 5 - он существует
        condition       = ${if >${strlen:$h_Reply-To:}{5} {yes}{no}}
        set     acl_m0  = ${eval:$acl_m0+20}

        # /\d{3}(\s|-)\d{2}(\s|-)\d{2}/
  warn  message         = "added 20 balls - found phone number"
        log_message     = "added 20 balls - found phone number"
        condition       = ${if !eq{$acl_m2}{1} {yes}{no}}
        condition       = ${if <{$message_size}{30k} {yes}{no}}
        condition       = ${if match{$message_body}{\N\d{3}(\s|-)\d{2}(\s|-)\d{2}\N} {yes}{no}}
        set     acl_m0  = ${eval:$acl_m0+20}
Убей их всех! Бог потом рассортирует...

cyrus_user
сержант
Сообщения: 181
Зарегистрирован: 2007-04-24 12:16:36

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение cyrus_user » 2007-09-06 12:22:56

Не жёсткая проверка соответствия А и MX записей
в удобном месте acl_smpt_rcpt

Код: Выделить всё

warn
# acl_m1 по аналогии выше означает белые списки как senders так и hosts
condition       = ${if !eq{$acl_m1}{1} {yes}{no}}
condition       = ${if and {\                                                                                           
#Проверим совпадение доменов 2-го уровня. Как раз для случая с пачкой доменов мail.ru
                {!eq {${extract{-2}{.}{${lc:$sender_host_name}}}}\                                                     
                {${extract{-2}{.}{${lc:$sender_helo_name}}}}\
                }\                                                                                                     
#Проверим соответствие маске /24. Это для более тяжёлых случаев где в helo пишут не то что в MX записях, но про свои домены. Если у вас слишком много кривонастроенных  отправителей понизить до маски /16
                {!match {${lookup dnsdb{defer_never,a=$sender_helo_name}{$value}fail}}\                                 
                    {${extract{1}{.}{$sender_host_address}}\.\                                                         
                    ${extract{2}{.}{$sender_host_address}}\.\                                                           
                    ${extract{3}{.}{$sender_host_address}}\.}\
                }\
#Проверим MX по helo. Проверка MX для $sender_host_name и $sender_host_address тут не подойдёт                                                                                                     
                {!match {${lc:${lookup dnsdb{defer_never,mx=$sender_helo_name}{$value}fail}}}\                         
                    {${lc:$sender_host_name}}\                                                                         
                }\                                                                                                     
                }{yes}{no}}
#Назначим очки спама. Deny не рекомендую, потому что кривонастроенных МТА более чем достаточно.
set acl_m2      = ${eval:$acl_m2+10}
#Запишем в лог для сбора статистики
log_message = Compare of A, MX records for $sender_helo_name and $sender_host_address failed
Последний раз редактировалось cyrus_user 2007-12-06 8:30:00, всего редактировалось 1 раз.

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение dikens3 » 2007-09-07 17:56:35

Скрипт управления Exim'ом:
Думаю многим новичкам пригодится скрипт exim_control.sh
Остальное по желанию из man exim, добавляем по аналогии.

Код: Выделить всё

#!/bin/sh

# Путь до Exim
command=/usr/local/sbin/exim

# Наш существующий внутренний E-Mail. (Используется при тестах)
internal_email="postmaster@mydomain.ru"

# E-Mail для проверки доставки во внешний мир. (Используется при тестах)
external_email="postmaster@mail.ru"

case $1 in
        send)
        echo
        echo "Отправка всех сообщений, находящихся в очереди"
        echo
        mailq | grep -v ^\$ | grep "<" | awk '{print $3}' | xargs $command -Mc
        echo
        ;;

        remove)
        echo
        echo "Удаление всех сообщений из очереди"
        echo
        # Удаление
        mailq | grep -v ^\$ | grep "<" | awk '{print $3}' | xargs $command -Mrm
        echo
        ;;

        config)
        # Как собран Exim и наша ОС
        echo
        echo "Вывод сведений о нашем сервере и информации об Exim"
        echo
        uname -a
        $command -bV
        echo
        ;;

        allconfig)
        #Вывод настроек Exim'а
        echo
        echo "Вывод основных настроек Exim"
        echo
        $command -bP
        echo
        echo "Вывод настроек транспортов Exim"
        echo
        $command -bP transports
        echo
        $command -bP +local_domains
        ;;

        test)
        # Тестирование роутеров для отправки/приёма сообщений
        echo
        echo "Тестирование доставки для нашего домена"
        echo
        $command -bt $internal_email
        echo
        echo "Тестирование доставки для внешнего домена"
        echo
        $command -bt $external_email
        echo
        ;;

        queue)
        # Просмотр очереди
        echo
        echo "Какие письма сейчас в очереди для доставки?"
        $command -bp
        echo
        ;;

        *)
        echo "Usage: [send|remove|config|allconfig|test|queue]"
        ;;
esac
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

cyrus_user
сержант
Сообщения: 181
Зарегистрирован: 2007-04-24 12:16:36

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение cyrus_user » 2007-09-10 8:21:16

auto_whitelists в файлах
В самом начале приведена конфигурация использования auto_whitelist совместно с mysql. Но для тех кого устраивает хранение информации в файлах, и exim собран с поддержкой perl, создадим исполняемый perl файл с необходимыми функциями, который будет лежать в /path/to/exim-perl.pl с владельцем указанным в exim_user

Код: Выделить всё

#добавление адреса в файл
sub white_senders_add () {                                                                                             
my $rcpt = Exim::expand_string('$acl_m0\@$acl_m1');                                                                     
open FILE,">>/usr/local/etc/exim/acls/32.white.senders";
printf FILE "%s %u_%02u_%02u\n",$rcpt,(localtime time)[5]+1900,(localtime time)[4]+1,(localtime time)[3];
close FILE; return; }

#изменение даты у адреса, чтобы список был актуальный. меняем старую дату, на текущую
sub white_senders_date () {
my $rcpt = Exim::expand_string('$acl_m0\@$acl_m1');
my $datenow=sprintf '%u_%02u_%02u',(localtime time)[5]+1900,(localtime time)[4]+1,(localtime time)[3];
local $^I = ''; #если мы укажем local $^I = '*.bak'; то старая версия файла попадёт в 32.white.senders.bak
local @ARGV = ("/usr/local/etc/exim/acls/32.white.senders");
while (<>) { ($mail, $data,) = split(/\s/); s/$data/$datenow/ if $mail eq $rcpt; print;} return;}               

#удаление старых адресов (удаляем адреса 2-х месячной давности).
sub report_time {my ($s)=@_; $s =~ s/\_//g;return $s;}                                                                 
sub white_senders_del() {                                                                                               
use POSIX qw(strftime); my $thisday = time; my $60DaysAgo = $thisday - 60*24*60*60;
local $^I = '.old'; local @ARGV = ("/usr/local/etc/exim/acls/32.white.senders");
while (<>) {($mail, $data,) = split(/\s/); print "$mail $data\n" if report_time($data) >= report_time(strftime "%02Y_%02m_%02d", localtime($60DaysAgo))); } return; }}     

теперь переходим к конфигурации exim-а

Код: Выделить всё

#в глобальном конфиге
ACLDIR = /usr/local/etc/exim/acls
#активируем наш perl файл
perl_startup = do '/path/to/exim-perl.pl'

# в удобном месте acl_smtp_rcpt:
warn                                                                                                                   
set acl_m0      = $local_part                                                                                           
set acl_m1      = $domain                                                                                               

#Все операции для auto_whitelist проходят только для адресов,на которые слали аутентифицированные пользователи

#добавим адрес в белый список
warn                                                                                                                   
authenticated   = *                                                                                                     
#Можно использовать различные конструкции для исключения и поиска адресов для добавления. Здесь сделано самое простое
#Исключим добавление и поиск для адресов нашего домена и домена наших друзей (заодно разгрузим поиск ниже)
condition       = ${if match{$acl_m1}{(OurDomain|OurFriends)\.ru}{0}{1}}                                         
#и не будем добавлять уже существующие адреса
condition       = ${lookup{$acl_m0@$acl_m1}lsearch{ACLDIR/32.white.senders}{0}{1}}                                 
#acl_m3 в данном примере нигде больше не используется. так просто вызывается функция
set acl_m3      = ${perl{white_senders_add}}

#изменим дату для существующего адреса
warn
authenticated   = *
condition       = ${lookup{$acl_m0@$acl_m1}lsearch{ACLDIR/32.white.senders}{1}{0}}
set acl_m3      = ${perl{white_senders_date}}


Вот и всё. Если cron для удаления старых адресов использовать не хочется, смотрим пример использования $tod_zulu в exim и сделаем по аналогии

Код: Выделить всё

#WARNING. Требуется доработка, если в указанное время (каждое 1-е число с 1:00 до 1:59 утра) не было писем, не сработает. Напротив если писем было много, то вызываться будет несколько раз.
warn
#У меня в это время некий обработчик логов шлёт заведомо точно одно письмо, что и проверяется в senders
senders         = report@local.adm
set acl_m3      = ${substr{6}{4}{$tod_zulu}}                                                                           
condition       = ${if eq{$acl_m3}{0101}{yes}{no}}
set acl_m3      = ${perl{white_senders_del}}

удаление старых адресов cron-ом например раз в месяц в 01:15 такой строкой:

Код: Выделить всё

15 1 1 * *  exim_user /path/to/exim-perl.pl white_senders_del

Аватара пользователя
gmn
сержант
Сообщения: 239
Зарегистрирован: 2007-02-28 18:01:37
Откуда: UA, Kiev
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение gmn » 2007-09-28 9:03:13

Защита от атак bounce-сообщений.
В acl smtp_rcpt

Код: Выделить всё

# ratelimit for bounce messages for recipient
# Блокируем в predata
  warn hosts      = !+relay_from_hosts
       senders    = :
       ratelimit  = 2 / 30m / per_rcpt / $local_part@$domain
       set acl_m3 = $local_part@$domain

В acl predata блокируем.

Код: Выделить всё

# Если определена acl_m3 - блокируем bounce-сообщение.
drop message    = Bounce messages rate exceeds per $sender_rate_period for $acl_m3
    log_message = Bounce ratelimit: rate $sender_rate, period $sender_rate_period for $acl_m3
     condition  = ${if def:acl_m3 {1}}

Почему не сразу в smtp_rcpt - зарубим sender verify callout на свой сервер.
Этими правилами ограничиваем, что не больше 2-х bounce-сообщений за 30 мин на один адрес получателя.

Еще для bounce есть такие acl.

Код: Выделить всё

# Допускается только один адрес получателя для NDR.
  drop  message   = Only one receipient accepted for NULL sender
        senders   = :
        condition = ${if >{$rcpt_count}{1} {1}}


А это в smtp_data ...

Код: Выделить всё

# Если нет "реального"(т.е. Mailer-Daemon и т.п.) отправителя для bounce сообщений - то позже будет deny. Пока только запись в лог.
# после тестов - deny. message вместо log_message
warn   senders = :
       log_message = A valid sender header is required for bounces
       !verify = header_sender

lucas
проходил мимо

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение lucas » 2008-02-19 13:43:22

Блокировка спамеров на этапе connect:

Код: Выделить всё

hostlist bad_hosts = 1.2.3.0/24 : 2.3.0.0/16 (или файл с адресами)

acl_smtp_connect = acl_check_connect

acl_check_connect:

deny message = brrr...?
hosts = +bad_hosts

accept

Аватара пользователя
dikens3
подполковник
Сообщения: 4856
Зарегистрирован: 2006-09-06 16:24:08
Откуда: Нижний Новгород
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение dikens3 » 2008-04-25 11:32:55

Отладка. Очень многое можно узнать запустив виртуальный тест доставки/приёма письма.

Предположим нам отправляют письмо от user@mail.ru, а получатель письма в нашем домене admin@mydomain.ru?
Тест будет выглядеть так:

Код: Выделить всё

Подключение к НАШЕМУ_СЕРВЕРУ НА 25 ПОРТ с IP-Адреса 194.67.23.20
EHLO mxs.mail.ru
MAIL FROM:user@mail.ru
RCPT TO: admin@mydomain.ru
DATA
Subject: test
.
QUIT
А сам скрипт вот так:

Код: Выделить всё

#!/bin/sh

# Тестирование от mail.ru
(echo "EHLO mxs.mail.ru"; echo "MAIL FROM:user@mail.ru"; echo "RCPT TO: admin@mydomain.ru"; echo "DATA"; echo "Subject: test"; echo "."; echo "QUIT";) \
| exim -d -bhc 194.67.23.20 > testlog 2>&1
Данный скрипт эмулирует получение письма нашим сервером exim от mail.ru. Exim обработает так, будто это реальное письмо, но без реальной доставки (только логи). Далее читам созданный файл testlog, в котором ищем ошибку. Лог довольно большой получится. :-)

Аналогично можно проверять доставку с интересующих вас E-Mail'ов или серверов, подставив необходимые данные, включая локальную доставку.
Лучше установить FreeBSD, чем потратить 30 лет на Linux'ы и выяснить какой из них хуже.

Аватара пользователя
serge
майор
Сообщения: 2131
Зарегистрирован: 2006-07-30 15:34:14
Откуда: Саратов
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение serge » 2008-06-06 12:37:05

Блокировка IP-Адресов по странам:

Пример использования (будут заблокированы отправители из России):

Код: Выделить всё

deny     message       = "Host in blacklist - $dnslist_domain \n $dnslist_text"
         dnslists      =  ru.countries.nerd.dk

Устанавливаете перед countries.nerd.dk обозначение зоны, соответствеющее какой нужно стране (cn, jp, ru) и почта с IP адресов этой страны блокируется.

neyro
сержант
Сообщения: 187
Зарегистрирован: 2008-03-07 20:24:25
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение neyro » 2008-07-23 15:26:51

Сортировка писем спам\не спам по папкам:

Пример для эксима с виртуальным юзерам в бд Mysql (синий текст-то, что нужно добавить).
Определять - спам или не спам мы будем по переменной acl_m0 (больше 59-спам, меньше-нет). Пример как можно считать эту переменную здесь (статья by Lissyra).
Добавляем в роуты после системных альясов (порядок важен, т.к. спам роутер должен стоять перед основными):
dnslookup:
driver = dnslookup
domains = ! +local_domains
transport = remote_smtp
ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
no_more

system_aliases:
driver = redirect
allow_fail
allow_defer
data = ${lookup mysql{SELECT `goto` FROM `alias` WHERE \
`address`='${quote_mysql:$local_part@$domain}' OR \
`address`='${quote_mysql:@$domain}'}}

mysqluser_spam:
driver = accept
domains = +local_domains
condition = ${if >{$acl_m0}{59}{yes}{no}}
transport = mysql_spam_delivery
no_verify
no_expn
no_more

mysqluser:
driver = accept
domains = +local_domains
condition = ${if eq{}{${lookup mysql{SELECT `maildir` FROM `mailbox` \
WHERE `username`='${quote_mysql:$local_part@$domain}'}}}{no}{yes}}
transport = mysql_delivery
Далее после транспорта remote_smtp добавляем наш транспорт для спама (здесь порядок значения не имеет т.к. всегда выбирается только 1 транспорт):
remote_smtp:
driver = smtp

mysql_spam_delivery:
driver = appendfile
check_string = ""
create_directory
delivery_date_add
directory = ${lookup mysql{SELECT CONCAT('/var/mail/exim/', `maildir`, '/', '.Spam') \
FROM `mailbox` WHERE `username`='${local_part}@${domain}'}}
directory_mode = 770
envelope_to_add
group = mail
maildir_format
maildir_tag = ,S=$message_size
message_prefix = ""
message_suffix = ""
mode = 0600


...
...
...
Все письма которые определились как спам автоматически складываются в папку Входящие\Spam.
Последний раз редактировалось neyro 2008-08-19 21:11:11, всего редактировалось 4 раза.

neyro
сержант
Сообщения: 187
Зарегистрирован: 2008-03-07 20:24:25
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение neyro » 2008-08-18 12:35:12

Автоматический ответ (к примеру если юзер в отпуске).
Пример для эксима с виртуальным юзерам в БД Mysql (синий текст-то, что нужно добавить).
В роутах после проверки на спам, перед основным роутом добавляем(порядок роутов важен):
.............................................
transport = mysql_spam_delivery
no_more

vacation_autoreply:
driver = accept
domains = +local_domains
condition = ${lookup mysql{SELECT active FROM vacation WHERE \
domain='${quote_mysql:$domain}' AND \
email='${quote_mysql:$local_part@$domain}' AND \
active='1'}{true}{false}}
senders = " ! ^.*-request@.*:\
! ^owner-.*@.*:\
! ^postmaster@.*:\
! ^listmaster@.*:\
! ^mailer-daemon@.*\
! ^root@.*\
! ^noreply@.*"
no_expn
no_verify
transport = vacation_autoreply
unseen


mysqluser:
driver = accept
domains = +local_domains
........................


Далее в транспортах (здесь порядок значения не имеет т.к. всегда выбирается только 1 транспорт):

vacation_autoreply:
driver = autoreply
to = $sender_address
from = "$local_part@$domain"
once = /var/mail/exim/vacation/$local_part.db
once_repeat = 7d
subject = Re: =?UTF-8?B?KNCw0LLRgtC+LdC+0YLQstC10YIpINCvINCyINC+0YLQv9GD0YE=?= \
=?UTF-8?B?0LrQtSBcIChhdXRvcmVwbHkpIEkgYW0gb24gdmFjYXRpb24=?=
text = "\
Здравствуйте $h_from\n\n\
Это - автоматический ответ на Ваше письмо $original_local_part@$original_domain \
Не стесняйтесь посылать дополнительную\n\
почту, поскольку это уведомление высылается 1 раз каждые 7 дней.\n\n\
English version below\n\n\
Dear $h_from\n\n\
This is an automatic reply to Your message for $original_local_part@$original_domain \
Feel free to send additional\n\
mail, as only this one notice will be generated once every 7 \
days."


Дамп mysql таблицы:
CREATE TABLE vacation (
email varchar(255) NOT NULL default '',
subject varchar(255) NOT NULL default '',
body text NOT NULL,
cache text NOT NULL,
domain varchar(255) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
active tinyint(4) NOT NULL default '1',
PRIMARY KEY (email),
KEY email (email)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Vacation';


Хеадер предварительно закодирован в UTF-8 поэтому проблем с отображением не будет.
Ответ высылается 1 раз в 7 дней т.е. если один и тот же юзер отправит 100 мессаг нашему юзеру то он получит только 1 авто ответ, следующий - через 7 дней ( если пошлет ему письмо еще раз) и т.д.. Опция которая регулирует через сколько слать ответ - once_repeat = 7d
Не забываем создать папочку /var/mail/exim/vacation и дать на нее права юзеру от которого работает эксим, так же формат создания файла данных можно изменить на user@domain.ru -
once = /var/mail/exim/vacation/$local_part@$domain.db

Пример ответа который получит юзер:

Код: Выделить всё

Заголовок: Re: (авто-ответ) Я в отпуске \ (autoreply) I am on vacation
Само письмо:
Здравствуйте xxx <xxx@gmail.com>

Это - автоматический ответ на Ваше письмо xxx@xxx.ru Не стесняйтесь посылать дополнительную
почту, поскольку это уведомление высылается 1 раз каждые 7 дней.

English version below

Dear xxx <xxx@gmail.com>

This is an automatic reply to Your message for xxx@xxx.ru Feel free to send additional
mail, as only this one notice will be generated once every 7 days.

Добавить vacation можно например из postfixadmin, поля которые реально работают в данном примере(и обязательны для заполнения) - mail, domain, active, пример заполнения - xxx@xxx.ru xxx.ru 1.
Изначально была идея включать часть сообщения + заголовок, но у эксима есть некоторые трудности с русс языком..поэтому пока от этого пришлось отказаться.

neyro
сержант
Сообщения: 187
Зарегистрирован: 2008-03-07 20:24:25
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение neyro » 2008-08-19 21:14:23

Переписывание даты письма на дату получения письма сервером много спама приходит с датой 2090+ годы и т.д...результатe-они всегда висят в списке сообщений.
(один из способов немного облегчить жизнь юзерам, но это противоречит RFC т.к. мы меняем тело письма.).
В системном фильтре (system-filter) добавляем:
headers remove "Date"
headers add "Date: $tod_full"

Liv
рядовой
Сообщения: 39
Зарегистрирован: 2008-09-12 0:25:42

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение Liv » 2008-09-13 17:45:07

Может кому-то будут полезны и мои скрипты.

Вывод очереди (назван был eq):

Код: Выделить всё

#!/usr/bin/perl

my $ar = "";

if ($#ARGV == -1) {
    $ar="q";
}
$ar= shift(@ARGV);

open ( MQ, "/usr/local/sbin/exim -bp|") or die "can't run the exim command\n";

$count = 0;
$state = 0;     # simple state machine
$recips = 0;
while ( <MQ> ) {
  $line = $_;
  chop $line;
  if ($state == 0) {    # line read is the sender info
        print "$line ";
  $count++;
        $state = 1;
        $recips = 0;
  } else {                      # line read is a recip
        if ($line =~ /^$/) {    # if blank, about to start new mail
          $state = 0;
          print "\n";
        } else {                        # append recipient to line
          if ($recips > 0) {    # separate recipients with :
                print ':';
          }
          if ($line =~ /^\s+\S\s+(.*)/) {
                print "$1";
          } elsif ($line =~ /^\s+(.*)/) {
                print "$1";
          }
          ++$recips;
        }
  }
}
print "count: ". $count."\n";

# end


Просто посмотреть содержимое письма по идентификатору, взятому из просмотра очереди (назвал eshow):

Код: Выделить всё

#!/bin/sh

exim  -Mvc $1|less


Простое удаление письма из очереди по идентификатору (назвал edel):

Код: Выделить всё

#!/bin/sh

exim -Mrm $1


Удаление из очереди писем с пустым отправителем (<>) (назвал edele):

Код: Выделить всё

#!/usr/bin/perl

my $ar = "";

if ($#ARGV == -1) {
    $ar="q";
}
$ar= shift(@ARGV);

open ( MQ, "/usr/local/sbin/exim -bp|") or die "can't run the exim command\n";

$count = 0;
$state = 0;     # simple state machine
$recips = 0;
while ( <MQ> ) {
  $line = $_;
  chop $line;
  if($line =~ /\<\>/) {
        if($line =~ /(.*) (.*) (.*) \<\>/) {
                $ident = $3;
                system("exim -Mrm ". $ident);
                $count++;
        }
  }
  if($line =~ /\|/) {
        if($line =~ /(.*) (.*) (.*) (.*)/) {
                $ident = $3;
                system("exim -Mrm ". $ident);
                $count++;
        }
  }
}
close(MQ);

print "Deleting count: ". $count."\n";

# end

kww
проходил мимо
Сообщения: 7
Зарегистрирован: 2007-09-08 18:55:09

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение kww » 2008-10-12 17:56:27

Часто бывает необходимо принимать почту на конкретные адреса
только со своего домена или списка IP адресов.
Например разрешить прием почты на support@mydomain.ru только от определенных хостов

Код: Выделить всё

acl_check_rcpt:
...
 # Проверяем недопустимые символы для нелокальных получателей:
...
  # Сообщения для support, support1 итд могут приходить только из локальных доменов
  deny    message       = Restricted sender in address
          domains       = +local_domains
          local_parts   = support : support1
          !hosts = 127.0.0.1 : +relay_from_hosts

где - relay_from_hosts - определяет список IP (наших сетей) с которых возможен прием сообщений .

Аватара пользователя
Agronom
сержант
Сообщения: 294
Зарегистрирован: 2006-12-11 10:30:13

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение Agronom » 2008-10-14 9:55:25

может кому ленивому пригодится эта строчка для убивания frozen сообщений из очереди "вручную":

Код: Выделить всё

#!/bin/sh
exim -bpu | awk '/\*\*\* frozen \*\*\*/ {print$3}' | xargs exim -Mrm

После запуска все сообщения в очереди с пометкой frozen убъются

kww
проходил мимо
Сообщения: 7
Зарегистрирован: 2007-09-08 18:55:09

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение kww » 2008-12-14 13:10:13

Фильтрация спама вида from: user@domain.org to: user@domain.org

Код: Выделить всё

# Рубим если отправка от себя к себе не с нашей сети
    deny hosts = !+relay_from_hosts
       domains   = +local_domains
       condition = ${if or{ { eq{$sender_address}{$local_part@$domain} }\
                         { eq{$sender_address_domain}{$domain} } } }
       log_message = The same local addresses or domain in MAIL FROM and RCPT TO from nonlocal relay
       message     = Access denied

Аватара пользователя
Cancer
Гл. Кастратор
Сообщения: 1269
Зарегистрирован: 2008-03-25 12:21:36
Откуда: г. Ростов-на-Дону
Контактная информация:

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение Cancer » 2008-12-16 21:44:35

Копирование всех исходящих и входящих писем на ящик audit@domain.ru
Думаю будет полезно для тех, кому была поставлена подобная задача

В секции begin routers ставим правило первым

Код: Выделить всё

copy_message:
   driver = redirect
   unseen
   domains = *
   data = audit@domain.ru

Аватара пользователя
Laa
ст. лейтенант
Сообщения: 1032
Зарегистрирован: 2008-02-21 18:25:33
Откуда: Украина, Россия

Re: Полезные скрипты/настройки для exim.

Непрочитанное сообщение Laa » 2009-01-06 1:49:13

Иногда клиенты не понимают сообщений exim-а о недоствке письма, или боунсы.
Звонят, пытаются разобраться или ругаются.
Чтобы облегчить себе жизнь, можно вложить перевод в эти сообщения.

Описываются эти файлы-темплэйты в основном конфиге так:

Код: Выделить всё

...
warn_message_file               = EXIM_DIR/warn_message_file
bounce_message_file             = EXIM_DIR/bounce_message_file
...


Ну и пример EXIM_DIR/warn_message_file:

Код: Выделить всё

Subject: Warning: message $message_exim_id delayed $warn_message_delay
Content-Type: text/plain; charset=koi8-r
****

Это сообщение было создано автоматически почтовым сервером.
(This message was created automatically by mail delivery software.)

Письмо, ${if eq{$sender_address}{$warn_message_recipients}
{которое вы отправили, }{отправленное

<$sender_address>

}}не было доставлено получателям спустя более чем
$warn_message_delay в почтовой очереди на $primary_hostname.

(A message ${if eq{$sender_address}{$warn_message_recipients}
{that you sent }{sent by

<$sender_address>

}}has not been delivered to all of its recipients after
more than $warn_message_delay on the queue on $primary_hostname.)

Идентификатор письма (The message identifier is):.$message_exim_id
Дата письма (The date of the message is):.........$h_date
Тема письма (The subject is):.....................$h_subject

Письма на следующие адреса не доставлены:
(The following address(es) have not yet been delivered:)
****
С вашей стороны не требуется никаких действий. Попытки доставить
письмо будут продолжаться некоторое время. Подобные предупреждения
возможно еще будут, если письмо не удастся доставить. Письмо
вернется к вам в ящик, если не удастся его доставить за весь период
доставки.

(No action is required on your part. Delivery attempts will
continue for some time, and this warning may be repeated at
intervals if the message remains undelivered. Eventually the
mail delivery software will give up, and when that happens,
the message will be returned to you.)


И пример второго файла EXIM_DIR/bounce_message_file:

Код: Выделить всё

Content-Type: text/plain; charset=koi8-r
Subject: Mail delivery failed ${if eq{$sender_address}{$bounce_recipient} {: returning message to sender}}
****
Это сообщение создано автоматически почтовой системой.
This message was created automatically by mail delivery software.

Сообщение, ${if eq{$sender_address}{$bounce_recipient}
  {которое отправили вы }{отправленное

<$sender_address>

}}не может быть доставлено получателям.
Это постоянная ошибка. Следующие адреса дали сбой:

A message ${if eq{$sender_address}{$bounce_recipient}
  {that you sent }{sent by

<$sender_address>

}}could not be delivered to all of its recipients.
This is a permanent error. The following address(es) failed:
****
Следующий текст был создан во время попыток доставки:
The following text was generated during the delivery attempt(s):
****
------ Вот копия письма со всеми заголовками. ------
------ This is a copy of the message, including all the headers. ------
****
------ The body of the message is $message_size characters long;
  only the first
------ $bounce_return_size_limit or so are included here.
****
exim: помните, что выдавая deny, вы можете недоставить ваше же письмо, зарубив sender-verify удаленного MTA к вашему MTA!!!


Вернуться в «MTA - Mail Transfer Agent»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 5 гостей