Table des matières

Postfix et SRS

C'est la suite de l'article sur Postfix et SPF parce qu'en pratique le protocole SPF créé un nouveau problème lors du “forward” de mail.

Je vais proposer ma solution, parce que celles que j'ai pu glaner sur le Net ne me convenait pas. ~~READMORE~~

SPF

Comme vu précédemment, le protocole SPF permet de dire au Monde qu'elles sont les serveurs autorisés a émettre des e-mails pour un domaine.

Donc, les serveurs qui tiennent comptent du protocole SPF peuvent filtrer les mails, et même les refuser.

Forwarding de mail

bases

Lorsqu'on “forward” (ou relaye) un e-mail, par defaut, on ne touche a rien à e-mail: on trouve juste une trace du transfert dans les entêtes.

Exemple, soit dans une ligne d'un fichier “virtual” de Postfix :

xmartin@tjaouen.fr        xmartin1234@dir.com

2 choses sont déterminant pour comprendre le problème!

  1. l'adresse de l'envoyeur
  2. le serveur destinataire (ou les serveurs intermédiaire)

Si le destinataire ne vérifie pas le protocole SPF: il n'y a aucun problème.

Si l'adresse de l'envoyeur n'appartient pas à un domaine qui gère le SPF: il n'y a aucun problème.

C'est le cas, par exemple, de Free.fr , qui n'interdit pas de forger des adresses e-mails en utilisant son domaine “@free.fr”.

On peut le vérifier avec la commande spfquery :

$ spfquery -ip=11.22.33.44 -sender=toto@free.fr
StartError
Context: Failed to query MAIL-FROM
ErrorCode: (2) Could not find a valid SPF record
Error: No DNS data for 'free.fr'.
EndError
none

Peu importe ip , il n'y a pas de support du SPF.

problèmes

Voila que (From) jojo@annu.com veut envoyer un e-mail a (To) xmartin@tjaouen.fr .

Que ce passe-t-il ?

Et BANG .

Les serveurs de tjaouen.fr ne sont pas autorisé a envoyer des e-mails From:jojo@annu.com .

Une solution simple (un peu trop a mon goût) est proposé là: http://www.openspf.org/FAQ/Forwarding

SRS

bases

Le SRS permet de changer l'enveloppe et d'encapsuler le From de tel sorte qu'on ait , à la fin , un domaine qualifié à envoyer des mails.

Par exemple, si on a un From:jojo@annu.com , et sera modifié pour devenir:

From:SRS0=cccc=dd=annu.com=jojo@tjaouen.fr

Où , en gros :

cccc un checksum pour empêcher des vilains de forger des mails
dd le jour de création (pour donner une durée de vie)

On retrouve aussi annu.com et jojo

Et surtout: @tjaouen.fr en domaine d'envoi.

Les serveurs du domaine tjaouen.fr sont bien autorisé a envoyer pour tjaouen.fr !

pré-requis

Afin de ne pas trop polluer mes logs et écarter les effets de bords, je vais mettre en place un nouveau (sous) domaine qui sera dédier au SRS.

Pour être clair: les mails forwardé avec SRS utiliseront le domain srs-forward.tjaouen.fr .

Et non simplement tjaouen.fr.

Cela nécessite de préparer le DNS: Un enregistrement MX pour ce sous domaine.

Il faut aussi préparer Postfix a accepter ce sous-domaine: même s'il est vide, et doit le rester.

(Car des mails utilisants le format “SRS” peuvent revenir, ne serait-ce des “bounce” ).

SRS avec bypass-srsd

Aprés avoir testé quelques solutions (dont pfix-srsd de l'ensemble pfixtools), j'ai écrit un petit scripte en Perl.

A mes yeux, ses avantages sont:

Choses en dur (et pas forcément un mal) :

Plus d'info: http://search.cpan.org/~shevek/Mail-SRS-0.31/lib/Mail/SRS.pm

Installation

dépendance

Mail::SPF et Mail::SRS

# aptitude update
# aptitude install libmail-spf-perl libmail-srs-perl

scripte

Installation rapide

$ cd /usr/local/bin
$ wget http://reload.eez.fr/_media/bypass-srsd-0-9-1.zip
$ unzip bypass-srsd-0-9-1.zip

Le scripte bypass-srsd est dans le répertoire courant.

Verifier qu'il compile , sinon, vérifier les dépendances:

$ perl -c ./bypass-srsd

Assurez-vous qu'il est executable:

$ chmod a+x ./bypass-srsd

Configuration

user

Créer un compte local sans droit, et dédié a l’exécution de ce scripte:

# adduser --system --no-create-home --group bypass-srs

secret

Créer un secret: cela permet de créer un checksum unique pour chaque renommage via SRS.
(En fait, le jour suivant, le checksum sera different pour un même e-mail)

Par exemple:

# cd /etc/postfix

# dd if=/dev/urandom bs=512 count=1000 | sha512sum - > bypass-srsd.key
# dd if=/dev/urandom bs=512 count=1000 | sha512sum - >> bypass-srsd.key
# dd if=/dev/urandom bs=512 count=1000 | sha512sum - >> bypass-srsd.key
:!: Il faut que ce soit des lignes de textes, avec un contenu aléatoire dedans…

Finir en mettant les bons droits, pour un secret:

# chown root:bypass-srs bypass-srsd.key
# chmod 0440 bypass-srsd.key
:!: Evidement, ce secret doit resté le même dans le temps ! sinon, les “decodage” SRS echoueront!

Postfix

choix

A ce stade, on doit pouvoir répondre a quelques questions simples:

Mes reponses:

IP publique 88.190.21.130
HELO mail.eez.fr
Domaine SRS srs-forward.tjaouen.fr

Ce sont ces paramètres que je vais utiliser par la suite… pour mon cas bien sur !

master.cf

Préparer l'éxecution du scripte en editant le fichier /etc/postfix/master.cf , afin d'avoir:

# TJ --------------
# encode
127.0.0.1:10005 inet n  n       n       -       0       spawn
      user=bypass-srs argv=/usr/local/bin/bypass-srsd
      --forward --srs-secret-key=file:///etc/postfix/bypass-srsd.key
      --quiet
      --fwd-domain=srs-forward.tjaouen.fr
      --fwd-ip-address=88.190.21.130
      --fwd-helo-identity=mail.eez.fr
# decode
127.0.0.1:10006 inet n  n       n       -       0       spawn
      user=bypass-srs argv=/usr/local/bin/bypass-srsd
      --reverse --srs-secret-key=file:///etc/postfix/bypass-srsd.key
      --quiet
      --fwd-domain=srs-forward.tjaouen.fr
# -----------------
:!: Remplacer --quiet par --debug --verbose pour voir plus de chose dans les logs !

Les daemons attendront les requêtes sur les port 10005 et 10006 : adapter selon vos disponibilité!

main.cf

Adapter /etc/postfix/main.cf ainsi :

# ---------------
# SRS Remapping
# ---------------
# bypass-srsd
# Decode
recipient_canonical_maps = tcp:127.0.0.1:10006
recipient_canonical_classes = envelope_recipient,header_recipient
# Encode
sender_canonical_maps = tcp:127.0.0.1:10005
sender_canonical_classes = envelope_sender
# ---
127.0.0.1:10005_time_limit = 3600
127.0.0.1:10006_time_limit = 3600
# ---------------
Update 2014/05/09 : recipient_canonical_classes = envelope_recipient,header_recipient

Test

Aprés avoir rechargé ou redemarré Postfix :

# postfix reload

ou

# /etc/init.d/postfix restart

Quelques tests:

Exemples:

$ host -t TXT emailing-newsletter.com
emailing-newsletter.com descriptive text "v=spf1 +a +mx -all"

forward:

$ postmap -q "toto@emailing-newsletter.com" tcp:localhost:10005
SRS0=J8jhkM=KC=emailing-newsletter.com=toto@srs-forward.tjaouen.fr

reverse:

$ postmap -q "SRS0=J8jhkM=KC=emailing-newsletter.com=toto@srs-forward.tjaouen.fr" tcp:localhost:10006
toto@emailing-newsletter.com

Pour le “forward”, si la transformation “SRS” n'est pas necessaire, alors ne retourne rien (sauf si l'option --fwd-catch-all )

Pour le “reverse”, si le reverse “SRS” fonctionne, alors retourne le resultat, sinon rien.

Les logs ( voir --debug et --verbose ) peuvent expliquer les raisons.

Ou sinon:

$ echo "get toto@emailing-newsletter.com" | nc -q 5 localhost 10005
200 SRS0=J8jhkM=KC=emailing-newsletter.com=toto@srs-forward.tjaouen.fr

Encodage (forward) encore:

Par exemple avec free.fr :

$ echo "get toto@free.fr" | nc -q 5 localhost 10005
500 No SRS needed

Effectivement: free.fr n'utilise pas le protocole SPF.

$ echo "get toto@annu.com" | nc -q 5 localhost 10005
200 SRS0=fkIWI5=KC=annu.com=toto@srs-forward.tjaouen.fr

Effectivement: annu.com utilise le protocole SPF.

Decodage (reverse) :

$ echo "get toto@annu.com" | nc -q 5 localhost 10006
500 reverse: can't parse 'toto@annu.com'

Effectivement: ce n'est pas un encodage SRS (ne commence pas par SRS0 entre autre)

$ echo "get SRS0=fk8WI5=KC=annu.com=toto@srs-forward.tjaouen.fr" | nc -q 5 localhost 10006
200 toto@annu.com

Effectivement: l'encodage SRS est correct.

$ echo "get SRS0=fk8WI5=KC=annu.com=toto@annu.com" | nc -q 5 localhost 10006
500 reverse: Domain 'annu.com' not allowed

Effectivement: C'est le domaine srs-forward.tjaouen.fr qui est attendu.

bypass-srsd options

Générales

Option Descriptions
--forward encode en SRS: si toutes les conditions sont remplis
--reverse decode SRS : si toutes les conditions sont remplis
--srs-secret-key= code secret ou fichier contenant le code secret (préfixé avec : file:// )
--debug trés bavard dans les logs
--verbose simplement bavard dans les logs
--quiet sans --debug et sans --verbose (ne log que les erreurs)
--fwd-domain= domaine dédié au SRS

avec ''--forward'' uniquement

Option Descriptions
--fwd-ip-address= IP publique du serveur de mails
--fwd-helo-identity= Nom du serveur de mails, lors du HELO
--no-spf-check Désactive le test SPF avant d'appliquer le SRS. Le renommage SRS sera toujours fait.
--spf-check (Default:Yes) Active le test SPF. Le renommage SRS n'aura lieu que si le test échoue.
--no-srs Interdit le renommage SRS dans tout les cas.
--srs (Default:Yes) Active le renommage SRS, si toutes les conditions sont remplis.
--fwd-catch-all Repond a toutes demande de forward (au lieu de retourner: “500 je ne sais pas faire”)

avec ''--reverse'' uniquement

Option Descriptions
--no-domain-strict ne verifie pas le domaine: le décodage s'applique a tous les domaines

Sources

SRS avec pfixtools

:!: pour info: ce n'est pas le service SRS que j'utilise, finalement.

compiler

# aptitude install libev3 libev-dev libsrs2-0 libsrs2-dev libpcre3-dev
# cd /usr/local/src
# git clone https://github.com/Fruneau/pfixtools.git
# cd pfixtools
# git submodule init
# git submodule update
# cd common
# make
# cd ../pfix-srsd
# make

Un petit coup d'oeil sur le résultat:

# file pfix-srsd
pfix-srsd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
# ldd pfix-srsd
      linux-vdso.so.1 =>  (0x00007ffffdbff000)
      libsrs2.so.0 => /usr/lib/libsrs2.so.0 (0x00007fa4f4080000)
      libev.so.3 => /usr/lib/libev.so.3 (0x00007fa4f3e72000)
      libc.so.6 => /lib/libc.so.6 (0x00007fa4f3b0f000)
      libresolv.so.2 => /lib/libresolv.so.2 (0x00007fa4f38f9000)
      libnsl.so.1 => /lib/libnsl.so.1 (0x00007fa4f36e1000)
      libm.so.6 => /lib/libm.so.6 (0x00007fa4f345e000)
      /lib64/ld-linux-x86-64.so.2 (0x00007fa4f428d000)

Installer

Installer à la main:

# cp /usr/local/src/pfixtools/pfix-srsd/pfix-srsd /usr/local/bin/

Créer/modifier un fichier /etc/init.d/pfix-srsd contenant:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          pfix-srsd
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: pfixtools SRS Daemon backend for Postfix
### END INIT INFO

PFIXSRSD_CONFIG="/etc/default/pfix-srsd"
NAME="pfix-srsd"
DAEMON="/usr/local/bin/pfix-srsd"
PID_FILE="/var/run/pfix-srsd.pid"

if [ -f $PFIXSRSD_CONFIG ]; then
  . $PFIXSRSD_CONFIG
else
  exit 0
fi

test -x $DAEMON || exit 0

case "$1" in
  start)
    echo -n "Starting Postfix SRS Daemon: $NAME"
    start-stop-daemon -S -q -b -p $PID_FILE -x $DAEMON -- -p $PID_FILE $OPTIONS $DOMAIN $SECRETS
    echo "."
    ;;
  stop)
    echo -n "Stopping Postfix SRS Daemon: $NAME"
    if [ -f $PID_FILE ]; then
      kill `cat $PID_FILE`
      rm $PID_FILE
    fi
    echo "."
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  force-reload)
    $0 restart
    ;;
  *)
    echo "Usage: $0 start|stop|restart|force-reload"
    exit 1
    ;;
esac

Rendre executable:

# chmod a+x /etc/init.d/pfix-srsd

Faire en sorte que le script soit executé au boot.

# update-rc.d pfix-srsd defaults

configurer

Créer un fichier /etc/default/pfix-srsd contenant (à adapter):

DOMAIN=eez.fr
SECRETS=/etc/postfix/pfix-srs.secrets
OPTIONS=-I

Créer le fichier de secret (PS:il faut un fichier texte avec des lignes…):

# ( for(( i=0; $i<5; i=$[$i+1] )) do dd if=/dev/urandom bs=200 count=1 | sha1sum -b - ; done ) >/etc/postfix/pfix-srs.secrets
# chmod 0400 /etc/postfix/pfix-srs.secrets
# chown root:root /etc/postfix/pfix-srs.secrets
:!: Il faut que ce soit des caractères “sha1sum like” , sinon, ça va deconner

demarrer

# /etc/init.d/pfix-srsd start

Encodage SRS sur le port 10001 Decodage SRS sur le port 10002

Tester

codage:

$ postmap -q "nobody@tjaouen.fr" tcp:localhost:10001
SRS0=NsPX=J6=tjaouen.fr=nobody@eez.fr

decodage:

$ postmap -q "SRS0=NsPX=J6=tjaouen.fr=nobody@eez.fr" tcp:localhost:10002
nobody@tjaouen.fr

Postfix

Dans master.cf : rien a faire. C'est un daemon indépendant.

Dans main.cf :

# ---------------
#    SRS
# ---------------
# Decode
recipient_canonical_maps = regexp:/etc/postfix/pfix-no-srs.regexp, tcp:127.0.0.1:10002
recipient_canonical_classes = envelope_recipient
# Encode
sender_canonical_maps = regexp:/etc/postfix/pfix-no-srs.regexp, tcp:127.0.0.1:10001
sender_canonical_classes = envelope_sender
# ---------------

Le fichier pfix-no-srs.regexp contient les regex des domaines à ne pas toucher par le SRS .

Exemple:

# ------------------------------------------------
#         __ _                                          
#  _ __  / _(_)_  __     _ __   ___        ___ _ __ ___ 
# | '_ \| |_| \ \/ /____| '_ \ / _ \ _____/ __| '__/ __|
# | |_) |  _| |>  <_____| | | | (_) |_____\__ \ |  \__ \
# | .__/|_| |_/_/\_\    |_| |_|\___/      |___/_|  |___/
# |_|                                                   
# 
# ------------------------------------------------
/^([^@]+@srs-forward\.tjaouen\.fr)$/        $1
/^([^@]+@eez\.fr)$/                     $1
/^([^@]+@tjaouen\.fr)$/                 $1
# ------------------------------------------------
# EOF

Recharger Postfix :

# postfix reload

… et puis surveillez les logs !

Un bilan