Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> почтовые системы —> exim + exchange

Настройка exim (relay) и M$ exchange (почтарь внутри локалки)

Автор: lissyara.


    Предистория. Делалось по заказу одного товарисча, с далёкого Сахалина. Ему нужен был, фактически, просто почтовый релей внутрь локалки, где стоял M$ Exchange. Однако, просто релей с перезаписью адресов - неинтересно. Поэтому, за основу был взят мой текущий конфиг exim+dovecot и допилен под текущие нужды. В частности, ввиду того, что внутри локалки используется адресация user@domain.local, была настроена перезапись адресов, с учётом, что внешних доменов у организации два - один с коротким именем, другой — с длинным (short-dom.ru и long-domain.ru). Отсюда - излишняя, пожалуй, сложность для просто релея.
   Разумная критика приветствуется, однако, бред не по теме будет удалён :)

   Итак. Исходные данные задачи. Два сервера на FreeBSD6.2, на каждом по два интерфейса - один наружу, другой внутрь. Два - потому, что нужна надёжность. Настройки будут разниться тока в части имён и IP, которые по возможности вынесены в макроопределения в начале конфига. Для проверки существоваания пользователей в домене (цель - генерить отлупы до приёма сообщения, на уровне "rcpt to:" - иначе, они могут пойти по фальшивому обратному адресу), exim будет лазить напрямую в виндовый ldap - для этого заведён специальный пользователь в домене, без права логинитсья.
   Для удобства, конфиг почтаря был разбит на несколько кусков, т.к. с одним очень большим стало нереально тяжело работать (особенно на Сахалине, с лагом в две секунды на каждое действие). Была реализована схема с т.н. "белыми списками", подсказанная ded3axap`ом. Реализация, правда не его, моя собственная. Также, с сайта http://www.iana.org/ был утянут список всех доменов верхнего уровня - он используется в проверках HELO - существует ли такой домен (проверка регулярным выражением на синтаксис - всё же не так эффективна).
   Итак. Обновляем порты, ставим exim. Для выставления всех опций один раз, и чтоб в дальнейшем не мучаться - как же я его собирал, выставляем нужные опции в /etc/make.conf, у меня он получился такой:
# default MySQL version
DEFAULT_MYSQL_VER=50
# default PHP version
DEFAULT_PHP_VER=4

PORTSDIR?=              /usr/ports
.if ${.CURDIR} == ${PORTSDIR}/mail/exim
# Поддержка MySQL
WITH_MYSQL=             yes
LOG_FILE_PATH?=         syslog
# Контентное сканирование
WITH_CONTENT_SCAN=      yes
# Дефолтовая кодировка заголовков
WITH_DEFAULT_CHARSET?=  koi8-r
# Отключаем IPv6
WITHOUT_IPV6=           yes
# Подрубаем LDAP
WITH_OPENLDAP=          yes
# Версия BDB - в чём ведёт свои БД подсказок
WITH_BDB_VER=           1
# Проверки SPF
WITH_SPF=               yes
# Подержка перекодировки (для заголовков)
WITH_ICONV=             yes
.endif

# for perl5.8
.if ${.CURDIR} == ${PORTSDIR}/lang/perl5.8
WITH_THREADS=yes
.endif

# MySQL server
.if ${.CURDIR} == ${PORTSDIR}/databases/mysql50-server
BUILD_OPTIMIZED=yes
BUILD_STATIC=yes
WITH_CHARSET=utf8
WITH_COLLATION=cp1251_bin
#WITH_LINUXTHREADS=yes
WITH_PROC_SCOPE_PTH=yes
.endif

# MySQL client
.if ${.CURDIR} == ${PORTSDIR}/databases/mysql50-client
BUILD_OPTIMIZED=yes
BUILD_STATIC=yes
WITH_CHARSET=cp1251
WITH_COLLATION=cp1251_bin
.endif

# vim
.if ${.CURDIR} == ${PORTSDIR}/editors/vim
WITHOUT_X11=            yes
.endif

   Соответственно - вовсе не обязательно вносить все пункты, но я решил быть дословным :). После чего, можно ставить exim:
mail$ cd /usr/ports/mail/exim
mail$ make install clean

   И сервер MySQL (exim притащит, как зависимость, лишь клиента) - если он будет стоять на этой машине:
mail$ cd /usr/ports/databases/mysql50-server/
mail$ make install clean

   Собственно - насчёт муси - насколько обязательна версия 5.0 - утверждать не берусь, ибо лень лезть в документацию, но, что в 4.0 отстутствуют функции используемые в конфигурации - это абсолютно точно. Также, не забываем поставить антивирус, я ставил с опциями по-умолчанию:
mail$cd /usr/ports/security/clamav
mail$ make install clean

   Далее - рисуем конфиги. По ним комментариев немного, они и сами неплохо прокоментированы (заодно оставил все старые ошмётки, от процесса их создания - может кому-то пригодятся). Прошу тока обратить внимание на имена файлов, был уже прикол, когда боролись с глюками у одного товарисча, а оказалось что не инклюдятся файлы - и, фактически, он работал на пустом конфиге :).
/usr/local/etc/exim/configure:
# моя конфига экзма. Будь проклят тот день,
# когда мне пришла в голову мысль подписать
# русские поясния ко всем пунктам! :) Хоть и
# делал я это в первую очередь для себя -
# чтоб лучше понять его, но работа эта оказалась
# слишком масштабная и неблагодарная...

# Инклюдим главные настройки
.include_if_exists /usr/local/etc/exim/includes/100.main.conf

### конфигурация ACL для входящей почты
begin acl
# Эти правила срабатывают для каждого получателя
acl_check_rcpt:

# Начало файла ACL - те, кого срубаем сразу же
.include_if_exists /usr/local/etc/exim/includes/200.acl_check_rcpt.conf
# Проверки на спам - по хостам и прочему.
.include_if_exists /usr/local/etc/exim/includes/300.acl_check_rcpt_spam_rule.conf
# Конец конфигурации - блэк-листы, задержки и прочее
.include_if_exists /usr/local/etc/exim/includes/400.acl_check_rcpt_end.conf

# Тут идут ACL проверяющие содержимое (тело) письма.
# Без них будут пропускаться все сообщения.
acl_check_data:
# Инклюдим конфигурацию проверки тела письма
.include_if_exists /usr/local/etc/exim/includes/500.acl_check_data.conf

# чё делаем с почтой
begin routers
# Инклюдим конфигурацию роутреров
.include_if_exists /usr/local/etc/exim/includes/600.routers.conf

# начинаются транспорты - как доставляем почту
begin transports
# Инклюдим транспорты
.include_if_exists /usr/local/etc/exim/includes/700.transports.conf

# Конфигурация повторов и перезаписи
.include_if_exists /usr/local/etc/exim/includes/800.retry_and_rewrite.conf

# Секция авторизации при отправке писем. Ввиду того,
# что почтовых клиентов много, и все всё делают
# по-своему, то и механизмов авторизации три...
begin authenticators
# Аутентификация юзеров.
.include_if_exists /usr/local/etc/exim/includes/900.authenticators.conf

# Фсё. Конфиг кончился. Два дня убил.
# © lissyara       2006-02-25, 01:19

/usr/local/etc/exim/includes/100.main.conf:
# Главняе настройки

# моя конфига экзма. Будь проклят тот день,
# когда мне пришла в голову мысль подписать
# русские поясния ко всем пунктам! :) Хоть и
# делал я это в первую очередь для себя -
# чтоб лучше понять его, но работа эта оказалась
# слишком масштабная и неблагодарная...

# Имя хоста. Используется в EHLO.
# Фигурирует в других пунктах, если они не заданы -
# типа qualify_domain и прочих..
# Если тут ничё не установлено (строка закомметрована)
# то используется то, что вернёт функция uname()
primary_hostname = mail.short-dom.ru

# Вводим данные для подключения к MySQL серверу.
# словечко `hide`, вначале, означает, что при
# вызове проверки конфига командой
# exim -bV config_file эти данные не будут отображаться.
# Если без него - то будут показаны... Формат записи:
# хост/имя_бд/пользователь/пароль
hide mysql_servers = localhost/exim_db/exim_user/exim_pass

# Эксчейнджевый домен
MS_EXCHANGE_DOMAIN = long-domain.local

# внутренний IP машины
INTERNAL_IP = 192.168.205.253

# внимание - изменённ дефолтовый разделитель списка!
ldap_default_servers = <; 192.168.205.2:3268 
#; dc2.domain.org:3268

# макросы для работы с LDAP
LDAP_AD_BINDDN = exim
LDAP_AD_PASS = pass_user_exim_in_domain
LDAP_AD_BASE_DN = DC=long-domain,DC=local

# макрос для проверки пользователей в домене
LDAP_AD_MAIL_RCPT = \
user=LDAP_AD_BINDDN \
pass=LDAP_AD_PASS \
ldap:///LDAP_AD_BASE_DN?mail?sub?\
(&(|(objectClass=user)(objectClass=publicFolder)(objectClass=group))\
(|(proxyAddresses=${quote_ldap:${local_part}@MS_EXCHANGE_DOMAIN})\
(proxyAddresses=smtp:${quote_ldap:${local_part}@MS_EXCHANGE_DOMAIN}))\
(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

# Делаем список локальных доменов. Далее этот
# список будет фигурировать в виде +local_domains
# В данном случае домены выбираются из БД MySQL. Также
# можно их просто перечислить через двоеточие. Есть интересная
# возможность, можно указать юзер@[хост] - lissyara@[222.222.4.5]
domainlist local_domains = mail.short-dom.ru : relay.long-domain.ru

# делаем список доменов с которых разрешены релеи.
# Далее этот список будет в виде +relay_to_domains
# Можно использовать символы подстановки, типа:
# .... = *.my.domen.su : !spam.my.domen.su : first.su
# тогда пропускается всё, что похоже на *.my.domen.su, но
# от spam.my.domen.su релеится почта не будет.
domainlist relay_to_domains = long-domain.ru : short-dom.ru

# Составляем список хостов с которых разрешён неавторизованый
# релей. Обычно в нём находятся локальные сети, и локалхост...
# ЛокалХост в двух видах был внесён сознательно - пару раз
# сталкивался с кривым файлом /etc/hosts - результатом было
# непонимание `localhost` но пониманием 127.0.0.1/8
hostlist   relay_from_hosts = localhost : 127.0.0.0/8 : 192.168.0.0/16 

# Вводим названия acl`ов для проверки почты. (В общем-то, это
# необязательно, если вы делаете открытый релей, или хотите
# принимать вообще всю почту с любого хоста для любых
# получателей... Тока потом не жалуйтесь что у Вас спам
# и провайдер выкатывает немеряный счёт :))
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

# Прикручиваем антивирус - при условии, что exim собран
# с его поддержкой. В качестве антивиря юзаем ClamAV,
# ибо - ПО должно быть свободным! :)
# Итак, указываем местоположение сокета clamd.
av_scanner = clamd:/var/run/clamav/clamd

# Адрес куда слать на проверку спама (SpamAssasin), но я
# это не юзаю. Не так много у меня спама...
# spamd_address = 127.0.0.1 783

# Имя домена добавляемое для локальных отправителей (реальных
# юзеров системы) т.е. почта отправляемая от root, будет от
# root@домен_указанный_здесь. Если пункт незадан, то используется
# имя хоста из `primary_hostname`. Логичней было бы написать здесь
# lissyara.su, но мне удобней иначе:
qualify_domain = mail.short-dom.ru

# Имя хоста для ситуации, обратной предыдущей, - это имя домена
# добавляемое к почте для системных юзеров, ну и вообще для почты
# пришедшей на адрес типа `root`, `lissyara`, & etc... Если этот
# пункт незадан то используется значение полученное из
# предыдущего пункта - `qualify_domain`
qualify_recipient = mail.short-dom.ru

# A это как раз кусок вышеописанного анахронизма - про почту в
# виде user@[222.222.222.222] - принимать её или нет. По дефолту
# (когда строка закомментирована) значение - false. Если захотите
# поставить true то надо будет добавить в список доменов
# комбинацию @[] - она означает `все локальные адреса`
allow_domain_literals = false

# Пользователь от которого работает exim
exim_user = mailnull

# группа в кторой работает exim
exim_group = mail

# запрещаем работу доставки под юзером root - в целях безопасности
never_users = root

# Проверяем соответствие прямой и обратной зон для всех хостов.
# Тока зачем это нужно - даже и незнаю... Спам на этом не режется...
# Зато возможны проблемы - если сервер зоны скажет `сервер файлед`
# то почту от этого хоста Вы не получите :)
#host_lookup = *

# Тоже анахронизм (на самом деле, не такой уж анахронизм, но все давно
# забили на ident и закрыли файрволлом tcp:113...) Это проверка - Ваш
# хост спрашивает у удалённого, с которого было подключение, а кто
# собстно ко мне подключился на такой-то порт? Если на удалённом хосте
# работает identd - он может ответить (а может и не ответить - как
# настроить), скажет UID пользователя от которого установлено
# соединение, тип ОС, и имя пользователя. Теперь, понимаете, почему
# у всех оно зарублено и файрволлами позакрыто? :) Это же палево :)
# Тока на мой взгляд, если на сервере всё настроено правильно -
# то вовсе это и не страшно.
# Короче - если хостс поставить * то будет проверять все. Таймаут -
# если поставить 0 то не будет ждать ответа ни от кого. По
# вышеописанным причинам - отключаем
#rfc1413_hosts = *
rfc1413_query_timeout = 0s

# По дефолту, экзим отфутболивает все `неквалифицированные` адреса,
# состоящие тока из локальной части. Для того чтобы разрешить такие письма
# определённых хостов используются эти директивы:
# для `неквалифицированных` отправителей
sender_unqualified_hosts = +relay_from_hosts
# для `неквалифицированных` получателей
recipient_unqualified_hosts = +relay_from_hosts

# Интересный пункт, тока я не вполне понимаю его логику.
# Позволяет выполнять что-то типа - пришло сообщение на
# локальный ящик user%test.su@lissyara.su и
# переправляет его на user@test.su. Делается это для
# перечисленного списка доменов (* - все):
# percent_hack_domains = *

# Если сообщение было недоставлено, то генерится соощение
# об ошибке. Если сообщение об ошибке не удалось доставить
# то оно замораживается на указанный в этом пункте срок,
# после чего снова попытка доставить его. При очередной
# неудаче - сообщение удаляется.
ignore_bounce_errors_after = 45m

# Замороженные сообщения, находящиеся в очереди, дольше
# указанного времени удаляются и генерится сообщение
# об ошибке (при условии, что это не было недоставленное
# сообщение об ошибке :))
timeout_frozen_after = 15d

# собсно на этом штатный конфиг кончился, но
# меня-то это не устраивает... Поэтому пошли пункты,
# почёрпнутые из других источников.

# список адресов, через запятую, на которые засылаются
# сообщения о замороженных сообщениях (о замороженых
# уведомлениях о заморозке, сообщения не генерятся. - я
# надеюсь эта строка понятна :))
#freeze_tell = admin@lissyara.su

# Список хостов, почта от которых принимается, несмотря
# на ошибки в HELO/EHLO (тут указана моя подсеть)
helo_accept_junk_hosts = 192.168.0.0/16

# Через какое время повторять попытку доставки
# замороженного сообщения
auto_thaw = 1h

# Приветствие сервера
smtp_banner = "$primary_hostname, ESMTP EXIM $version_number"

# Максимальное число одновременных подключений по
# SMTP. Рассчитывать надо исходя из нагрузки на сервер
smtp_accept_max = 50

# максимальное число сообщений принимаемое за одно соединение
# от удалённого сервера (или пользователя). C числом 25
# я имел проблемы тока один раз - когда у меня три дня лежал
# инет и после его подъёма попёрли мессаги. Но у меня не так
# много почты - всего 30 пользователей.
smtp_accept_max_per_connection = 25

# чё-то про логи и борьбу с флудом - я так понимаю -
# максимальное число сообщений записываемых в логи
smtp_connect_backlog = 30

# максимальное число коннектов с одного хоста
smtp_accept_max_per_host = 20

# Ход ладьёй - для увеличения производительности,
# директория `spool` внутри, разбивается на
# директории - это ускоряет обработку
split_spool_directory = true

# Если у сообщения много адресатов на удалённых хостах,
# то запускатеся до указанного числа максимально число
# параллельных процессов доставки
remote_max_parallel = 15

# при генерации сообщения об ошибке прикладывать
# не всё сообщение, а кусок (от начала) указанного
# размера (иногда полезно и целиком - в таком случае
# просто закомментируйте эту строку)
return_size_limit = 70k

# размер сообщения. У меня стоит относительно большой
# размер (`относительно` - потому, что на большинстве
# хостов оно ограничено 2-5-10мб, либо стоит анлим.)
message_size_limit = 64M

# разрешаем неположенные символы в HELO (столкнулся
# с этим случайно - имя фирмы состояло из двух слов
# и какой-то раздолбай домен обозвал my_firme_name
# прям с подчёркиваниями... Виндовые клиенты при
# соединении радостно рапортовали о себе
# `vasya.my_firme_name` ну а экзим их футболил :))
helo_allow_chars = _

# Принудительная синхронизация. Если отправитель
# торопится подавать команды, не дождавшись ответа,
# то он посылается далеко и надолго :) Немного,
# спам режется.
smtp_enforce_sync = true

# Выбираем, что мы будем логировать
# + - писать в логи,
# - - Не писать в логи.
# +all_parents - все входящие?
# +connection_reject - разорваные соединения
# +incoming_interface - интерфейс (реально - IP)
# +lost_incoming_connections - потеряные входящие
# соединения
# +received_sender - отправитель
# +received_recipients - получатель
# +smtp_confirmation - подтверждения SMTP?
# +smtp_syntax_error - ошибки синтаксиса SMTP
# +smtp_protocol_error - ошибки протокола SMTP
# -queue_run - работа очереди (замороженные мессаги)
log_selector = \
	+all \
#	-incoming_port \
#	-incoming_interface \
	-arguments \
	-smtp_connection \
	-lost_incoming_connection \
	-queue_run

# Системный фильтр, копирование проходящей почты
system_filter			= /usr/local/etc/exim/filters/system-filter
system_filter_pipe_transport	= address_pipe
system_filter_user		= mailnull
system_filter_group		= mail

# Убираем собственную временную метку exim`a из логов, её ставит
# сам syslogd - нефига дублировать
syslog_timestamp = no
log_file_path = syslog : /var/log/exim/%s-%D.log

/usr/local/etc/exim/includes/200.acl_check_rcpt.conf:
 # Проверка получателей

  # принимать сообщения которые пришли с локалхоста,
  # не по TCP/IP
  accept  hosts = :

  # Запрещаем письма содержащие в локальной части
  # символы @; %; !; /; |. Учтите, если у вас было
  # `percent_hack_domains` то % надо убрать.
  # Проверяются локальные домены
	deny	message	= "incorrect symbol in address"
		domains	= +local_domains
		local_parts	= ^[.] : ^.*[@%!/|]
		delay	= 30s

  # Проверяем недопустимые символы для
  # нелокальных получателей:
	deny	message	= "incorrect symbol in address"
		domains	= !+local_domains
		local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
		delay	= 30s

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

#  accept  local_parts   = postmaster
#          domains       = +local_domains

  # Запрещщаем, если невозможно проверить отправителя
  # (отсутствует в списке локальных пользователей)
  # У себя я это закоментил, по причине, что некоторые
  # железяки (принтеры, & etc) и программы (Касперский, DrWEB)
  # умеют слать почту, в случае проблем но не умеют ставить
  # нужного отправителя. Такие письма эта проверка не пускает.
#  require verify        = sender

  # Запрещщаем тех, кто не обменивается приветственными
  # сообщениями (HELO/EHLO)
	deny	message		= "HELO/EHLO require by SMTP RFC"
		condition	= ${if eq{$sender_helo_name}{}{yes}{no}}
		delay		= 30s

  # Принимаем сообщения от тех, кто аутентифицировался:
  # Вообще, большинство конфигов в рунете - это один и тот же
  # конфиг написанный Ginger, в котором этот пункт расположен
  # внизу. Но при таком расположении рубятся клиенты с adsl,
  # ppp, и прочие зарезанные на последующих проверках. Но это
  # жа неправильно! Этом мои пользователи из дома! Потому
  # я это правило расположил до проверок.
  accept  authenticated = *

# Рубаем нах, тех, кто подставляет свой IP в HELO
	deny	message		= We don't allow domain literals, many spam...
		hosts		= !+relay_from_hosts:*
		condition	= ${if isip{$sender_helo_name}{yes}{no}}
		delay		= 30s

# Рубаем хело с нашим именем
	deny	condition	= ${if match_domain{$sender_helo_name} \
			{$primary_hostname:+local_domains:+relay_to_domains} \
			{true}{false}}
		message		= Message was delivered by ratware - own
		log_message	= remote host used our name in HELO/EHLO.
		delay	= 30s

# Рубаем мудаков с недопустимыми символами в helo (пока видел тока такие)
  deny    condition     = ${if match{$sender_helo_name}{\N_\N}{yes}{no}}
          hosts         = !127.0.0.1 : !localhost : !+relay_from_hosts : *
          set acl_m0    = ${eval:$acl_m0+20}

# Ограничения эксчейнджа - юзер не может начинаться/заканчиваться точкой.
  deny          message =       Invalid address
                senders =       \N^\.|\.@\N

/usr/local/etc/exim/includes/300.acl_check_rcpt_spam_rule.conf:
# Проверка на спам - по хосту
# тут оставлено много отладки - раскомментите что надо...

#  # Вводим переменную acl_m0 - в ней будет счётчик,
#  # сколько очков спамерских насчиталось...
  warn	  set acl_m0	= 0
#          logwrite	= "ACL m0 set default as $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name (domain in e-mail = $sender_address_domain)"

  # Проверяем соответствие HELO и обратной записи DNS для севера:
  warn    condition     = ${if !eq{$sender_helo_name}{$sender_host_name}{yes}{no}}
          hosts         = !+relay_from_hosts : *
          set acl_m0	= ${eval:$acl_m0+30}
#	  logwrite	= "STAGE1: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - reverse sone not match with HELO"

  # Смотрим, нашлась ли обратная запись для этого хоста
  warn    condition	= ${if eq{$host_lookup_failed}{1}{yes}{no}}
          hosts         = !+relay_from_hosts : *
          set acl_m0	= ${eval:$acl_m0+30}
#	  logwrite	= "STAGE2: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - no reverse zone for host"

# Удалено, т.к. пееркрывается проверками на реальность домена первого уровня
  # Cчитаем длинну имени хоста (из HELO). если  меньше 5 - добавляем
  # - таких хостов не может существовать
#  warn    condition	= ${if <{${strlen:$sender_helo_name}}{5}{yes}{no}}
#	  hosts         = !+relay_from_hosts : *
#	  set acl_m0	= ${eval:$acl_m0+60}
#	  logwrite	= "STAGE3: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - lenth helo chars small 5"

  # Считем число точек или дефисов в доменном имени. (больше 4-х - в топку)
  warn    condition	= ${if match{$sender_host_name} \
				{\N((?>\w+[\.|\-]){4,})\N}{yes}{no}}
	  hosts         = !+relay_from_hosts : *
	  set acl_m0	= ${eval:$acl_m0+40}
#	  logwrite	= "STAGE4: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - more dots in name"

  # Смотрим, есть ли вобще точки в HELO - дохера уродов с ``friends'' (удалено,
# т.к. перекрывется проверками на реальность домена первого уровня)
#  warn    condition	= ${if !match{$sender_helo_name}{\N\w\.\w\N}{yes}{no}}
#	  hosts         = !+relay_from_hosts : *
#	  set acl_m0	= ${eval:$acl_m0+60}
#	  logwrite	= "STAGE5: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - helo not contain dots"

# Проверяем длинну обратного почтовго адреса - пследнее время сцуки повадились
# слать с безумными обратными адресами типа Fulbrightbackstage@absacargo.com,
# damsel'stailpipe`s@abbeywindows.co.uk и т.п.
  warn	condition	= ${if <{${strlen:$sender_address}}{25}{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+10}
#	logwrite	= STAGE6: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with HELO=$sender_helo_name \
#- many big sender address [$sender_address]

# Добавляем очков за всякие dialup хосты
  warn	condition	= ${lookup{$sender_host_name} \
			wildlsearch{/usr/local/etc/exim/db/dialup_hosts} \
			{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+60}
#	logwrite	= "STAGE9: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#host=$sender_helo_name - dialup, ppp & etc..."

  warn	condition	= ${lookup{$sender_helo_name} \
			wildlsearch{/usr/local/etc/exim/db/dialup_hosts} \
			{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+60}
#	logwrite	= "STAGE10: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - dialup, ppp & etc..."

#recipients_count
# Проверяем счётчик сообщений в сессии - нормальные пользователи редко шлют
# сообщения с большим числом получателей, а для крупных почтовых сервисов
# всё сбросится по белому листу серверов, что находится дальше
  warn	condition	= ${if >{$recipients_count}{4}{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+($recipients_count*20)}
#	logwrite	= STAGE11: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name; counter = $recipients_count

# Проверяем существование зоны из HELO (на этом правиле огребают очков все
# уродцы с HELO типа 'friends' или 'localhost.localdomain')
  warn	condition	= ${if !eq{${lookup mysql{SELECT 1 FROM \
			`list_top_level_domains` WHERE `zone` = \
			LCASE(CONCAT('.', SUBSTRING_INDEX( \
			'${quote_mysql:$sender_helo_name}', \
			'.', -1)))}}}{1}{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+150}
#	logwrite	= non-existent domain in HELO - \
#'$sender_helo_name' setting acl_m0 = $acl_m0



  # Добавляем очки, если spf не соответствует (спасибо dikens3 за наводку)
  warn	spf		= fail
	hosts		= !+relay_from_hosts : *
	set acl_m0	= ${eval:$acl_m0+60}
#	logwrite	= "SPF status: spf_result = $spf_result; \
#spf_smtp_comment = $spf_smtp_comment"
#	logwrite	= "STAGE11-SPF: ACL m0 set = $acl_m0 for \
#host=$sender_host_name [$sender_host_address] with \
#HELO=$sender_helo_name - SPF check failed: \
#$sender_host_address is not allowed to send mail from $sender_address_domain"

# Вводим acl_m2 с нулевым значением
  warn	set acl_m2	= 0
# Проверяем - не было ли писем НА домен отправителя от наших юзеров за 
# последние два месяца (оптимальное, на мой взгляд, число)
# Если были - то потом, в фильтре, обнулим количество насчитанных очков.
  warn	condition	= ${if eq{${lookup mysql{SELECT 1 FROM `sended_list` \
			WHERE `user_to` = \
			LCASE('${quote_mysql:$sender_address}') \
			AND `user_from` \
			= LCASE('${quote_mysql:$local_part@$domain}') \
			AND `last_mail_timestamp` < `last_mail_timestamp` \
			+ (60*24*60*60) LIMIT 1}}}{1}{yes}{no}}

	condition	= ${lookup mysql{INSERT IGNORE INTO `domain_whitelist` \
			(`domainname`, `domain_ip`, `added_timestamp`, \
			`last_mail_timestamp`, `mail_count`) VALUES \
			(LCASE('${quote_mysql:$sender_address_domain}'), \
			'${quote_mysql:$sender_host_address}', \
			UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '1') \
			ON DUPLICATE KEY UPDATE \
			`last_mail_timestamp` = UNIX_TIMESTAMP(), \
			`mail_count` = `mail_count` + 1}}
	hosts		= !+relay_from_hosts : *
	set acl_m2	= 1
#	logwrite	= STAGE12: $sender_address ==> $local_part@$domain; \
#setting acl_m2 = $acl_m2; WHITELIST for this addresses

# Переменная изменилась лишь если это были те же самые получатели,что и общались
# при внесении данных в транспорте. Для остальных этот домен так и остался
# без изменений. Соответственно надо сделать его и для остальных белым.
  warn	condition	= ${if eq{${lookup mysql{SELECT 1 \
			FROM `domain_whitelist` \
			WHERE `domain_ip` = \
			'${quote_mysql:$sender_host_address}' \
			LIMIT 1}}}{1}{yes}{no}}
	hosts		= !+relay_from_hosts : *
	set acl_m2	= 1
#	logwrite	= STAGE13: $sender_address ==> $local_part@$domain; \
#setting acl_m2 = $acl_m2; WHITELIST for ALL domains

#	warn		logwrite = Variables: \
#sender_address = $sender_address; sender_host_name = $sender_host_name; \
#sender_helo_name = $sender_helo_name; sender_ident = $sender_ident; \
#host_lookup_failed = $host_lookup_failed; \
#return_path = $return_path; recipients_count = $recipients_count; rcpt_count = \
#$rcpt_count; rcpt_defer_count = $rcpt_defer_count; rcpt_fail_count = \
#$rcpt_fail_count; received_count = $received_count; received_for = \
#$received_for

/usr/local/etc/exim/includes/400.acl_check_rcpt_end.conf:
# Конец конфигурации проверки отправителя

# Сбрасываем спамерскую переменную, если домен в белом списке
  warn	condition	= ${if eq{$acl_m2}{1}{yes}{no}}
	logwrite	= Resetting acl_m0 $acl_m0 --> 0, host in whitelist \
				($sender_address ==> $local_part@$domain)
	set acl_m0	= 0

  # Задержка. Режется довольно много не-MTA - спамерских скриптиков.
#  warn
#	set acl_c0	= 5s
  warn
	# 
#	condition	= ${if !eq{$acl_m0}{0}{yes}{no}}
#	condition	= ${if <{$acl_m0}{150}{yes}{no}}
	set acl_c0	= 15s
  warn
	# Вычисляем задержку на основании насчитанных за спам очков:
	condition	= ${if !eq{$acl_m0}{0}{yes}{no}}
	condition	= ${if >{$acl_m0}{150}{yes}{no}}
	set acl_c0	= ${eval:$acl_m0/10}s
  warn
	# ставим задержку в 0 секунд своим хостам
	hosts = +relay_from_hosts
	set acl_c0	= 0s
  warn
	# Ставим нулевую задержку хостам из белого листа
	condition	= ${if eq{$acl_m2}{1}{yes}{no}}
	set acl_c0	= 0s
  warn
	# пишем в логи задержку (если оно вам надо)
#	logwrite = Delay $acl_c0 (spam counter = $acl_m0; \
#white host = $acl_m2) for $sender_host_name \
#[$sender_host_address] with HELO=$sender_helo_name. Mail \
#from $sender_address to $local_part@$domain.
	delay		= $acl_c0

  # Рубаем тех, кто в блэк-листах. Серваки перебираются
  # сверху вниз, если не хост не найден на первом, то
  # запрашивается второй, и т.д. Если не найден ни в одном
  # из списка - то почта пропускается.
  deny	message		= "you in blacklist - $dnslist_domain --> \
				$dnslist_text; $dnslist_value"
	hosts		= !+relay_from_hosts
	dnslists	= cbl.abuseat.org : \
			dynablock.njabl.org : \
			dul.dnsbl.sorbs.net : \
			list.dsbl.org : \
			sbl-xbl.spamhaus.org
	delay		= 30s

  # для фильтра - устанавливаем переменные (отладка)
#  warn	set acl_m4	= $sender_address
#	set acl_m5	= $local_part@$domain

                          
  # проверяем пользователей из файла альясов (системные)
	accept	domains	= +local_domains
		verify	= recipient

  # Проверяем пользователей в эксчейндже
	deny	domains = +relay_to_domains
		message = "Unknown user for this domain"
# изначальное условие проверки юзера было такое. Однако, при письме на 
# альяс, ldap возвращал адрес получателя, а не альяс (вполне логично :))
# пришлось использовать match вместо eq (a логичней вообще оставить
# проверку на ротерах а тут verify = recipient)
#		condition = ${if !eq{${lookup ldap {LDAP_AD_MAIL_RCPT}}}\
#		{${local_part}@MS_EXCHANGE_DOMAIN}{yes}{no}}
		condition = ${if !match{${lookup ldap {LDAP_AD_MAIL_RCPT}}}\
				{@MS_EXCHANGE_DOMAIN}{yes}{no}}
#	  accept	domains	= +relay_to_domains
#			endpass
#			message	= "No route to host... $acl_verify_message"
#			verify	= recipient


  # Разрешаем почту от доменов в списке relay_from_hosts
	accept	hosts	= +relay_from_hosts

  # приниаем почту для эксчейнджевых доменов
	accept	domains	= +relay_to_domains

  # Если неподошло ни одно правило - чувак явно ищет
  # открытый релей. Пшёл прочь. :)
  deny		message	= "Access deny - this not open relay!"
		delay	= 30s

/usr/local/etc/exim/includes/500.acl_check_data.conf:
# Проверяем тело письма

# Рубаем по расширениям
  deny	message = contains $found_extension file (blacklisted).
  	demime  = com:vbs:bat:pif:scr:exe

# проверяем MIME
  deny  message = This message contains a MIME error ($demime_reason)
        demime = *
        condition = ${if >{$demime_errorlevel}{2}{1}{0}}

  # Проверяем письмо на вирусы
# deny malware = *
  warn malware = *
  logwrite = VIRUS from host $sender_host_name [$sender_host_address]. \
  Mail from $sender_address to $local_part@$domain.
  set acl_m1 = 1
  logwrite = "In e-mail found VIRUS - $malware_name"

# Сообщения с NUL-символами
  deny	message		= This message contains NUL characters
	log_message	= NUL characters!
	condition	= ${if >{$body_zerocount}{0}{1}{0}}

# Синтаксис заголовков 
# 2007-02-15: закомменчено - очень много сообщений нормальных рубится...
# 2007-02-28: добавлено условие про очки - стало нормально
# 2007-03-29: условие про очки убрано - всё пучком, я неправильно использовал,
# оно возвращает истину если заголовки корректны...
deny	message		= Incorrect headers syntax
	hosts		= !+relay_from_hosts:*
#	condition	= ${if >{$acl_m0}{190}{yes}{no}}
	!verify		= header_syntax

# проверяем скрытые копии (немногие юзеры пользуются этим, пусть лучше
# отдельными письмами пишут) у тех, у кого уже есть спамерские очки
  deny	message		= Administrative denied 'blind' ('hidden') copy messages
	condition	= ${if >{$acl_m0}{110}{yes}{no}}
	hosts		= !+relay_from_hosts:*
	!verify		= not_blind

  # Вводим ACL для заполнения таблицы что и куда ходило
#  warn	condition = ${lookup mysql{INSERT INTO `mail_history` (`to`, `from`, \
#			`message_size`,`sending_timestamp`) VALUES \
#			('$recipients', '$sender_address', \
#			'$message_size', UNIX_TIMESTAMP())}}


# отладка - выводим пеерменную - надо найти про отправителя конверта.
#	warn	logwrite	= return_path = $return_path; sender_address \
#= $sender_address; sender_address_local_part@sender_address_domain = \
#$sender_address_local_part@$sender_address_domain; reply_address = $reply_address

# проверяем нету ли в поле From адреса с которым переписываемся (web интерфейсы
# любят подставлять себя - поэтому тут и изгаляемся.)
  warn	condition	= ${if eq{${lookup mysql{SELECT 1 FROM `sended_list` \
			WHERE `user_to` = \
			LCASE(SUBSTR('${quote_mysql:$reply_address}', \
			POSITION('<' IN '${quote_mysql:$reply_address}') +1, \
			POSITION('>' IN '${quote_mysql:$reply_address}') \
			- POSITION('<' IN '${quote_mysql:$reply_address}') -1) \
			) AND `user_from` \
			= LCASE('${quote_mysql:$local_part@$domain}') AND \
			`last_mail_timestamp` < `last_mail_timestamp` \
			+ (60*24*60*60) LIMIT 1}}}{1}{yes}{no}}

        condition       = ${lookup mysql{INSERT IGNORE INTO `domain_whitelist` \
			(`domainname`, `domain_ip`, `added_timestamp`, \
			`last_mail_timestamp`, `mail_count`) VALUES \
			(LCASE('${quote_mysql:$sender_address_domain}'), \
			'${quote_mysql:$sender_host_address}', \
			UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '1') \
			ON DUPLICATE KEY UPDATE \
			`last_mail_timestamp` = UNIX_TIMESTAMP(), \
			`mail_count` = `mail_count` + 1}}
	hosts		= !+relay_from_hosts : *
	set acl_m2	= 1

  # Если есть необходимость - тут проверки на спам

  # Пропускаем остальное
  accept

/usr/local/etc/exim/includes/600.routers.conf:
# Конфигурация роутеров

# роутер для преобразования адресов из внешних во внутренние
conversion_router:
	driver		=	redirect
#	data		=	$local_part@MS_EXCHANGE_DOMAIN
#	data		=	$local_part
	data		=	${lookup ldap {LDAP_AD_MAIL_RCPT}}
	user		=	mailnull
	group		=	mail
	domains		=	+relay_to_domains

# умный роутер - шлём почту на внутренний эксчейндж (192.168.205.2)
exchange_router:
	driver		=	"manualroute"
	domains		=	MS_EXCHANGE_DOMAIN
#	domains		=	+relay_to_domains
#	data		=	$local_part
	transport	=	remote_smtp
	route_list	=	* 192.168.205.2
	no_more

# Поиск маршрута к хосту в DNS. Если маршрут не найден в DNS -
# то это `унроутабле аддресс`. Не проверяются локальные
# домены, 0.0.0.0 и 127.0.0.0/8
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
	data		=	${lookup{$local_part}lsearch{/etc/aliases}}
	user		=	mailnull
	group		=	mail
	file_transport	=	address_file
	pipe_transport	=	address_pipe
	allow_fail
	allow_defer

# локальные пользователи
localuser:
	driver = accept
	check_local_user
	transport = local_delivery
	cannot_route_message = Unknown user

/usr/local/etc/exim/includes/700.transports.conf:
# Конфигурация транспортов

# Доставка на удалённые хосты - по SMTP
remote_smtp:
	driver	= smtp
#	headers_add	= "X-Descriptions: powered by www.lissyara.su"
# следующая строка - это внесение в таблицу отправленных писем - грамотней не 
# придумал,поэтому на неё идут варнинги в логах, однако работает :)
	hosts_avoid_esmtp =  ${lookup mysql{INSERT IGNORE INTO `sended_list` \
			(`user_from`, `user_to`, `added_timestamp`, \
			`last_mail_timestamp`, `mail_count`) VALUES \
			(LCASE('${quote_mysql:$sender_address}'), \
			LCASE('${quote_mysql:$local_part@$domain}'), \
			UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '1') ON DUPLICATE \
			KEY UPDATE `last_mail_timestamp` = UNIX_TIMESTAMP(), \
			`mail_count` = `mail_count` + 1}}

# локальная доставка
local_delivery:
	driver = appendfile
	file = /var/mail/$local_part
	delivery_date_add
	envelope_to_add
	return_path_add
	group = mail
	user = $local_part
	mode = 0660
	no_mode_fail_narrower


# Имя программы
address_pipe:
	driver = pipe
	return_output

address_file:
	driver = appendfile
	delivery_date_add
	envelope_to_add
	return_path_add


# Транспорт для автоответов
address_reply:
	driver = autoreply

# В никуда
null_transport:
	driver = appendfile
	file = /dev/null

/usr/local/etc/exim/includes/800.retry_and_rewrite.conf:
# Конфигурация повторов и перезаписи адресов

# Начинаются повторы недоставленных писем.
begin retry

# Этот кусок я не трогал. Думаю разработчики лучше знают,
# какие тут должны быть цифирьки. Если же вы это знаете
# лучше их - меняйте. Хотя... А какого, если Вы такой
# умный, читаете этот мануал? Может ну, их, цифирьки, а? :)
# Address or Domain  Error   Retries
# -----------------  -----   -------
*                    *       F,2h,15m; G,16h,1h,1.5; F,4d,6h


# преобразование адресов. Переписываем домен эксчейнджана внешний
begin rewrite
# основное правило перезаписи - внутренний на внешний домены
# однако, при отсылке внутри тоже пеерзаписывает, после 
# обработки эксчейнджевым роутером.... Посему - извращаемся
*@MS_EXCHANGE_DOMAIN	"${if eq{$interface_address}{INTERNAL_IP}\
				{$1@long-domain.ru}fail}"
#*@MS_EXCHANGE_DOMAIN	"${if or !}"
#*@MS_EXCHANGE_DOMAIN	$1@long-domain.ru
*@short-dom.ru		$1@long-domain.ru

/usr/local/etc/exim/includes/900.authenticators.conf:
# Аутентификация для исходящих сообщений.

# А вот по какому методу авторизуется оутглюк - я уже и
# не помню... Хотя в своё время долго ковырялся,
# пока настроил... Толь plain, толь login...
#auth_plain:
#  driver = plaintext
#  public_name = PLAIN
#  server_condition = ${lookup mysql{SELECT `username` FROM \
#                     `mailbox` WHERE `username` = \
#                     '${quote_mysql:$auth2}' AND `password` = \
#                     '${quote_mysql:$auth3}'}{yes}{no}}
#  server_prompts = :
#  server_set_id = $auth2

# Вроде по этому оутглюк, а по предыдущему нетскейп.
#auth_login:
#  driver = plaintext
#  public_name = LOGIN
#  server_condition = ${lookup mysql{SELECT `username` FROM \
#                     `mailbox` WHERE `username` = \
#                     '${quote_mysql:$auth1}' AND `password` = \
#                     '${quote_mysql:$auth2}'}{yes}{no}}
#  server_prompts = Username:: : Password::
#  server_set_id = $auth1

# А так авторизуется "Летучая Мышь" - TheBat!
#auth_cram_md5:
#  driver = cram_md5
#  public_name = CRAM-MD5
#  server_secret = ${lookup mysql{SELECT `password` FROM \
#                        `mailbox` WHERE `username` \
#                        = '${quote_mysql:$auth1}'}{$value}fail}
#  server_set_id = $auth2
#

/usr/local/etc/exim/db/dialup_hosts:
# for test - mx.grand-prix.ru
#^\.*grand\.*

# dialup hosts
^\.*dsl\.*
^\.*dialup\.*
^\.*dialin\.*
^\.*pool\.*
^\.*peer\.*
^\.*dhcp\.*
^\.*dynamic\.*
^\.*cable\.*
^\.*ppp\.*

# expressions for digit in hosts
^\d+[-\.]\d+[-\.]\d+[-\.]
^\d{5,}

# by ded3axap
^.*([1-9]+)\\-([0-9]+)\\-([0-9]+)\\-([1-9]+).*
^.*([1-9]+).([0-9]+).([0-9]+).([1-9]+).*
^.*pool.*
^.*dial.*
^.*dyn.*
^.*ppp.*
^.*fbx.*
^.*cable.*
^.*dsl.*
^.*dynamic.*
^.*fibertel.*
^.*broadband.*
^.*hsd1.*
^.*telecable.*
^.*dhcp.*
^.*kabel.*
^.*client.*
^.*in-addr.*
^.*user.*
^.*cpe.*
^.*tampabay.*
^.*phx1.*
^.*static.*
^.*rev.*
^.*speedy.*
^.*genericrev.*
^.*cdma.*
^.*catv.*
^.*customer.*

# optional - by ded3axap
^.*rima-tde\\.net
^.*comcast\\.net
^.*pppoe\\.mtu-net\\.ru
^.*proxad\\.net
^.*bezeqint\\.net
^.*arcor-ip\\.net
^.*novis\\.pt
^.*rr\\.com
^.*verizon\\.net
^.*chello\\.nl
^.*ono\\.com
^.*t-dialin\\.net
^.*telenet\\.be
^.*virtua.com\\.br
^.*veloxzone.com\\.br
^.*tpnet\\.pl
^.*com\\.au
^.*asianet\\.co\\.th
^.*interbusiness\\.it
^.*webandnetworksolutions\\.com
^.*xtra.co\\.nz
^.*atlanticbb\\.net
^.*sinor\\.ru
^.*tiscali\\.fr
^.*wanadoo\\.fr
^.*pacbell\\.net
^.*prodigy\\.net
^.*charter\\.com
^.*barak-online\\.net
^.*qwest\\.net
^.*cm\\.vtr\\.net
^.*link\\.com\\.eg
^.*t-ipconnect\\.de
^.*mindspring\\.com
^.*telesp\\.net\\.br
^.*home\\.nl
^.*cable\\.ntl\\.com
^.*netvision\\.net\\.il
^.*btcentralplus\\.com
^.*surewest\\.net
^.*anteldata\\.net\\.uy
^.*mm\\.pl
^.*euskaltel\\.es
^.*satnet\\.net
^.*kabelbw\\.de
^.*skylink\\.ru
^.*consumerpcinc\\.com
^.*yourhostingaccount\\.com

/usr/local/etc/exim/filters/system-filter:
logfile /var/log/exim/system-filter.log

# проверяем, нет ли вирусов
if $acl_m1 contains "1"
then
    # копируем письма. с вирусами нам не нужны.
    deliver viruses@eliron.ru
    #no_more
else

# Спам
 
#logwrite "EXIM FILTER: debug - digit in variable acl_m0 = $acl_m0 (before)"
# Проверяем содержимое переменной про спам (содержит ли цифры)
if $acl_m0 matches ^\\d+
then
#logwrite "FILTER: debug - digit in variable acl_m0 = $acl_m0 (after first if)"
        # Строим новую тему письма - если спам
        # Проверяем содержимое переменной со счётчиком спамерских очков.
        # На данный момент считаем - что если 60 и более - это спам.

	# Добавляем заголовки с объяснением происходящего
	headers add "X-Spam-Description: if spam count > 60 - this is spam"
	headers add "X-Spam-Count: $acl_m0"


	# рихтуем хеадеры
        if $acl_m0 is above 59
        then

#		headers add "Old-Subject: $h_subject:"
#		headers remove "Subject"
#		headers add "Subject: (*** SPAM ***) $h_old-subject:"
                headers add "X-Spam: YES"
                # Старый заголовок оставляем, на всякий случай
                #headers remove "Old-Subject"
		#logwrite "EXIM FILTER: Spam count = $acl_m0 ; Added SPAM header"
		
        endif
# Закрытие - содержит цифры
endif

#logwrite "EXIM FILTER: interface_address = $interface_address"
# перезапись заголовков, которые не окучены штатно - exim`ом
if $interface_address is INTERNAL_IP
then
	headers add \
		"Old-Disposition-Notification-To: $h_Disposition-Notification-To:"
	headers add "Old-Return-Receipt-To: $h_Return-Receipt-To:"
	headers remove "Disposition-Notification-To"
	headers remove "Return-Receipt-To"
	headers add "Disposition-Notification-To: <$sender_address>"
	headers add "Return-Receipt-To: <$sender_address>"
	logwrite "EXIM FILTER: heders rewritten in filter"
endif

# закрываем проверку на вирусы в письме
endif

   Теперь, нужно создать БД в MySQL, согласно приложенному дампу:
Дамп таблиц для exim`a
файл скачан размер размещён примечание
exim_db.sql
2529 35.2kb 2007-05-30 БД для exim`a - списки доменов верхнего уровня, таблицы для ведения т.н. "Белых списков" - доменов ск оторыми юзеры переписываются.

   Также, создаём такой скриптик:

more /usr/local/scripts/work/delete_from_exim_whitelist.sh
#!/bin/sh

# Дропаем домены в белом списке, которые старше 60 дней. Если переписка всё
# ещё идёт, то в таблице отправленных останутся записи - там дропается
# по дате последней отправки
/usr/local/bin/mysql --user=exim_user --password=exim_pass --database=exim_db \
        --execute="DELETE FROM \`domain_whitelist\` WHERE \`added_timestamp\` \
                        < (UNIX_TIMESTAMP() - 60*24*3600)"

# Дропаем из списка отправленных записи которые не обновлялись более 60 дней.
/usr/local/bin/mysql --user=exim_user --password=exim_pass --database=exim_db \
        --execute="DELETE FROM \`sended_list\` WHERE \`last_mail_timestamp\` \
                        < (UNIX_TIMESTAMP() - 60*24*3600)"

# Дропаем рикошеты. Чтоб не мешались.
/usr/local/bin/mysql --user=exim_user --password=exim_pass --database=exim_db \
        --execute="DELETE FROM \`sended_list\` WHERE \`user_from\` = ''" 

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



размещено: 2007-05-30,
последнее обновление: 2008-06-24,
автор: lissyara


XBOCT, 2007-07-26 в 12:01:39

Привет!

1. Если установлен Exchange 2003 (лучше всего с SP2 - там это точно есть), то у него есть встроенные механизмы проверки "rcpt to". Для этого необходимов в иксченджовой консоли поставить 2 галки: а) запускаем System Manager, открываем Administrative Groups - Servers - <имя вашего иксченджа> - Protocols - SMTP - Default SMTP Virtual Server - Properties - Advanced - Edit, ставим галку Apply Recipient filter, закрываем и идем б) Global Settings - Message Delivery - Properties - закладка Recepients Filtering, ставим галку Filter Recipients who are not in the directory. В результате при попытке заспамить на несуществующие адреса Иксчендж ответит - 550 5.1.1 User unknown.

2. Exchange умеет принимать почту для нескольких доменов. Настраивается тут: System Manager - Recipients - Recipients Policy - Default Policy - Properties - E-mail Addresess (Policy). Нажимаем New, выбираем SMTP, вписываем @short-dom.ru Повторяем шаг и вписываем long-domain.ru. Единственное что - один из этих доменов будет Primary а другой Secondary. (Выбирать кто примари а кто секондари там рядом кнопка есть). Почта будет приходить для обоих доменов, а вот когда юзер отправяет письмо, то в качестве sender адреса будет подставляться Primary. Эта настройка в иксченже не как не связана с доменом AD. То есть AD-шный домен может быть .local, а  почта спокойно будет приниматься для 2ух указанных доменов ru.

С уважением,
ХВОСТ.

P.S. Распозныный спам тегируется в сабжекте словом [SPAM]. Иксчендж научен тегированные письма складывать в папочку "Нежелательная почта" ("Junk E-mail"). Невостребованные в течении 30 дней письма в папке Нежелательная почта безвозвратно удаляются. Если кому интересно могу рассказать как все это сделать. В данный момент ведуться работы по вкручиванию кнопок в Аутлук типа Report Spam и Report NOSpam чтобы обучать DSPAM. Так же могу отписаться чем дело кончилось если опять таки будет интерес.

O.B., 2007-08-16 в 13:49:59

>ХВОСТ

Расскажи как у тебя это реализовано, всем будет интересно, а особенно обратная связь с DSPAM и кнопки к Аутглюку

Спасибо,

O.B.

XBOCT, 2007-10-02 в 19:32:55

Значит так:
1.ставим на иксчендж сервис-пак-2. В папку, где лежит сам иксчендж вот сюда вот С:\Program Files\Exchsrvr\bin\MSCFV2
кладем файлик обязательно вот с таким вот именем MSExchange.UceContentFilter.xml
Текст файла:
<?xml version="1.0" encoding="UTF-16"?>
<CustomWeightEntries xmlns="http://schemas.microsoft.com/2005/CustomWeight">
    <CustomWeightEntry Type="SUBJECT" Change="MAX" Text="[SPAM]"/>
</CustomWeightEntries>
Далее идем запускаем System Manager, открываем Administrative Groups - Servers - <имя вашего иксченджа> - Protocols - SMTP - Default SMTP Virtual Server - Properties - Advanced - Edit, ставим галку Apply Intelligent Message Filter, закрываем и идем Global Settings - Message Delivery - Properties - закладка Intelligent Message Filtering там 1 и 3 пункт без имзененния вроде у меня две "восьмерки стоят" посередине ставим No Action. Перезапувкаем иксчендж.
В результате все что затегировалось словом [SPAM] будет приходить в Junk E-Mail, если аутглюк русский то соответсвенно в Нежелательную почту. Далее следует настроить очистку джанк емайла если письмо не востребовано к примеру в течении 30 дней. (кароче mailbox mangement). при чем пишем 2 правила для junk email и для нежелательная почта по отдельности=))

2. сообщить о спаме из аутлука:
а) сделать Public Folder как в GFI антиспаме, настроить дейстивие на немедленный отсыл почты как только пользователь претаскивает туда письмо. Плохой вариант, т.к. если письмо хорошее, то его нужно туда копировать, оставив копию у себя; вопросы безопасности - если это секретное письмо которое случайно попало в спам? вдруг кто увидит... в общем мне больше нравится другой вариант
б)ставим  OLSpamCop c сайта http://www.olspamcop.org/.
В результате в аутлуке появляются красивые кнопочки spam / ham.
Вписываем куда отсылать почту spam/nospam, ставим после отсыла спам удалять, после отсыла неспам переложить во входящие, Report Options: чекаем галки (сверху вниз) 1,3,5, остальные не нужны. General option ставим первую и последнюю, остальные тоже не нужны. а теперь учим дспам, учим... ))

Владислав, 2008-01-15 в 11:53:02

Статья очень хорошая спасибо но заметил один глюк если все делать как в статье то работать толком не будет долго маялся и нашел решение вместо MS_EXCHANGE_DOMAIN поставить реальное имя то все работает эта переменная не передается по файлам или весь конфиг слить в один файл тогда тоже все работает

sad, 2008-10-15 в 2:32:38

Спасибо за статью. ОООчень много от сюда почерпнул.
есть опечатка
# Проверяем длинну обратного почтовго адреса - пследнее время сцуки повадились
# слать с безумными обратными адресами типа Fulbrightbackstage@absacargo.com,
# damsel'stailpipe`s@abbeywindows.co.uk и т.п.
 warn    condition    = ${if<{${strlen:$sender_address}}{25}{yes}{no}}

кондишен- не "<" а ">"

mef, 2008-11-08 в 14:28:42

300.acl_check_rcpt_spam_rule.conf:
Сюда первым блоком добавил проверку на существующие адреса. Отсекает на ранней стадии.
deny    !recipients    = /usr/local/etc/exim/address.list
   hosts        = !127.0.0.1 : !localhost: *
   message        = "Invalid address!!!"
В общем статья классная но после проверки в блеклистах пришлось добавить еще вот такой блок
deny    condition    = ${if >{$acl_m0}{150}{yes}{no}}
   message        = "Последняя отсечка тех у кого очков много"

Денис, 2009-07-20 в 10:21:49

Конечно, это некростатья, но все еще полезная. Замечу насчет опций в make.conf: начиная с exim багфикс-версии к 4.24 одной опции WITH_OPENLDAP=yes не достаточно. Необходимо еще добавить конкретную версию OPENLDAP (например, 2.4), указав в make.conf WITH_OPENLDAP_VER=24.



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0789 секунд
Из них PHP: 66%; SQL: 34%; Число SQL-запросов: 78 шт.
Исходный размер: 117352; Сжатая: 28456