[Карта]                [Начало]                [Sendmail-ссылки]                [Синтаксис]                [Типовые задачки]                  [Задачки по маршрутизации]                  [Задачки по маcкарадингу]                  [SendmailACL]                  [Spamooborona]                  [VadeRetro]                  [Regex]                  [Тонкости]                  [Недок.особен.]                  [Несущ.юзеры]                  [Прячемся!]                  [RFC1893.Цитаты]                  [ТП.Эмоции]                  [Антиспам&Разум]                  [Экзерсисы]                 


Типовые задачки по sendmail. Часть первая. ([Часть вторая]    [Часть третья]    [Рейтинг])


22.03.06. Обнаружена проблема безопасности в sendmail, необходимо срочное обновление до v.8.13.6
13.11.2008.Ура!!! Хостинг-провайдера отключили от интернета за распространение спама. ИНформация с форума www.opennet.ru.
Скоро мой раздел станет ненужным! Ура!!!
Nota Bene! А вы здесь были? То, что описано на n моих страницах, оказывается, можно сделать одним мановением руки. Можно сказать, что мой Sendmail-раздел становится продуктом "артели "Напрасный труд" :)
Nota Bene! При использовании check_compat вы заметите, что отлуп происходит не сразу, как сработает правило, а письмо сначала будет принято, а потом будет сгенерирована ошибка "Service unavailable" и выслан отчет отправителю. Этим check_compat отличается от остальных наборов check_*. Claus Assmann советует вместо набора правил check_compat использовать check_rcpt, подавая на вход дополнительный параметр $&f (конвертный адрес отправителя):
Scheck_rcpt
R$*            $: $1 $| $&f
Поэтому рекомендую все упомянутые на этой странице наборы правил check_compat заменить на check_rcpt с добавлением $&f.

  • 0.1. Встроенные антиспам-средства sendmail'a.
  • 0.2. Мои примеры check_relay, check_mail,check_compat, check_rcpt
  • 1. Изменяем маршрут почты: как перенаправить определенную почту в локальный почтовый ящик или дальше.
  • 2. Как запретить посылать почту на определенный домен вместе с его поддоменами.
  • 3. Как разрешить определенному пользователю принимать почту только с определенного IP-адреса.
  • 3A. Как разрешить пользователям принимать почту только с определенного IP-адреса (запрет получения почты извне за исключением одного внешнего ip-адреса). .
  • 4. Как разрешить определенному пользователю принимать почту только с определенного e-mail адреса.
  • 4A. Как разрешить некоторым пользователям принимать почту только с локальных адресов.
  • 4B. Как запретить некоторым пользователям принимать почту с внешних адресов.
  • 5. Частный случай. Как отвергать почту, приходящую с локальных административных адресов, но не с локальных ip-адресов.
  • 5.1. Общий случай. Как запретить почту с внешних ip-адресов, подписанную моим почтовым доменом.
  • 5.2. Как заставить локальных пользователей подписываться в e-mail только локальным доменом.
  • 6. Как установить жесткое соответствие между локальным e-mail-адресом и локальным IP-адресом для отправки сообщений локальными пользователями.
  • 7. Как запретить определенному локальному пользователю посылать сообщения за пределы локального домена.
  • 8. Как разрешить определенному локальному пользователю посылать сообщения только на определенный внешний адрес.
  • 9. Как ограничить группу пользователей работой(прием/отправка) только внутри локального почтового домена.
  • 10.Как разрешить пользователю переписку с любым пользователем, кроме указанного адреса.
  • 11.Как запретить фальшивую рассылку с адресов gluck@mail.subscribe.ru и namma123456@subscribe.ru
  • 12.Фильтруем входящую почту по параметру HELO
  • 13.Как заблокировать письма с единственным подзаголовком Received: (как определить, что переменная пуста)
  • 14.Как бороться с перебором имен почтовых ящиков (dictionary attack, define(`confBAD_RCPT_THROTTLE',`3'))
  • 15.Как заблокировать перебор имен почтовых ящиков (наложение ограничения на число отказов "User unknown")
  • 16.Как избежать двойной отлуп (define(`confDOUBLE_BOUNCE_ADDRESS', `'))
  • 17.Как заблокировать письма, посылаемые на определенный mx-relay (блокировка по MX-релею получателя)
  • 18.Как проверять в RBL-базах не только ip непосредственного отправителя-почтовика, но и ip всех предшествоваших релеев, определенных в подзаголовках Received:
  • 19.Как ограничить общее количество соединений за определенный промежуток времени и количество одновременных соединений с одного хоста.
  • 19.1.Как ограничить количество сообщений за одну сессию (соединение)?
  • 19.2.Как ограничить кол-во писем по IP? (Как ограничить количество соединений и количество сообщений за одну сессию (соединение) с одного IP?)
  • 20.Как заблокировать почту с ip-адресов, для которых прямая и обратная проверки в днс не соответствуют друг другу.
  • 21.Reserved.
  • 22.Горячий спам (ноябрь-декабрь 2006г.)
  • 23.Как заставить локальных клиентов проходить smtp-авторизацию?
  • 24.Продолжение. Часть вторая.
  • 25.Обратная связь.


  • 0.1. Встроенные антиспам-средства sendmail'a.

    FEATURE На каком этапе smtp-диалога срабатывает Обязательная сопутствующая FEATURE Как сделать исключение
    FEATURE(dnsbl) check_relay нет FEATURE(delay_checks) or tag CONNECT:1.2.3.4 OK (/etc/mail/access)
    FEATURE(ratecontrol) check_relay нет CONNECT:1.2.3.4 [TAB] OK(или RELAY) или ClientRate:127.0.0.1 [TAB] 0 (/etc/mail/access)
    FEATURE(conncontrol) check_relay нет CONNECT:1.2.3.4 [TAB] OK(или RELAY) или ClientConn:127.0.0.1 [TAB] 0 (/etc/mail/access)
    FEATURE(`greet_pause') check_relay нет GreetPause:1.2.3.4 [TAB] 0 (/etc/mail/access)

    Следующие фичи я не использую, так как они появились позже, чем я стала делать это же самостоятельно своими правилами, поэтому я не знаю, на каком этапе проводится эта проверка, предполагаю, что check_relay. А по поводу FEATURE(`block_bad_helo') README говорит, что check_rcpt.
    FEATURE(`badmx') ?check_relay нет Сделать исключение штатными средствами невозможно
    FEATURE(`require_rdns')?check_relay нет CONNECT:1.2.3.4 [TAB] OK(или RELAY)(/etc/mail/access) или 1.2.3.4 в /etc/mail/relay-domains или FEATURE(delay_checks) вкупе с smtp-auth
    FEATURE(`block_bad_helo') check_rcpt delay_checks Сделать исключение штатными средствами невозможно, но по умолчанию smtp-авторизованная почта и почта из локальных сетей будет пропущена за счет использования FEATURE(delay_checks).

    Почитайте внимательно README, там все про эти фичи написано. Мои же ссылки указывают только на мои мысли по этому поводу.


    0.2. Некоторые примеры Local_check_relay, Local_check_mail,check_compat, Local_check_rcpt можно посмотреть в sendmail.mc-файлах, использующих regex-spam-фильтр. На данной странице рассмотрены примеры, не вошедшие в вышеупомянутые конфигурационные файлы.


    1.  Изменяем маршрут почты: как перенаправить определенную почту в локальный почтовый ящик или дальше.
    Для начала упомяну 3 способа глобального перенаправления почты:

    define(`MAIL_HUB', `mailer:hostname')
    define(`LOCAL_RELAY', `mailer:hostname')
    define(`SMART_HOST',`[smarthost.example.net]')dnl
    Robert Harker
    The SMART_HOST macro causes sendmail to forward all non-local mail to a relay, and the MAIL_HUB macro forwards all local mail to a relay.
    Or you could use the nullclient configuration:
    FEATURE(`nullclient',smtprelay.fordham.edu)
    which dose the same thing and a bit more like masquerading as the relay, smtprelay.fordham.edu.


    1.1 Перенаправление почты в зависимости от адреса получателя.
    Для изменения маршрута исходящей почты предназначены Virtusertable и Mailertable.
    Между этими таблицами есть три отличия.

    Virtusertable.
    Первая таблица предназначена для работы с виртуальными почтовыми доменами на одном почтовом сервере. Это означает, что исходные получатели могут быть любыми: как существующими на данном сервере (и системными, и не системными (например, хранящимися в БД)), так и не существующими.
    Таблица работает исключительно с локальными и виртуальными доменами, то есть
    домен перемаршрутизируемого исходного получателя должен обязательно принадлежать классу w
    (он должен быть упомянут в /etc/hosts или в /etc/mail/local-host-name) или классу VirtHost.

    Перенаправлению подлежит почта отправленная на
    - определенный локальный или виртуальный домен,
    - на определенный локальный или виртуальный адрес.

    То есть через таблицу virtusertable проходит как входящая, так и исходящая почта, если доменом получателя (в обоих случаях) является локальный домен(класс {w}) или домен, специально определенный в классе {VirtHost} (создается макросом VIRTUSER_DOAMIN). Виртуальный домен не обязательно прописывать именно в классе {VirtHost}. Можно ограничиться классом {w}.

    Почта может быть перенаправлена на
    - локальный адрес;
    - внешний адрес;
    - внешний домен;
    - а также может быть отвергнута.
    Примеры.

    15.04.2008. Одна, кажется недокументированная, особенность от Andrzej Adam Filip. В строке virtusertable можно использовать обратный слэш \ с тем, чтобы отменить действие @:
    @example.net %1\@example.net
    Для чего это нужно?
    Один человек зачем-то создал системных юзеров в виде user@domain.com, а потом столкнулся с тем, что sendmail удаляет доменную часть, и почта складывается в дир-ию user, вместо user@domain.ru
    Andrzej Adam Filip кроме того предлагает еще одно решение :
    "... I have created a *simple* hook (custom ruleset) called for local email domains just before classic selection of local mailer via patch to cf/m4/proto.m4.
    It will allow to select local-dom mailer for *some* local domains. Rule set 5 can be used to redirect non existing "u...@example.com" to "user" for such domains ..."

    Mailertable.
    Вторая таблица работает исключительно с нелокальными доменами в адресе получателя.

    Перенаправлению подлежит почта, отправленная на
    - определенный нелокальный домен,
    - определенный нелокальный домен со всеми его поддоменами.

    То есть через таблицу mailertable проходит как входящая транзитная почта, так и исходящая от локальных пользователей почта, если ее получателем (во втором случае, ведь в случае транзитной почты другого быть не может) является нелокальный пользователь.

    Почта может быть перенаправлена на
    - локальный адрес;
    - внешний хост;
    - а также может быть отвергнута.
    Примеры.

    Из этого следует, что с.п. mailertable невозможно перенаправить почту, отправленную на определенный адрес postbox@нелокальный домен.
    /usr/src/sendmail/cf/README гласит :"Note: e-mail to "user@my.domain" does not match any entry in the above table ..."

    Решение, которое лежит на поверхности, - перевести домен получателя в разряд локального и воспользоваться virtusertable.
    Но это может быть не всегда удобно.
    В этом случае есть 3 способа решения задачи.
    1.1.1.    Вот здесь лежит патч Andrzej Filip, позволяющий указывать в mailertable в качестве ключа электронный адрес.
    1.1.2.    Mожно подправить sendmail.cf напрямую, вставив эти правила сразу за SParse1 (в Ruleset 0).
    Должно получиться следующее:
    #
    # Parse1 -- the bottom half of ruleset 0.
    #
    SParse1
    #Заворачиваем постмастеру всю почту, отправленную на адреса reklama@anydomain.ru
    Rreklama$*                $#local $: postmaster
    #Заворачиваем постмастеру всю почту, отправленную на любой адрес домена elki.ru. Привожу эту строку исключительно ради спорт. интереса, так как такое перенаправление прекрасно отработает и через mailertable вот таким образом: .elki.ru.          local:postmaster
    R$* < @ $*elki.ru. >                $#local $: postmaster
    #Заворачиваем постмастеру всю почту, отправленную на адрес elka@elka.ru
    Relka < @ elka.ru. >                $#local $: postmaster
    Отправляем почту, посланную для consiglio@anrb.ru, за пределы локального домена:
    Rconsiglio<@anrb.ru.>               $#esmtp $@ apache.anrb.ru $: paradise<@consiglio.anrb.ru.>
    Rconsiglio<@anrb.ru.>               $#esmtp $@ [212.193.135.6] $: paradise<@consiglio.anrb.ru.>
    (Домен anrb.ru не является локальным для почтовика, с которого отправляется данная почта).

    Но тогда придется каждый раз при пересборке вручную править sendmail.cf.

    1.1.3. Третий способ заключается в редактировании файла /usr/src/sendmail-XXX/cf/m4/proto.m4
    В нем нужно найти все тот же SParse1 и вставить сразу после него указанные выше правила.
    Теперь эти правила будут автоматически включатся в конфиг при пересборке.

    26.09.2008. Четвертый способ. Оказывается, в sendmail предусмотрен цивилизованный способ добавления маршрутов через LOCAL_RULE_O. Таким образом добавляются правила в набор правил 0.
    LOCAL_CONFIG
    LOCAL_RULE_0
    Rconsiglio<@anrb.ru.>               $#esmtp $@ apache.anrb.ru $: paradise<@consiglio.anrb.ru.>
    Rumbrellone<@anrb.ru.>               $#local $: umbrella


    1.1.1 Перенаправление почты в зависимости от адреса получателя и ip-адреса релея, с которого пришло письмо.

    Ну, то, что дорога в ад вымощена благими намерениями, это мы все хорошо знаем.
    Зайдя однажды на sendmail-конфу, чтобы задать свой вопрос, увидела я задачку по маршрутизации, которая показалась мне интересной, и я не удержалась и решила попытать свои силы, смогу ее решить или нет. Решить-то я ее решила, по крайней мере, на моем почтовике все заработало как надо. Но, или я суть вопроса не поняла (провинциальное образование, имхо, в первую очередь выдает плохое знание иностранных языков:), или все-таки вопрошавший сделал что-то не так, но у него мой набор не заработал.
    Тем не менее выкладываю решение здесь, а вдруг кому и пригодится, зря я что-ли время свое тратила?
    Постановка задачи такая. Если в mailertable мы напишем следующее:
    domain.tld               esmtp:[zz.zz.zz.zz]
    sub.domain.tld               esmtp[yy.yy.yy.yy]
    то, почта для домена domain.tld пойдет на хост zz.zz.zz.zz, а почта для sub.domain.tld пойдет на хост yy.yy.yy.yy.
    А что делать, если на хост yy.yy.yy.yy должна уходить только та почта для sub.domain.tld, которая пришла с хоста xx.xx.xx.xx?

    Находим в sendmail.cf строку SParse1 и сразу после нее добавляем следующее:
    Если домен получателя sub.domain.tld, то подаем на вход еще адрес отправителя и ip-адрес релея-отправителя.
    R$+<@sub.domain.tld.>               $: <$&f><$&{client_addr}> $| $1<@sub.domain.tld.>
    Я не гуру, многого не знаю, но заметила, что Parse1 отрабатывает и для получателя, и для отправителя.
    Для того, чтобы в мою проверку не попали отправители с доменом sub.domain.tld, я добавила в предыд. строку макрос $&f - адрес отправителя.
    Также я заметила,что когда Parse1 обрабатывает адрес отправителя, этот макрос остается пустым.
    Видимо, адрес отправителя помещается в этот макрос уже после первоначального прохода Parse1.
    Поэтому, если этот макрос пустой, то делать ничего не нужно: мы оставляем в рабочей области лишь исходное значение $+<@sub.domain.tld.>, поданное в Parse1.
    И дальше мои правила не сработают.
    R<><$+> $| $+               $: $2

    А вот когда начинается обработка адреса получателя, этот макрос оказывается заполненным, то есть не пустым. Избавляемся от макроса $&f.
    R< $+ ><$+> $| $+               $: <$2> $| $3

    Проверяем ip релея отправителя. Если он xx.xx.xx.xx - перенаправляем на yy.yy.yy.yy
    R< xx.xx.xx.xx > $| $+               $#esmtp $@ [yy.yy.yy.yy] $: $1
    Если ip другой - блокируем. Здесь я автора не поняла: действительно ли он хотел блокировать или же отправлять по основному маршруту (на zz.zz.zz.zz).
    R<$+> $| $+                $#error $@ 5.7.1 $: "550 Access for IP " $1 " denied: " $2
    Всю почту, предназначенную domain.tld, отправляем на хост zz.zz.zz.zz
    R$+<@domain.tld.>               $#esmtp $@ [zz.zz.zz.zz] $: $1<@domain.tld.>

    И, кстати, потом Andrzej Adam Filip выложил свое решение, я думаю, оно самое правильное и грамотное.
    20.01.2009. Новое решение этой задачи с использованием LOCAL_RULE_0. Теперь все грамотно и культурно.


    1.2 Перенаправление почты в зависимости от адреса отправителя.
  • Neil Rickert. Маршрутизация почты в зависимости от адреса отправителя.
  • Andrzej Adam Filip. Smarttable (находится в open-sendmail.tar.gz) - маршрутизация почты в зависимости от адреса отправителя.
  • Andrzej Adam Filip. Smarttable (устаревшее, автором не поддерживается, но есть описание таблицы, чего пока нет на новом месте (инфа от 14.02.2008)
  • Консультация Andrzej Adam Filip на opennet.ru по набору правил smarttable.
  • Консультации Andrzej Adam Filip по вопросу использования smarttable.

    14/10/2008. Задачки по маршрутизации находятся здесь.
    12.04.2012. Решение для exim.

    2. Итак, запрещаем локальным пользователям посылать почту на определенный домен и все его поддомены.
    При этом получать почту с этих доменов пользователи смогут.
    В check_rcpt (или local_check_rcpt)
    С{baddom} domain1.ru domain2.ru
    R$*                 $: $>Parse0 $>3 $1
    R$* <$* $={baddom}.>                 $# error $@5.7.1 $:"You must not send mail to this address."
    Зачем это нужно? Однажды некий админ в ответ на сканирование моим пользователем его сети заблокировал мою сетку так, что почта с его домена ко мне приходила, но обратного движения не наблюдалось, лог исправно заполнялся отлупами с того сервера. Поскольку админ на контакт упорно не шел, а maillog прилично забивался сообщениями о невозможности доставки, пришлось пойти на такую хитрость. Хитрость придумана не мной. Мне ее подсказал на opennet.ru Z0termaNN.
    NB! Запретить локальным пользователям посылать почту на конкретный домен можно простым редактированием /etc/mail/access:
    To:domain1.ru DISCARD (или REJECT)
    26.08.2008. Не знаю, почему так получилось тогда, что я не смогла заблокировать всю почту с этого домена (может версия такая была "неправильная", ведь давно это было), а на самом деле /etc/mail/access должен справиться с этим на "ура", ведь README гласит:
    "...For example
    From:cyberspammer.com                 REJECT
    would refuse mail from any user from cyberspammer.com (or any host within the cyberspammer.com domain)..."

    3.Как разрешить определенному пользователю принимать почту только с определенного IP-адреса.
    Предположим, Вы создали список рассылки и хотите, чтобы сообщения на него можно было посылать только с конкретных ip-адресов. Можно поступить так:
    Добавляем в sendmail.mc след. строки

    LOCAL_CONFIG
    #В этом файле перечисляем разрешенные IP-адреса:
    KADDR_LIST hash /etc/mail/addrlist
    KCheckRcpt2 regex -a@LIST2 ^list$

    LOCAL_RULESETS
    SLocal_check_rcpt
    R$*             $: $>Parse0 $>3 $1
    # Является ли адрес получателя списком рассылки? Попутно избавляемся от доменной части адреса получателя.
    R$+<@$=w.>                $: $(CheckRcpt2 $1 $:$1 $)
    Если да, смотрим IP-адрес отправителя письма.
    R@LIST2                $: $>CheckUserIP
    Если нет - пропускаем его и завершаем работу набора правил.
    R$*                 $@ OK

    SCheckUserIP
    R$*                $: $&{client_addr}
    R$-.$-.$-.$-                 $: $(ADDR_LIST $1.$2.$3.$4 $)
    Если IP-адрес включен в файл /etc/mail/addrlist, то принимаем письмо:
    ROK                $@ OK
    Если нет - даем отлуп.
    R$*                 $#error $: 554 Sorry, you can not send letter to this list.

    Формат файла /etc/mail/addrlist:
    127.0.0.1                OK

    Не забываем про команду:
    makemap hash addrlist < addrlist

    Пересобираем sendmail.cf и перезапускаем sendmail.
    25.03.2009. Другой вариант решения.

    Еще одно решение.
    LOCAL_CONFIG
    #В этом файле перечисляем разрешенные IP-адреса:
    KADDR_LIST hash /etc/mail/addrlist
    # Списки рассылок
    KCheckRcpt2 regex -a@LIST2 ^maillist1|maillist2|maillist3$
    Ksyslog syslog
    LOCAL_RULESETS
    SLocal_check_rcpt
    R$*                            $: $(syslog syslog:rcpt:0 $1 $) $1
    R$*<$+@$=w>                           $: <$(Rcp $2 $:CONTINUE $)>
    R< CONTINUE >                           $@ OK
    R$+@$=w                            $: <$(Rcp $1 $:CONTINUE $)>
    R< CONTINUE >                            $@ OK
    R$+@$+                            $@ OK
    R$+                            $: <$(Rcp $1 $:CONTINUE $)>
    R< CONTINUE >                           $@ OK

    R$*                            $: $(syslog syslog:rcpt:1 $1 $) $1
    R< @LIST2 >                            $: < @LIST2 ><$&{client_addr}>
    R< @LIST2 ><$-.$-.$-.$->                           $: $(ADDR_LIST $1.$2.$3.$4 $)

    R$*                            $: $(syslog syslog:rcpt:2 $1 $) $1
    R< @LIST2 >                           $@ OK
    R< @LIST2 ><$+>                           $#error $: 554 "Sorry, restricted maillist. Please contact to postmaster@yourdomain.ru"

    3A.Как разрешить пользователям принимать почту только с определенного IP-адреса (запрет получения почты извне за исключением одного внешнего ip-адреса).

    Порой меня упрекают в том, что я усложняю решение задач, берясь за написание собственных правил тогда, когда решить проблему можно штатными методами sendmail. Признаюсь, что порой так бывает, но не от избытка лишнего времени, а от недостатка знаний. Вот, например, необходимо, чтобы внешняя почта могла поступать только с одного ip-адреса. Я буду решать эту задачку в Local_check_relay, проверяя значение макросов $&_ или $&{client_addr}.
    На самом же деле эта задачка решается средствами /etc/mail/access.
    Предположим, вам нужно запретить прием почты извне за исключением адреса 1.2.3.4
    Для того, чтобы блокировка произошла еще на этапе check_relay, редактируем access c использованием тэга connect:
    #Локальный адрес сервера:
    connect:127.0.0.1                OK
    #Ваша локальная сеть:
    connect:192.168.0.0                OK
    #Разрешенный внешний адрес:
    connect:1.2.3.4                 OK
    #Все остальное запрещаем:
    connect:0                REJECT
    connect:1                 REJECT
    ...
    connect:255                REJECT
    makemap hash access <access
    Задачка решена.

    4. Как разрешить определенному пользователю принимать почту только с определенного e-mail адреса.
    Добавляем в sendmail.mc след. строки

    LOCAL_CONFIG
    #Разрешенный отправитель:
    KSnd regex -a@LIST1 ^someuser<@somedomain.ru.>$
    #Получатель, который может получать почту только от указанного выше отправителя :
    KRcp regex -a@LIST2 ^youruser$

    LOCAL_RULESETS
    Scheck_compat
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    #Проверяем, является ли получатель тем самым юзером, к-й ограничен в правах. Доменная часть адреса получателя нам больше не нужна ($3), за собой ее больше не таскаем:
    R$+ $| $+<@$=w.>                 $: $1 $| $(Rcp $2 $:$2 $)
    #Да - проверяем, кто отправитель:
    R$+ $| @LIST2                 $: $>CheckSender $1
    #Нет - завершаем работу набора правил
    R$*             $@OK
    Здесь по смыслу мы должны были использовать следующую конструкцию:
    R$* $| $*             $@OK
    #Но наша единственная лексема $* будет содержать обе лексемы из вышестоящего правила подстановки, разделенные "\377" ( $| ). Исходя из этого в дальнейшей работе с check_compat в соотвествующих случаях я буду использовать только единичную лексему.

    SCheckSender
    R$+                 $: $(Snd $1 $:$1 $)
    #Если тот, которому все можно - завершаем работу набора правил
    R@LIST1                 $@ OK
    #Нет - даем отлуп
    R$*                 $#error $: 554 Sorry, you can not send letter to this user.
    Пересобираем sendmail.cf и перезапускаем sendmail.

    27.02.2009. Упрощенное решение:
    1)check_comapt заменен на Local_check_rcpt;
    2) вместо вызова рулсета CheckSender используются маркеры ;
    3) отказалась от вызова 3-го рулсета.

    LOCAL_CONFIG
    #Разрешенный отправитель:
    KSnd regex -a@LIST1 ^root$
    #Получатель, который может получать почту только от указанного выше отправителя :
    KRcp regex -a@LIST2 ^mailer-daemon|operator$

    LOCAL_RULESETS
    SLocal_check_rcpt
    R<$+@$=w>             $: <$(Rcp $1 $)>
    R<@LIST2>             $: <@LIST2><$&f>
    R<@LIST2><$+@$=w>             $: <@LIST2><$(Snd $1 $)>
    R<@LIST2><@LIST1>             $@ OK
    R<@LIST2><$+>             $#error $: 554 "Sorry, restricted account. Please use postmaster@yourdomain.ru"

    4A. Как разрешить некоторым пользователям принимать почту только с локальных e-mail адресов.
    На www.sendmail.org это делается так - protected.html
    У меня задачка решена немного по другому.
    LOCAL_CONFIG
    #Получатели, которые могут получать только локальную почту :
    KRcp regex -a@LIST ^test|guest$

    LOCAL_RULESETS
    Scheck_compat
    R$* $| $*                 $: $2 $| $>Parse0 $>3 $1
    R$* $| $*                 $: $2 $| $>Parse0 $>3 $1
    #Проверяем, является ли получатель тем самым юзером, к-й ограничен в правах.
    R$+ $| $+<@$=w.>                 $: $1 $| $(Rcp $2 $:$2 $)
    #Да - проверяем, кто отправитель:
    R$+ $| @LIST                 $: $>CheckSender $1
    #Нет - завершаем работу набора правил
    R$*                 $@OK

    SCheckSender
    #Если отправитель локальный - завершаем работу набора правил
    R$+ <@$=w.>                 $@OK
    #Нет - даем отлуп
    R$*                 $#error $: 554 Sorry, you can not send letter to this user.
    Пересобираем sendmail.cf и перезапускаем sendmail.

    11.03.2010. Решение переписанное в соответствии с рекомндацией Claus Assmann не использовать check_compat.
    Здесь я ограничиваю в правах список рассылок, состоящий из всех юзеров моего домена. Он не может получать почту извне (с IP адресов вне локальной сети).
    LOCAL_CONFIG
    #Получатели, которые могут получать только локальную почту :
    KRcp regex -a@LIST ^alllist$

    LOCAL_RULESETS
    Scheck_rcpt
    R$*                 $: $&f $| $1
    #Проверяем, является ли получатель тем самым юзером, к-й ограничен в правах.
    R$+ $| $+<@$=w.>                 $: $1 $| $(Rcp $2 $:$2 $)
    #Да - проверяем, кто отправитель:
    R$+ $| @LIST                 $: $>CheckSenderIP <$&{client_addr}>
    #Нет - завершаем работу набора правил
    R$*                 $@OK

    SCheckSenderIP
    #Если отправитель имеет локальный IP адрес, т.е. прописан в файле /etc/mail/relay-domains, - завершаем работу набора правил
    R< $=R $* >                 $@OK
    #Нет - даем отлуп
    R$*                 $#error $: 554 Sorry, you can not send letter to this user.
    Пересобираем sendmail.cf и перезапускаем sendmail.

    Если для разрешения релеинга вы используете /etc/mail/access, то набор правил для CheckSenderIP можно взять здесь.

    4B. Как запретить некоторым пользователям принимать почту с внешних адресов.
    Задачка решается аналогично предыдущей за исключением двух строк:
    #Получатели кроме тех, которые могут получать любую почту :
    #NotaBene! Адм-адреса, заявленные для контактов при регистрации домена, и прочие контактные адреса в этот список вносить нельзя: postmaster, webmaster, adm, etc...
    #Вы обязаны получать внешнюю почту, поступающую на административные адреса.
    #Иначе рискуете наступить на такие вот грабли, разбросанные по конфигам многих почтовиков:
    #FEATURE(rhsbl, `postmaster.rfc-ignorant.org',`"550 Mail from domain " $`'&{RHS} " refused. MX of domain does not have a working postmaster address - see http://www.rfc-ignorant.org/"')

    RFC 2821: "...
    Any system that includes an SMTP server supporting mail relaying or
    delivery MUST support the reserved mailbox "postmaster" as a case-
    insensitive local name. This postmaster address is not strictly
    necessary if the server always returns 554 on connection opening (as
    described in section 3.1). The requirement to accept mail for
    postmaster implies that RCPT commands which specify a mailbox for
    postmaster
    at any of the domains for which the SMTP server provides
    mail service, as well as the special case of "RCPT TO:"
    (with no domain specification), MUST be supported.

    SMTP systems are expected to make every reasonable effort to accept
    mail directed to Postmaster from any other system on the Internet.
    In extreme cases --such as to contain a denial of service attack or
    other breach of security-- an SMTP server may block mail directed to
    Postmaster. However, such arrangements SHOULD be narrowly tailored
    so as to avoid blocking messages which are not part of such attacks.
    ..."

    KRcp regex -n -a@NOLIST ^test|guest$
    R$+ $| @NOLIST $: $>CheckSender $1
    Возможно, у это задачки есть более простое решение с использованием /etc/mail/access, FEATURE(blacklist_recipients). Но мне его реализовать не удалось.

    5. Частный случай. Как отвергать почту, приходящую с локальных административных адресов, но не с локальных ip-адресов.
    В последнее время мне то и дело сыпятся уведомления от антивирусов различных почтовых систем, что с адм. адресов моего домена adm, postmaster, MAILER-DAEMON, etc приходят вирусы. Кроме того, с этих же электронных адресов стали приходить вирусы и спам и моим пользователям, естественно, из чужих сетей. Попробуем справиться с этим так.
    Добавляем в sendmail.mc след. строки
    LOCAL_CONFIG
    KADM_ADDR_LIST hash /etc/mail/admaddrlist
    KADMADR regex -a@ADMLIST ^root|postmaster|adm|mailer-daemon|hostmaster|webmaster$

    LOCAL_RULESETS
    SLocal_check_mail
    R$*             $: $>Parse0 $>3 $1
    R<@>                 $@ OK
    R$+<@$=w.>                 $: $(ADMADR $1 $: $1 $)
    R@ADMLIST                 $: $>CheckAdmIP
    R$*                 $@ OK

    SCheckAdmIP
    R$*                 $: $&{client_addr}
    R$-.$-.$-.$-                 $: $(ADM_ADDR_LIST $1.$2.$3.$4 $)
    ROK                 $@ OK
    R$*                 $#discard $: discard
    или
    R$*                 $#error: $: 554 Sorry, you cannot send a mail from this ip-address. Please, contact to postmaster.
    Разница в том, что в случае discard письмо будет принято и тихо уничтожено, а в случае #error , возможно, именно вы будете получать большое количество извещений от чужих MAILER-DAEMON'ов о невозможности доставки сообщения локальному пользователю, ведь в адрес отправителя подделан и в нем указан один из административных адресов, почта на которые обычно перенаправляется одному администратору.

    Формат файла /etc/mail/admaddrlist, в котором содержатся ip-адреса, с которых разрешено приходить административной почте:
    127.0.0.1                OK
    и т.д.

    Не забываем про команду:
    makemap hash admaddrlist < admaddrlis
    Пересобираем sendmail.cf и перезапускаем sendmail.


    5.1. Общий случай. Как запретить почту с внешних ip-адресов, подписанную моим почтовым доменом.
    Запрещаем почту с адресов someuser@mydomain.ru с адресов, не прописанных в relay-domains.
    Это решение учитывает только конвертный адрес отправителя (MAIL FROM:), заголовочный From: (DATA) здесь не проверяется. Полное решение - здесь.

    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_mail
    R$*                $: $>Parse0 $>3 $1
    R$+<@$=w.>                $: $>CheckIP-auth
    Если такую блокировку вы хотите сделать на почтовике, который каким-либо образом перенаправляет почту на внутренний почтовик, то нужно добавить такую строку:
    R$+<@доменное_имя_внутр.почт.. >                $: $>CheckIP-auth
    R$*                $@ OK

    SCheckIP-auth
    #Если юзер из локальной сети (определяется по наличию сетки в файле /etc/mail/relay-domains (для access это будет длиннее)), пропускаем письмо
    R$*                 $: $&{client_addr}
    R$=R $*                 $@ OK
    #Если юзер прошел smtp-авторизацию, пропускаем его
    R$*                $: <$&{auth_authen}>
    R<$+>                $@ OK
    Все остальные юзеры - чужие, блокируем.
    R$*                 $#error: $: 554 Sorry, ...


    5.2. Как заставить локальных пользователей подписываться в e-mail только локальным доменом.
    Желание не бесспорное, но иногда кому-то бывает это нужно.
    Итак, запрещаем почту из локальной сети и smtp-авторзованную, если она подписана чужим доменом.
    NB: не проверялось! Тот, кто про это спросил, исчез, не сообщив о результате.

    LOCAL_CONFIG
    LOCAL_RULESETS
    SLocal_check_mail
    R$+                $:$1 $| <$&{auth_authen}>
    #Если юзер прошел smtp-авторизацию, проверяем его e-mail
    R$+ $| <$+>                $: $>Check_email $1

    #Если юзер из локальной сети (определяется по наличию сетки в файле /etc/mail/relay-domains (для access это будет длиннее)), проверяем его e-mail
    R$+                 $:$1 $| <$&{client_addr}>
    R$+ $| < $=R $* >                $: $>Check_email $1

    #Все остальное (почта от внешних юзеров локальным) - пропускаем
    R$*                $@ OK

    SCheck_email
    #Канонизируем адрес отправителя
    R$+                $: $>Parse0 $>3 $1
    #Если домен наш - пропускаем
    R$+<@$=w.>                $@ OK
    #Нет - блокируем.
    R$*                $#error: $: 554 Sorry, invalid sender domain. Please, contact to postmaster.


    6. Как прописать жесткое соответствие между e-mail-адресом и локальным ip-адресом для отправки сообщений локальными пользователями.

    Создаем файл /etc/mail/open:
    user1<>192.168.0.1              YES
    user2<>192.168.0.2              YES
    user3<>192.168.0.3              YES
    user4<>192.168.0.4              YES
    В командной строке:
    makemap hash open < open

    В конец стандартного sendmail.mc добавляем:
    LOCAL_CONFIG
    Определяем специальное преобразование OPEN:
    KOPEN hash /etc/mail/open
    LOCAL_RULESETS
    SLocal_check_mail
    R$*             $: $>Parse0 $>3 $1
    Если адрес отправителя локальный, отправляем на проверку соответствия между именем почтвого ящика и IP-адресом.
    R$+<@$=w.>             $: $>CheckLocalMail $1
    Если нет, то пропускаем такую почту.
    R$*             $@ OK

    SCheckLocalMail
    На вход набору правил CheckLocalMail подан e-mail-адрес, добавляем к нему IP-адрес хоста, установившего smtp-соединение:
    R$*              $: $1 $&{client_addr}
    Проверяем, соотвествует ли полученная комбинация какой-либо записи в файле /etc/mail/open:
    R$+<>$-.$-.$-.$-             $: $(OPEN $1$2.$3.$4.$5 $: $1$2.$3.$4.$5 $)
    Да - пропускаем почту.
    RYES              $@ OK
    Нет - блокируем
    R$*              $#error $: 554 Sorry, you cannot send a mail from this ip-address. Please, contact to postmaster.

    Пересобираем sendmail.cf и перезапускаем sendmail.


    7. Как запретить ОПРЕДЕЛЕННОМУ локальному пользователю посылать сообщения за пределы локального домена. (Решение задачи ограничения ВСЕХ локальных пользователей пересылкой собщений только в локальный домен - здесь).

    В конец стандартного sendmail.mc добавляем:

    LOCAL_CONFIG
    Определяем специальное преобразование Sender для локального пользователя с усеченными правами:
    KSender regex -a@LIST restricted_user

    LOCAL_RULESETS
    Scheck_compat
    Исходные данные для этого набора правил имеют вид $1 $| $2, где $1 - отправитель, $2 - получатель в виде <user@domain.ru>
    #После канонизации адресов они примут вид: $1<@$2> $| $3<@$4>
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    Если отправитель - локальный, проверяем его на принадлежность списку Sender и в случае положительного ответа отправляем адрес получателя на проверку в набор правил CheckLocalMail.
    R$+<@$=w.> $| $+             $: $(Sender $1 $:$1 $) $| $3
    R@LIST $| $+             $: $>CheckLocalMail $1
    Почту от внешнего отправителя пропускаем.
    R$* $| $*              $@ OK

    SCheckLocalMail
    На вход набору правил CheckLocalMail подан e-mail-адрес получателя в виде user<@domain.ru>. Делаем разбор доменной части электр. адреса, если она локальная - пропускаем.
    R$+<@$=w.>              $@ OK
    Нет - блокируем
    R$*              $#error $: 554 Sorry, you cannot send a mail to non-local address. Please, contact to postmaster.

    Пересобираем sendmail.cf и перезапускаем sendmail.

    Или так:
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$+<@$=w.> $| $+             $: $(Sender $1 $:$1 $) $| $3
    R@LIST $| $+<@$=w.>             $@ OK
    R@LIST $| $*              $#error $: 554 Sorry, you cannot send a mail to non-local address. Please, contact to postmaster.
    R$*              $@ OK


    8.Как запретить ОПРЕДЕЛЕННОМУ локальному пользователю посылать сообщения за пределы локального домена за исключением одного или нескольких внешних адресов.

    LOCAL_CONFIG

    #Обиженный админом локальный отправитель:
    KSnd regex -a@LIST1 ^somelocaluser$
    #Получатель, с которым разрешено общаться несчастному :
    KRcp regex -a@LIST2 user<@somedomain.ru>

    LOCAL_RULESETS
    Scheck_compat
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    #Проверяем, является ли отправитель локальным и ограниченным в правах: да - отправляем на дальнейшую проверку в
    CheckLocalUser адрес получателя; нет - пропускаем:
    R$+<@$=w.> $| $+             $: $(Snd $1 $:$1 $) $| $3
    R@LIST1 $| $+             $: $>CheckLocalUser $1
    Почту от внешнего отправителя пропускаем.
    R$* $| $*              $@ OK

    SCheckLocalUser
    #Проверяем, кто получатель. Если локальный - пропускаем.
    R$+<@$=w.>              $@ OK
    R$+              $: $(Rcp $1 $:$1 $)
    #Если тот, который в списке Rcp - завершаем работу набора правил (пропускаем письмо)
    R@LIST2              $@ OK
    #Нет - даем отлуп
    R$*              $#error $: 554 Sorry, you can not send letter to this user.



    9.А теперь ограничиваем группу пользователей работой(прием/отправка) только внутри почтового домена
    Остальные пользователи работают в обычном режиме.
    Подобная задача решается здесь - http://www.spirit.org.ua:8080/sendmail/ и здесь. И еще одно решение.
    Попробую и я добавить свои 5 копеек :)

    Создаем файл /etc/mil/restr_user, здесь перечисляем всех ограниченных в правах локальных пользователей:
    localuser1              LIST
    localuser2              LIST
    localuser3              LIST
    localuser4              LIST
    Затем в командной строке выполняем:
    makemap hash restr_user <restr_user

    Редактируем sendmail.mc.

    LOCAL_CONFIG

    KRESTR_USER hash /etc/mail/restr_user

    LOCAL_RULESETS
    SLocal_check_rcpt
    #Исходные данные для этого набора правил имеют вид $&f $| $1, где $&f - отправитель, $1 - получатель.
    #После канонизации адресов они примут вид: $1<@$2> $| $3<@$4>
    #Хитрость со сменой порядка параметров при передаче их на канонизацию почерпнута отсюда -http://www.informatik.uni-kiel.de/%7Eca/email/check.html#check_rcpt
    #
    R$*             $: $&f $| $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    R$* $| $*             $: $2 $| $>Parse0 $>3 $1
    #Обильно сдабриваем набор правил промежуточным выводом.
    R$* $| $*              $: $(syslog COMPAT1_syslog: $1-$2 $) $1 $| $2

    #Внутри локального почтового домена почта ходит беспрепятственно
    R$+<@$=w.> $| $+<@$=w.>              $@ OK

    #Сообщения от мэйлер-демонов (локального и чужих) пропускаем
    R<@> $| $+              $@ OK
    #Это сообщения от локального MAIL-DAEMON
    RMAILER-DAEMON $| $+              $@ OK

    #Теперь разберемся с алиасами.
    #Предположим, в etc/mail/aliases есть такая строка:
    #vasya:              petya
    #Пусть некий someuser@somedomain.ru посылает письмо для пользователя vasya@mydomain.ru
    #Тогда входные данные для набора правил check_compat после канонизации будут такими:
    #someuser<@somedomain.ru> $| petya
    #Переадресация данных через алиасы на обработку программам или в файл также исключает наличие <@>.
    #Для "бездоменных" локальных адресов нужны дополнительные правила.
    #Для того, чтобы отличить их от обычных адресов, помечаем всех пользователей
    #меткой <LOCAL>, затем анализируем отправителя/получателя на наличие доменной
    #части и, если она присутствует, убираем метку.
    #Таким образом, останутся помеченными локальные адреса без доменной части адреса.

    R$+ $| $+              $: <LOCAL> $1 $| <LOCAL> $2
    R<LOCAL>$+<@$+> $| $+              $: $1<@$2> $| $3
    R$+ $| <LOCAL>$+<@$+>              $: $1 $| $2<@$3>

    #Движение внутри домена разрешаем.
    #Следует ометить, что по моим наблюдениям это правило сработало бы только с том случае, когда отправителем являлся локальный MAILER-DAEMON. Но на этот случай имеется вышеуказанное правило. Другие "бездоменные" локальные отправители мне не известны, так что нижеследующее правило можно опустить.
    R<LOCAL>$+ $| <LOCAL>$+              $@ OK
    R$* $| $*              $: $(syslog COMPAT2_syslog: $1-$2 $) $1 $| $2
    По этой же причине я не разбираю случая R<LOCAL>$+ $| $+

    #Если источник - локальный, то пропускаем письмо
    R$+<@$=w.> $| <LOCAL>$+              $@ OK

    #Нет - проверяем дальше
    R$+ $| <LOCAL>$+              $: $1 $| $(RESTR_USER $2 $:$2 $)
    R$* $| $*              $: $(syslog COMPAT3_syslog: $1-$2 $) $1 $| $2
    R$+ $| <LOCAL>LIST              $#error $: 554 Sorry, you can not send a letter to this user
    #Остальным локальным клентам письмо отдаем
    R$+ $| <LOCAL>$+              $@ OK

    #Локальных получателей проверяем на принадлежность списку
    #ограниченных в правах пользователей
    R$+ $| $+<@$=w.>              $: $1 $| $(RESTR_USER $2 $:$2<@$3.> $)
    R$* $| $*             $: $(syslog COMPAT4_syslog: $1-$2 $) $1 $| $2
    R$+ $| LIST             $#error $: 554 Sorry, you can not send a letter to this user
    #Остальным локальным клентам письмо отдаем
    R$+ $| $+<@$=w.>              $@ OK

    #Локальных отправителей проверяем на принадлежность списку
    #ограниченных в правах пользователей:
    #R$+<@$=w.> $| $+             $: $(RESTR_USER $1 $:$1 $) <@$2.> $| $3
    R$+<@$=w.> $| $+             $: $(RESTR_USER $1 $:$1<@$2.> $) $| $3
    R$* $| $*              $: $(syslog COMPAT5_syslog: $1-$2 $) $1 $| $2
    RLIST $| $+             $#error $: 554 Sorry, you can not send a letter to this user
    #От остальных локальных клентов письма берем
    R$+<@$=w.> $| $+             $@ OK

    #Интересно, а какая почта осталась не охваченной нашими правилами?
    R$* $| $*              $: $(syslog COMPAT6_END1_syslog: $1-$2 $) $1 $| $2
    R$*              $: $(syslog COMPAT6_END2_syslog:$1 $) $1
    Например, почта от внешнего отправителя внешнему получателю. Как же так, скажете вы, у меня же open relay закрыт?
    Все просто: если в aliases есть перенаправление почты на внешний адрес, то как раз этот случай и будет отмечен двумя вышестоящими правилами.
    Возможно, мною не учтено что-то еще. Обнаружите - дайте знать! :)

    Вы думаете, на этом все?
    Нет, ведь пользователи давно смекнули, что можно подделывать адрес отправителя. Можно подставить адрес не ограниченного в правах коллеги, а можно и свой внешний адрес.
    Значит, нужно сделать невозможной подмену обратного адреса.
    При всем неоднозначном отношении sendmail-общественности к запретам на подмену адреса отправителя (см. здесь, вот здесь, а здесь такая практика названа фашистской ;) ) в случае работы корпоративного почтового сервера, я думаю, такое дело оправдано. Поэтому могу предложить такой способ: прикручиваем smtp-авторизацию, убираем из relay-domains все адреса и сетки, кроме 127.0.0.1; убираем из access все строки с RELAY кроме 127.0.0.1 и редактируем sendmail.mc на предмет сравнения параметров $&{auth_authen} и $&{f}. Они должны быть одинаковыми.
    Claus Assmann при проверке соответствия адреса отправителя и параметра auth предлагает попробовать это:
    "...Theoretically you can use the macro storage map to store $&{auth_authen} in $f... You have to play around with that..."

    You must enforce that the envelope sender is the same as the authenticated user. This requires a little Local_check_mail ruleset that compares the sender address with {auth_authen}. [1]

    29.10.2010. Как можно сравнить адрес отправителя и имя, использованное для smtp-авторизации можно посмотреть здесь.


    10.Как разрешить пользователю переписку с любым пользователем, кроме указанного адреса (запрет определенной связки отправитель-получатель).
    Необходимо пересобрать sendmail.cf, задействовав FEATURE(`compat_check'), добавить в /etc/mail/access строку
    Compat:sender@onedomain.ru<@>recipient@somedomain.ru DISCARD
    Затем makemap hash access <access и перезапустить sendmail.

    Из /usr/src/sendmail/cf/README:
    compat_check
    Enable ruleset check_compat to look up pairs of addresses with the Compat: tag --
    Compat:sender<@>recipient
    -- in the access map.
    Valid values for the RHS include
                  DISCARD silently discard recipient
                   TEMP: return a temporary error
                   ERROR: return a permanent error
                   In the last two cases, a 4xy/5xy SMTP reply code should follow the colon.


    25.01.2010. Задачка, противоположная этой задачке.
    На самом деле я не собираюсь никого наказывать, просто надоело получать на адрес hostamster'a рассылки от NewsLand & GuidePark, на которые я не подписывалась.
    На этот случай в sendmail предусмотрена FEATURE(`compat_check'), которая вкупе с записью в access-файле
    Compat:bounce@subscribe.gidepark.ru<@>hostmaster@anrb.ru                    ERROR:"550 I don't accept mail from spammers. Why did you subscribe me?"
    дает требуемый эффект. Но проблема в том, что hostmaster - это alias, а набор правил compat_check разбирается после разалиасинга. Я могла бы указать в этой паре реального получателя, но на эту рассылку был самовольно подписан и мой реальный адрес, а в одном экземпляре получать эту рассылку я не против. Поэтому я написала свой набор правил, хотя скорее всего существует другое решение, более грамотное и правильное (т.е. все из себя гламурное и кошерное).

    R$*                                    $: $&f $| $1
    Rbounce@subscribe.newsland.ru $| <hostmaster@anrb.ru>         $#error $:"550 I don't accept mail from spammers. Why did you subscribe me?"
    R$* $| $*                           $: $2


    11.Как запретить фальшивую рассылку с адресов gluck@mail.subscribe.ru и namma123456@subscribe.ru.

    В последнее время стали приходить спам-письма с подделанным адресом отправителя gluck@mail.subscribe.ru. Если посмотреть заголовок письма, то можно увидеть, что источником рассылки являются различные хосты, чаще всего подобного вида adsl-3-206-15.mia.bellsouth.net [65.3.206.15], а в подзаголовке Received нет и намека на почтовые системы subscribe.ru:
    From gluck@mail.subscribe.ru Wed Mar 23 05:04:07 2005
    Return-Path: <gluck@mail.subscribe.ru>
    Received: from cp35317-a.landg1.lb.home.nl (cp35317-a.landg1.lb.home.nl [84.25.130.3])
                   by host.dom.ru (8.13.3/8.13.3) with SMTP id j2N042l6025515
                   for <k@dom.ru>; Wed, 23 Mar 2005 05:04:05 +0500
    Message-ID: <e19b01c52f36$644e9e02$ff7893a7@mail.subscribe.ru>
    From: office <gluck@mail.subscribe.ru>
    To: k@dom.ru
    Subject: Re:
    Редактируем sendmail.mc.

    LOCAL_CONFIG
    Kgluck regex -n -a@NOgluck gluck<@mail.subscribe.ru.>
    KSubscribe regex -a@CAT subscribe\.ru

    LOCAL_RULESETS
    SLocal_check_mail
    #Канонизируем адрес отправителя.
    R$*             $: $>Parse0 $>3 $1
    #Проверяем, имеет ли он вид gluck<@mail.subscribe.ru.>
    R$+<@$+>                             $: $(gluck $1<@$2> $: $1<@$2> $)
    #Если нет - пропускаем письмо
    R@NOgluck                             $@ OK
    #Если да - проверяем доменное имя хоста-отправителя.
    R$*                             $: $(Subscribe $&_ $)
    #Если оно имеет вид something.subscribe.ru, то пропускаем письмо
    R@CAT                             $@ OK
    #В противном случае - блокируем.
    R$*                  $#error $: "554 Forged sender address."

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

    From fishka@yandex.ru Thu Mar 10 15:53:29 2005
    Return-Path: <fishka@yandex.ru>
    Received: from pD4B9DF4F.dip.t-dialin.net (pD4B9DF4F.dip.t-dialin.net [212.185.223.79])
    by mail.domain.ru (8.13.3/8.13.3) with SMTP id j2AArBIJ007666;
    Thu, 10 Mar 2005 15:53:17 +0500
    Received: from [81.9.34.176] (port=25 helo=cat176.subscribe.ru)
    by mx19.mail.ru
    with esmtp id 1D9JJ5-0006ee-00 for 9990@mail.ru; Thu, 10 Mar 2005 11:46:11 +0300
    Received: id DB680220533; Thu, 10 Mar 2005 11:45:05 +0300
    List-Id: <comp.soft.review.fscomm.subscribe.ru>
    List-Help:<http://subscribe.ru/catalog/comp.soft.review.fscomm>
    List-Subscribe: <mailto:comp.soft.review.fscomm-sub@subscribe.ru>
    List-Unsubscribe: <mailto:comp.soft.review.fscomm-unsub@subscribe.ru>
    List-Archive: <http://subscribe.ru/archive/comp.soft.review.fscomm>
    List-Owner: <mailto:ask@subscribe.ru>
    List-Post: NO
    Message-Id: <20050310110634.hk.6419385@comp.soft.review.fscomm.subscribe>
    Date: Thu, 10 Mar 2005 11:06:39 +0300
    From: "FILP" <namma6419385@subscribe.ru>
    To: "comp.soft.review.fscomm" <9990@mail.ru> (6419385)


    В этом заголовке настораживает тот факт, что хост, с которого пришла рассылка Subscribe.ru, опять-таки не имеет отношения к почтовому домену subscribe.ru, а заголовок Received:, в котором упоминаются реквизиты subscribe.ru , стоит вторым: это могло бы означать, что письмо пересылалось через cat176.subscribe.ru хосту mx19.mail.ru. А затем оно было передано для дальнейшей доставки pD4B9DF4F.dip.t-dialin.net (причем запись о передачи письма с mx19.mail.ru на D4B9DF4F.dip.t-dialin.net отсутствует. Интересно, как оно туда попало?:)) . Спрашивается, зачем subscribe.ru пересылать почту через третьи лица??? Почему бы не послать письмо сразу, без пересылочных хостов?
    В письмах второго типа неизменно присутствует строка вида:
    Received: from [81.9.34.176] (port=25 helo=cat176.subscribe.ru или helo=round.agava.net ) by mx19.mail.ru (это выглядит так, как будто бы спамер имеет почтовый ящик на Subscribe.ru, который настроен на автоматическую пересылку почты в почтовый ящик на Mail.ru)
    Вот над этой строкой и поработаем:
    Редактируем sendmail.mc.

    LOCAL_CONFIG
    KChCATHeader regex -n -a@NOCAT \(port=[0-9]+.helo=((cat|gato)[0-9]+\.subscribe\.ru|round.agava.net)\)

    LOCAL_RULESETS
    HReceived:                              $>+CheckReceived
    SCheckReceived
    #Проверяем подзаголовки Received: на наличие (port=25 helo=cat176.subscribe.ru)
    R$*                             $: $(ChCATHeader $1 $)
    #Если такая строка не найдена - пропускаем письмо.
    R@NOCAT                             $@ OK
    #В противном случае - блокируем.
    R$*                             $#error $: "554 Forged sender address."

    А вот как выглядит достоверный заголовок письма от Subscribe.ru:

    Return-Path: <gluck@mail.subscribe.ru>
    Received: from cat178.subscribe.ru (cat178.subscribe.ru [81.9.34.178])
    by mail.domain.ru (8.13.3/8.13.3) with ESMTP id j299wdxf016812
    for <user@mail.domain.ru>; Wed, 9 Mar 2005 14:58:41 +0500
    Received: id 8C4551930090; Wed, 9 Mar 2005 12:34:45 +0300

    Здесь можно посмотреть настройки фильтров для различных почтовых клиентов - http://subscribe.ru/ip/antispam/filter.html


    12. Фильтруем входящую почту по параметру HELO

    Nota Bene! Начиная с версии 8.14.0 в sendmail есть FEATURE(`block_bad_helo'), которая позволяет отвергать почту, если в EHLO/HELO содержится не полное (unqualified) имя клиента либо данные вашего сервера, а не клиента. Предусмотрен пропуск почты из локальной сети и smtp-авторизованной почты. См. README.

    Значение HELO видно в подзаголовке Received:
    Если сайт следует общепринятым правилам, и он не имеет днс-имени, то в первой строке можно увидеть информацию вида Received: from [x.x.x.x] ([x.x.x.x]).
    Данные до круглых скобок - это то, что заявила исходящая система в комманде HELO/EHLO.
    Имя и IP в круглых скобках - это то, что определил сам sendmail в качестве IP и днс-имени исходящей системы, т.е.фактически в sendmail эти данные берутся из макроса $_ (подтвержденный адрес отправителя)(см. п.5.2. "D - Определение Макроса")
    В большинстве случаев информация вне круглых скобок и внутри их должна совпадать. Если она не совпадает, то в большинстве случаев это свидетельство использования отправителем спам-программ либо неправильно работающих программ либо неверно настроенных программ (обычно на windows-системах). Иногда информация может различаться вследствие наличия нескольких имен у исходящего хоста: имя, которым хост сам себя идентифицирует может отличаться от того, который получит sendmail от ДНС.
    Еще один случай: multi-homed хост (компьютер, присоединенный к нескольким физическим линиям данных). Один из сетевых интерфейсов получает от DNS имя, не совпадающее с самоназванием данного интерфейса (информация от первичного интерфейса). Но эти случаи редки.

    Чаще всего возникает необходимость заблокировать письма, в HELO которых указан домен или ip-адрес получателя. Нижеуказанные правила можно поместить в любом из наборов правил.
    Исключения.
    Следует иметь в виду, что любое письмо, посланное непосредственно с почтовика (например, cron-ом, telnet-ом (sendmail -bs)), будет также заблокировано: почтовик в качестве HELO передаст свое собственное доменное имя. Для того, чтобы это не случилось, добавим проверку ip-адреса хоста-источника на равенство 127.0.0.1.
    Telnet( sendmail -bs): если ip-адрес не резолвится, то в HELO(EHLO) будет выставлено заданное вами значение.
    Если же ip-адресу источника письма соответствует определенное доменное имя, то в HELO будет проставлено именно оно, даже если вы в строке HELO(EHLO) укажете совсем другое имя.
    Почтовый клиент TheBAT! (возможно, и другие почтовые клиенты) в HELO выставляет заключенный в квадратные скобки ip отправителя или (зависит от ОС) имя компьютера, указанное пользователем при установке системы (вы помните о том, что TheBat! выдает кривое HELO и ошибку "syntactically invalid HELO argument(s)", если имя компьютера при установке набрано русскими буквами?).
    Netscape Messenger в HELO выставляет доменную часть электронного адреса, указанного в Preferences -> Mail&Newsgroups -> Identity.
    OE может выставить netbios-имя хоста.
    Вообще говоря, значение, выставленное почтовым клиентом в HELO, зависит от настроек самого клиента, от его версии, от ОС, на которой работает данный почтовый клиент.
    Поэтому для того, чтобы не заблокировать почту от своих клиентов, необходимо добавить проверку ip-адреса источника на принадлежность вашей сети.

    Еще немного инфы оHELO
    LOCAL_CONFIG
    LOCAL_RULESETS
    HFrom:                    $>CheckFrom
    SCheckFrom
    R$*                   $: $&{client_addr}
    R127.0.0.1                   $@OK
    R$=R $*                   $@ OK
    R$*                    $: $&s
    Rsomedomain.ru                    $#error $: 554 ...
    R111 . 222 . 111 . 222                   $#error $: 554 ...

    Если есть необходимость заблокировать цифровые HELO(что крайне не рекомендуется), то можно поступить так:
    LOCAL_CONFIG
    KCheckHELO regex -a@BOGUS_HELO ^[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+$
    LOCAL_RULESETS
    HFrom:                    $>CheckFrom
    SCheckFrom
    R$*                    $: $&s
    R$*                    $: $(CheckHELO $1 $)
    R@BOGUS_HELO                    $#error $: 550 Access denied - bogus HELO
    R$*                    $@ OK

    Привожу здесь еще один набор правил от sproot для проверки HELO. Первоисточник - здесь.

    # for bad-HELO
    F{bh}/etc/mail/top-level-domain (файл д.б. заполнен корневыми доменами, их можно взять отсюда)
    Kipadr regex -aFOUND [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
    SLocal_check_mail
    R$*                    $:$1 $| <$&{auth_authen}>
    R$* $| <$+>                    $:$1
    R$* $| <$*>                    $:$1 $| <[$&{client_addr}]>[$&s]
    R$* $| <$=w>[$*]                    $:$1
    R$* $| <[0]>[$*]                    $:$1
    R$* $| <[$-.$-.$-.$-]>[$*]                    $:$1 $| <$( access $2.$3.$4.$5 $:[$2.$3.$4] $)>[$6]
    R$* $| [$*]                    $:$1
    R$* $| <[$-.$-.$-]>[$*]                    $:$1 $| <$( access $2.$3.$4 $:[$2.$3] $)>[$5]
    R$* $| [$*]                   $:$1
    R$* $| <[$-.$-]>[$*]                    $:$1 $| <$( access $2.$3 $:[$2] $)>[$4]
    R$* $| [$*]                    $:$1
    R$* $| <[$-]>[$*]                    $:$1 $| <$( access $2 $:[$2] $)>[$3]
    R$* $| [$*]                    $:$1
    R$* $| <[$*]> $=w                    $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s

    R$* $| <[$*]> [$=w]                    $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s
    R$* $| <[$*]> [[127.$-.$-.$-]]                    $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s
    R$* $| <[$*]> [[10.$-.$-.$-]]                    $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s
    R$* $| <[$*]> [[172.$-.$-.$-]]                    $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s
    R$* $| <[$*]> [[192.168.$-.$-]]                   $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s
    R$* $| <[$*]> [[$+]]                    $:$1 $| <[$2]> [[ $( ipadr $3 $) ]]
    R$* $| <[$*]> [[FOUND]]                    $:$1
    R$* $| <[$*]> [$+.$={bh}]                    $:$1
    R$* $| <[$*]> [$*]                 $#error $@5.7.1 $:"550 Access denied - bogus HELO " $&s


    13. Как заблокировать письма с единственным подзаголовком "Received:" (как определить, что переменная пуста; работа с пустым подзаголовком)
    О таких письмах подробно расcказано на странице спам-фильтра.
    А здесь я привожу пример простой блокировки такой почты ( без дополнительной проверки "Message-Id"):
    LOCAL_CONFIG
    Kstorage macro
    LOCAL_RULESETS
    HReceived:                   $>+CheckReceived
    Запоминаем текущее состояние подзаголовков "Received:". Если рассылка произведена непосредственно через ваш почтовик, то на вход набору правил CheckReceived не будет подано ничего, нижеследующее правило не сработает, и переменная {ReceivedCheck} окажется пустой.
    SCheckReceived
    R$*                   $: $(storage {ReceivedCheck} $@ OK $) $1

    Scheck_eoh
    # Проверяем $&{ReceivedCheck}:
    R$*                    $: < $&{ReceivedCheck} >
    R$*                   $: $(syslog $&{ReceivedCheck} $1 $) $1
    # Очищаем эту переменную для следующего сообщения:
    R$*                    $: $(storage {ReceivedCheck} $) $1
    #Если переменная не пустая, то пропускаем письмо:
    R< $+ >                   $@ OK

    #Разрешаем также почту из нашей локальной сети:
    R$*                   $: < $&{client_addr} >
    R< $* $=R $* >                   $@ OK

    ## Разрешаем почту с локального адреса - root@localhost (имеет место при отсутствии файла submit.cf):
    #R$*                   $: <$&_>
    #R                   $@ OK

    # Разрешаем почту, прошедшую smtp-авторизацию:
    R$*                    $: < $&{auth_authen} >
    R< $+ >                   $@ OK

    #Списки исключений для почтовиков, не добавляющих свой Received: в заголовок письма (список составлен по ложным срабатываниям только моего почтовика )
    # Allow missing Received from some non-compliant-RFC mail servers
    #Возможно, ambar.mail.ru формирует тело сообщения и сразу помещает его в очередь, поэтому рассылки приходят с единственным заголовком Received
    R$*                   $: < $&{client_name} >
    R< ambar.mail.ru >                   $@ OK

    #А эти почтовики используют Microsoft Exchange и также не заполняют Received.
    #
    R< etc.bash.ru >                    $@ OK
    R< mail.airrb.ru >                   $@ OK

    # Во всех остальных случаях блокируем письмо:
    R$*                    $#error $: "554 You are not a local user and you cannot send a letter to my server directly."


    А теперь то же самое, но с дополнительной проверкой: если почта приходит клиенту, прописанному в файле /etc/mail/Eoh_no_check, то для него почту пропускаем без проверки на количество Received:
    LOCAL_CONFIG
    # Macro
    #Включаем проверку для всех пользователей по умолчанию
    D{Eoh_Check}1
    #Это для отключения оной
    D{No_Check}0
    Kstorage macro
    #В этом файле перечислены все локальные юзеры, почта для которых не будет проверяться:
    KEoh_no_check hash /etc/mail/Eoh_no_check
    LOCAL_RULESETS
    SLocal_check_rcpt # empty address?
    R<>                    $#error $@ nouser $: "554 User address required"
    R$@                    $#error $@ nouser $: "554 User address required"

    #Канонизируем адрес получателя
    R$*                    $: $>3 $1
    #Локального получателя отправляем на доп. проверку
    R$* < @$=w. >                    $: $(Eoh_no_check $1 $)
    R@LIST                    $: $(storage {Eoh_Check} $@ $&{No_Check} $)
    R$*                   $@ OK

    Scheck_eoh
    R$*                   $: <$&{Eoh_Check}>
    R<0>                    $@ OK
    # Очищаем переменную для следующего сообщения:
    R$*                    $: $(storage {Eoh_Check} $)

    Далее по тексту:
    # Check the macro $&{ReceivedCheck}
    R$*                   $: < $&{ReceivedCheck} >
    ...

    Файл /etc/mail/Eoh_no_Check
    user1                    [tab]                    @LIST
    ...
    затем
    makemap hash Eoh_Check < Eoh_Check

    И еще раз то же самое, но теперь с двумя другими дополнительными проверками:
    1) если письмо пришло от Microsoft Exchange ( он не всегда вставляет в заголовок письма свой Received:), то пропускаем его без дальнейшей проверки;
    2) если письмо от IP из файла /etc/mail/nospam_relays, то тоже пропускаем.
    Формат файла:
    1.2.3.4       [TAB]      @MATCH
    1.2.3      [TAB]      @MATCH
    1.2      [TAB]      @MATCH

    Не забываем про команду
    makemap hash nospam_relays < nospam_relays

    Редактируем sendmail.mc:
    LOCAL_CONFIG
    D{ME_Check}1

    Ksyslog syslog
    Kstorage macro
    KNOSPAM hash /etc/mail/nospam_relays
    LOCAL_RULESETS

    HReceived:                   $>+CheckReceived
    SCheckReceived
    R$*                  $: $(storage {ReceivedCheck} $@ OK $) $1

    HX-MIMEOLE:                   $>+CheckMIMEOLE
    HX-MimeOLE:                  $>+CheckMIMEOLE

    SCheckMIMEOLE
    R$*Microsoft Exchange$*                  $: $(storage {ME_Check} $@ 0 $)

    Scheck_eoh
    R$*                  $: <$&{ME_Check}>
    R$*                  $: $(storage {ME_Check} $) $1
    R<0>                   $@ OK

    R$*                  $: < $&{ReceivedCheck} >
    R$*                  $: $(syslog $&{ReceivedCheck} $1 $) $1
    R$*                  $: $(storage {ReceivedCheck} $) $1
    R< $+ >                  $@ OK

    # Разрешаем почту, прошедшую smtp-авторизацию:
    R$*                    $: < $&{auth_authen} >
    R< $+ >                   $@ OK

    #Разрешаем также почту из нашей локальной сети:
    R$*                  $: $&{client_addr}
    R $* $=R $*                   $@ OK

    #Разрешаем также почту из сетей, перечисленных в /etc/mail/nospam_relays:
    R $-.$-.$-.$-                  $: $(NOSPAM $1.$2.$3.$4 $:$1.$2.$3 $)
    R@MATCH                  $@ OK
    R $-.$-.$-                  $: $(NOSPAM $1.$2.$3 $:$1.$2 $)
    R@MATCH                  $@ OK
    R $-.$-                  $: $(NOSPAM $1.$2 $)
    R@MATCH                  $@ OK
    # Во всех остальных случаях блокируем письмо:
    R$*                  $#error $: "554 You are not a local user and you cannot send a letter to my server directly."

    14. Как бороться с перебором имен почтовых ящиков (dictionary attack, наложение ограничения на число отказов "User unknown")
    /usr/src/sendmail/cf/README:
    BadRcptThrottle=N
    [no short name] If set and more than the specified number of recipients in a single SMTP envelope are rejected, sleep for one second after each rejected RCPT command.

    http://www.sendmail.org/~ca/email/doc8.12/op-sh-5.html#sh-5.6:
    BadRcptThrottle=N
    [no short name] If set and more than the specified number of recipients in a single SMTP envelope are rejected, sleep for one second after each rejected RCPT command.
    В sendmail.mc следует добавить строку
    define(`confBAD_RCPT_THROTTLE',`3')

    Через 3 неудачные попытки подбора имени почтового юзера происходит односекундная задержка с ответом после каждой команды RCPT со стороны спамера..
    Это не остановит перебор имен, но замедлит процесс перебора и "свяжет(вытянет, потратит)" ресурсы переборщика.
    Если вы хотите увеличить время задержки, то подправьте файл /usr/src/sendmail/sendmail/srvrsmtp.c
    Claus Assmann использует 30-секундную задержку
    Это поможет только в том случае, если неверные адреса перебираются за одну smtp-сессию.
    Побочное действие опции BAD_RCPT_THROTTLE: в какой-то мере это истощает ресурсы не только удаленной системы, но и вашей: количество открытых соединений может значительно увеличиться (некоторые могут висеть часами), что может повлечь при превышении значения MaxDaemonChidren отказ вашей системы в обслуживании. Следовательно, требуется наблюдение и последующее выставление оптимального значения MaxDaemonChidren.
    А можно тихо отказаться от почты для несуществующих пользователей, отправляя всю ее в специальный почтовый ящик или в /dev/null:
    define(`LUSER_RELAY', `local:unknown_users_mailbox')
    или
    define(`LUSER_RELAY', `smtp:unknown_users_mailbox@somehost.ru')
    или
    define(`LUSER_RELAY', `/dev/null')

    В этом случае в sendmail.cf появятся дополнительные строки:
    # place to which unknown users should be forwarded
    Kuser user -m -a<>
    DLlocal:unknown_users_mailbox
    # send unrecognized local users to a relay host

    R< > $+                    $: < $L > $(user $1 $) look up user
    R< $* > $+ <>                   $: < > $2

    Многие постмастеры предлагают на comp.mail.sendmail делать постоянное приращение времени задержки за одну сессию вместо постоянной 1-секундной задержки.

    В Сети есть еще такое решение

    15. Как заблокировать перебор имен почтовых ящиков (наложение ограничения на число отказов "User unknown")
    Оказывается некие:) почтовики под Windows умеют подсчитывать количество несуществующих юзеров в RCPT TO и на основании этого отказывать в приеме почты. Попробуем сделать что-то подобное в sendmail. По причине большого объема это решение перенесено сюда.

    16. Как избежать двойной отлуп.

    Предположим, вы перенаправляете через /etc/mail/aliases почту вашего клиента на другой почтовый сервер. Если этот сервер на этапе smtp-диалога отказывается принять от вас перенаправленное письмо, например, сочтя его за спам, то ваш почтовик постарается известить отправителя о накладке. Теперь предположим, что адрес отправителя поддельный и такого пользователя в природе не существует. Значит, ваш почтовик стучится, чтобы сообщмть о невозможности доставки, а ему в ответ - "User unknown".
    Что делает в такой ситуации sendmail. Правильно, отправляет двойной отлуп Постмастеру.

    В логе это выглядит так:
    Nov 28 17:50:32 ns1 sendmail[30636]: jASCoE28030636: from=<acumen@remcomp.fr>, size=8378, class=0, nrcpts=1, msgid=<e02b01c5f415$0111c6e8$323b1ed1@remcomp.fr>, proto=SMTP, daemon=MTA, relay=[218.1.214.119]
    Nov 28 17:50:32 ns1 drweb-smf: [jASCoE28030636]: dwlib[30639]: scan: the message(drweb.tmp.YoOWOb) sent by acumen@remcomp.fr to user@anrb.ru is passed
    Nov 28 17:50:32 ns1 drweb-smf: [jASCoE28030636]: processing message from acumen@remcomp.fr is over
    Nov 28 17:50:44 ns1 sendmail[30643]: jASCoE28030636: to=user@mail.ru, delay=00:00:17, xdelay=00:00:12, mailer=esmtp, pri=38545, relay=mxs.mail.ru. [194.67.23.20], dsn=5.0.0, stat=Service unavailable
    Nov 28 17:50:44 ns1 sendmail[30643]: jASCoE28030636: jASCoi28030643: DSN: Service unavailable
    Nov 28 17:50:49 ns1 sendmail[30643]: jASCoi28030643: to=<acumen@remcomp.fr>, delay=00:00:05, xdelay=00:00:05, mailer=esmtp, pri=30000, relay=web-future.remcomp.fr. [213.200.104.17], dsn=5.1.1, stat=User unknown
    Nov 28 17:50:50 ns1 sendmail[30643]: jASCoi28030643: jASCoi29030643: return to sender: User unknown
    Nov 28 17:50:50 ns1 sendmail[30643]: jASCoi29030643: to=postmaster, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=30000, dsn=2.0.0, stat=Sent
    Здесь письмо, адресованное user@anrb.ru перенаправляется на user@mail.ru, но отвергается почтовой системой mail.ru.
    При попытке известить отправителя acumen@remcomp.fr выясняется, что его не существует. И вся эта летопись в конечном счете сваливается к Постмастеру.

    Если вы не хотите получать двойные отлупы вообще, то воспользуйтесь этим -
    define(`confDOUBLE_BOUNCE_ADDRESS', `')
    Если же вы хотите перенаправлять их в другой ящик для последующего, скажем, еженедельного просмотра, то
    define(`confDOUBLE_BOUNCE_ADDRESS', `someuser')

    Что говорит по этому поводу документация?
    op.me:
    DoubleBounceAddress=error-address
    [no short name] If an error occurs when sending an error message, send the error report (termed a "double bounce" because it is an error "bounce" that occurs when trying to send another error "bounce") to the indi- cated address. The address is macro expanded at the time of delivery. If not set, defaults to "postmaster". If set to an empty string, double bounces are dropped.
    README:
    confDOUBLE_BOUNCE_ADDRESS DoubleBounceAddress
    [postmaster] If an error occurs when sending an error message, send that "double bounce" error message to this address. If it expands to an empty string, double bounces are dropped.


    17. Как заблокировать письма, посылаемые на определенный mx-relay (блокировка по MX-домену получателя)

    01.11.2007. Перенесено в раздел "Неработающие решения."
    Тут непонятно, вроде это сначала работало, а сейчас нет.
    Надо разбираться, а времени нет.
    Если есть идеи - буду рада услышать.
    10.11.2007. Заработало так.


    18. Как проверять в RBL-базах не только ip непосредственного отправителя-почтовика, но и ip всех предшествоваших релеев, определенных в подзаголовках Received:

    На это вопрос ответил сам Clauss Assmann, привожу правила здесь из боязни потери этой информации на comp.mail.sendmail.
    "...If you know the format, you can parse it. Here are some hints how to do this, you have to check whether it works for you. The basic trick is to extract the client address and call the appropriate ruleset.

    C{KnownRelay}some.other.host
    HReceived: $>+CheckReceived
    # macro storage map
    Kstore macro

    SCheckReceived
    R$* from $+ ($-@[$+]) by $={KnownRelay} $*                    $: <TEMP> $(store {client_addr} $@ $4 $) $>Basic_check_relay [$4] $| $4
    R$* from $+ ($+ [$+] (may be forged)) by $={KnownRelay} $*                    $: <TEMP> $(store {client_addr} $@ $4 $) $>Basic_check_relay [$4] $| $4
    R$* from $+ ([$+]) by $={KnownRelay} $*                    $: <TEMP> $(store {client_addr} $@ $3 $) $>Basic_check_relay [$3] $| $3
    R<TEMP> $#$*                    $#$1
    R$* from $+ ($+ [$+]) by $={KnownRelay} $*                    $: $(store {client_addr} $@ $4 $) $>Basic_check_relay $3 $| $4


    19. Как ограничить общее количество соединений за определенный промежуток времени и количество одновременных соединений с одного хоста.

    Промежуток времени определяется этим параметром (10 сек)
    define(`confCONNECTION_RATE_WINDOW_SIZE',`10')
    Значение по умолчанию - 60 сек.

    FEATURE(ratecontrol) позволяет ограничивать количество соединений с определенного, а также любого хоста, за упомянутый выше промежуток времени.
    При этом необходимо отредактировать /etc/mail/access:
    ClientRate:10.1.2.3 [TAB] 4
    ClientRate:127.0.0.1 [TAB] 0
    ClientRate: [TAB] 10
    С хоста 10.1.2.3 разрешено не более 4 соединений в минуту, с 127.0.0.1 - ограничений нет, с остальных хостов - не более 10.

    Если все сделано правильно, в логах вы увидите:
    Jan 21 04:22:20 ns1 sendmail[6721]: ruleset=check_relay, arg1=[84.119.75.231], arg2=84.119.75.231, relay=fr-lim-C3-04-084119075231.chello.fr [84.119.75.231] (may be forged), reject=452 4.3.2 Connection rate limit exceeded.
    Jan 21 04:27:42 ns1 sendmail[6820]: ruleset=check_relay, arg1=cable82a011.usuarios.retecal.es, arg2=213.254.82.11, relay=cable82a011.usuarios.retecal.es [213.254.82.11], reject=452 4.3.2 Connection rate limit exceeded.

    FEATURE(conncontrol) позволяет ограничивать количество одновременных smtp-соединений.
    Редактируем /etc/mail/access:
    ClientConn:10.1.2.3 [TAB] 4
    ClientConn:127.0.0.1 [TAB] 0
    ClientConn: [TAB] 10
    С хоста 10.1.2.3 разрешено не более 4 одновременных соединений, с 127.0.0.1 - ограничений нет, с остальных хостов - не более 10.
    В логе вы увидите сообщение "Too many open connections."

    5.05.2008. Как говорится в /usr/src/sendmail/cf/README:
    "appropriate rulesets are called at the end of check_relay, i.e., after DNS blacklists and generic access_db operations. The features require FEATURE(`access_db') to be listed earlier in the mc file."
    А это означает, что, как заметил Владимир Васильев, "фичи ratecontrol и conncontrol (в отличие от greet_pause) не работают для хостов в access, прописанных с тэгом CONNECT: и значениями OK или RELAY."
    По поводу greet_pause
    ("... ruleset is used to specify the amount of time to pause before sending the initial SMTP 220 greeting.
    If any traffic is received during that pause, an SMTP 554 rejection response is given instead of the 220 greeting and all SMTP commands are rejected during that connection. This helps protect sites from open proxies and SMTP slammers ...")

    можно добавить следующее: если FEATURE(`access_db') задействован, но в /etc/mail/access не указано значение greet_pause для данного соединения (f.e., GreetPause:1.2.3.4 [TAB] 0 или GreetPause: [TAB] 4000 ), то по умолчанию время выжидания паузы становится равным необязательному аргументу, заявленному в определении этой фичи. Например, если указать FEATURE(`greet_pause', `5000'), то значением по умолчанию для всех соединений будет 5000ms.
    (/usr/src/sendmail/cf/README:When using FEATURE(`access_db'), the optional FEATURE(`greet_pause') argument becomes the default if nothing is found in the access database.)

    19.1. Как ограничить количество сообщений за одну сессию (соединение)?

    27.11.2008. Предположим, спамер открыл соединение и начал штамповать сообщения:
    telnet mail.domain.ru 25
    EHLO elan
    mail from:user@yandex.ru
    rcpt to:user1@domain.ru
    data
    spam message
    .
    mail from:user@rambler.ru
    rcpt to:user2@domain.ru
    data
    spam message
    .
    и т.д.
    QUIT
    Как этому противостоять, ведь средства из пункта 19 не подойдут: соединение одно.
    define(`confMAX_RCPTS_PER_MESSAGE', `10') тоже не подойдет - у нас один получатель на одно письмо.
    Я пыталась поставить счетчик на количество сообщений. Но в этом случае каждое письмо - это отдельный процесс, так что счетчик не растет.

    README:
    SMTP_MAILER_MAXMSGS         [undefined] If defined, the maximum number of messages to deliver in a single connection for the smtp, smtp8, esmtp, or dsmtp mailers.
    То есть все, что нам нужно - это define(`SMTP_MAILER_MAXMSGS',`10')

    А теперь усложним задачку. Требуется установить свое собственное кол-во сообщений за одну сессию в соответствии с доменом получателя. Здесь нам в помощь будет mailertable.
    Per Hedeland:
    Not in access db, but you can use mailertable to choose different mailers based on the destination. If you only need one or two values you can set SMTP_MAILER_MAXMSGS and/or RELAY_MAILER_MAXMSGS and choose 'esmtp' or 'relay' in mailertable, otherwise you'll have to define additional SMTP mailers in your .mc, with different m= fields.
    По этой теме есть статья - Creating a new sendmail mailer. Статья очень интересная, поэтому я ее сохранила и у себя.

    А если мы захотим, чтобы mailer выбирался в соответствии не с доменом получателя, а его MX-ом?
    Что же, "...but sendmail.cf is a program, it can do anything.:-) ... говорит Per Hedeland и предлагает следующее решение.
    Completely untested, assuming you only need one "special" mailer, and hijacking 'relay' for that:
    define(`confRELAY_MAILER', `esmtp')
    define(`RELAY_MAILER_MAXMSGS', `20')
    LOCAL_CONFIG
    Kmymx bestmx -z:
    C{BadMX} mailhost.service.domain otherhost.example.com

    LOCAL_NET_CONFIG
    R$* < @ $* . >               $: $1 < @ $2. > $| : $(mymx $2 $) :
    R$* < @ $* . > $| $* : $={BadMX} : $*              $#relay $@ $2. $: $1 < @ $2. >
    R$* < @ $* . > $| $*               $: $1 < @ $2. >


    19.2. Как ограничить кол-во писем по IP? (Как ограничить количество соединений и количество сообщений за одну сессию (соединение) с одного IP?)


  • 22.05.2009. Сразу на 2 форумах спросили практически про одно и то же - [1], [2]. Решение гармонично складывается из двух предыдущих решений.
    Для людей, предпочитающих "стерильные решения", выход один - milter-limit/0.14 от SnertSoft.
    Остальным же подойдет вот такая штука. Предположим, вам нужно ограничить локальных отправителей 1 письмом в 2 минуты.
    1. Определяем окно - 2 минуты.
    define(`confCONNECTION_RATE_WINDOW_SIZE',`120')
    2. Определяем количество возможных соединений с локальных IP (сеть x.y.z) и остальных IP:
    FEATURE(ratecontrol)
    3. в /etc/mail/access:
    ClientRate:127.0.0.1 [TAB] 0
    ClientRate:1.2.3 [TAB] 1
    ClientRate: [TAB] 5
    4. Юзер может открыть сессию и наштамповать кучу сообщений, стало быть, ему нужно "крылышки подрезать". Делается это с.п. нового mailer'a ([1], [2])
    5. Затем, в LOCAL_RULE_0 для IP из локальных сетей вызывается новый mailer.
    Все просто, чинно, благородно.
    Кстати, если задачу упростить и потребовать, чтобы ограничение работало для всех, то достаточно к пунктам 1-3 добавить одну из следующих опций в виде define(`SMTP_MAILER_MAXMSGS', `1') , и "будет вам счастье":
    LOCAL_MAILER_MAXMSGS         [undefined] If defined, the maximum number of
                               messages to deliver in a single connection. Only
                               useful for LMTP local mailers.

    SMTP_MAILER_MAXMSGS         [undefined] If defined, the maximum number of
                               messages to deliver in a single connection for the
                               smtp, smtp8, esmtp, or dsmtp mailers.
    RELAY_MAILER_MAXMSGS         [undefined] If defined, the maximum number of
                               messages to deliver in a single connection for the
                               relay mailer.


    20. Как заблокировать почту с ip-адресов, для которых прямая и обратная проверки в днс не соответствуют друг другу.

    Вообще-то, это явление само по себе еще не означает, что почта будет спамом. Например, если одному ip-адресу соответствует несколько доменных имен, то в прямой зоне будет несколько записей, но в обратной зоне можно прописать только одну PTR-запись, и не факт, что она будет соответствовать именно почтовому домену.
    Но если у вас небольшой трафик, то при наличии списка исключений такая проверка может оказаться полезной.

    12.03.2009.Спасибо, что поправляете мои ляпы. На этот раз thx to Alexander Dilevskiy.
    PTR записей может быть столько, сколько нужно, в том числе, когда IP адресу web-сервера соответствует несколько доменных имен. Другое дело, что "размножение" PTR может иметь побочные эффекты ([1], [2], [3]).
    Однако, продолжим. Как sendmail определяет, что прямая и обратная проверки в днс не соответствуют друг другу? Для этого предусмотрен макрос ${client_resolve}:
    op.me: "... Holds the result of the resolve call for ${client_name}. Possible values are:
    OK               resolved successfully
    FAIL               permanent lookup failure
    FORGED               forward lookup doesn't match reverse lookup
    TEMP               temporary lookup failure
    Defined in the SMTP server only. sendmail performs a hostname lookup on the IP address of the connecting client. Next the IP addresses of that hostname are looked up. If the client IP address does not appear in that list, then the hostname is maybe forged. This is reflected as the value FORGED for ${client_resolve} and it also shows up in $_ as "(may be forged)".

    То есть sendmail смотрит IP->hostname->IP
    Здесь мне интересно еще, как именно делается запрос к ДНС. Похоже, первый раз sendmail использует спец. преобразование host, а второй раз - dns -R A. Причем в обоих случаях эти СП могут вернуть только одно значение. host sendmail'a не равнозначен команде host из дистрибутива bind. Первый работает только в одном направлении:
    host     Canonifies host domain names. Given a host name it calls the name server to find the canonical name for that host.
    Я не вижу другого способа в sendmail определить по доменному имени IP адрес кроме как использовать dns -R A.
    Есть еще один интересный макрос - ${client_ptr} : The result of the PTR lookup for the client IP address. Note: this is the same as ${client_name} if and only if ${client_resolve} is OK. Defined in the SMTP server only.
    Лог экспериментов с несколькими PTR-записями можно посмотреть здесь.

    Nota Bene! Начиная с версии 8.14.0 в sendmail есть FEATURE(`require_rdns'), которая позволяет отказывать в приеме почте с неправильной обратной записью в днс.
    require_rdns: Reject mail from connecting SMTP clients without properrDNS (reverse DNS), functional gethostbyaddr() resolution.
    Note: this feature will cause false positives, i.e., there are legitimate MTAs that do not have proper DNS entries. Rejecting mails from those MTAs is a local policy decision.

    16.10.2008. Если вы посмотрите свой конфиг, то уже обнаружите следующие строки в наборе правил Relay_ok, который в свою очередь вызывается из check_rcpt:
    ### Relay_ok: is the relay/sender ok?
    ######################################################################
    SRelay_ok
    # anything originating locally is ok
    # check IP address
    R$*                           $: $&{client_addr}
    R$@                           $@ RELAY originated locally
    R0                           $@ RELAY originated locally
    R127.0.0.1                           $@ RELAY originated locally
    RIPv6:::1                           $@ RELAY originated locally
    R$=R $*                           $@ RELAY relayable IP address
    R$*                           $: $>A <$1> <?> <+ Connect> <$1>
    R<RELAY> $*                            $@ RELAY relayable IP address

    R<<TMPF>> $*                           $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
    R<$*> <$*>                           $: $2
    R$*                            $: [ $1 ] put brackets around it...
    R$=w                           $@ RELAY ... and see if it is local

    # check client name: first: did it resolve?
    R$*                           $: < $&{client_resolve} >
    R<TEMP>                           $#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
    R<FORGED>                           $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
    R<FAIL>                           $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}

    Здесь мы видим предварительную обработку исключений (например, почта, отправляемая непосредственно с почтового сервера или ip адрес релея из наших сетей (определяется по файлам relay-domains($=R) и access ($>A) ))

    То есть по умолчанию слабый вариант этой проверки уже присутствует в конфиге, вы это увидите и по вашему логу.
    Было бы логично предположить, что дополнительное использование FEATURE(`require_rdns') приведет к жесткому контролю за релеем отправителя на этапе check_relay. Напомню, что в этот момент не известны ни адрес отправителя, ни адрес получателя, поэтому невозможно сделать исключения по этим параметрам. Правда, с помощью опции FEATURE(delay_check) можно отложить исполнение этого рулсета до набора check_rcpt, во время исполнения которого нам становятся известными получатели, и до которого становится известен отправитель. Но ведь тогда, имхо, эта фича становится лишней, так как почти полностью соответствует той, что уже включена в конфиг!
    Но именно с этого места начинается путаница.
    Вот правила (выделены жирным шрифтом), которые добавляет FEATURE(`require_rdns').
    SBasic_check_relay
    # check for deferred delivery mode
    R$*                           $: < $&{deliveryMode} > $1
    R< d > $*                  $@ deferred
    R< $* > $*                  $: $2

    R$+ $| $+                  $: $>D < $1 > <?> <+ Connect> < $2 >
    R $| $+                  $: $>A < $1 > <?> <+ Connect> <>         empty client_name
    R<?> <$+>                  $: $>A < $1 > <?> <+ Connect> <>         no: another lookup
    R<?> <$*>                  $: OK                                    found nothing
    R<$={Accept}> <$*>         $@ $1                                    return value of lookup
    R<REJECT> <$*>                  $#error $@ 5.7.1 $: "550 Access denied"
    R<DISCARD> <$*>                  $#discard $: discard
    R<QUARANTINE:$+> <$*>         $#error $@ quarantine $: $1
    R<ERROR:$-.$-.$-:$+> <$*>         $#error $@ $1.$2.$3 $: $4
    R<ERROR:$+> <$*>                  $#error $: $1
    R<$* <TMPF>> <$*>                  $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
    R<$+> <$*>                  $#error $: $1

    R$*                  $: $>"RateControl" dummy
    R$*                  $: $>"ConnControl" dummy

    # DNS based IP address spam list bl.spamcop.net
    R$*                           $: $&{client_addr}
    R$-.$-.$-.$-                  $: <?> $(dnsbl $4.$3.$2.$1.bl.spamcop.net. $: OK $)
    R<?>OK                           $: OKSOFAR
    R<?>$+<TMP>                  $: TMPOK
    R<?>$+                  $#error $@ 5.7.1 $: Spam blocked see: http://spamcop.net/bl.shtml?$&{client_addr}

    R$*                           $: $&{client_addr} $| $&{client_resolve}
    R$=R $*                           $@ RELAY                  We relay for these
    R$* $| OK                  $@ OK                           Resolves.
    R$* $| FAIL                  $#error $@ 5.7.1 $: 550 Fix reverse DNS for $1
    R$* $| TEMP                  $#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve
    R$* $| FORGED                  $#error $@ 4.1.8 $: 451 Possibly forged hostname for $1


    Здесь мы видим и пропуск почты, разрешенной в /etc/mail/access (
    R<$={Accept}> <$*>         $@$1
    ), и пропуск без проверки почты, отправленной из сетей /etc/mail/relay-domains (
    R$=R $*                           $@ RELAY
    ).
    Единственная существенная разница - это коды ошибок. И по моим ощущениям, в первом случае они строже, чем во втором.
    Смотрите, и в первом случае, и во втором на < FAIL > мы реагируем кодом permanent ошибки 5.7.1 , только сообщения разные.
    А вот < FORGED > (ПРЯМАЯ И ОБРАТНАЯ ЗОНЫ НЕ СООТВЕТСТВУЮТ ДРУГ ДРУГУ) в первом случае выдаст все тот же строгий отказ 5.7.1, а во втором случае - временную ошибку 4.1.8
    На < TEMP > же первая проверка отреагирует, как и ожидалось, более лояльно через 4.4.0 нежели вторая (4.1.8).

    В общем, я запуталась. Помогите, кто чем может, а :) ?

    Ну а здесь - http://www.cs.niu.edu/~rickert/cf/hack/require_rdns.m4 - старый вариант этой же проверки от Neil Rickert за 2003год. Подозреваю, что именно он лег в основу современного решения.

    А это решение, когда-то взятое с sendmail-конфы и когда-то мною усложненное. Именно здесь мы видим самое деликатное обращение с проверкой $&{client_resolve}: временная ошибка на <TEMP> и <FORGED >, и серьезная ошибка на <FAIL>.
    LOCAL_RULESETS
    SEnforce_RDNS_check_relay
    # check client name: did it resolve?
    R$*                    $: < $&{client_resolve} >
    R<TEMP>                    $#TEMP $@ 4.7.1 $: "451 Access temporarily denied. Cannot resolve PTR record for " $&{client_addr}
    R<FORGED >                    $#TEMP $@ 4.7.1 $: "451 Access temporarily denied. IP name possibly forged " $&{client_name}
    R<FAIL>                    $#error $@ 5.7.1 $: "550 Access denied. IP name lookup failed " $&{client_name}
    И мои добавления:
    А теперь тоже самое, но исключаем из проверки:
    - всех локальных юзеров (локальность определяет по доменной части эл. адреса ($=w))
    - внешнего пользователя user@domain.ru
    - всех пользователей домена somedomain.com
    - сеть 1.2.3

    LOCAL_RULESETS
    SLocal_check_mail
    R$*                    $: $>Parse0 $>3 $1
    R$+<@$=w.>                    $@OK
    Ruser<@domain.ru.>                   $@OK
    R$+<@somedomain.com.>                   $@OK
    R$+<@$+>                   $>CheckUserIP
    R$*                    $@OK
    SCheckUserIP
    R$*                   $: < $&{client_addr} >
    R < 1.2.3.$+ >                   $@OK
    R$*                    $: < $&{client_resolve} >
    R<TEMP>                    $#TEMP $@ 4.7.1 $: "451 Access temporarily denied. Cannot resolve PTR record for " $&{client_addr}
    R<FORGED >                    $#TEMP $@ 4.7.1 $: "451 Access temporarily denied. IP name possibly forged " $&{client_name}
    R<FAIL>                    $#error $@ 5.7.1 $: "550 Access denied. IP name lookup failed " $&{client_name}


    22. Горячий спам (ноябрь-декабрь 2006)

    22.1. Вы еще не видели такие подзаголовки Received: ?
    from 193.227.145.228 (HELO mailrelay.faz.de)\n by anrb.ru with esmtp (-Z6,,5P057UK 33E;12)\n id 9NLQV)-L-'UW--6D\n
    from что-то by yourdomain.ru with esmtp (7A:2HR6QV 4:GT0)\n id =:*T(O-LC?Z1X-S6\n
    from что-то by yourdomain.ru with esmtp (4-'@4F)4-G ,)R6)\n id 6L-G*3-39,1)*-C*\n
    from что-то by yourdomain.ru with esmtp (X(.V62K544 .N7G5)\n id XK*Z5P-X@L,+=-RA\n
    from что-то by yourdomain.ru with esmtp (Q/-5A0T3A+ K2UP0)\n id N/;I0Z-),T)C.-42\n

    LOCAL_CONFIG
    KRec1 regex -a@MATCH by.yourdomain.ru.with.esmtp.(.*[0-9].*[0-9].*[0-9].*[0-9].*)
    LOCAL_RULESETS
    HReceived:                    $>+CheckReceived
    SCheckReceived
    R$*                   $: $(Rec1 $1 $)
    R@MATCH                    $#error $: "554 Sorry, и т.д. ...."

    Около 500 срабатываний в сутки, неплохо.
    Вообще-то, текст в скобках в Received: в таких спам-письмах намного содержательнее, чем (.*[0-9].*[0-9].*[0-9].*[0-9].*), и поначалу планировалась проверка посложнее, но поскольку и это спец. преобразование Rec1 ловит такой спам неплохо, пока оставляю все как есть.

    22.2. Вам приходит спам-почта, подписанная адресом mail@from.adres? Этот адрес отправителя указывается спамерами на этапе "DATA", поэтому в логе он не фигурирует и его невозможно проверить в наборе правил Local_check_mail, но на этот случай предусмотрен набор Check_From.
    LOCAL_CONFIG
    LOCAL_RULESETS
    HFrom:                   $>CheckFrom
    SCheckFrom
    #'Это запись в лог просто для проверки правильности работы правила
    #R$* mail@from.adres $*                   $: $(syslog syslog:From: $1 mail@from.adres $2 $) $1 mail@from.adres $2
    R$* mail@from.adres $*                   $#error $: 554 Sorry, и т.д...
    Около 300-400 срабатываний в сутки.
    30.12.2006. Уже ни одного. Не актуально.

    22.3.1. 30.12.2006. Еще одна блокировка. Вы, наверное, давно заметили в первом сверху (но последнем по маршруту) подзаголовке Received спам-писем такое: from localhost.localdomain.
    Это не являлось бы признаком спама, если бы присутствовало в последнем сверху, но первым по маршруту Received:, на этом этапе идет обмен информацией между почтовым клиентом отправителя и почтовым сервером, который его обслуживает, и здесь макрос $s может оказаться каким-угодно, подробности - ниже.
    Но что настораживает в приведенных ниже строках:
    письма приходят с моего второго mx-релея, но почтовик-отправитель представился моему релею как localhost.localdomain

    from localhost.localdomain (ip151-108-173-82.adsl2.versatel.nl [82.173.108.151])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBTNHO7d013877\n\t
    from localhost.localdomain ([86.42.157.247])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBTNK36p013931\n\t
    from localhost.localdomain (132.Red-83-57-236.dynamicIP.rima-tde.net [83.57.236.132])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBTNYls7014242\n\t
    from localhost.localdomain ([60.50.238.151])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBTNmcbx014531\n\t
    from localhost.localdomain (84.94.17.216.cable.012.net.il [84.94.17.216] (may be forged))\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBTNvg4P014647\n\t
    from localhost.localdomain (cvl92-2-82-228-144-66.fbx.proxad.net [82.228.144.66])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBU0sZt6015548\n\t
    from localhost.localdomain ([62.117.102.137])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBU27i7X016597\n\t
    from localhost.localdomain (BSN-61-33-116.dial-up.dsl.siol.net [86.61.33.116])\n\tby ns1.anrb.ru (ver./ver.) with SMTP id kBU29upU016620\n\t

    Что не совсем корректно.
    Стандартный Received: сендмэйла имеет такой вид:
    #########################
    # Format of headers #
    #########################

    H?P?Return-Path: <$g>
    HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
    $.$?{auth_type}(authenticated$?{auth_ssf} bits=${auth_ssf}$.)
    $.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}
    (version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})$.$?u
    for $u; $|;
    $.$b

    Первый макрос $s - имя хоста-отправителя, подробнее о нем можно прочитать здесь. И по моим ощущениям он никак не может быть localhost.localdomain на последнем этапе маршрута.

    HReceived:               $>+CheckReceived
    SCheckReceived
    R$+ localhost.localdomain $+ yoursecond.mx-relay.ru $+               $#error $: "554 Sorry, ..."

    От 1500 до 3000 срабатываний день.

    22.3.2. 07.02.2007. После некоторых раздумий решила сделать аналогичную проверку и на первом mx-почтовике.
    LOCAL_RULESETS
    SLocal_check_mail
    R$*                 $: $(storage {Mail_from} $@ $1 $) $1

    #Do not check if it is local ip-address
    R$*                 $: < $&{client_addr} >
    R< $=R $* >                 $@ OK

    #Do not check if it is smtp-authenticated mail
    R$*                  $: < $&{auth_authen} >
    R< $+ >                  $@ OK

    R$*                  $: $&s
    R$* localhost.localdomain $*                 $#error $: "554 Sorry, ..."

    5000-8000 срабатывний в день.

    Если этот набор правил (3.2) поместить и на остальные ваши mx-сервера, то пункт 3.1 на первом mx-сервере не нужен, т.к. блокировка будет происходить сразу на этих серверах, и до вашего почтовика почта с Received в виде localhost.localdomain не дойдет. Но, если остальными mx-ами управляете не вы (т.е. не имеете возможности отредактировать на них конфиг в соотвествие с п.3.2), то п.3.1 - это то, что вам нужно.


    22.4. Немного не в тему, но некогда заводить отдельную страницу.
    Я использую на почтовике Drweb. С ноября было много случаев пропуска почты, зараженной Limar. Обновляю теперь базы каждые 15 минут, но периодически ситуация с пропуском повторяется. Как мне ответили на форуме Drweb , "... В принципе такое возможно что с одним и тем же набором баз демон и сканер дают различные результаты. В них используются различные парсеры почтового формата. Если Вы такое обнаружте вышлите пожалуйста письмо или заведите баг на bugs.drweb.com ..."
    Честно говоря, не думаю, что это баг, потому что после скачивания энного обновления, такая почта начинает распознаваться как зараженная.
    Но так как мне некогда рапортовать о багах, то я использую для фильтрации procmail. Как я уже говорила, sendmail, к сожалению, не умеет распознавать вложения в письма, так информация о них находится во втором поле Content-Type, который находится в теле письма и поэтому сендмэйлом не рассматривается.
    Перенаправляю письма с подозрительными вложениями в отдельный файл.
    /etc/procmailrc:
    LOGFILE=/var/log/procmaillog
    :0 B
    *
    ^Content-Type:.+name="(.+(elm|log|txt|msg|dat|log).(pif|scr|bat|exe|cmd)|Update-KB.*x86.(exe|zip)|(document|docs|doc|readme|test|body|message|messages|file|text|data).zip)"
    /var/spool/mail/virus/virus
    Мера временная, не следует забывать проверять файл virus на наличие нормальной почты, а еще лучше, настроить procmail на рассылку извещений локальным клиентам о перенаправлении адресованной им почты.


    23.1.Как сделать так, чтобы почта от локального клиента локальному тоже требовала smtp-авторизацию?
    Когда-то выкладывала решение здесь . Сама не проверяла, но вот у человека заработало. Возможно, есть более простое решение, советую обратить внимание на посты Lavr в этом треде.

    LOCAL_CONFIG
    Ksyslog syslog

    LOCAL_RULESETS
    SLocal_check_rcpt
    # empty address?
    R<>                 $#error $@ nouser $: "554 User address required"
    R$@                  $#error $@ nouser $: "554 User address required"

    #Добавляем адрес отправителя
    R$*                 $: $1 $| $&f

    #Канонизируем адреса
    R$* $| $*                 $: $2 $| $>Parse0 $>3 $1
    R$* $| $*                  $: $2 $| $>Parse0 $>3 $1

    #Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
    R$+<@$=w.> $| $+<@$=w.>                 $: $>CheckLocalAuth

    #Другие варианты fqdn-адресов пропускаем (внеш-внеш, внутр-внеш, внеш-внутр)
    R$+<@$+> $| $+<@$+>                 $@ $1

    #Алиасы, MAILER-DAEMON и др. лок. получатели без доменной части - в ту же проверку
    R$+ $| $+                  $: $>CheckLocalAuth

    #Контрольная проверка - кто там не охвачен нашими правилами: если сработает - покажешь, подправим
    R$*                 $: $(syslog syslog:PROBLEM: $1 $) $1

    SCheckLocalAuth
    #Почту с самого сервера пропускаем
    R$*                  $: $&{client_addr}
    R127.0.0.1                  $@OK

    #Если авторизация имела место - пропускаем
    R$*                  $: < $&{auth_authen} >
    R< $+ >                  $@ OK

    #Все остальное блокируем
    R$*                 $#error: $: 554 Sorry, you must use smtp-authentication. Please, contact to postmaster.


    23.2. Как заставить пользователей локальной сети использовать SMTH AUTH, если в MAIL FROM: они хотят указать email, почтовый домен которого привязан к данному smtp-серверу как локальный (указан в файле /etc/mail/local-host-domains)

    Набор правил от Troex Nevelin:
    LOCAL_CONFIG
    F{LocalDomains} /etc/mail/local-host-names

    LOCAL_RULESETS
    Scheck_mail
    R$*                 $: $>3 $1
    R$*                 $:$1 $| <$&{auth_authen}>
    R$* $| <$+>                 $@ OK
    R$* $| <$*>                 $:$1$|<$&{client_addr}>[$&s]
    dnl skip if auth
    R$* $| <$=R $*>[$*]                 $@ OK
    R$*<@$={LocalDomains}.>$*                 $#error $@ 5.7.1 $: "550 Relay denied. Use SMTP AUTH."


                                                                                                                                                                              Продолжение. Часть вторая.
    Обратная связь
    Страница создана 4 мая 2004г. Последнее обновление - 25 января 2010г.
    Замечания, комментарии, идеи, пожалуйста, сюда sciurus@mail.ru
    Или напрямую постмастеру этого домена (пока что я еще здесь служу).
    Вопросы также можно задавать, но отвечать на них я уже не обещаю:
    во-первых, все, что я знаю и умею, уже выложено;
    во-вторых, все, что выходит за рамки выложенного, скорее всего будет не по моему уму.
    Этот почтовый ящик я проверяю не чаще раза в неделю, поэтому не обессудьте за задержку с ответом.
    ---------------------------------------------------------------------------
    You can ask me a question in English.
    Le domande potrebbe fare in italiano.
    Сорауларны момкин татар, башкорт, казах телендэ бирергэ.
    ---------------------------------------------------------------------------
    Найти меня также можно здесь:
    www.opennet.ru#Medlar
    www.sysadmin.ru#Medlar
    www.linux.org.ru#Sciurus
    sendmail-конференция#Sciurus

    Если вы обращаетесь ко мне по эл.почте - просьба в качестве темы сообщения указать слово "Sendmail", иначе я не получу быстрого извещения о письме.
    Если ваша задача мне по силам и мне интересна, отвечу обязательно при условии четко описанной проблемы и четких ответов на мои вопросы.
    Если вы боитесь/ленитесь показать логи и конфиги или не понимаете, зачем мне это нужно, или полагаете, что вам лучше меня известно, какая информация мне необходима, то лучше не беспокойте меня:
    1) я ценю свое время;
    2) я не ясновидящая: без логов, конфигов и ответов на мои вопросы помочь ничем не могу;
    3) (08.02.07) мне чудовищно надоело клещами вытаскивать из вас информацию !!!

    (20.11.07) Сообщения вида "Спасибо, переписал/усовершенствовал/обработал_правила_напильником, и все заработало" воспринимаю как оскорбление. Иногда все-таки лучше молчать.
    Во-первых, мои правила совершенны. А, если не совершенны и требуют доработки, то совсем не напильником, а всего лишь надфилем ;)
    Во-вторых, если первое не верно, то почему я об этом не знаю?
    А именно: что было неверно/криво/нерационально/несовершенно?
    По-моему, я имею право это знать, коли уж вы сообщаете мне, что все переписали и затем свершилось чудо.

    Все приведенные на этой странице примеры - работающие (за исключением задачек, помеченных маячком "не проверялось"): они проверены либо на моей почтовой системе, либо на почтовых системах тех, кто задавал мне вопросы. Но при переносе правил на эту страницу я могу допустить неточности-ошибки-опечатки. Поэтому, если у вас какой-либо набор правил не срабатывает - сообщайте, будем разбираться при соблюдении вышеуказанных условий.
    ------------