… y las notas que he tomado. No todas, algunas están también en mi wiki.
Propósitos
- Entender cómo funciona un enrutador en la configuración de exim4.
- Escribir uno para obtener los usuarios locales.
- Aprender cómo se testea un enrutador en exim4.
Conceptos
En la jerga de exim un enrutador (router) es código que opera sobre direcciones de correo electrónico. Al contrario que un transporte (transport), que es la parte del programa que envía mensajes de correo electrónico a una cola de mensajes del programa, bien para despacharlas localmente con algún programa, bien para enviarlas a otros servidores fuera de su entorno.
El enrutador puede cambiar las direcciones, decidir si son válidas o no y qué transporte usar en caso afirmativo. Esto es, se usan tanto para validar direcciones como para decidir qué hacer con ellas a continuación. Un enrutador puede funcionar para los dos fines o sólo para uno.
Las direcciones de correo electrónico se procesan pasándolas en orden por cada uno de los enrutadores, siempre que se cumplan algunas precondiciones en los mismos (por ejemplo si la parte del dominio de la dirección es local o no), hasta que uno de ellos indica que la dirección es aceptable o debe ser rechazada.
Cumplidas las condiciones un enrutador recibe la dirección y decide lo que sucede a continuación retornando alguno de estos valores:
- accept: el enrutador acepta la dirección y, o bien le asigna un transporte, o bien crea una o más direcciones hijas. El proceso de la dirección se interrumpe en él a menos que tenga el atributo unseen. Las posibles direcciones hijas son procesadas de forma independiente comenzando por el primer enrutador de la lista; puede también definirse cuál con el empleo de redirect_router.
- pass: el enrutador acepta la dirección pero no puede manejarla él mismo y pide que se pase a otro enrutador; éste puede ser el siguiente en la lista (comportamiento predeterminado) o el indicado en la opción pass_router.
- decline: el enrutador no reconoce la dirección y no la acepta por lo que debe pasar al siguiente enrutador en la lista a menos que exista el atributo no_more, que convierte la acción decline en fail.
- fail: el enrutador determina que la dirección es fallida y que el sistema debe crear un mensaje de rebote. Si existe el atributo unseen se seguirá procesando la dirección de correo.
- defer (aplazar): el enrutador no puede ocuparse de la dirección en este momento -es un fallo temporal- por lo que no se detiene el proceso de envío hasta el siguiente intento.
- error: hay algún error en el enrutador (errores de síntaxis o cualquier otra cosa) y el envío debe aplazarse.
Si la dirección pasa por todos los enrutadores sin haber sido aceptada por alguno se da por no válida y se crea un mensaje de rebote.
Funciones de búsqueda en LDAP
Existen tres tipos de búsqueda en un directorio LDAP en exim. Ambas emplean un URL como forma de pasar los parámetros y se diferencian en los resultados que devuelven:
- ldap: obliga a que el resultado sea una única entrada. Si hay más se considera un error.
- ldapm: permite que el resultado devuelva más de una entrada, retornando los atributos de todas ellas.
- ldapdn: el resultado debe ser una única entrada pero no devuelve ningún atributo; en su lugar retorna el DN de la entrada.
Para las búsquedas con ldap y ldapm debe existir algún atributo que retornar. En caso contrario Exim4 considera la búsqueda infructuosa.
El URL de consulta sigue las normas del RFC 2255 y, dado que no existe forma de pasar credenciales u otro tipo de información, la función de búsqueda admite una lista de pares variables/valor de los que cito algunos:
- USER = DN para acreditarse en el directorio (bind DN); es conveniente emplear la función quote_ldap_dn para proteger caracteres extraños, como los espacios en blanco.
- PASS = contraseña de acceso; también conviene utilizar entrecomillado pero esta vez empleando la función quote.
- SIZE = limita el nº de entradas retornadas.
- TIME = establece un temporizador para la búsqueda.
El URL está compuesto entonces por los siguientes elementos, de los cuales sólo es obligatorio el primero:
- Esquema:
ldap://
- Servidor y puerto:
ldap://localhost:389
- Base de búsqueda:
ldap://localhost:389/ou=users
- Atributos a recuperar:
ldap:///ou=users?name,mail
- Ámbito de búsqueda (base,one o sub):
ldap://ou=users?mail?sub
- Filtro de búsqueda:
ldap://ou=users?mail?one?(uid=coco)
- Extensiones.
Los valores retornados dependerán del operador de búsqueda (ldap,ldapm y ldapdn) y de lo que encuentre.
Opciones de configuración para LDAP
- ldap_default_servers: lista de servidores LDAP con los que contactar en orden si no se indica ninguno en el URL.
- ldap_start_tls: fuerza el uso del cifrado vía TLS sobre una conexión regular.
Enrutador para destinos locales en LDAP
A continuación podemos ver el enrutador que tengo funcionando en varios sistemas reducido a la expresión mínima que funciona.
ldap_users: debug_print = "R: LDAP users lookup for $local_part@$domain" driver = accept domains = +local_domains condition = ${lookup ldap {ldap://LDAP_SERVER/LDAP_BASE??sub?(uid=${quote_ldap:$local_part})}} transport = LOCAL_DELIVERY
Depurando la configuración
Una vez realizamos los cambios en la configuración recreamos ésta sobre un archivo temporal para probarla antes de pasarla a producción.
$ cd /etc/exim4 $ sudo update-exim4.conf -v -o test.conf $
Podemos pasarle primero un chequeo sintáctico empleando lo siguiente:
$ sudo exim4 -bV -C /etc/exim4/test.conf
Pero al no realizar expansión de valores tiene una utilidad limitada. Si necesitamos ver con más detalle lo que ocurre en cada fase (el enrutado nuevo por ejemplo) emplearemos lo siguiente:
$ sudo exim4 -bt -C /etc/exim4/test.conf -d+route prueba@empresa.net ... ... fully qualified name = empresa.net host_find_bydns yield = HOST_FIND_FAILED (0); returned hosts: localhost <null> MX=0 * dnslookup router declined for prueba@empresa.net "more" is false: skipping remaining routers no more routers prueba@empresa.net is undeliverable: all relevant MX records point to non-existent hosts search_tidyup called >>>>>>>>>>>>>>>> Exim pid=3757 terminating with rc=2 >>>>>>>>>>>>>>>>
Enlaces y referencias