Páginas

domingo, 5 de mayo de 2013

Filtrado de IPs "unknown" para Zimbra


Para iniciar la creación de un script lo que primero debemos tener es una necesidad, pues este era mi caso, yo necesitaba mejorar el filtrado de spam en el servidor de correo de la compañía... "El filtrado que trae Zimbra CS es bastante bueno, pero yo quería hacer lo mucho mejor".

Realmente lo que quería hacer era bloquear todo origen de correo que no se pudiera resolver correctamente por medio de los PTR, cuando un MTA no logra hacer una buena resolución inversa del origen de correo lo marca como "unknown", suponemos entonces que NO es un origen confiable de correo ó que el servicio de correo no esta bien configurado.

Como este no es un blog para hablar de Zimbra, postfix, ni correo en general, no entrare en detalles de la configuración, solo voy a mostrar como por medio de bashscript cree no solo la lista de IPs a bloquear, si no que también como cree otro script para limpiar los falsos positivos.

Nota: El script "spammers.sh" como yo lo llamo, esta basado en una solución propuesta por Riaan Pretorius colaborador de zimbra.com, yo solo lo adapte a mi necesidad.

Primer Script: spammers.sh


export LANG=C # Adds execution speed

LOG="/var/log/maillog"
TMP_SPAMMERS="/opt/zimbra/conf/postfix_rbl_ip_spammers.tmp"
TMP_LOG1="/opt/zimbra/conf/postfix_rbl_ip_spammers.log1"
TMP_LOG2="/opt/zimbra/conf/postfix_rbl_ip_spammers.log2"
SPAMMERS="/opt/zimbra/conf/postfix_rbl_ip_spammers"
WHITELIST="/opt/zimbra/conf/postfix_rbl_ip_whitelist"

awk '/ connect from/ {print $8}' $LOG | \
grep unknown | \
awk '{print $1}' | \
cut -d[ -f2 | cut -d] -f1 | \

while read ip ; do
    host $ip > /dev/null 2>&1;\
    if [ $? -ne 0 ] ; echo "$ip         REJECT" >> $TMP_SPAMMERS; then
        echo "$ip";
    fi;
done

cat $TMP_SPAMMERS | sort | uniq | grep -v -f $WHITELIST > $TMP_LOG1
cat $TMP_LOG1 $SPAMMERS > $TMP_LOG2
cat $TMP_LOG2 | sort | uniq | grep -v -f $WHITELIST > $SPAMMERS
rm -f $TMP_LOG1 $TMP_LOG2 $TMP_SPAMMERS
su - -c "postmap $SPAMMERS" zimbra
su - -c "zmmtactl restart" zimbra


En este script se hace uso de variables, awk (pattern scanning and processing language), grep (print lines matching a pattern), sort (sort lines of text files), uniq (report or omit repeated lines) y cut (remove sections from each line of files) para obtener la IP a bloquear, todo esto por medio de un bucle con "while". Luego de determinar la IP procedemos a registrarla en los diferentes archivos de configuración.

Este proceso tienen  una falencia y es que muchos servidores de correo no están bien configurados o por lo menos sus registros DNS, así que llegamos al punto de los falsos positivos. Aquí era necesario tener un procedimiento para limpiar de los db de postfix las IPs que eran orígenes correctos y agregarlos a listas blancas, así empece con "whitelist.sh" en colaboración con +Víctor Daniel .

Segundo Script: whitelist.sh


#   Usage: whitelist [options]
#
#  Options:
#    <arg>            DOMINIO ó MAIL
#    --help           This help message

EXPECTED_MIN_ARGS=1
EXPECTED_MAX_ARGS=1
E_BADARGS=65
E_NOROOT=1
BASE_NAME=`basename $0`

if [[ $# -gt $EXPECTED_MAX_ARGS ]] ||
   [[ $# -lt $EXPECTED_MIN_ARGS ]] ||
   [[ $1 == "--help" ]] ; then
  echo "Usage: $BASE_NAME <arg>" 1>&2
  echo "Usage: $BASE_NAME --help" 1>&2
  exit $E_BADARGS
fi

if [ "$(id -u)" != "0" ]; then
   echo "$BASE_NAME: This script must be run as root." 1>&2
   exit $E_NOROOT
fi

LOCK_FILE="/var/lock/whitelist"
ULIMIT_N=`ulimit -n`
let "FLOCK_FD = ULIMIT_N - 1"
START_DATE=`date`
ERROR_EXIT="1"

(
  eval "exec $FLOCK_FD<> $LOCK_FILE"
  if flock -n $FLOCK_FD ; then
# flock START

Slog="/var/log/maillog"
PostPath="/opt/zimbra/conf"
DBSpammers="postfix_rbl_ip_spammers.db"
FSpammers="postfix_rbl_ip_spammers"
FWhitelist="postfix_rbl_ip_whitelist"
IP=`grep $1 $Slog | grep -m 1 -E 'rejected: Access denied' | awk '{print $10}' | cut -d[ -f2 | cut -d] -f1`
 
# 1. buscar bloqueado - recibe parametro "arg" (email ó dominio).
# Ejemplo de log:
# Mar  8 06:22:32 mail postfix/smtpd[12196]: NOQUEUE: reject:
# RCPT from unknown[201.230.203.167]: 554 5.7.1 <unknown[201.230.203.167]>:
# Client host rejected: Access denied; from=<diplomadosprogramas8@yahoo.es>
# to=<info@summan.com> proto=SMTP helo=<192.168.1.20>
function SearchArgument(){
    if [[ $IP != "" ]]; then
        echo $IP
        return 0
    else
        echo "Argumento no encontrado!"
    fi
    return 1
}

# 2. busca la ip correspondiente al domino encontrado en la base de datos
# de spammers. "/opt/zimbra/conf/postfix_rbl_ip_spammers", y la borra.
function DeleteIPFSpammers() {
    sed '/^'$IP'/d' $PostPath/$FSpammers > $PostPath/fspam.tmp
    cat $PostPath/fspam.tmp > $PostPath/$FSpammers
    rm -f $PostPath/fspam.tmp
}

# 3. agrega la ip en la base de datos postfix_rbl_whitelist.
function AddIPWhitelist() {
    echo $IP >> $PostPath/$FWhitelist
}

# 4. regenera la base de datos de spammers
# "postmap /opt/zimbra/conf/postfix_rbl_ip_spammers".
function ReloadDBSpammers() {
    su - zimbra -c "rm -f $PostPath/$DBSpammers"
    su - zimbra -c "postmap $PostPath/$FSpammers"
}

# 5. recargar la base de datos "zmmtactl restart"
function RestartMta() {
    su - zimbra -c "zmmtactl restart"
}

function DeleteLock() {
    rm -f $LOCK_FILE
}


if SearchArgument ; then
   echo "Procesando dominio $1 con la IP: $IP"
   DeleteIPFSpammers
   AddIPWhitelist
   ReloadDBSpammers
   RestartMta
   DeleteLock
else
   echo "Argumento $1 no encontrado!"
fi

# flock END
  else
    echo "$BASE_NAME: Another instance is currently running."
  fi
)

Código fuente: spammers.sh whitelist.sh

En este script utilice un poco de expresiones regulares, funciones como le llama mi compañero +Víctor Daniel "El segundo nivel de bash", condicionales  etc. La forma de utilizarlo es ejecutando y entregando el argumento a utilizar, como por ejemplo dominio ó email.

Espero que a alguien le sirva estos scripts o le ayuden a construir otros, si tiene alguna sugerencia de como mejorarlos por favor dejen sus comentarios.

No hay comentarios.:

Publicar un comentario