Un mensaje de correo-e puede entrar en Postfix de forma local (mediante el programa /usr/lib/sendmail, que presenta una interfaz compatible en gran medida con el mismo programa de Sendmail) o mediante una conexión SMTP. En el primer caso, el mensaje se acepta siempre. Es en el segundo caso cuando entran en acción los controles de acceso (llamados UCE controls en la documentación de Postfix). Sin embargo aún tenemos mecanismos para rechazar mensajes tanto si llegan de una manera como de otra: el filtrado (content_filter) y las comprobaciones de cabeceras (header_checks) y de contenido (body_checks). Como hemos dicho, nos centraremos sólo en los controles de acceso por SMTP y no en estos otros mecanismos. Tampoco entraremos en temas de autentificación o comunicaciones seguras entre servidores de correo (SASL, TLS).
En Postfix, por defecto, un mensaje que llega por SMTP se acepta sólo si se cumple alguna de las siguientes condiciones:
?ste es el comportamiento por defecto, sin embargo tenemos a nuestra disposición mecanismos muy flexibles para adaptarlo a nuestras necesidades.
Existen cuatro parámetros de configuración principales para controlar el acceso, cada uno de los cuales puede tomar como su valor una serie de restricciones. Postfix evalua la serie de restricciones que componen cada uno de estos parámetros tras cada una de las primeras fases del diálogo SMTP con el cliente. Las fases y los parámetros son:
A partir de ahora, a estos parámetros los llamaremos RC (del término usado en la documentación, Restriction Class). Las restricciones que pueden usarse se detallan en la tabla que se muestra más abajo. Cada restricción puede devolver uno de los siguientes tres valores posibles: Aceptar, Rechazar, No-Sé. Por ejemplo, una restricción puede ser buscar la dirección IP del cliente en un fichero con el siguiente formato:
Conexión smtpd_client_restrictions HELO/EHLO smtpd_helo_restrictions MAIL FROM smtpd_sender_restrictions RCPT TO smtpd_recipient_restrictions
Si la dirección IP del cliente es a.b.c.d, el mensaje será aceptado. Si aquélla es e.f.g.h, será rechazado. Si es i.j.k.l, será rechazado, pero con un fallo temporal, con lo que el cliente volverá a intentar su entrega más tarde. Si la dirección IP del cliente es cualquier otra, el resultado de la restricción será No-Sé, con lo cual se evaluará la siguiente restricción, si la hay.a.b.c.d OK e.f.g.h REJECT i.j.k.l 450 Fallo temporal
Cuando Postfix evalúa, tras cada fase del diálogo SMTP, la lista de restricciones que componen el parámetro smtpd_xxx_restrictions correspondiente a esa fase, actúa así:
La evaluación de las restricciones se efectúa de forma secuencial, tal como aparecen en el fichero de configuración (main.cf).
Si una RC evalúa a rechazar el mensaje, éste es rechazado, sin que haga falta evaluar las RCs de las fases posteriores. Pero si evalúa a aceptar o No-Sé, sí se evalúan dichas RCs. Como el resultado por defecto de las tres primeras RCs en Postfix es No-Sé (de hecho, por defecto no tienen ningún valor asignado), no tiene sentido incluir, en esas tres RCs, restricciones que no puedan devolver como resultado un rechazo. O sea, si queremos rechazar conexiones por dirección/hostname del cliente (caso de un bombardeo o un indeseable, por ejemplo, o permitir conexiones sólo de una serie de máquinas internas ) o por nombre de host declarado en HELO/EHLO o por dirección de correo origen (casos estos poco frecuentes por lo fácil de falsear la información proporcionada) entonces sí tiene sentido poner restricciones en las tres primeras RCs. En caso contrario no lo tiene. ?sa es la razón por la que mucha gente pone todas las restricciones en la última RC.
La idea básica es que hasta que no se pasa la fase RCPT TO, normalmente no se puede saber si el mensaje debe ser aceptado o rechazado, pues sea quien sea la máquina cliente y la dirección origen, si el destinatario es local normalmente se aceptará.
(existen casos donde no es así; por ejemplo si obligamos a que si una conexión viene de una máquina interna la dirección origen sea del tipo [email protected], esto se podría detectar en la fase MAIL FROM; este tipo de controles se pueden hacer pero de forma más compleja).
Por tanto, la idea es no rechazar nada antes de que pase esa fase, salvo que tengamos razones concretas para ello.
Pongamos un ejemplo: queremos tener los controles habituales, pero también que una serie de usuarios amigos de otros dominios puedan usar nuestro servidor para enviar correo a donde quieran. Lo que puede parecer más lógico es:
main.cf
/etc/postfix/amigossmtpd_client_restrictions = check_client_access hash:/etc/postfix/amigos
Esto no tiene ningún efecto, porque en el caso de conexiones de estos hosts, el resultado de la primera RC será Aceptar, en vez del habitual No-Sé, y ya hemos visto que ambos tiene el mismo significado como resultado final de un RC. Si desde una de esas máquinas se quiere enviar un mail a una dirección que no sea de nuestro dominio, la cuarta RC lo rechazará. Para conseguir lo que queremos habría que hacer es, usando el mismo fichero amigos, poner en main.cf:host.friend1.com OK host.friend2.org OK
De esta manera, si el resultado de esa restricción es Aceptar, éste será asimismo el de toda la RC, y como es la última, se aceptará.smtpd_recipient_restrictions = permit_mynetworks, check_client_access hash:/etc/postfix/amigos, check_relay_domains
Una aplicación interesante de este mecanismo es definir reglas de acceso en base a más de un parámetro. Las restricciones en Postfix (ver más adelante en este mismo documento) se evaluan siempre sobre un parametro (excepto check_relay_domains y algunas más), como las direcciones de origen o destino, dirección IP del cliente, etc. Usando RCs podemos saltarnos esta restricción. La mejor forma de explicarlo es un ejemplo: Queremos que los mails enviados desde nuestra red solo puedan llevar como remitente direcciones (en MAIL FROM) del tipo [email protected]. Si no es así, serán rechazadas por el servidor. Vemos que la decisión depende de la relación entre dos datos: la dirección IP del cliente y la dirección de correo-e del remitente. Veamos cómo implementarlo:
main.cf
smtpd_restriction_classes = misremitentes misremitentes = check_sender_access regexp:/etc/postfix/misremitentes smtpd_sender_restrictions = check_client_access hash:/etc/postfix/misclientes
/etc/postfix/misremitentes
/@(.*\.)?midominio\.com$/ OK /.*/ 554 La direccion remitente debe ser local
/etc/postfix/misclientes
La comprobación se puede hacer en este caso tras la fase MAIL FROM, y como supone un comportamiento más restrictivo que el inicial de Postfix, se puede poner en smtpd_sender_restrictions en vez de en la última RC, como dijimos anteriormente. En ese momento se comprueba primero el nombre del host cliente (check_client_access usa la dirección IP del cliente y su nombre de host -obtenido por consulta DNS inversa- en la tabla que le demos) en la tabla misclientes. Si la máquina no pertenece a nuestro dominio, el resultado será No-Sé, o sea, se le permite pasar a la siguiente fase. Si es de nuestro dominio, el resultado será el que se obtenga de evaluar nuestra RC, misremitentes, la cual mira la dirección de correo-e del remitente (check_sender_access busca la dirección correo-e del remitente en la tabla) y su resultado es aceptar (si es de nuestro dominio o subdominios, en el patrón que hemos usado) o denegar; esta RC no puede devolver No-Sé, porque el último patrón empareja cualquier dirección.midominio.com misremitentes
Usamos una tabla tipo regexp (expresiones regulares) porque se examinan secuencialmente y permite poner al final una expresión catch-all. Con tablas indexadas creo que no habría manera de conseguir esto. Sin embargo hay una forma de hacerlo sólo con tablas indexadas:
main.cf
smtpd_restriction_classes = misremitentes misremitentes = check_sender_access hash:/etc/postfix/misremitentes, reject smtpd_sender_restrictions = check_client_access hash:/etc/postfix/misclientes
/etc/postfix/misremitentes
midominio.com OK
/etc/postfix/misclientes
Pero en este caso el rechazo se haría en la restricción reject, que no devuelve la causa al cliente.midominio.com misremitentes
Mencionar por último que aunque Postfix decida en cualquier fase que no va a aceptar el mensaje, deja pasar por todas las fases y emite el error al final de la fase RCPT TO, lo cual nos puede despistar al hacer pruebas. Este comportamiento se puede anular con smtpd_delay_reject = no.
Notacion | |
---|---|
D(IP) | Nombre de dominio por resolucion inversa de DNS de la direccion IP |
[IP] | Esta IP o su red |
[a,b] | Este dominio o su padre |
[x] | El dominio x o dominios padre |
El dominio x o subdominios |
Restricción | Arg | RC | Depende de | Explicación | Acción | Notas |
---|---|---|---|---|---|---|
Conexión de IP | ||||||
reject_unknown_client | IP | CHSR | - | IP no tiene PTR | Reject | |
permit_mynetworks | IP | CHSR | $mynetworks | - | Permit | |
check_client_access | IP | CHRS | map:client_access [IP],[D(IP)] | 1,3 | ||
reject_maps_rbl | IP | CHSR | $maps_rbl_domains | 2 | ||
HELO/EHLO h | ||||||
reject_invalid_hostname | h | HSR | - | Sintaxis incorrecta de 'h' | Reject | |
permit_naked_ip_address | h | HSR | - | h es una direcciín IP sin [] | Dunno | |
reject_unknown_hostname | h | HSR | - | h no tiene en DNS registro A ni MX | Reject | |
reject_non_fqdn_hostname | h | HSR | - | h no está en la forma FQDN | Reject | |
check_helo_access | h | HSR | map:helo_access [h] | 1 | ||
MAIL FROM [email protected] | ||||||
reject_unknown_sender_domain | b.c | SR | - | b.c no tiene registro A ni MX | Reject | |
check_sender_access | [email protected] | SR | map:sender_access [email protected],[b.c],a@ | 1,4 | ||
reject_non_fqdn_sender | b.c | SR | - | b.c no está en la forma FQDN | Reject | |
reject_sender_login_mismatch | ||||||
RCPT TO [email protected] | ||||||
permit_mx_backup | e.f | R | - | Somos MX para e.f && Permit | Accept | |
check_recipient_access | [email protected] | R | map:recipient_access [email protected],[e.f],d@ | 1,4 | ||
reject_unknown_recipient_domain | e.f | R | - | e.f no tiene registro A ni MX | Reject | |
reject_non_fqdn_recipient | e.f | R | - | e.f no está en forma FQDN | Reject | |
permit_auth_destination | e.f | R | $relay_domains | e.f = <$relay_domains> && Permit |
Dunno | |
$mydestination | e.f = $mydestination && Permit | |||||
$inet_interfaces | e.f = $inet_interfaces && Permit | |||||
$virtual_maps | e.f => $virtual_maps && Permit | |||||
reject_unauth_destination | e.f | R | $relay_domains | e.f = <$relay_domains> && Dunno | Reject | |
$mydestination | e.f = $mydestination && Dunno | |||||
$inet_interfaces | e.f = $inet_interfaces && Dunno | |||||
$virtual_maps | e.f => $virtual_maps && Dunno | |||||
check_relay_domains | IP, e.f | R | $relay_domains | D(IP) = <$relay_domains> && Permit | Reject | |
$relay_domains | e.f = <$relay_domains> && Permit | |||||
$mydestination | e.f = $mydestination && Permit | |||||
$inet_interfaces | e.f = $inet_interfaces && Permit | |||||
$virtual_maps | e.f => $virtual_maps && Permit | |||||
header_check, body_checks |
1?? | Si se encuentra en la tabla, aplicar el resultado que figure. Si no, No-Sé. |
2 | Si se encuentra, rechazar. Si no, No-Sé. |
3 |
Si la dirección IP del cliente es a.b.c.d que se resulve al nombre de dominio x.y.z, Postfix busca en la tabla en el orden:
Se queda con la primera que encuentre. Si el tipo de la tabla es regexp o pcre, entonces se recorre secuencialmente y se intentan emparejar todas sus entradas con x.y.x y después con a.b.c.dx.y.z y.z z a.b.c.d a.b.c a.b a |
4 |
Si la dirección de correo-e [email protected] Postfix busca en la tabla en el orden:
Se queda con la primera que encuentre. Si el tipo de la tabla es regexp o pcre, entonces se recorre secuencialmente y se intentan emparejar todas sus entradas con [email protected][email protected] x.y.z y.z z v@ |
Si una restricción no devuelve aceptar o rechazar, el resultado es No-Sé.
Las restricciones con C pueden aparecer en la RC smtpd_client_restrictions
Las restricciones con H pueden aparecer en la RC smtpd_helo_restrictions
Las restricciones con S pueden aparecer en la RC smtpd_sender_restrictions
Las restricciones con R pueden aparecer en la RC smtpd_recipient_restrictions
Tras cada fase del diálogo SMTP, las restricciones que figuren en smtpd_{client,helo,sender,recipient}_restrictions son evaluadas secuencialmente. Tan pronto como una de ellas devuelve aceptar o rechazar, no se evalúan las siguientes y el resultado de la RC es ése. Si el resultado de una restricción es No-Sé, se evalúan las siguientes.
Si el resultado de una RC es aceptar o No-Sé, se aplicará la RC de la siguiente fase.
Si alguna restricción de una RC evalúa a rechazar, el mensaje será rechazado (tras la fase RCPT TO, excepto si se usa $smtpd_delay_reject=no).
Postfix obliga, por razones de seguridad, a incluir, en la RC smtpd_recipient_restriction, al menos una de las siguientes restricciones: check_relay_domains, reject_unauth_destination o reject, porque todas ellas devuelven rechazo si no se cumplen ciertas condiciones.