ReLoad

Thierry Jaouen ~ WikiBlog
"Rien à foutre d'être lu, tant que je peux me relire."

Outils pour utilisateurs

Outils du site


blog:2013:07:29:spamassassin_et_apprentissage_par_les_utilisateurs

SpamAssassin et apprentissage par les utilisateurs

Afin de soulager la vie de quelques usagés, on va mettre en place un système automatique pour apprendre a SpamAssassin a mieux reconnaitre les SPAMs, et a mieux reconnaitre les NON-SPAMs (les HAMs).

Pour que ça marche bien, il faut que les utilisateurs collaborent en soumettant eux-même ce qui est du “spam” ou du “ham”.

Il y a plusieurs méthodes, plus ou moins bien documentées (ou comprises !).

~~READMORE~~

:!: la configuration Postfix sur laquelle repose ce blog-post est un peu ancienne mais est décrite par

Problèmes à résoudre

IMAP et POP3

D'abord, nos utilisateurs ne sont pas tous en IMAP: si c'était le cas, un simple script appliqué sur les répertoires “.Junk” ou “.Spam” pourrait être suffisant.

Non, quelques utilisateurs récalcitrants sont toujours en POP3 !

Frontaux

Sur notre mini-infrastructure, SpamAssassin n'est pas en place sur le serveur final (mail.local.eez.fr), mais sur des frontaux (mx0.local.eez.fr et mx1.local.eez.fr) .
Ainsi, tous les traitements lourds et nuisibles sont relégués loin des clients finaux.

Une solution

Vite dit

En fait, on va créer des comptes e-mails factices uniquement dédiés à la réception , en pièce jointes , des SPAMs ou des NON-SPAMs soumis par les utilisateurs.

Régulièrement, chaque frontal récupèrera les e-mails, via “fetchmail” , et puis entrainera SpamAssassin a ré-considérer les messages comme du SPAM ou du HAM.

Comptes e-mail SPAM et HAM

:!: Il ne faut qu'ils soient accessibles par des vilains

Serveur final

( le serveur qui livre les mails dans les comptes locaux )

Dans le fichier /etc/aliases , on ajoute:

spam: /dev/null
ham: /dev/null
nospam: ham

/dev/null” est provisoire !
Pour l'instant, tout ce que reçoit “spam” ou “ham” va dans le trou noir du “/dev/null”.

Ne pas oublier la mise à jour de la table aliases :

# newaliases

Dans le fichier /etc/postfix/virtual , on ajoute les adresses e-mail.
On peut préférer une variante en utilisant /etc/postfix/virtual.regexp contenant:

/^spam@/            spam
/^(ham|nospam)@/    ham

… ainsi, peut importe le domaine, ils ont tous les mêmes destinataire locaux.

Composer/modifier un fichier /etc/postfix/recipient_access.regexp afin de limiter les accès aux boites.

# =========================================
# Limites sur le destinataire
# (il faut faire de même sur tous les frontaux)
# =========================================
# Limiter l'envoi a (spam|nospam|ham)
/^spam(\+?.*)?@/i       permit_mynetworks,reject
/^nospam(\+?.*)?@/i     permit_mynetworks,reject
/^ham(\+?.*)?@/i        permit_mynetworks,reject
# --- misc -----
/^chamard@tjaouen.fr/   550 Asshole close
# =========================================
# EOF

Dans /etc/postfix/main.cf , compléter l'instruction smtpd_recipient_restrictions en ajoutant:

regexp:/etc/postfix/recipient_access.regexp

Ce qui donne pour moi (a titre d'informations) :

smtpd_recipient_restrictions =
    check_recipient_access regexp:/etc/postfix/recipient_restrictions.regexp
    permit_mynetworks
    permit_sasl_authenticated
    reject_unauth_destination
    regexp:/etc/postfix/recipient_access.regexp

(les autres options ne seront pas expliqués ici)

Et enfin:

# postfix reload

Faire de même sur les frontaux

Pour les frontaux, n'ajouter que les restrictions sur les adresses e-mails. C'est à dire:

  • Composer le fichier /etc/postfix/recipient_access.regexp (voir ci-dessus)
  • Ajouter la restriction dans /etc/postfix/main.cf pour l'instruction smtpd_recipient_restrictions (voir ci-dessus)

Un bilan intermédiaire

A ce stade:

  • Les mails a destination de “spam@xxx.xx” ou “ham@xxx.xx” ou “nospam@xxx.xx” sont livrés … a la poubelle.
  • Il n'y a que les utilisateurs locaux (dans “mynetworks”) qui peuvent leurs envoyer des mails.

Comptes locaux (alias) SPAM et HAM des Frontaux

Retour sur le serveur “final” (celui qui détient les comptes mails).

:!: Il s'agit uniquement de comptes locaux: personne n’envoie directement des mails dedans

Créations

On va donc créer les comptes locaux dédiés à la collecte des SPAMs et des HAMs soumis par les utilisateurs.

Rappel: Dans notre cas, il s'agit de comptes “PAM”, et les commandes sont surement différentes pour d'autres configuration Postfix.

Bref: 2 frontaux, et donc 4 comptes a créé: 2 SPAMs et 2 HAMs.

1er frontal nommé “mx0” :

# adduser mx0-spam
# adduser mx0-ham

2ieme frontal nommé “mx1” :

# adduser mx1-spam
# adduser mx1-ham

Aliases

Maintenant, on peut ajuster correctement le fichier /etc/aliases :

spam : mx0-spam,mx1-spam
ham : mx0-ham,mx1-ham
nospam: ham

Recharger Postfix avec la nouvelle configuration:

# newaliases
# postfix reload

Test

A ce stade, ce qui est destiné à “spam@xxxx.xx” ou “ham@xxxx.xx” est dupliqué respectivement dans les comptes locaux, “mx0-spam” “mx1-spam” et “mx0-ham” “mx1-ham”.

( Dans notre configuration, les mails arrivent dans /home/<compte>/Maildir/new/ )

On en a terminé sur ce serveur.

FIXME: CRON pour vérifier que les mails sont bien relevés…

Les frontaux

Il reste a faire les choses suivantes, sur chaque frontal :

  • Recuperation des mails
  • Extraction des pièces jointes (qui sont des mails aussi)
  • Re-apprentissage de SpamAssassin a partir de ces mails

Ce qui va suivre s'applique a chaque frontal.
On va expliquer uniquement comment faire pour le 1er, c'est à dire celui qu'on nomme “mx0”.

Introduction

Chaque frontal a déjà un compte local “debian-spamd” dédié au traitement des SPAMs avec SpamAssassin.
(Dans un précédent blog-post, ce compte était “spamc-nobody”)

On va utiliser ce compte déjà existant pour faire le job.
Libre a vous d'en utiliser un autre (mais éviter “root” !).

Extraire les pièces jointes

Présentons d'abord le petit script pour extraire toutes les pièces jointes…

Le script

Le script Perl qui va extraire les pièces jointes est là:

Il est inspiré de ce script: http://jmason.org/software/scripts/extract-rfc822-attachment.txt

Son fonctionnement:

$ split-rfc822-attachment.pl < message-mail /tmp/attachment

Dans cette exemple, toutes les pièces jointes du fichier “message-mail” sont alors extraites en multiples fichiers dans /tmp/attachment .
Le but étant de récupéré les sources de chaque mail extrait, et non pas d'extraire et de reconstruire des documents.

:!: il n'est surement pas parfait , mais il m'a semblé suffisant

Mise en place

Scripts

On va le mettre , par exemple, dans /usr/local/bin … donc:

# cp split-rfc822-attachment.pl /usr/local/bin/
# chmod a+x /usr/local/bin/split-rfc822-attachment.pl

Vérifier qu'il compile sans erreur:

# perl -c /usr/local/bin/split-rfc822-attachment.pl
/usr/local/bin/split-rfc822-attachment.pl syntax OK
Répertoires

Ensuite, il faut choisir un endroit où on va déposer les pièces jointes “spam” et “ham”.

A la racine de l'utilisateur choisit (pour nous ce sera debian-spamd ), on aura:

  • Pour le SPAM: ~/sa-retrain/spam
  • Pour le HAM: ~/sa-retrain/ham

Créer et attribuer les “bons” droits a ces répertoires:

# su -s /bin/bash debian-spamd
$ mkdir ~/sa-retrain
$ mkdir ~/sa-retrain/{spam,ham}

Ceci fait, voyons la suite pour que les mails arrivent dans ces répertoires.

Récupération

La manière de récupérer des mails la plus évidente est simplement le protocole POP3 !

On va utiliser la commande fetchmail pour récuperer les mails.

Problèmes

Mais il y a un petit hic:
Lorsque fetchmail récupère un mail, il le livre au Postfix local ! Ce qui a les conséquences suivantes:

  • Des tags sont ajoutés aux mails
  • Le mails est livré dans une Maildir ou mbox selon la configuration.
  • SpamAssassin va tagguer le mail !!!!

Il y a plusieurs manière de corriger cela, mais ça oblige a faire, encore et encore, des modifications dans Postfix et SpamAssassin.

Notre solution

Donc, on va faire plus simple: On va dire a fetchmail de livrer a notre propre service de livraison, notre “MDA” à nous .

Rassurez-vous: Notre “MDA” sera un simple scripte (voir section suivant).

Notre "MDA"

Service rendu

En dehors d'être un faux (“fake”) “MDA” , il va:

  • Extraire les pièces jointes en utilisant le script “split-rfc822-attachment.pl
  • Si il y a une erreur, envoi un mail d'information à l'envoyeur. FIXME: trouver autre chose.
Télécharger

Le script Bash de notre “MDA” est là:

Installation

On va le mettre , par exemple, dans /usr/local/bin … donc:

# cp sa-retrain-fake-mda /usr/local/bin/
# chmod a+x /usr/local/bin/sa-retrain-fake-mda

Fetchmail

Installer
# aptitude update
# aptitude install fetchmail

Note:

[warn] Not starting fetchmail daemon, disabled via /etc/default/fetchmail ... (warning).

On peut ignorer: Nous n'avons pas besoin d'activer le “daemon” pour que ça marche.

configurer

Retour en tant qu'utilisateur “debian-spamd” (ou autres).

# su -s /bin/bash debian-spamd
$

A la racine de la “HOME” :

$ cd ~

… on compose un fichier nommé .fetchmailrc contenant:

# ----------------------

set postmaster root
set no bouncemail
#set syslog

poll <HOST> protocol POP3
  user mx0-spam there with password '<PASSWORD>' is debian-spamd here options ssl
  and wants mda "/usr/local/bin/sa-retrain-fake-mda spam %F %T"

poll <HOST> protocol POP3        
  user mx0-ham there with password '<PASSWORD>' is debian-spamd here options ssl
  and wants mda "/usr/local/bin/sa-retrain-fake-mda ham %F %T"

# ----------------------        
# EOF
mx0-spam et mx0-ham A adapter selon le compte e-mail associé au frontal
<HOST> Adresse du service “pop”. (Exemple: pop.local.eez.fr )
<PASSWORD> Passe affecté au moment de la création du compte e-mail
debian-spamd … ou autre nom de compte (par exemple: spamc-nobody )
options ssl Si on veut chiffrer les echanges. Voir configuration spécifique à SSL ici .

Le fichier .fetchmailrec contenant des mots de passe, il faut faire:

$ chmod 0700 .fetchmailrc
MDA: le script

L'instruction mda “sa-retrain-fake-mda spam %F %T” dit:

  • Utiliser ce script “/usr/local/bin/sa-retrain-fake-mda” (décrit plus haut) pour livrer les mails.
  • Passer les paramètres: “spam” ou “ham”, puis l'adresse de l'envoyeur, puis le compte du destinataire.

Comme dit plus haut, on force fetchmail a utiliser “notre” propre “MDA”.

Tester

Maintenant, on doit avoir une chaine de transfert complète. (Reste juste une étape, voir juste après).

Pour tester:
Il suffit d'envoyer un e-mail avec un ou plusieurs e-mail en pièces jointes à l'adresse spam@… ou ham@…..

Par exemple, on envoi un mail avec 2 spams en pièces jointes.

Sur le serveur, on voit le mail:
Dans les logs:

Jul 18 06:05:21 mail clamsmtpd: 100174: from=<hidden>@<hidden>, to=spam@tjaouen.fr, status=CLEAN
Jul 18 06:05:21 mail postfix/smtpd[25367]: disconnect from localhost[127.0.0.1]
Jul 18 06:05:21 mail postfix/local[25373]: AC76454C4A: to=<mx0-spam@mail.local.eez.fr>, orig_to=<spam@tjaouen.fr>, relay=local, delay=0.26, delays=0.25/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to maildir)
Jul 18 06:05:21 mail postfix/local[25373]: AC76454C4A: to=<mx1-spam@mail.local.eez.fr>, orig_to=<spam@tjaouen.fr>, relay=local, delay=0.27, delays=0.25/0.01/0/0.01, dsn=2.0.0, status=sent (delivered to maildir)
Jul 18 06:05:21 mail postfix/qmgr[23951]: AC76454C4A: removed

… mail qu'on retrouve dans chaque compte “spam” local:

# ls /home/mx{0,1}-spam/Maildir/new/
/home/mx0-spam/Maildir/new/:
1375020321.Vca02I408fM962049.mail
/home/mx1-spam/Maildir/new/:
1375020321.Vca02I4090M967836.mail

Maintenant, on va sur l'un des frontals , et on récupère le mail en attente.

Sur le frontal:
Devenir l'utilisateur qui traite les SPAMs et les HAMs:

# su -s /bin/bash debian-spamd

Récupérer les mails en attente:

$ fetchmail
1 message pour mx0-spam dans pop.local.eez.fr (51924 octets).
lecture du message mx0-spam@mail.local.eez.fr:1 parmi 1 (51924 octets) éliminé
fetchmail: Aucun message pour mx0-ham dans pop.local.eez.fr

En vrai: fetchmail râle parce que mon certificat “ssl” est auto-signé !
Voir solution ici.

On a bien récupéré le mail, mais il est où ?
Dans les logs on voit:

Jul 18 06:11:52 mx1 sa-retrain-fake-mda: spam From: <hidden>@<hidden> - OK

… le script “sa-retrain-fake-mda” a fait son boulot.

Les 2 pièces jointes sont bien extraites , et là:

$ ls ~/sa-retrain/spam/ -lart
-rw------- 1 debian-spamd debian-spamd 26193 juil. 18 06:11 split-rfc822-0140259F035200DB7.2
-rw------- 1 debian-spamd debian-spamd 21896 juil. 18 06:11 split-rfc822-0140259F035200DB7.1

Reste a les faire apprendre à “sa-learn”.

''sa-learn'' sur les mails

Enfin, il faut réaliser un script qui va traiter les “spam” ou les “ham” qui ont été précédement extraits des pièces jointe.

le script

Le script Bash qui va apprendre a partir des mails est là:

Ce qu'il fait:

  • Regarde dans les répertoires ~/sa-retrain/{spam|ham}
  • En fonction du nom du répertoire (“spam” ou “ham”), ré-apprend SpamAssassin que le mail est du “spam” ou du “ham”

Installer

# cp sa-retrain-spamham /usr/local/bin
# chmod a+x /usr/local/bin

Tester

# su -s /bin/bash debian-spamd

Et puis:

$ sa-retrain-spamham
sa-retrain-spamham: spam - /var/lib/spamassassin/sa-retrain/spam/split-rfc822-0140259F035200DB7.1
Learned tokens from 1 message(s) (1 message(s) examined)
sa-retrain-spamham: spam - /var/lib/spamassassin/sa-retrain/spam/split-rfc822-0140259F035200DB7.2
Learned tokens from 1 message(s) (1 message(s) examined)

Dans les logs, on peut voir aussi:

Jul 18 06:31:58 mx1 sa-retrain-spamham: sa-learn - spam:2 ham:0

CRON

Maintenant que c'est fonctionnel, il suffit de démarrer tout ça dans un CRON.

# crontab -u debian-spamd -e

Et ajouter:

MAILTO=root
*/10 * * * * fetchmail >/dev/null ; sleep 1 ; /usr/local/bin/sa-retrain-spamham >/dev/null

Et ainsi, toutes les 10 minutes:

  • Relève des mails et extractions des pièces jointes.
  • Ré-apprentissage des SPAMs et des HAMs
:!: sa-retrain-spamham peut être long. Un “lock” est présent pour écarter des accès concurrents

Sources

blog/2013/07/29/spamassassin_et_apprentissage_par_les_utilisateurs.txt · Dernière modification: 2013/07/30 17:57 par thierry