Sendmail, Dovecot, SpamAssassin, Rainloop, Sieve, OpenDKIM, SPF, DMARC en FreeBSD


En este artículo aprenderemos como montar un sistema de emails completo, podremos enviar/recibir emails, acceder mediante interfaz web, filtrar spam, definir filtros Sieve y firmar los emails salientes mediante DKIM, las tecnologías utilizadas para ello son:

  • Sendmail: Envía y recibe emails
  • Dovecot: Permite el acceso a los emails almacenados desde la interfaz web
  • SpamAssassin: Filtra los emails entrantes en base a unas reglas determinadas
  • Rainloop: Interfaz web de acceso a los emails
  • Sieve: Sistema de filtrado/categorización de emails

 

Este artículo es bastante extenso y se compone de varias partes:


Sendmail:

El primer paso será aseguramos de que nuestro servidor conozca su propio hostname:

vi /etc/hosts
127.0.0.1        DrWho.alfaexploit.com localhost localhost.my.domain DrWho

Sendmail viene instalado por defecto en FreeBSD, arrancamos el servicio:

sysrc sendmail_enable=yes
sysrc sendmail_msp_queue_enable=yes
service sendmail start

Comprobamos que podamos acceder por red:

telnet X.X.X.X 25
220 DrWho.alfaexploit.com ESMTP Sendmail 8.15.2/8.15.2; Thu, 19 Mar 2020 22:11:58 +0100 (CET)

En el magnífico handbook de FreeBSD podemos encontrar una guía muy útil de la cual he extraído la siguiente información.

Los permisos de acceso se filtran por origen en el fichero: /etc/mail/access

OK: Permitiremos la entrada del mail siempre y cuando el destino sea un dominio local(/etc/mail/local-host-names)
RELAY: Permitiremos el envío de mails a dominios de terceros a través de nuestro server
ERROR: Denegaremos el envío de mails con el mensaje indicado
SKIP: Denegaremos el envío de mails sin avisar al cliente que el email ha sido destruido
QUARANTINE: El mail se guardará en el servidor local pero no se enviará a su destino, el cliente recibirá una explicación de porque su email ha sido retenido

#From:cyberspammer.com          ERROR:"550 We don't accept mail from spammers"
#From:okay.cyberspammer.com     OK
#Connect:sendmail.org           RELAY
#To:sendmail.org                RELAY
#Connect:128.32                 RELAY
#Connect:128.32.2               SKIP
#Connect:IPv6:1:2:3:4:5:6:7     RELAY
#Connect:suspicious.example.com QUARANTINE:Mail from suspicious host
#Connect:[127.0.0.3]            OK
#Connect:[IPv6:1:2:3:4:5:6:7:8] OK

Pode defecto se aplica la política de OK si el destino es local o está listado en /etc/mail/local-host-names

Por ejemplo si intentamos enviar un email a kr0m@alfaexploit.com nos denegará el acceso pero para kr0m@localhost lo permitirá:

telnet X.X.X.X 25
Trying X.X.X.X...
Connected to X.X.X.X.
Escape character is '^]'.
220 DrWho.alfaexploit.com ESMTP Sendmail 8.15.2/8.15.2; Thu, 19 Mar 2020 22:11:58 +0100 (CET)
ehlo Y.Y.Y.Y
250-DrWho.alfaexploit.com Hello [Y.Y.Y.Y], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-STARTTLS
250-DELIVERBY
250 HELP
mail from: test@kr0m.com
250 2.1.0 test@kr0m.com... Sender ok
rcpt to: kr0m@alfaexploit.com
550 5.7.1 kr0m@alfaexploit.com... Relaying denied. IP name lookup failed [Y.Y.Y.Y]
rcpt to: kr0m@localhost
250 2.1.5 kr0m@localhost... Recipient ok
data
354 Enter mail, end with "." on a line by itself
AA
.
250 2.0.0 02JGtpI9012050 Message accepted for delivery
quit
221 2.0.0 DrWho.alfaexploit.com closing connection
Connection closed by foreign host.

El usuario kr0m puede leer el mail recibido:

mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/mail/kr0m": 1 message 1 new
>N  1 test@kr0m.com         Thu Mar 19 17:56  13/437 
&
Message 1:
From test@kr0m.com Thu Mar 19 17:56:29 2020
Date: Thu, 19 Mar 2020 17:55:51 +0100 (CET)
From: test@kr0m.com
To: undisclosed-recipients:;
AA
&

Añadimos alfaexploit.com al grupo de dominios locales:

vi /etc/mail/local-host-names
alfaexploit.com

Regeneramos el hash del fichero:

makemap hash /etc/mail/access < /etc/mail/access
service sendmail restart

Volvemos a realizar la prueba:

telnet X.X.X.X 25
Trying X.X.X.X...
Connected to X.X.X.X.
Escape character is '^]'.
220 DrWho.alfaexploit.com ESMTP Sendmail 8.15.2/8.15.2; Thu, 19 Mar 2020 22:11:58 +0100 (CET)
ehlo Y.Y.Y.Y
250-DrWho.alfaexploit.com Hello [Y.Y.Y.Y], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-STARTTLS
250-DELIVERBY
250 HELP
mail from: test@kr0m.com
250 2.1.0 test@kr0m.com... Sender ok
rcpt to: kr0m@alfaexploit.com
250 2.1.5 kr0m@alfaexploit.com... Recipient ok
data
354 Enter mail, end with "." on a line by itself
BB
.
250 2.0.0 02JH0o7r071431 Message accepted for delivery
quit
221 2.0.0 DrWho.alfaexploit.com closing connection
Connection closed by foreign host.

Leemos el mail:

mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/mail/kr0m": 1 message 1 new
>N  1 test@kr0m.com         Thu Mar 19 18:03  13/443 
&
Message 1:
From test@kr0m.com Thu Mar 19 18:03:46 2020
Date: Thu, 19 Mar 2020 18:03:35 +0100 (CET)
From: test@kr0m.com
To: undisclosed-recipients:;
BB
&

NOTA: Al meter el dominio alfaexploit.com en local-host-names es equivalente a haber creado las cuentas de email a partir de todos los usuarios que hay en el sistema operativo, para entornos mas grandes deberiamos buscar algún tipo de integración de usuarios virtuales a partir de una base de datos MySQL, LDAP o similar.

El fichero aliases define direcciones de correo que expanden a otros usuarios, direcciones externas, ficheros, programas u otros alias, en mi caso lo dejamos como viene por defecto pero root será un alias a kr0m@alfaexploit.com:

vi /etc/mail/aliases
MAILER-DAEMON: postmaster
postmaster: root
_dhcp:    root
_pflogd: root
auditdistd:    root
bin:    root
bind:    root
daemon:    root
games:    root
hast:    root
kmem:    root
mailnull: postmaster
man:    root
news:    root
nobody:    root
operator: root
pop:    root
proxy:    root
smmsp:    postmaster
sshd:    root
system:    root
toor:    root
tty:    root
usenet: news
uucp:    root
abuse:    root
security:    root
ftp:         root
ftp-bugs:     ftp
root: kr0m@alfaexploit.com

Regeneramos el hash del fichero:

newaliases

Para realizar la conversión de una dirección de email a un mailbox utilizaremos el fichero virtusertable, el destino pueden ser mailboxes locales, mailboxes remotos, alias definidos en /etc/mail/aliases, o ficheros. En mi caso no es necesario tocarlo.

root@example.com                root
postmaster@example.com          postmaster@noc.example.net
@example.com                    joe

NOTA: Las entradas se comprueban en el orden en el que se encuentran en el fichero de configuración, en este ejemplo se ha configurado una entrada genérica para el dominio example.com, si el destinatario es cualquier distinto de root o postmaster se enviará a joe.

Regeneramos el hash del fichero y reiniciamos Sendmail:

makemap hash /etc/mail/virtusertable < /etc/mail/virtusertable
service sendmail restart

Si necesitamos que algún equipo externo pueda utilizar nuestro servidor para enviar emails debemos indicar las ips/dns en el fichero relay-domains, en mi caso no es necesario:

vi /etc/mail/relay-domains
service sendmail restart

Dovecot:

Con Sendmail podremos enviar y recibir emails pero no leer los recibidos, para ello necesitamos un servidor IMAP:

pkg install dovecot

Copiamos los ficheros de configuración de ejemplo:

cd /usr/local/etc/dovecot
cp -R example-config/* ./

Eliminamos la configuración SSL ya que accederemos a los emails por interfaz web, el único punto de contacto con el exterior será a través de Sendmail para enviar/recibir emails.

vi /usr/local/etc/dovecot/conf.d/10-ssl.conf
ssl = no

La interfaz web solo accede a Dovecot vía IMAP:

vi /usr/local/etc/dovecot/dovecot.conf
protocols = imap lmtp

Bindeamos Dovecot a la ip del servidor:

vi /usr/local/etc/dovecot/dovecot.conf
listen = X.X.X.X

Le indicamos a Dovecot donde debe buscar los emails recibidos:

vi /usr/local/etc/dovecot/conf.d/10-mail.conf
mail_location = mbox:~/mboxDir:INBOX=/var/mail/%u
mail_privileged_group = mail

Ajustamos los permisos del directorio /var/mail:

chmod a+rwxt /var/mail

Creamos los directorios de email en el home del usuario:

su -l kr0m
touch mboxDir/Sent
touch mboxDir/Drafts
touch mboxDir/Spam
touch mboxDir/Trash
touch mboxDir/Archive
chmod 600 mboxDir/Sent
chmod 600 mboxDir/Drafts
chmod 600 mboxDir/Spam
chmod 600 mboxDir/Trash
chmod 600 mboxDir/Archive
exit

Arrancamos el servicio:

sysrc dovecot_enable=yes
service dovecot start

Rainloop:

Instalamos Rainloop, una interfaz web que nos permitirá leer y enviar emails:

pkg install -y unzip curl wget socat
pkg install -y php74 php74-mbstring php74-tokenizer php74-pdo php74-pdo_mysql php74-openssl php74-json php74-phar php74-filter php74-zlib php74-dom php74-xml php74-xmlwriter php74-xmlreader php74-pecl-imagick php74-curl php74-session php74-ctype php74-iconv php74-gd php74-simplexml php74-zip php74-filter php74-tokenizer php74-calendar php74-fileinfo php74-intl php74-phar php74-soap php74-xmlrpc php74-opcache php74-mysqli php74-bcmath php74-gmp
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

Ajustamos algunos parámetros en el php.ini para poder enviar adjuntos de mayor tamaño:

vi /usr/local/etc/php.ini
date.timezone = Europe/Madrid
upload_max_filesize = 25M
post_max_size = 25M

Arrancamos el servicio php-fpm:

sysrc php_fpm_enable=yes
service php-fpm start

Instalamos un MySQL para poder almacenar los contactos del usuario:

pkg install -y mysql80-server

Arrancamos el servicio:

sysrc mysql_enable=yes
service mysql-server start

Configuramos la base de datos:

mysql_secure_installation

Creamos la base de datos y un usuario con acceso a esta:

mysql
CREATE DATABASE rainloop;
CREATE USER rainloop@'X.X.X.X' IDENTIFIED WITH mysql_native_password BY 'ZZZZZZZZZZ';
GRANT ALL PRIVILEGES ON rainloop.* TO rainloop@'X.X.X.X';
FLUSH PRIVILEGES;
exit;

Instalamos Nginx:

pkg install -y nginx

Arrancamos el servicio:

sysrc nginx_enable=yes
service nginx start

Creamos un vhost para Rainloop:

vim /usr/local/etc/nginx/rainloop.conf
server {

  listen 80;
  server_name mail.alfaexploit.com;

  root /usr/local/www/rainloop;

  index index.php;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  location ^~ /data {
     deny all;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_keep_conn on;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass 127.0.0.1:9000;
  }
  
}

Incluimos el vhost en la configuración general de Nginx, añadimos el include y aumentamos el máximo del tamaño del body en la sección http{}:

vi /usr/local/etc/nginx/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    client_max_body_size 25M;
    include rainloop.conf;

Reiniciamos el servicio:

service nginx reload

Nos bajamos e instalamos Rainloop:

mkdir -p /usr/local/www/rainloop
cd /usr/local/www/rainloop
wget http://www.rainloop.net/repository/webmail/rainloop-latest.zip
unzip rainloop-latest.zip -d /usr/local/www/rainloop
rm rainloop-latest.zip
chown -R www:www /usr/local/www/rainloop

Accedemos al panel de administración:

http://mail.alfaexploit.com/?admin
admin
12345

Lo primero será cambiar el password

Configuramos el acceso a la base de datos donde se guardarán los contactos del usuario:

Contacts -> MySQL:
mysql:host=X.X.X.X;port=3306;dbname=rainloop
rainloop
ZZZZZZZZZZZZZZZZZ

Le damos al botón Test para comprobar el correcto acceso.

Añadimos el dominio:

Domains -> alfaexploit.com
IMAP
X.X.X.X
143
SMTP
X.X.X.X
25
Use short login

NOTA: Use short login -> Necesario ya que estamos utilizando los usuarios del sistema(pam) y estos no tienen @alfaexploit.com

Accedemos a la cuenta de email como usuario:

http://mail.alfaexploit.com
kr0m
PASSWORDSO

Configuramos los directorios donde guardar los emails:

Ruedecita dentada de abajo -> Folders
System Folders

Asignamos el directorio a cada Folder, Deleted items y Junk emails podemos darle al ojo para que no salgan.

Realizamos pruebas de envío y recepción de emails y consultamos los logs asociados:

tail -f /var/log/maillog

Sieve es un servicio de clasificación de emails, mediante filtros definidos por el sysadmin/usuario se pueden catalogar los emails entrantes, por ejemplo en base a ciertas cabeceras, origenes, esto resulta muy útil si combinamos Spamassassin con Sieve ya que Spamassassin nos marcará los emails con sus cabeceras y mediante Sieve filtraremos en base a estas.

Spamassassin:

Instalamos el milter de Spamassassin:

pkg install -y spamass-milter

Habilitamos el servicio spamd indicándole desde que ips aceptará conexiones, en este caso la propia ip del servidor:

sysrc spamd_enable="YES"
sysrc spamd_flags="-u spamd -H /var/spool/spamd -A X.X.X.X"

Habilitamos el milter indicándole donde debe generar el socket Unix:

sysrc spamass_milter_enable="YES"
sysrc spamass_milter_socket="/var/run/spamass-milter.sock"

El resto de opciones que podríamos configurar los podemos ver en:

cat /usr/local/etc/rc.d/spamass-milter
: ${spamass_milter_enable="NO"}
: ${spamass_milter_socket="/var/run/spamass-milter.sock"}
: ${spamass_milter_flags="-f -p ${spamass_milter_socket} ${spamass_milter_localflags}"}
: ${spamass_milter_socket_owner="root"}
: ${spamass_milter_socket_group="wheel"}
: ${spamass_milter_socket_mode="644"}

Actualizamos las reglas de SpamAssassin y las compilamos:

sa-update
sa-compile

Arrancamos Spamassassin y Spamassassin-milter:

service sa-spamd start
service spamass-milter start

Generamos un fichero base de configuración para Sendmail:

cd /etc/mail/
make

El comando anterior habrá generado un fichero con el nombre del host, definimos el milter al final del fichero:

vi DrWho.alfaexploit.com.mc
INPUT_MAIL_FILTER(`spamassassin', `S=local:/var/run/spamass-milter.sock, F=, T=C:15m;S:4m;R:4m;E:10m')
define(`confINPUT_MAIL_FILTERS', `spamassassin')

Compilamos a M4 la nueva configuración:

make

Actualizamos la configuración de Sendmail con la nuestra:

cp sendmail.cf sendmail.cf.ori
cp DrWho.alfaexploit.com.cf sendmail.cf

Reiniciamos el servicio:

service sendmail restart

Ponemos un tail para ver los logs:

tail -f /var/log/maillog

Nos enviamos un email y podemos ver en los logs como spamd intercepta el email entrante y le asigna una puntuación:

Mar 25 20:54:03 DrWho spamd[75380]: spamd: connection from X.X.X.X [X.X.X.X]:53024 to port 783, fd 5 
Mar 25 20:54:03 DrWho spamd[75380]: spamd: processing message <CAO=uDhoZ80Of3F9L4E1reooE01PnacCnZNnYoxBAaUA1hqV41A@mail.gmail.com> for root:58 
Mar 25 20:54:05 DrWho spamd[75380]: spamd: clean message (1.0/5.0) for root:58 in 1.2 seconds, 2362 bytes. 
Mar 25 20:54:05 DrWho spamd[75380]: spamd: result: . 0 - BODY_SINGLE_WORD,DKIM_INVALID,DKIM_SIGNED,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS scantime=1.2,size=2362,user=root,uid=58,required_score=5.0,rhost=X.X.X.X,raddr=X.X.X.X,rport=53024,mid=<CAO=uDhoZ80Of3F9L4E1reooE01PnacCnZNnYoxBAaUA1hqV41A@mail.gmail.com>,autolearn=no autolearn_force=no

Si miramos el email en raw veremos las cabeceras añadidas por Spamassassin:

X-Spam-Status: No, score=1.0 required=5.0 tests=BODY_SINGLE_WORD,DKIM_INVALID,
    DKIM_SIGNED,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no
    autolearn_force=no version=3.4.3
X-Spam-Checker-Version: SpamAssassin 3.4.3 (2019-12-06) on
    DrWho.alfaexploit.com

NOTA: Si queremos marcar como Spam un dominio o dirección en concreto añadimos al final del fichero local.cf de Spamassassin:

vi /usr/local/etc/mail/spamassassin/local.cf
blacklist_from *@126.com
blacklist_from hacker@xxxxxxx.com

Reiniciamos el servicio:

service sa-spamd restart

Ahora que ya marcamos nuestros emails habrá que catalogarlos según la reputación asignada por Spamassassin, para ello emplearemos Sieve que nos permitirá configurar filtros en base a multitud de aspectos sobre el email, pero para poder utilizarlo debemos hacer que Sendmail entregue los mails locales vía  LMTP a Dovecot:

cd /etc/mail/
vi DrWho.alfaexploit.com.mc

Sustitumos:

FEATURE(local_lmtp)

Por:

FEATURE(local_lmtp,`[IPC]',`FILE /var/run/dovecot/lmtp')dnl

Recompilamos la configuración:

make

Sustituimos la configuración actual por la nuestra:

cp DrWho.alfaexploit.com.cf sendmail.cf

Reiniciamos el servicio:

service sendmail restart

Instalamos el paquete necesario para que Dovecot soporte Sieve:

pkg install -y dovecot-pigeonhole

Lo habilitamos como protocolo:

vi /usr/local/etc/dovecot/dovecot.conf
protocols = imap lmtp sieve

Y como pulgin LMTP:

vi /usr/local/etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
  mail_plugins = $mail_plugins sieve
}

En la configuración de plugins configuramos donde se almacenarán los filtros Sieve de los usuarios y que filtro se debe aplicar, además indicamos un filtro que siempre se ejecutará antes que los definidos por el usuario, ideal para que los sysadmins puedan realizar sus filtrados pre-user:

vi /usr/local/etc/dovecot/conf.d/90-plugin.conf
plugin {
    sieve = file:~/.sieve;active=~/.sieve/dovecot.sieve
    sieve_before = file:/var/lib/dovecot/default.sieve
}

Cuando se programan scripts en Sieve se debe indicar arriba del todo las librerias que requiere y luego ya hacer uso de ellas en el resto de script:

mkdir /var/lib/dovecot
vi /var/lib/dovecot/default.sieve
require ["fileinto"];
  
if header :contains "X-Spam-Flag" "YES" {
    fileinto "Spam";
    stop;
}

Compilamos el script:

sievec /var/lib/dovecot/default.sieve

Creamos el directorio de los scripts Sieve en el home del usuario:

su -l kr0m
mkdir /home/kr0m/.sieve
exit

Comprobamos que el módulo LMTP de Dovecot haya cargado el plugin Sieve:

doveconf -f service=lmtp mail_plugins
mail_plugins =  sieve

Nos conectamos manualmente al Sieve-manager:

telnet 127.0.0.1 4190
Trying 127.0.0.1...
Connected to DrWho.alfaexploit.com.
Escape character is '^]'.
"IMPLEMENTATION" "Dovecot Pigeonhole"
"SIEVE" "fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext"
"NOTIFY" "mailto"
"SASL" "PLAIN"
"STARTTLS"
"VERSION" "1.0"
OK "Dovecot ready."

Ya debería de ejecutarse el script sieve_before(/var/lib/dovecot/default.sieve) que mueve los emails marcados como spam por Spamassassin al directorio Spam.

Accedemos al panel de administración de Rainloop y habilitamos el Sieve para nuestro dominio:

http://mail.alfaexploit.com/?admin
admin
ZZZZZZZZZZZ
Domains -> alfaexploit.com

Sieve configuration:
Allow sieve scripts
Allow custom user script
Server: X.X.X.X Port: 4190
Secure: None

Clickamos sobre el botón Update.

Accedemos con la cuenta de usuario normal y configuramos un filtro:

Configuración -> Filters

NOTA: Debemos filtrar el tráfico de red mediante firewall para evitar accesos no autorizados a los servicios de Sieve(4190)/Spamassassin(783)


SPF:

Mediante SPF indicaremos que servidores están autorizados a enviar emails de nuestro dominio, esto no es mas que unas entradas DNS indicando las ips, en mi caso quedaría del siguiente modo.

A 92.176.161.228 mail.alfaexploit.com
MX mail.alfaexploit.com
TXT spf2.0/mfrom,pra ip4:92.176.161.228 -all
TXT v=spf1 mx -all

NOTA: La primera entrada es una entrada simple A resolviendo mail.alfaexploit.com a la ip, la segunda indica que servidor(MX) es el encargado de recibir emails, la tercera indica que ip está autorizada a enviar email para el dominio y la cuarte hace lo mismo que la tercera, pero se trata de spf1, en spf1 se puede indicar que se permita la ip del servidor indicado en el registro MX del dominio.

SPF soporta dos tipos de fails:

  • hardfails: Cualquier email que provenga de una ip no permitida se eliminará, este comportamiento se indica al meter -all en la entrada DNS.
  • softfail: Cualquier email que provenga de una ip no permitida se marcará como Spam, este comportamiento se indica al meter ~all en la entrada DNS.

Comprobamos que todas las entradas resuelvan como es debido:

dig mx alfaexploit.com +short
0 mail.alfaexploit.com.
dig mail.alfaexploit.com +short
92.176.161.228
dig txt alfaexploit.com +short
"spf2.0/mfrom,pra ip4:92.176.161.228 -all"
"v=spf1 mx -all"

DKIM:

Mediante DKIM seremos capaces de firmar los emails salientes con una clave privada de este modo el receptor podrá verificar que el email fué enviado desde nuestro servidor y no desde otro haciéndose pasar por nosotros, la clave de este proceso consiste en publicar la pubkey en una entrada DNS para que el receptor pueda obtenerla y comprobar así la autenticidad del email.

Instalamos el milter Opendkim:

pkg install -y opendkim

Habilitamos el servicio:

sysrc milteropendkim_enable=yes

Generamos la pareja private-key/pub-key:

mkdir /var/db/dkim
cd /var/db/dkim
opendkim-genkey -s smtp -d alfaexploit.com

NOTA: El parámetro -s smtp no es mas que el selector, se trata del un string con el que se tendrá que realizar la query DNS para obtener el valor de la pubkey.

La configuración de Opendkim quedaría del siguiente modo:

vi /usr/local/etc/mail/opendkim.conf
Domain          alfaexploit.com
KeyFile         /var/db/dkim/smtp.private
InternalHosts   /var/db/dkim/internal_hosts
Selector        smtp
Socket          local:/var/run/milteropendkim/milter-opendkim.sock
Syslog          Yes

Definimos que ips podrán conectar al milter, en mi caso la ip del propio servidor:

vi /var/db/dkim/internal_hosts
X.X.X.X

Arrancamos el servicio:

service milter-opendkim start

Configuramos Sendmail para que haga uso del milter nuevo:

cd /etc/mail
vi DrWho.alfaexploit.com.mc
MAIL_FILTER(`spamassassin', `S=local:/var/run/spamass-milter.sock, F=, T=C:15m;S:4m;R:4m;E:10m')
MAIL_FILTER(`dkim-filter', `S=/var/run/milteropendkim/milter-opendkim.sock, F=T, T=R:2m')
define(`confINPUT_MAIL_FILTERS', `spamassassin, dkim-filter')

Compilamos  y actualizamos la configuración:

make
cp DrWho.alfaexploit.com.cf sendmail.cf

Reiniciamos el servicio:

service sendmail restart

Si enviamos un email veremos que salen firmados.

DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alfaexploit.com;
    s=smtp; t=1585239682;
    bh=Ndt8L6xRegVJ+RtO9stJroY3XjqvRcO4y5DUvtnndrU=;
    h=Date:From:Subject:To;
    b=SRUc+Zz2T8p4+Z64o2Lediy80caQNTzztgzsLwxTd0nXrQmmt4wtyLvL7T16KNkQf
     NH4UMVyXXkz5+LNAagNUkgGjezv6Whfa2zF9Ms+f0ElBcjGySQo5BDvOc2JbO2Zpx8
     zKLDcIzncQFmUaKrYZdLEv+bBL2Stz5C7Y5OzpwI=

Pero debemos publicar nuestra pubkey en Internet para que los servidores que reciban los emails nuestros puedan comprobar que la firma del email se generó con la private key correspondiente a la pubkey publicada:

cat /var/db/dkim/smtp.txt
smtp._domainkey    IN    TXT    ( "v=DKIM1; k=rsa; "
      "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6l6oAODR0hUzsHqb2StBHVKlXdemKhbRNaCNDdoqMH9yi7TOfYeO4Ko5Wnp4Gq449ur8h14Afvgji24DC6GCBNbHCcDh67M9HZW28BJPRoaaIInQHzt5+9oVa9BREliNa50gfbwmNS/WnrZ6o3X94xCCbb6xcdQJC6FCrGoyMQIDAQAB" )  ; ----- DKIM key smtp for alfaexploit.com

El registro TXT tendrá el siguiente contenido:

v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6l6oAODR0hUzsHqb2StBHVKlXdemKhbRNaCNDdoqMH9yi7TOfYeO4Ko5Wnp4Gq449ur8h14Afvgji24DC6GCBNbHCcDh67M9HZW28BJPRoaaIInQHzt5+9oVa9BREliNa50gfbwmNS/WnrZ6o3X94xCCbb6xcdQJC6FCrGoyMQIDAQAB

La entrada DNS final debe contener el selector(smtp):

TXT smtp._domainkey v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6l6oAODR0hUzsHqb2StBHVKlXdemKhbRNaCNDdoqMH9yi7TOfYeO4Ko5Wnp4Gq449ur8h14Afvgji24DC6GCBNbHCcDh67M9HZW28BJPRoaaIInQHzt5+9oVa9BREliNa50gfbwmNS/WnrZ6o3X94xCCbb6xcdQJC6FCrGoyMQIDAQAB

Si consultamos la entrada nos devuelve la pubkey configurada:

dig TXT smtp._domainkey.alfaexploit.com +short
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6l6oAODR0hUzsHqb2StBHVKlXdemKhbRNaCNDdoqMH9yi7TOfYeO4Ko5Wnp4Gq449ur8h14Afvgji24DC6GCBNbHCcDh67M9HZW28BJPRoaaIInQHzt5+9oVa9BREliNa50gfbwmNS/WnrZ6o3X94xCCbb6xcdQJC6FCrGoyMQIDAQAB"

DMARK:

DMARK son unos registros DNS donde indicamos a los servidores que reciben emails que deben hacer con este cuando el email entrante no supere el SPF/DKIM. Por supuesto cada ISP luego puede respetar lo indicado en el DMARK o no.

TXT _dmarc.alfaexploit.com
v=DMARC1\; p=reject\; rua=mailto:kr0m@alfaexploit.com\; ruf=mailto:kr0m@alfaexploit.com\; pct=100

Diseccionemos cada uno de los campos:

  • v: Versión del protocolo
  • p: Indica la política DMARC a seguir
  • rua: Donde se enviarán las notificaciones cuando se reciba un email que no supere el SPF/DKIM
  • ruf: Donde se enviará una copias de los emails-spam cuando se reciba un email que no supere el SPF/DKIM
  • pct: A que % de los emails recibidos se le debe aplicar el filtro DMARC

Las posibles políticas son:

  • none: Tratar el email sin aplicar DMARC
  • quarantine: Aceptar el email pero tratarlo como Spam
  • reject: Rechazar el email

Comprobamos que el registro DNS responda con la información correcta:

dig TXT _dmarc.alfaexploit.com +short
"v=DMARC1; p=reject; rua=mailto:kr0m@alfaexploit.com; ruf=mailto:kr0m@alfaexploit.com; pct=100"

Podemos ver como Google da por buenas las tres comprobaciones:


SSL Rainloop:

Si vamos a acceder a la interfaz del Rainloop desde Internet mas vale hacerlo por SSL, para ello conseguiremos un certificado SSL y reconfiguraremos Nginx:

vi /usr/local/etc/nginx/rainloop.conf
server {

  listen X.X.X.X:443 ssl  default_server;
  server_name  mail.alfaexploit.com;

  root /usr/local/www/rainloop;
  
  ssl_certificate "/usr/local/etc/ssl/alfaexploit.com/fullchain.cer";
  ssl_certificate_key "/usr/local/etc/ssl/alfaexploit.com/alfaexploit.com.key";

  index index.php;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  location ^~ /data {
     deny all;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_keep_conn on;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass 127.0.0.1:9000;
  }
  
}

Reiniciamos el servicio:

service nginx restart

DEBUG:

Podemos habilitar el debug de Dovecot y Sieve configurando ciertos parámetros:

vi conf.d/10-logging.conf
log_path = syslog
syslog_facility = mail
mail_debug = yes

Consultamos los logs:

tail -f /var/log/debug.log

Podemos dumpear toda la running-config de Dovecot con:

doveconf -a

Los plugins cargados en el servicio LMTP de Dovecot:

doveconf -f service=lmtp mail_plugins

Algunos enlaces interesantes:

https://wiki.dovecot.org/Pigeonhole/Sieve/Troubleshooting
https://wiki1.dovecot.org/Logging

Una web muy interesante cuando experimentamos problemas de entregabilidad es:

https://mxtoolbox.com/

Si te ha gustado el artículo puedes invitarme a un redbull aquí.
Autor: kr0m -- 28/03/2020 02:02:03