Exim4

De Astillas.net

El autor de Exim es Philip Hazel que además ha escrito un libro muy interesante, aunque en la actualidad no trabaja ya en el programa.

Enlaces y referencias

Conceptos

Bounce messages

Los mensajes de rebote son, estrictamente hablando, notificaciones de estado de despacho (DSN, Delivery Status Notifications), creadas cuando una entrega falla.

En Exim estos mensajes normalmente se envían de vuelta al emisor.

Retry

El comportamiento predeterminado de Exim es intentar entregar los mensajes inmediatamente a su recepción, a menos que se le indique otra cosa.

Aunque esto funciona bien en condiciones normales, existen ocasiones en las que los servidores remotos fallan debido a condiciones de carga extrema ó a operaciones de mantenimiento, y los mensajes tienen que ser almacenados durante un tiempo hasta que se produzca un reintento (retry) de despacho.

Exim dispone de un juego de reglas que controlan la frecuencia de reintentos de envío, aunque no son simples de calcular, puesto que dependen a su vez de la frecuencia de proceso de las colas de mensajes. La opción predeterminada consiste en una única regla en el archivo /etc/exim4/conf.d/retry/30_exim4-config.

Frozen messages

Un mensaje congelado es aquél que tiene una condición de error lo bastante seria como para justificar su permanencia en la cola de mensajes, sin más reintentos de despacho.

La descongelación de mensajes puede efectuarse manualmente o automáticamente tras un tiempo concreto en dicho estado. En el primer caso se emplean las opciones -M ó -qff con el programa exim y en el segundo está controlado por la opción auto_thaw de la configuración. Tras la descongelación del mensaje se intenta un nuevo despacho y, si se producen condiciones similares, el mensaje puede volver a la categoría inicial.

Queues

Una cola de mensajes ó cola a secas es una colección de mensajes de correo bajo el control de Exim. Para el programa dicha cola es más bien un fondo común, un depósito, sin orden ni preferencia ni separación por dominios ú otros factores.

Cada elemento en la cola representa un mensaje de correo con uno ó varios destinatarios, y que permanecen guardados allí hasta que un proceso especial los extrae de ella para despacharlos a su destino. Y esto, siempre que dicha entrega no se haya podido realizar tras la recepción por las causas arriba comentadas.

Despacho de mensajes

El proceso de despacho de mensajes que lleva a cabo Exim consiste en encontrar información acerca de los destinatarios de un mensaje y en cómo llevarlos hasta allí.

Para todo ello en el programa existen unos bloques de código -separada e independientemente configurables- llamados controladores (drivers en el argot del autor) en el sentido génerico del término. Pueden hacer cosas tan dispares como resolver direcciones IP, conectar vía SMTP con otras máquinas o almacenar mensajes en buzones locales.

Existe tres tipos de controladores:

  • enrutadores (routers): encargados de procesar direcciones de correo.
  • transportes (transports): encargados de despachar mensajes, ya sea copiándolos en otros archivos, en tuberías o hacia conexiones SMTP.
  • autentificadores (smtp authenticators): encargados de las transacciones seguras (identificación, cifrado, ...) dentro del protocolo SMTP.

El procedimiento habitual consiste en determinar primero cuales son las direcciones finales destinatarias del mensaje, invocando a todos los enrutadores necesarios, para después llamar a los transportes que entregan los archivos de forma local ó remota; en este último caso es posible que necesite emplear algún tipo de autentificación.

Routers

Un enrutador se emplea para decidir qué hacer con un mensaje una vez que es aceptado previamente por el mecanismo de control de acceso (Access control list). Es decir, mediante los enrutadores se determinan las direcciones destinatarias de los mensajes.

Cada enrutador se prueba por orden de aparición en la configuración hasta que el mensaje es aceptado en uno de ellos (lo que significa que también puede rechazarlo y no efectuar más comprobaciones).

Aquí hay ejemplo de enrutador para buscar alias locales en un directorio LDAP.

Transports

Los transportes se emplean para llevar a cabo el despacho actual de mensajes una vez que han sido aceptados y procesados por los enrutadores.

Configuración

LDAP

El uso de un servidor LDAP para gestionar las cuentas de correo comprende varios aspectos. El directorio debe tener las entradas en el formato adecuado y exim4 debe realizar consultas especializadas tanto para autentificar a los usuarios como para efectuar el despacho de correo.

Control de acceso

Para autentificar usuarios empleando LDAP puede utilizarse el operador ldapauth de manera que, empleando el identificador del usuario y su contraseña se pueda verificar si está autorizado.

En la sección correspondiente definimos:

plain_server:
  driver = plaintext
  public_name = PLAIN
  server_prompts = :
  server_condition = ${if \
     ldapauth \
       { user="uid=${quote_ldap:$auth2},ou=People,dc=example,dc=net" \
         pass=${quote:$auth3} \
         ldap://localhost\
       }{yes}{no}}
  server_set_id = $auth2

Representación de usuarios

Es necesario que las entradas del directorio que definan a los usuarios tengan en cuenta varios aspectos que por diseño pueden ser obviados. El primero es el identificador de usuario (o RDN en la jerga LDAP) que debería coincidir con la cuenta UNIX subyacente y para lo que se puede emplear el ID de usuario (atributo uid) en lugar del nombre común (atributo cn).

El segundo aspecto es el propio contenido de la entrada; la clase estructural bajo la que se representa al usuario debe contener los siguientes atributos:

  • mail: puesto que se trata de despachar correo la dirección electrónica es imprescindible.
  • mailbox: para poder efectuar despacho de correo local es necesario disponer de un directorio. Puede valer perfectamente el atributo homeDirectory pero eso dependerá de si se desea tener separados ambos conceptos.

Una entrada típica podría ser:

# esteban, people, example.net
dn: uid=esteban,ou=people,dc=example,dc=net
uid: esteban
cn: Esteban Pelaez
givenName: Esteban
sn: Pelaez
mail: esteban@example.net
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
shadowLastChange: 15309
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1020
gidNumber: 1000
homeDirectory: /home/esteban
gecos: Esteban Pelaez,,,

Archivos de registro de Exim

El programa exim4 registra su actividad en los siguientes archivos a menos que se le indique expresamente lo contrario:

  • /var/log/exim4/mainlog
  • /var/log/exim4/rejectlog
  • /var/log/exim4/paniclog

Formato de mainlog

Cada entrada aparece en una única línea de texto, y algunas pueden llegar a ser bastante largas.

Cada línea comienza por una marca de tiempo con el siguiente formato:

YYYY-MM-DD HH:MM:SS 

y, si está registrando la recepción ó el despacho de un mensaje incluyen alguno de los siguientes indicadores:

  • <= para indicar una recepción
  • => para indicar un despacho satisfactorío
  • == para indicar un aplazamiento en el despacho
  • ** para indicar un fallo de envío
  • ->
  • *>

Filtro antivirus Clamav

Respecto a clamav los pasos a seguir son dos:

  1. Incluir al usuario clamav en el grupo Debian-exim (Debian-exim:x:102:clamav).
  2. Declarar el escáner de virus en la zona de la configuración que define las macros para que quede algo como
    av_scanner = clamd:/var/run/clamav/clamd.ctl

Este último valor puede que esté en el archivo /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs o en /etc/exim4/conf.d/main/000_localmacros dependiendo de la instalación.

Tras reiniciar el sistema de correo con

# /etc/init.d/exim4 restart

se deben vigilar los registros de actividad del servidor de correo, especialmente paniclog.

Probando el filtro de virus

Para efectuar pruebas del filtro antivirus se puede emplear el programa swaks auxiliado por mpack junto con un virus desarmado.

  1. Descargar cualquier versión de empaquetado del armazón de virus estándar eicar.
  2. Crear un mensaje con mpack.
  3. Abrir una conexión con el servidor de correo y enviarle el mensaje ya construído.
$ wget https://secure.eicar.org/download/eicar_com.zip                                                     
...                                                                                                             
$ mpack -s "virus test" -o message eicar_com.zip                                                      
$ cat message | swaks -s localhost -f victor@localhost -t victor@taquiones.net -g                               
=== Trying localhost:25...                                                                                      
=== Connected to localhost.                                                                                     
<-  220 daga.taquiones.net ESMTP Exim 4.50 Wed, 25 Oct 2006 18:31:07 +0100                                   
-> EHLO daga.taquiones.net                                                                                   
<-  250-daga.taquiones.net Hello localhost [127.0.0.1]                                                       
<-  250-SIZE 20000000                                                                                        
<-  250-PIPELINING                                                                                           
<-  250-AUTH PLAIN LOGIN                                                                                     
<-  250-STARTTLS                                                                                             
<-  250 HELP                                                                                                 
-> MAIL FROM:<victor@localhost>                                                                        
<-  250 OK                                                                                                   
-> RCPT TO:<victor@taquiones.net>                                                                      
<-  250 Accepted                                                                                             
-> DATA                                                                                                      
<-  354 Enter message, ending with "." on a line by itself                                         
-> Message-ID: <21712.1161797390@daga.taquiones.net>                                                   
-> Mime-Version: 1.0                                                                                         
-> Subject: virus test                                                                                       
-> Content-Type: multipart/mixed; boundary="-"                                                     
->                                                                                                           
-> This is a MIME encoded message.  Decode it with "munpack"                                       
-> or any other MIME reading software.  Mpack/munpack is available                                           
-> via anonymous FTP in ftp.andrew.cmu.edu:pub/mpack/                                                        
-> ---                                                                                                       
-> Content-Type: application/octet-stream; name="eicar_com.zip"                                    
-> Content-Transfer-Encoding: base64                                                                         
-> Content-Disposition: inline; filename="eicar_com.zip"                                           
-> Content-MD5: bOb0FdhHVUW+W6EU8giw/w==                                                                     
->                                                                                                           
-> UEsDBAoAAAAAAOCYuCg8z1FoRAAAAEQAAAAJAAAAZWljYXIuY29tWDVPIVAlQEFQWzRcUFpY                                  
-> NTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCpQ                                  
-> SwECFAAKAAAAAADgmLgoPM9RaEQAAABEAAAACQAAAAAAAAABACAA/4EAAAAAZWljYXIuY29t                                  
-> UEsFBgAAAAABAAEANwAAAGsAAAAAAA==                                                                          
->                                                                                                           
-> -----                                                                                                     
->                                                                                                           
-> .                                                                                                         
<** 550-El mensaje contiene un virus ó un programa malicioso                                                 
<** 550 (Eicar-Test-Signature).                                                                              
-> QUIT                                                                                                      
<-  221 daga.taquiones.net closing connection

El mensaje de error se ha personalizado editando el archivo /etc/exim4/conf.d/acl/40_exim4-config_check_data y cambiando directamente los textos en todas las directivas message.

Recetario

Buscando entre los mensajes encolados

Existe una utilidad llamada exiqgrep que sirve para realizar búsquedas en los mensajes encolados y no despachados aún. Es un programa Perl escrito por Matt Hubbard y que llama a exim -bpu para obtener un flujo de datos sobre los que buscar.

Parámetro Efecto
-f <regex> Aplicar la expresión regular al emisor del mensaje.
-r <regex> Aplicar la expresión regular al destinatario del mensaje.
-z Limitar la búsqueda a mensajes congelados.
-x Limitar la búsqueda a mensajes descongelados.
-i Mostrar sólo el identificador del mensaje resultante de la búsqueda. Útil para realizar operaciones con los mensajes.
-c Mostrar sólo un total de mensajes coincidentes.

Manipulando la cola de mensajes

Acción a realizar Llamada y parámetros
Procesar la cola de mensajes localhost:~# exim -q -v
Procesar la cola de mensajes sólo para destinos locales localhost:~# exim -ql -v
Despachar un mensaje (sea cual sea su condición) localhost:~# exim -M <message-id> [...]
Eliminar un mensaje localhost:~# exim -Mrm <message-id> [...]

cacert.org y exim4

Una vez generados los certificados se pueden guardar en cualquier sitio seguro (como /etc/cacert) e indicar al servidor de correo que los use mediante las siguientes estrofas del archivo /etc/exim4/conf.d/main/000_localmacros:

#       Habilitando acceso seguro al servidor de correo
MAIN_TLS_ENABLE = True
MAIN_TLS_CERTIFICATE = /etc/cacert/cert.pem
MAIN_TLS_PRIVATEKEY = /etc/cacert/private.key

El archivo cert.pem contiene el certificado firmado por cacert.org mientras que el archivo private.key es la clave generada durante la creación de nuestro certificado (vér en wikipedia).

SPF

Implementar SPF en un servidor exim consta de dos partes:

  1. Configurar el registro DNS del dominio para indicar al exterior que está autorizado para enviar mensajes en su nombre.
  2. Configurar el servidor para que valide los correos entrantes consultando los registros DNS de los que proceden.

Para crear el registro DNS se pueden emplear herramientas como SPF Wizard y obtener así el formato correcto que luego se deberá incluir en el registro DNS. Es útil echarle un vistazo antes a la documentación oficial porque aclara conceptos básicos y proporciona más enlaces interesantes.

La validación del registro DNS (una vez que exista y se ha propagado) puede realizarse por varios medios:

DKIM

DKIM es el acrónimo de Domain Keys Identified Mail y es un mecanismo que también consta, como [#SPF], de dos partes; ambas deben comenzar con la creación de un par de claves pública/privada que se utilizarán en:

  • La parte pública en un registro del DNS con formato especial.
  • La parte privada en el servidor que envía el correo y con la que firmará todos los que emita.

De esta manera aquél servidor que reciba nuestro correo firmado podrá descargar la clave pública de los registros del DNS y efectuar la verificación sobre los mensajes.

Los pasos a seguir mencionados en ésta o ésta página son:

  1. Elegir un texto breve como selector que se utilizará en ambos lados: DNS y exim. Vale cualquier cosa pero emplear algo estándar como exim o default es buena idea para no tener que recordar nombres extraños cuando verificamos lo que hemos hecho.
  2. Crear un par de claves pública/privada con openssl teniendo en cuenta las limitaciones de espacio del registrador (gandi.net por ejemplo sólo admite 1024 bytes de longitud).
  3. Configurar exim para que emplee las clave privada para firmar los mensajes salientes.
  4. Crear y publicar un registro TXT en el DNS con la parte pública.
  5. Verificar (una vez todo se ha actualizado) que los mensajes están correctamente firmados:
    1. Emplear un servicio en línea como DKIM Key Checker
    2. Enviar un correo a check-auth@verifier.port25.com o similar para obtener resultados desde el punto de vista del receptor.

La configuración de exim es sencilla. Una vez hemos guardado a salvo la clave cambiamos la configuración (el archivo /etc/exim4/conf.d/transport/10_exim4-config_transport-macros por ejemplo) para indicar que lo emplee cada vez que transporte un correo.

DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim4/dkim/dominio.com.private.key
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
DKIM_SELECTOR = exim

Podemos revisar la configuración de exim con:

# exim4 -bV
Exim version 4.84 #2 built 17-Feb-2015 17:01:49
Copyright (c) University of Cambridge, 1995 - 2014
(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2014
Berkeley DB: Berkeley DB 5.3.28: (September  9, 2013)
Support for: crypteq iconv() IPv6 PAM Perl Expand_dlfunc GnuTLS move_frozen_messages Content_Scanning DKIM Old_Demime PRDR OCSP
Lookups (built-in): lsearch wildlsearch nwildlsearch iplsearch cdb dbm dbmjz dbmnz dnsdb dsearch ldap ldapdn ldapm mysql nis nis0 passwd pgsql sqlite
Authenticators: cram_md5 cyrus_sasl dovecot plaintext spa
Routers: accept dnslookup ipliteral iplookup manualroute queryprogram redirect
Transports: appendfile/maildir/mailstore/mbx autoreply lmtp pipe smtp
Fixed never_users: 0
Size of off_t: 8
Configuration file is /var/lib/exim4/config.autogenerated
# 

Registro DNS para DKIM

Se emplea un registro tipo TXT cuyo valor es un nombre DNS ficticio formado por el selector de clave definido en DKIM_SELECTOR, el literal _domainkey y el nombre del dominio completo (empresa.net por ejemplo).

Así pues quedaría de la siguiente forma:

default._domainkey.empresa.net 10799 IN TXT "v=DKIM1;p=..." 

donde el valor númerico es el TTL del registro y la clave pública va como valor del parámetro p, toda junta sin saltos de línea ni espacios.

Depurando la configuración de exim4

Para ver qué hace exim nada mejor que usar el parámetro de depuración -d con las opciones que necesitemos. Si queremos incluirlas todas usaremos -d+all y si necesitamos restringir algunas prefijamos su nombre con un signo menos (como en -d+all-acl).

Esta es la tabla de opciones (no he traducido las que no he estudiado con más detenimiento):

Categoría Descripción
acl Interpretación del control de acceso
auth Identificación
deliver Lógica general de despacho de correo
dns Búsquedas DNS lookups (ver también la categoría resolver
dnsbl Listas negras por DNS (también conocidas como RBL)
exec Parámetros para llamadas a execv()
expand Expansión de textos y cadenas
filter Manejo de filtros
hints_lookup hints data lookups
host_lookup Todos los tipos de manejos entre nombres y direcciones IP
ident ident lookup
interface lists of local interfaces
lists Búsquedas de cosas en listas
load system load checks
local_scan can be used by local_scan()
lookup Código de búsquedas en general incluyendo todas las búsquedas
memory Gestión de memoria
pid Añadir el ID del proceso (PID) a todas las líneas de depuración
process_info setting info for the process log
queue_run Proceso de colas
receive Lógica general en la recepción de mensajes
resolver Activar la depuración del buscador DNS
retry Gestión de reintentos
rewrite Reescritura de direcciones
route Enrutado de direcciones
timestamp Añadir una marca de tiempo a todas las líneas de depuración
tls Lógica TLS
transport Transportes de correo
uid Cambios de UID/GID y búsquedas de los mismos
verify Lógica de verificación de direcciones
all Prácticamente todas las opciones incluyendo el parámetro -v


Las excepciones son las siguientes:

  • +all: Se excluye la categoría memory puesto que es la opción preferida para enviar informes a los desarrolladores y la información es excesiva para su gusto (y el de cualquiera).
  • +resolver: sólo se incluye información del buscador DNS cuando se ha compilado exim con la opción DEBUG.
  • La opción predeterminada para depurar, el parámetro -d pelado, excluye las siguientes categorías: expand, filter, interface, load, memory, pid, resolver y timestamp.

Usando una sesión SMTP

Para simular que exim está recibiendo una conexión SMTP desde el exterior se usa el parámetro -bh con la dirección IP que queremos simular.

# exim -bh 10.9.8.7.1234
**** SMTP testing session as if from host 10.9.8.7
**** but without any ident (RFC 1413) callback.
**** This is not for real!

>>> host in hosts_connection_nolog? no (option unset)
>>> host in host_lookup? yes (matched "*")
>>> looking up host name for 10.9.8.7
>>> IP address lookup using gethostbyaddr()
>>> IP address lookup failed: h_errno=1
LOG: no host name found for IP address 10.9.8.7
>>> host in host_reject_connection? no (option unset)
>>> host in sender_unqualified_hosts? no (option unset)
>>> host in recipient_unqualified_hosts? no (option unset)
>>> host in helo_verify_hosts? no (option unset)
>>> host in helo_try_verify_hosts? no (option unset)
>>> host in helo_accept_junk_hosts? no (option unset)
220 cimitarra ESMTP Exim 4.67 Sat, 19 May 2007 20:50:13 +0200

pudiendo añadirle el puerto entrante si lo separamos con un punto al final del todo.

Si necesitamos rápidamente una sesión SMTP y concentrarnos en el contenido tenemos la opción con el programa swaks, un excelente testeador para el correo:

# swaks --pipe "exim4 -d+all -bh 10.9.8.7.1234" -f yo@mismo.com -t tu@tambien.com

y si necesitamos que el contenido sea un mensaje de factura propia usaremos cualquiera de sus opciones para ello.

Verificando la expansión de valores

Se emplea los parámetros -be y se comienzan a introducir las expresiones y nombres de variables para que exim muestre lo que produce:

 # exim -be 
 > Mi nombre de servidor es $primary_hostname
 Mi nombre de servidor es daga.taquiones.net
 >