# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

Exim: monitorizar la cola de correo en Big Brother


Hoy vamos a ver la forma de integrar en el sistema de monitorización Big Brother la supervisión del estado de la cola de correos de exim. Todo ello gracias al script bb-exim.sh creado por Carl C. Inglis.

Es un script fácil de entender, modificar y personalizar a nuestros requerimientos. Lo más básico a conocer es que podemos realizar y monitorizar lo siguiente:

# Tests are:
#               RUN - Test if the daemon is running
#               QUEUE - Check the size of the queue (see below)
#               REJECT - Check to see if the reject log is > 0 bytes long
#               PANIC - Check to see if the panic log is > 0 bytes long
#               FROZEN - Check to see if there are any frozen messages
#                 IGNOREFROZENERRS - Ignore frozen messages with a sender
#                                    of "<>".  (i.e., error responses.)
TESTRUN="y"
TESTQUEUE="y"
TESTREJECT="n"
TESTPANIC="y"
TESTFROZEN="y"
IGNOREFROZENERRS="y"

Como veis, por defecto revisa que el demonio de exim está corriendo, así como el tamaño de la cola de correo, el tamaño de los logs panic y reject (no por defecto para el reject)así como el número de correo en estado frozen o sin destinatario válido. Después, hay dos variables para seleccionar el umbral de aviso para warning y panic con el número de correos en cola:

TESTQUEUEALERT="50"
TESTQUEUEPANIC="100"

Revisad también que la ruta al binario de exim es la correcta, a los logs, etc:

EXIMBINARY="/usr/sbin/exim"
EXIMREJECT="/var/log/exim/rejectlog"
EXIMPANIC="/var/log/exim/paniclog"

La instalación es igual que cualquier extensión de Big Brother, ubicáis el script en la carpeta ext/, le asignais permisos de ejecución para el usuario y después lo añadís en el fichero bb-bbext y reiniciamos Big Brother:

# vim /ruta_a_big_brother/ext/bb-exim.sh
# chmod 0750 /ruta_a_big_brother/ext/bb-exim.sh
# chown usuariobb. /ruta_a_big_brother/ext/bb-exim.sh
# vim /ruta_a_big_brother/etc/bb-bbexttab
localhost :  : bb-exim.sh

Personalmente he realizado unas cuantas modificaciones para adecuarlo a mis necesidades. Entre ellas la necesidad de usar sudo ya que el usuario Big Brother no tiene privilegios, otra de ellas la visualización de la cola de correo. En lugar de mostrar la lista de mensajes como se vería con un exim -bp, la parseo mediante exiqsumm -c para que sea agradable a la vista y más rápido de visualizar y claro:

# exim -bp
 2h  5.9K xx-0000ko-HA
          xxx_70@xxx.com

 2h  6.0K xx-0000kt-OZ
          xxx_70@xxx.com

76m  9.3K xx-0003Ee-OO
          xxx@xxx.org

51m  7.8K xx-0005cQ-Te
          xxx.xxx@xxx.org
# exim -bp | exiqsumm -c

Count Volume Oldest Newest Domain
----- ------ ------ ------ ------

279 23MB 63h 30m xxx.org
2 12KB 2h 2h xxx.com
2 272KB 14h 12h xxx.com

---------------------------------------------------------------
289 28MB 63h 20m TOTAL

El resultado final, podría ser algo así:

Exim Big Brother

Podéis descargar el script original aquí.

Exim: establecer filtros anti-spam para entrada y salida de correo


eximExim nos brinda la posibilidad de establecer filtros para todos los correos que circulan por el servidor, tanto entrada como salida. Estos filtros son personalizables y permiten crear reglas que revisen las cabeceras, asunto y cuerpo de los correos en busca de ciertos patrones maliciosos conocidos, expresiones regulares, etc.

Por defecto, en servidores con cPanel disponemos de una base de reglas en el fichero /etc/antivirus.exim en el cual podemos ver bastantes reglas ya establecidas y usarlas como base para las nuestras. Si queremos activar estos filtros antes debemos acceder a WHM -> Exim Configuration Editor y modificar la opción:

** System Filter File

The system filter file is usually stored as /etc/cpanel_exim_system_filter. [INFO] Custom values must be existing files.

En el cuadro de texto ponemos la ruta contra el fichero /etc/antivirus.exim.

Una vez activado, simplemente queda modificar, borrar o añadir nuestras reglas personalizadas, la sintaxis y estructura a utilizar es sencilla:

if $message_body matches "XXXXXXXXX"
then
  fail text "Texto que aparece en el log\n\
             cuando se filtra un correo\n\
             con esta regla, se pueden \n\
             utilizar variables $1 $2 $3.\n\
  seen finish
endif
if $header_content-type: matches "XXXXXXXX"
then
  fail text "Texto que aparece en el log\n\
             cuando se filtra un correo\n\
             con esta regla, se pueden \n\
             utilizar variables $1 $2 $3.\n\
  seen finish
endif

A partir de aquí todo depende de la pericia de cada uno con las expresiones regulares. Se puede activar un log independiente para el registro de todos los correos electrónicos filtrados, establecemos la siguiente directiva al comienzo del fichero:

logfile /var/log/filtros-exim.log 0744

Y creamos el fichero de log:

# touch /var/log/filtros-exim.log
# chown cpaneleximfilter. /var/log/filtros-exim.log
# chmod 0744 /var/log/filtros-exim.log

En caso de establecer un log, debemos especificar en cada una de las reglas si queremos que se registre dicho filtrado y como, se hace mediante la directiva logwrite, también se pueden establecer las variables y datos a registrar en el log:

if $header_content-type: matches "XXXXXXXX"
then
  logwrite "$tod_log $message_id from $sender_address TEXTO_PERSONALIZADO"
  fail text "Texto que aparece en el log\n\
             cuando se filtra un correo\n\
             con esta regla, se pueden \n\
             utilizar variables $1 $2 $3.\n\
  seen finish
endif

Este filtro central para Exim puede ser muy útil para evitar el spam, tanto entrante como saliente y establecer ciertas reglas puntuales para controlar el tráfico de correo en el servidor.

Este es el fichero base para aquellos que no lo tengáis:

# Exim filter
## Version: 0.17
#	$Id: system_filter.exim,v 1.11 2001/09/19 11:27:56 nigel Exp $

## Exim system filter to refuse potentially harmful payloads in
## mail messages
## (c) 2000-2001 Nigel Metheringham 
##
##     This program is free software; you can redistribute it and/or modify
##    it under the terms of the GNU General Public License as published by
##    the Free Software Foundation; either version 2 of the License, or
##    (at your option) any later version.
##
##    This program is distributed in the hope that it will be useful,
##    but WITHOUT ANY WARRANTY; without even the implied warranty of
##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##    GNU General Public License for more details.
##
##    You should have received a copy of the GNU General Public License
##    along with this program; if not, write to the Free Software
##    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
## -A copy of the GNU General Public License is distributed with exim itself

## -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
## If you haven't worked with exim filters before, read
## the install notes at the end of this file.
## The install notes are not a replacement for the exim documentation
## -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## -----------------------------------------------------------------------
# Only run any of this stuff on the first pass through the
# filter - this is an optomisation for messages that get
# queued and have several delivery attempts
#
# we express this in reverse so we can just bail out
# on inappropriate messages
#
if not first_delivery
then
  finish
endif

## -----------------------------------------------------------------------
# Check for MS buffer overruns as per BUGTRAQ.
# http://www.securityfocus.com/frames/?content=/templates/article.html%3Fid%3D61
# This could happen in error messages, hence its placing
# here...
# We substract the first n characters of the date header
# and test if its the same as the date header... which
# is a lousy way of checking if the date is longer than
# n chars long
if ${length_80:$header_date:} is not $header_date:
then
  fail text "This message has been rejected because it has\n\
	     an overlength date field which can be used\n\
	     to subvert Microsoft mail programs\n\
             The following URL has further information\n\
	     http://www.securityfocus.com/frames/?content=/templates/article.html%3Fid%3D61"
  seen finish
endif

## -----------------------------------------------------------------------
# These messages are now being sent with a <> envelope sender, but
# blocking all error messages that pattern match prevents
# bounces getting back.... so we fudge it somewhat and check for known
# header signatures.  Other bounces are allowed through.
if $header_from: contains "@sexyfun.net"
then
  fail text "This message has been rejected since it has\n\
	     the signature of a known virus in the header."
  seen finish
endif
if error_message and $header_from: contains "Mailer-Daemon@"
then
  # looks like a real error message - just ignore it
  finish
endif

## -----------------------------------------------------------------------
# Look for single part MIME messages with suspicious name extensions
# Check Content-Type header using quoted filename [content_type_quoted_fn_match]
if $header_content-type: matches "(?:file)?name=(\"[^\"]+\\\\.(?:ad[ep]|ba[st]|chm|cmd|com|cpl|crt|eml|exe|hlp|hta|in[fs]|isp|jse?|lnk|md[be]|ms[cipt]|pcd|pif|reg|scr|sct|shs|url|vb[se]|ws[fhc])\")"
then
  fail text "This message has been rejected because it has\n\
	     potentially executable content $1\n\
	     This form of attachment has been used by\n\
             recent viruses or other malware.\n\
	     If you meant to send this file then please\n\
	     package it up as a zip file and resend it."
  seen finish
endif
# same again using unquoted filename [content_type_unquoted_fn_match]
if $header_content-type: matches "(?:file)?name=(\\\\S+\\\\.(?:ad[ep]|ba[st]|chm|cmd|com|cpl|crt|eml|exe|hlp|hta|in[fs]|isp|jse?|lnk|md[be]|ms[cipt]|pcd|pif|reg|scr|sct|shs|url|vb[se]|ws[fhc]))"
then
  fail text "This message has been rejected because it has\n\
	     potentially executable content $1\n\
	     This form of attachment has been used by\n\
             recent viruses or other malware.\n\
	     If you meant to send this file then please\n\
	     package it up as a zip file and resend it."
  seen finish
endif

## -----------------------------------------------------------------------
# Attempt to catch embedded VBS attachments
# in emails.   These were used as the basis for
# the ILOVEYOU virus and its variants - many many varients
# Quoted filename - [body_quoted_fn_match]
if $message_body matches "(?:Content-(?:Type:(?>\\\\s*)[\\\\w-]+/[\\\\w-]+|Disposition:(?>\\\\s*)attachment);(?>\\\\s*)(?:file)?name=|begin(?>\\\\s+)[0-7]{3,4}(?>\\\\s+))(\"[^\"]+\\\\.(?:ad[ep]|ba[st]|chm|cmd|com|cpl|crt|eml|exe|hlp|hta|in[fs]|isp|jse?|lnk|md[be]|ms[cipt]|pcd|pif|reg|scr|sct|shs|url|vb[se]|ws[fhc])\")[\\\\s;]"
then
  fail text "This message has been rejected because it has\n\
	     a potentially executable attachment $1\n\
	     This form of attachment has been used by\n\
             recent viruses or other malware.\n\
	     If you meant to send this file then please\n\
	     package it up as a zip file and resend it."
  seen finish
endif
# same again using unquoted filename [body_unquoted_fn_match]
if $message_body matches "(?:Content-(?:Type:(?>\\\\s*)[\\\\w-]+/[\\\\w-]+|Disposition:(?>\\\\s*)attachment);(?>\\\\s*)(?:file)?name=|begin(?>\\\\s+)[0-7]{3,4}(?>\\\\s+))(\\\\S+\\\\.(?:ad[ep]|ba[st]|chm|cmd|com|cpl|crt|eml|exe|hlp|hta|in[fs]|isp|jse?|lnk|md[be]|ms[cipt]|pcd|pif|reg|scr|sct|shs|url|vb[se]|ws[fhc]))[\\\\s;]"
then
  fail text "This message has been rejected because it has\n\
	     a potentially executable attachment $1\n\
	     This form of attachment has been used by\n\
             recent viruses or other malware.\n\
	     If you meant to send this file then please\n\
	     package it up as a zip file and resend it."
  seen finish
endif
## -----------------------------------------------------------------------

#### Version history
#
# 0.01 5 May 2000
#	Initial release
# 0.02 8 May 2000
#	Widened list of content-types accepted, added WSF extension
# 0.03 8 May 2000
#	Embedded the install notes in for those that don't do manuals
# 0.04 9 May 2000
#	Check global content-type header.  Efficiency mods to REs
# 0.05 9 May 2000
#	More minor efficiency mods, doc changes
# 0.06 20 June 2000
#	Added extension handling - thx to Douglas Gray Stephens & Jeff Carnahan
# 0.07 19 July 2000
#	Latest MS Outhouse bug catching
# 0.08 19 July 2000
#	Changed trigger length to 80 chars, fixed some spelling
# 0.09 29 September 2000
#	More extensions... its getting so we should just allow 2 or 3 through
# 0.10 18 January 2001
#	Removed exclusion for error messages - this is a little nasty
#	since it has other side effects, hence we do still exclude
#	on unix like error messages
# 0.11 20 March, 2001
#	Added CMD extension, tidied docs slightly, added RCS tag
#	** Missed changing version number at top of file :-(
# 0.12 10 May, 2001
#	Added HTA extension
# 0.13 22 May, 2001
#	Reformatted regexps and code to build them so that they are
#	shorter than the limits on pre exim 3.20 filters.  This will
#	make them significantly less efficient, but I am getting so
#	many queries about this that requiring 3.2x appears unsupportable.
# 0.14 15 August,2001
#	Added .lnk extension - most requested item :-)
#	Reformatted everything so its now built from a set of short
#	library files, cutting down on manual duplication.
#	Changed \w in filename detection to . - dodges locale problems
#	Explicit application of GPL after queries on license status
# 0.15 17 August, 2001
#	Changed the . in filename detect to \S (stops it going mad)
# 0.16 19 September, 2001
#	Pile of new extensions including the eml in current use
# 0.17 19 September, 2001
#	Syntax fix
#
#### Install Notes
#
# Exim filters run the exim filter language - a very primitive
# scripting language - in place of a user .forward file, or on
# a per system basis (on all messages passing through).
# The filtering capability is documented in the main set of manuals
# a copy of which can be found on the exim web site
#	http://www.exim.org/
#
# To install, copy the filter file (with appropriate permissions)
# to /etc/exim/system_filter.exim and add to your exim config file
# [location is installation depedant - typicaly /etc/exim/config ]
# in the first section the line:-
#	message_filter = /etc/exim/system_filter.exim
#	message_body_visible = 5000
#
# You may also want to set the message_filter_user & message_filter_group
# options, but they default to the standard exim user and so can
# be left untouched.  The other message_filter_* options are only
# needed if you modify this to do other functions such as deliveries.
# The main exim documentation is quite thorough and so I see no need
# to expand it here...
#
# Any message that matches the filter will then be bounced.
# If you wish you can change the error message by editing it
# in the section above - however be careful you don't break it.
#
# After install exim should be restarted - a kill -HUP to the
# daemon will do this.
#
#### LIMITATIONS
#
# This filter tries to parse MIME with a regexp... that doesn't
# work too well.  It will also only see the amount of the body
# specified in message_body_visible
#
#### BASIS
#
# The regexp that is used to pickup MIME/uuencoded body parts with
# quoted filenames is replicated below (in perl format).
# You need to remember that exim converts newlines to spaces in
# the message_body variable.
#
#	  (?:Content-					# start of content header
#	  (?:Type: (?>\s*)				# rest of c/t header
#	    [\w-]+/[\w-]+				# content-type (any)
#	    |Disposition: (?>\s*)			# content-disposition hdr
#	    attachment)					# content-disposition
#	  ;(?>\s*)					# ; space or newline
#	  (?:file)?name=				# filename=/name=
#	  |begin (?>\s+) [0-7]{3,4} (?>\s+)) 		# begin octal-mode
#	  (\"[^\"]+\.					# quoted filename.
#		(?:ad[ep]				# list of extns
#		|ba[st]
#		|chm
#		|cmd
#		|com
#		|cpl
#		|crt
#		|eml
#		|exe
#		|hlp
#		|hta
#		|in[fs]
#		|isp
#		|jse?
#		|lnk
#		|md[be]
#		|ms[cipt]
#		|pcd
#		|pif
#		|reg
#		|scr
#		|sct
#		|shs
#		|url
#		|vb[se]
#		|ws[fhc])
#	  \"						# end quote
#	  )						# end of filename capture
#	  [\s;]						# trailing ;/space/newline

#
#
### [End]

[Actualización crítica] Elevación de privilegios en Exim 4.69-23


cPanel Admin ha informado de un fallo de seguridad en Exim 4.69-23 que permite la elevación de privilegios por parte de un usuario del sistema y ejecutar comandos como root. cPanel ha publicado ya un parche que podemos instalar utilizando la herramienta de upgrade de exim:

# /scripts/eximup

Para verificar la versión instalada de exim en el sistema:

# rpm -qa | grep -i exim

Se pueden ver los detalles de esta vulnerabilidad en este enlace.

Exim + cPanel: configurar IP de salida smtp por dominio


cPanel permite modificar la configuración de exim de tal manera que podamos especificar una IP de salida específica para un dominio en concreto. De este modo evitamos que aunque haya dominios con IP propia dentro de un hosting compartido, todos salgan a través de la misma IP por el protocolo SMTP.

Para especificar la IP de salida para el correo de un dominio en concreto, accederemos a WHM (pueto 2086) y entraremos en la sección de configuración de exim (Exim Configuration Editor). Una vez dentro, en la sección “Domains and IPs” encontramos lo siguiente:

Send outgoing mail from the ip that matches the domain name in /etc/mailips (*: IP can be added to the file to change the main outgoing interface).

Send outgoing mail from the ip that matches the domain name in /etc/mailips (*: IP can be added to the file to change the main outgoing interface).

Marcamos esa casilla y editamos el fichero indicado según nuestros requerimientos (/etc/mailips):

vim /etc/mailips

En nuestro caso usamos la IP 192.168.0.100 para la salida general de correo (todos los dominios) y la IP 192.168.0.111 para la salida de nuestro dominio test.com:

*:192.168.0.100
test.com: 192.168.0.111

Ahora nuestro dominio “test.com” usará su IP propia para el envío de correos en lugar de la IP compartida del servidor.

cPanel: Configurar exim en puerto alternativo


Son muchos los ISP (véase Telefónica por ejemplo) que aleatoriamente bloquean el puerto SMTP 25 a sus clientes debido a que desde sus IPs (habitualmente dinámicas) se realizan envíos de correo no solicitado (SPAM). Normalmente el cliente no es el culpable ya que hereda una IP con mala reputación.

Este problema impide que el cliente pueda enviar correos con cuentas externas a su ISP de forma correcta, provocando fallos en todas sus cuentas de correo. Los proveedores de Hosting llegados a este punto se pueden ver en la obligación de ofrecer al cliente puertos alternativos para el uso del correo electrónico.

La primera opción puede ser ofrecer el uso de SMTP seguro a través de puerto 465. Si tampoco es viable esta opción, en servidores con cPanel y Exim podemos habilitar de forma sencilla una nueva copia del servicio (tendríamos dos copias de Exim corriendo en un mismo servidor) en otro puerto, por ejemplo el 26.

Para ello accedemos a WHM vía web, a través del puerto 2086 o 2087 y accedemos a la sección Service Manager, donde encontraremos la opción de asignar un puerto alternativo a Exim, el que queramos:

Exim puerto alternativo

A partir de ese momento ya podremos ofrecer ese puerto alternativo a los clientes, verificadlo ejecutando un telnet contra el nuevo puerto:

$ telnet servidor 26
Trying xx.xx.xx.xx...
Connected to xx.xx.xx.xx.
Escape character is '^]'.
220-xx.xx.xx.xx ESMTP Exim x.xx #1 Sun, 04 Apr 2010 19:18:22 +0200
220-We do not authorize the use of this system to transport unsolicited,
220 and/or bulk e-mail.

Exim: retry time not reached for any host after a long failure period


En caso de encontrar este error en los logs de exim hay que conocer que son debidos a que el host al que hace referencia el error ha estado fallando gran cantidad de veces (normalmente 4 ó 5 días seguidos), y ha superado el límite de reintentos (retry).

En las FAQ de exim podéis ver la explicación:

This message means that all hosts to which the message could be sent have been failing for so long that the end of the retry period (typically 4 or 5 days) has been reached. In this situation, Exim still computes a next time to retry, but any messages that arrive in the meantime are bounced straight away. You can alter this behavior by unsetting the delay_after_cutoff option on the smtp transport. Then Exim will try most messages for those hosts once before giving up.”

A partir de este momento automáticamente exim rechazará enviar mensajes hacia dicho host. Esto queda guardado en la bd de exim. En caso de conocer que el problema con el servidor destino ha quedado resuelto, podemos vaciar esta base de datos para que exim vuelva a intentar enviar correos al mismo, para ello haced lo siguiente:

exim_tidydb -t 10m /var/spool/exim retry
exim_tidydb -t 10m /var/spool/exim wait-remote_smtp

Ya deberíais poder enviar al host implicado sin problemas.

Exim: User 0 set for local_delivery transport is on the never_users list


Cuando encontréis un error similar a este en los log de exim (exim_mainlog / exim_paniclog):

2009-02-20 05:13:10 15e8aa-4404Bm-Ql User 0 set for local_delivery transport is on the never_users list

Es debido a que se ha tratado de enviar un correo a un usuario añadido en el “never_users =” del fichero de configuración de exim (exim.conf).

Por ejemplo, normalmente root está añadido a never_users, de modo que si alguien intenta enviar un correo a root@maquina (root es el User 0 que sale en el log) ese email automáticamente será rechazado, mostrando la línea indicada anteriormente del log.

Si necesitáis esto activo, simplemente quitad a root del never_users, reiniciad exim y solucionado.

cPanel: Añadir una nueva RBL a Exim


Como ya sabréis, cPanel y su configurador de exim solamente permiten añadir las listas negras (RBL) r spamcop y spamhaus. Pues bien, podemos añadir las RBL que queramos del siguiente modo:

Las RBL y su configuración se guardan en la carpeta /usr/local/cpanel/etc/exim/acls/ACL_RBL_BLOCK:

#cd /usr/local/cpanel/etc/exim/acls/ACL_RBL_BLOCK
#ls -l
-rw-r--r-- 1  500  500  146 Sep  8 01:21 spamcop_rbl
-rw-r--r-- 1  500  500  158 Sep  8 01:21 spamhaus_rbl
-rw-r--r-- 1  500  500  175 Sep  8 01:21 spamhaus_spamcop_rbl

Una vez ahí, simplemente copiad uno de esos ficheros para después renombrarlo con el nombre de la RBL nueva. Posteriormente, editad el fichero y cambiad la dirección de las dnslists por la de la nueva RBL, en el siguiente caso cambiariamos “bl.spamcop.net” por la nueva RBL:

# cat spamcop_rbl

 deny message = JunkMail rejected - $sender_fullhost is in an RBL, see $dnslist_text
     dnslists = bl.spamcop.net
     hosts = +backupmx_hosts 

 warn
     dnslists = bl.spamcop.net
     set acl_m8 = 1
     set acl_m9 = "JunkMail rejected - $sender_fullhost is in an RBL, see $dnslist_text"
     [% ACL_RBL_WHITELIST %]

 warn
     condition = ${if eq {${acl_m8}}{1}{1}{0}}
     ratelimit = 0 / 1h / strict / per_conn
     log_message = "Increment Connection Ratelimit - $sender_fullhost because of RBL match"

 drop
     condition = ${if eq {${acl_m8}}{1}{1}{0}}
     message = ${acl_m9}

Finalmente ejecuta:

/scripts/buildeximconf