você está aqui: Home  → Arquivo de Mensagens Programação Shell Linux: Inscrições Abertas

GrayList no servdir de emails (EXIM, MYSQL) - Mini tutorial

Colaboração: Silmar A. Marca

Data de Publicação: 30 de Maio de 2005

Graylist é uma lista "cinza", onde o servidor rejeita a mensagem por um determinado tempo. Tal atitude forca a mensagem a ser re-enviada, o que geralmente não acontece caso a mesma seja enviada por um servidor de SPAM ou por inúmeros tipos de VIRUS. Uma vez a mensagem conseguir ser enviada, o servidor que a enviou poderá postar sucessivas mensagens sem atraso.

Funciona bem na versão 4.50 ou superior do EXIM. É pré-requisito compilar o exim com suporte a mysql.

Vale a pena ressaltar que o GrayList apresentado é modificado do padrão original. O mesmo valida apenas o dominio de quem envia e a rede do mesmo. Valida também mensagens de erro (Bounce). Tal modificação tem apresentado os efeitos positivos de diminuir atrasos na entrega da mensagem em caso de round-robing nos ips de entrega, isto sem causar impacto na eficiencia da ferramenta.

Observa se que é importante adicionar o graylist no final das clausulas rcpt e data e não no inicio! Adicionar antes do aceite final para qualquer hosts! A mesma não impede usuarios autenticados, relay Hosts e SPF validados (caso habilitado).

Partes do código foram baseados em diversos tutorias na internet.

Criar tabela no mysql:

#
# Estrutura da tabela ``greylist``
#

CREATE TABLE ``greylist`` (
 ``id`` bigint(20) NOT NULL auto_increment,
 ``relay_ip`` varchar(20) default NULL,
 ``sender_type`` enum('NORMAL','BOUNCE') NOT NULL default 'NORMAL',
 ``sender`` varchar(150) default NULL,
 ``recipient`` varchar(150) default NULL,
 ``block_expires`` datetime NOT NULL default '0000-00-00 00:00:00',
 ``record_expires`` datetime NOT NULL default '9999-12-31 23:59:59',
 ``create_time`` datetime NOT NULL default '0000-00-00 00:00:00',
 ``TYPE`` enum('AUTO','MANUAL') NOT NULL default 'MANUAL',
 ``passcount`` bigint(20) NOT NULL default '0',
 ``last_pass`` datetime NOT NULL default '0000-00-00 00:00:00',
 ``blockcount`` bigint(20) NOT NULL default '0',
 ``last_block`` datetime NOT NULL default '0000-00-00 00:00:00',
 PRIMARY KEY  (``id``),
 UNIQUE KEY ``relay_ip`` (``relay_ip``,``sender``,``recipient``,``sender_type``)
) TYPE=MyISAM COMMENT='GrayList ';

# --------------------------------------------------------

#
# Estrutura da tabela ``greylist_log``
#

CREATE TABLE ``greylist_log`` (
 ``id`` bigint(20) NOT NULL auto_increment,
 ``listid`` bigint(20) NOT NULL default '0',
 ``timestamp`` datetime NOT NULL default '0000-00-00 00:00:00',
 ``kind`` enum('deferred','accepted') NOT NULL default 'deferred',
 PRIMARY KEY  (``id``)
) TYPE=MyISAM COMMENT='GrayList Log';

Arquivo exim.conf:

<..Outras configuracoes iniciais...>

#Comentar caso nao haja base Mysql
MYSQL_SERVER            = "localhost/baseexim/usuarioeximbd/senhaeximbd"

#-DEF: Lista GreyList (Defer Temporario)
.ifdef MYSQL_SERVER
 GREYLIST_ENABLED_GREY          = yes
 # GREYLIST_ENABLED_LOG         = yes
 GREYLIST_INITIAL_DELAY         = 12 MINUTE
 GREYLIST_INITIAL_LIFETIME      = 4 HOUR
 GREYLIST_WHITE_LIFETIME        = 36 DAY
 GREYLIST_BOUNCE_LIFETIME       = 7 DAY
 GREYLIST_RECORD_LIFETIME       = 90 DAY
 GREYLIST_TABLE                 = greylist
 GREYLIST_LOG_TABLE             = greylist_log
 # GREYLIST_SKPSPF              = yes
.endif

<..Outras configuracoes iniciais...>

.ifdef MYSQL_SERVER
 .ifdef GREYLIST_ENABLED_GREY
   GREYLIST_TEST = SELECT CASE \
      WHEN now() > block_expires THEN "accepted" \
      ELSE "deferred" \
    END AS result, id \
    FROM GREYLIST_TABLE \
    WHERE (now() < record_expires) \
      AND (sender_type = ${if def:sender_address_domain{'NORMAL'}{'BOUNCE'}}) \
      AND (sender      = '${quote_mysql:${if def:sender_address_domain{$sender_address_domain}{${domain:$h_from:}}}}') \
      AND (recipient   = '${quote_mysql:${if def:domain{$domain}{${domain:$h_to:}}}}') \
      AND (relay_ip    = '${quote_mysql:${mask:$sender_host_address/24}}') \
    ORDER BY result DESC LIMIT 1

   GREYLIST_ADD = REPLACE INTO GREYLIST_TABLE \
     (relay_ip, sender_type, sender, recipient, block_expires, \
      record_expires, create_time, type) \
    VALUES ( '${quote_mysql:${mask:$sender_host_address/24}}', \
     ${if def:sender_address_domain{'NORMAL'}{'BOUNCE'}}, \
     '${quote_mysql:${if def:sender_address_domain{$sender_address_domain}{${domain:$h_from:}}}}', \
     '${quote_mysql:${if def:domain{$domain}{${domain:$h_to:}}}}', \
     DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_DELAY), \
     DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_LIFETIME), \
     now(), \
     'AUTO' \
   )

   GREYLIST_DEFER_HIT = UPDATE GREYLIST_TABLE \
                        SET blockcount=blockcount+1, last_block=now() \
                        WHERE id = $acl_m9

   GREYLIST_OK_COUNT = UPDATE GREYLIST_TABLE \
                       SET passcount=passcount+1, last_pass=now() \
                       WHERE id = $acl_m9

   GREYLIST_OK_NEWTIME = UPDATE GREYLIST_TABLE \
                         SET record_expires = DATE_ADD(now(), INTERVAL GREYLIST_WHITE_LIFETIME) \
                         WHERE id = $acl_m9 AND type='AUTO'

   GREYLIST_OK_BOUNCE = UPDATE GREYLIST_TABLE \
                        SET record_expires = DATE_ADD(now(), INTERVAL GREYLIST_BOUNCE_LIFETIME) \
                        WHERE id = $acl_m9 AND type='AUTO'

   GREYLIST_CLEAN = DELETE FROM GREYLIST_TABLE \
                    WHERE (record_expires > DATE_ADD(now(), INTERVAL GREYLIST_RECORD_LIFETIME)) AND (type='AUTO')

   GREYLIST_LOG = INSERT INTO GREYLIST_LOG_TABLE \
                  (listid, timestamp, kind) \
                  VALUES ($acl_m9, now(), '$acl_m8')
 .endif
.endif

<..Outras configuracoes iniciais...>

#-Definicao da ACL. Clausula GreyList (ocorre antes do rcpt e do data):
.ifdef GREYLIST_ENABLED_GREY
 greylist_acl:

 # Limpar tabela automaticamente 09:3xBRST 10:3xBRDT (horario normal)
 warn  condition       = ${if eq {${substr{9}{3}{$tod_zulu}}} {123}{yes}{no}}
       set acl_m4      = ${lookup mysql{GREYLIST_CLEAN}}

 warn set acl_m8       = ${lookup mysql{GREYLIST_TEST}{$value}{result=unknown}}
      set acl_m9       = ${extract{id}{$acl_m8}{$value}{-1}}
      set acl_m8       = ${extract{result}{$acl_m8}{$value}{unknown}}

 accept
      condition        = ${if eq {$acl_m8} {unknown} {yes}}
      condition        = ${lookup mysql{GREYLIST_ADD}{yes}{no}}

 .ifdef GREYLIST_ENABLED_LOG
 warn condition        = ${lookup mysql{GREYLIST_LOG}}
 .endif

 accept
      condition        = ${if eq{$acl_m8} {deferred} {yes}}
      condition        = ${lookup mysql{GREYLIST_DEFER_HIT}{yes}{yes}}

 warn condition        = ${lookup mysql{GREYLIST_OK_COUNT}}

 warn !senders         = : postmaster@* : Mailer-Daemon@*
      condition        = ${lookup mysql{GREYLIST_OK_NEWTIME}}
 warn senders          = : postmaster@* : Mailer-Daemon@*
      condition        = ${lookup mysql{GREYLIST_OK_BOUNCE}}
 deny
.endif

<..Outras configuracoes de ACL...>

acl_check_rcpt:
  <... Outras configuracoes deste rcpt. Como verificações de sender, aceitar relay_hosts e autenticados...>
  <... Geralmente coloca se esta clausula antes do accept final para quem não é ralay_host e autenticado...>
  .ifdef GREYLIST_ENABLED_GREY
   defer hosts         = !+relay_from_hosts
        !authenticated = *
        .ifdef GREYLIST_SKPSPF
        !spf           = pass
        .endif
        acl            = greylist_acl
        message        = GreyListed: please try again later
        delay          = 15s
  .endif
 .endif

<..Outras configuracoes. Outros ACLs...>

acl_check_data:
  <... Outras configuracoes deste rcpt. Como verificações de sender, aceitar relay_hosts e autenticados...>
  <... Geralmente coloca se esta clausula antes do accept final para quem não é ralay_host e autenticado...>
 .ifdef GREYLIST_ENABLED_GREY
   defer
        .ifdef GREYLIST_SKPSPF
        !spf           = pass
        .endif
        acl            = greylist_acl
        message        = GreyListed: please try again later
        delay          = 15s
 .endif

Silmar A. Marca, GrupoGSN - Desenvolvimento, Implantação e Verificação de Servidores Profissionais baseados em Linux/Novell



Veja a relação completa dos artigos de Silmar A. Marca