HOWTO Spamassassin SQL via procmail et qmail

Un article de Gentoo Linux Wiki.

Sommaire

[modifier] Introduction

Le problème réside dans la capacité du système à différencier les « bons » mails des « mauvais ». Aucun système n’est parfait, surtout dans ce domaine où en permanence les spammeurs ajustent leurs techniques d’attaque à nos techniques de défense.

[modifier] Principe

Pour ne pas prendre le risque de vous faire perdre de « bons mails », le système suivant peut être mis en place :

  1. Un mail arrive sur notre serveur à destination d'une adresse email. Qmail transmet la gestion du mail au filtre procmail
  2. Le mail est dirigé vers le contrôle anti-spam (spamassassin)
  3. le contrôle anti-spam analyse le mail et lui attribue une note en fonction de multiples critères. Plus cette note est élevée, plus il y a de chances que ce soit du spam.
  4. Si la note dépasse un premier seuil (que nous pouvons régler), le mail est tagué par spamassassin avec une inscription du style [**SPAM**]
  5. A son retour d’analyse, notre système regarde le score atteint et décide de l’avenir du mail, indépendamment du fait qu'il ait été tagué ou pas.
    1. Note de 0 à un second seuil --> Le mail est dirigé vers votre boite de réception.
    2. Note comprise entre le second seuil et le troisième seuil --> Le mail est dirigé dans votre dossier Spam sur le serveur (Il y a de forte chance que ce soit du spam, mais un « bon mail » pourrait s’y trouver...)
    3. Note supérieur au troisième seuil --> Le mail est détruit.

[modifier] Exemple

  • Note de 0 à 3 : mail transmis tel quel dans la boite de réception
  • Note > 3 : Le mail est tagué [**SPAM** _HITS_] avec la note obtenue, mais est tout de même transmis dans la boite de réception.
  • Note > 5 : Le mail est dirigé vers votre dossier Spam sur le serveur. Le client de messagerie POP ne le chargera pas, Mais il est possible de consulter et vider ce dossier par IMAP ou Webmail)
  • Note > 15 : Le mail est détruit.

Tous ces seuils sont réglables.

[modifier] Emerger les programmes

Je suppose que vous partez d'une installation style OVH release 2 (Base Gentoo) où qmail fonctionne via vpopmail.
Si procmail et spamassassin ne sont pas installés il faut le faire avec un portage à jour.

Code : Emerger procmail et spammassassin
#emerge --sync
#emerge procmail
#emerge spamassassin

[modifier] Configuration

[modifier] Vue d'ensemble

La complexité de la configuration réside dans la nécessité d'intervenir sur la configuration de 3 services différents (qmail, procmail et spamassassin) et sur trois niveaux différents (Configuration globale, au niveau de chaque domaine, voire au niveau de chaque adresse mail).
il y aura donc des fichiers de configuration à modifier/rédiger au niveau global, mais aussi au niveau des domains dans vpopmail.

[modifier] Configuration globale

[modifier] spamassassin

Le deamon spamassassin s'appelle spamd. Un #man spamd permet de voir tous les flags associés. nous allons d'emblée configurer spamassassin pour un fonctionnement couplé à MySQL.
Pour plus de détails, je vous engage à consulter le site de Spamassassin et notamment les pages concernant l'utilisation sous MySQL.

Code : Paramétrage du deamon de spamassassin
#vim /etc/conf.d/spamd
Modifier les flags comme ceci :
SPAMD_OPTS="-m 5 -H -q -D --siteconfigpath=/etc/spamassassin/"
# rc-update add spamd default

Vous pouvez supprimer le -D si vous ne souhaitez pas le debuggage.
Le -q indique à Spamassassin que l'on va utiliser une base de donnée. rc-update permet de lancer automatiquement le deamon au démarrage.

Il faut maintenant créer un base de donnée qui contiendra nos paramètres ainsi que utilisateur disposant des droits nécessaires sur cette base. Pour ma part, j'utilise PHPMyAdmin mais vous pouvez très bien le faire en ligne de commande. J'ai nommé la base de donnée spamd et créé un utilisateur du même nom (spamd). Dans cette base, j'ai créé une table avec la structure suivante :

Code : Table mysql
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Base de données: `spamd`
--

-- --------------------------------------------------------

--
-- Structure de la table `userpref`
--

CREATE TABLE IF NOT EXISTS `userpref` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `username` varchar(255) NOT NULL default '',
  `preference` varchar(64) NOT NULL default '',
  `value` varchar(255) default NULL,
  `domain` varchar(255) default NULL,
  `obs` varchar(255) default NULL,
  `modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  UNIQUE KEY `id` (`id`),
  KEY `added_by` (`obs`),
  KEY `preference` (`preference`),
  KEY `username` (`username`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='Spamassassin Preferences';

Adaptez éventuellement le code MySQL suivant votre configuration (MyISAM au lieu d'InnoDB, CHARSET=latin1, ...)
Seuls les champs username, preference et value sont absolument nécessaires. Les autres sont à adapter à votre convenance.

Il est maintenant nécessaire de configurer Spamassassin.
Pour cela, nous allons éditer le fichier de configuration et inscrire le fait que les paramètres sont à rechercher dans une base MySQL

Code : Editer le fichier de configuration de base de spamassassin
#vim /etc/mail/spamassassin/local.cnf
Code : Saisir les lignes suivantes

user_scores_dsn                 DBI:mysql:spamd:localhost
user_scores_sql_username        spamd
user_scores_sql_password        votremotdepasse
user_scores_sql_custom_query    SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '$GLOBAL' OR username = CONCAT('%',SUBSTRING_INDEX(_USERNAME_,'@',-1)) ORDER BY username ASC 

Mettre en commentaire toutes les autres lignes en plaçant un # devant

Concernant la requête SQL dans user_scores_sql_custom_query, j'utilise la fonction SQL SUBSTRING_INDEX(_USERNAME_,'@',-1) pour extraire le nom de domaine de la variable _USERNAME_.
Au moment du transfert du mail à Spamassassin il sera nécessaire de transmettre l'adresse mail de destination (-u $EXT@$HOST dans procmail, voir plus loin) qui se retrouvera dans _USERNAME_.
Les variables de configuration seront alors chargées au niveau général ($GLOBAL), du domaine (%domaine.tld) ou d'un compte mail particulier (user@domaine.tld).
Le ORDER BY username ASC fait en sorte que si un paramètre spamassassin est défini à plusieurs niveaux, la priorité sera donnée au compte mail, puis au domaine et en dernier lieu au global.

Il faut maintenant saisir quelques paramètres dans la table de paramètres

Code : Exemple de paramétrage enregistré dans la table userprefs de la base spamd
INSERT INTO `userpref` (`username`, `preference`, `value`, `domain`, `obs`) VALUES
('$GLOBAL', 'required_hits', '6.00', NULL, NULL),
('$GLOBAL', 'subject_tag', '[SPAM-_HITS_]-', NULL, NULL),
('$GLOBAL', 'report_safe', '0', NULL, NULL),
('$GLOBAL', 'use_bayes', '0', NULL, NULL),
('$GLOBAL', 'bayes_auto_learn', '0', NULL, NULL),
('$GLOBAL', 'timelog_path', '/var/log/spamassassin', NULL, NULL),
('$GLOBAL', 'rewrite_header Subject', '[SPAM _HITS_] -', NULL, NULL),
('%domain1.tld', 'rewrite_header Subject', '[**SPAM** _HITS_]', 'domain1.tld', NULL),
('user1@domain1.tld', 'required_hits', '3', 'domain1.tld', NULL),
('%domain2.tld', 'required_hits', '5.5', 'domain2.tld', NULL),
('user1@domain2.tld', 'required_hits', '3', 'domain2.tld', NULL);

Bien évidemment, vous devez adapter à vos domaines et adresses mail. C'est justement à cet endroit que l'on personnalise le comportement de Spamassassin.

Maintenant, nous allons tester le bon fonctionnement de Spammassassin sous SQL

Code : Démarrer spamassassin s'il ne l'est pas
# /etc/init.d/spamd 
Code : Test1
# echo -e "From: user\nTo:user\nSubject: Test\n\n" | spamc -u 'user1@domain2.tld'
X-Spam-Flag: YES
X-Spam-Checker-Version: SpamAssassin 3.2.1-gr1 (2007-05-02) on
        xxxxx.votredomain.tld
X-Spam-Level: *****
X-Spam-Status: Yes, score=5.1 required=3.0 tests=FH_FROMEML_NOTLD,MISSING_DATE,
        MISSING_MID,NO_RECEIVED,NO_RELAYS,TO_MALFORMED,TVD_SPACE_RATIO
        autolearn=disabled version=3.2.1-gr1
X-Spam-Report:
        *  0.0 MISSING_MID Missing Message-Id: header
        *  0.0 TO_MALFORMED To: has a malformed address
        *  2.2 FH_FROMEML_NOTLD E-mail address doesn't have TLD (.com, etc.)
        *  0.0 MISSING_DATE Missing Date: header
        * -0.0 NO_RELAYS Informational: message was not relayed via SMTP
        *  2.9 TVD_SPACE_RATIO BODY: TVD_SPACE_RATIO
        * -0.0 NO_RECEIVED Informational: message has no Received headers
From: user
To:user
Subject: [SPAM 5.1] - Test
X-Spam-Prev-Subject: Test 

On s'aperçoit au travers de required=3.0 que c'est bien le paramètre spécifique de user1@domain2.tld qui a été pris en compte. De ce fait, notre message a droit au statut de spam (X-Spam-Status: Yes).

Le même message sans spécifier d'utilisateur donne

Code : Test2
# echo -e "From: user\nTo:user\nSubject: Test\n\n" | spamc
X-Spam-Checker-Version: SpamAssassin 3.2.1-gr1 (2007-05-02) on
        xxxxx.votredomain.tld
X-Spam-Level: *****
X-Spam-Status: No, score=5.1 required=6.0 tests=FH_FROMEML_NOTLD,MISSING_DATE,
        MISSING_MID,NO_RECEIVED,NO_RELAYS,TO_MALFORMED,TVD_SPACE_RATIO
        autolearn=disabled version=3.2.1-gr1
From: user
To:user
Subject: Test 

On s'aperçoit au travers de required=6.0 que c'est le paramètre global qui a été pris en compte. notre message n'a pas le statut de spam (X-Spam-Status: no).

Reste maintenant à organiser les aiguillages entre qmail et spamassassin via procmail

[modifier] qmail

Je suppose que qmail est utilisé avec vpopmail. Pour d'autres configurations, des adaptations doivent être possibles.

Code : Diriger qmail sur procmail
# locate .qmail-default
en fonction de la localisation des fichiers trouvés (Dans /var, dans /home , etc )
# cd /home/vpopmail/domains/domain1.tld
# vim .qmail-default
Commenter la ligne existante 
# | /home/vpopmail/bin/vdelivermail '' bounce-no-mailbox
et la remplacer par
| preline /usr/bin/procmail -p -m /home/vpopmail/domains/domain1.tld/procmailrc 

Il faut répéter l'opération pour chaque domaine que vous souhaitez faire contrôler par notre système.

Reste maintenant à configurer procmail pour qu'il aiguille correctement les mails.

[modifier] procmail

Procmail réagit en fonction de règles. Il existe un fichier de configuration globale (/etc/procmailrc), mais il ne nous est pas nécessaire. Dans notre cas, nous devons rédiger un fichier au niveau du domaine, ce qui nous permettra des réglages différents pour chaque domaine.

Code : Configurer procmail au niveau du domaine
Si vous n'etes pas dans le bon répertoire :
# cd /home/vpopmail/domains/domain1.tld

#vim procmailrc
copiez ceci :

SHELL=/bin/bash
VHOME=`/home/vpopmail/bin/vuserinfo -d $EXT@$HOST`
VERBOSE=no
LOGFILE=/var/log/procmail_log
DROPPRIVS=yes
# Make sure that we have a .Spam and .Virus folder to sort spam and virus into.
# This will create directorys under the ~vpopmail/domains///Maildir
# direcory. This directory will be created as soon as the user
# recives any mail. It simply creates the .Spam and .Virus directories,
# as well as subscribes them to courier-imap
:0wic
* ? test ! -d $VHOME/Maildir/.Spam
|( /var/qmail/bin/maildirmake $VHOME/Maildir/.Spam ; /bin/echo .INBOX/Spam. >> $VHOME/Maildir/.bincimap-subscribed )
:0wic
* ? test ! -d $VHOME/Maildir/.Virus
|( /var/qmail/bin/maildirmake $VHOME/Maildir/.Virus ; /bin/echo .INBOX/Virus. >> $VHOME/Maildir/.bincimap-subscribed )

# Run Anti-Virus and Anit-spam tests.
# :0fw
# | /var/qmail/bin/scanmail.sh

# :0:
# * ^X-Virus-Status: INFECTED
# $VHOME/Maildir/.Virus/

#SPAMASSASSIN
:0fw
| /usr/bin/spamc -f -u $EXT@$HOST

:0:
* ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
/dev/null
# Sort anything marked as SPAM into the users Maildir/.Spam/
:0:
# * ^X-Spam-Status: YES
* ^X-Spam-Level: \*\*\*\*\*
$VHOME/Maildir/.Spam/

# Everything else goes to the users default Maildir/
#:0:
#*
#$VHOME/Maildir/
:0w
| /home/vpopmail/bin/vdelivermail '' bounce-no-mailbox

La création automatique des répertoires de spam et virus vient de ce site
Vérifiez bien et n'hésitez pas à adapter vos chemins et nommage (Exemple : Maildir différent de maildir différent de .maildir).
J'ai laissé en commentaire les règles concernant la gestion des virus, au cas où quelqu'un serait intéressé de prolonger le sujet.
| /usr/bin/spamc -f -u $EXT@$HOST transmet le mail avec l'adresse du destinataire qui sera récupérée par _USERNAME_ dans Spamassassin

Au retour de spamassassin, les header du mail ont été modifiés. Un nouvelle règle s'applique :

0:
  • ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

/dev/null
Si le niveau de spam dépasse 15, le mail est directement détruit, un log est inscrit dans /home/vpopmail/domains/idigitale.fr/procmail-log et procmail s'arrête.

Sinon on passe à la règle suivante :

0:
  1. * ^X-Spam-Status: YES
  • ^X-Spam-Level: \*\*\*\*\*

$VHOME/Maildir/.Spam/
Si le niveau de spam dépasse 5, le mail est orienté vers le dossier Spam sur le serveur. L'utilisateur ne le chargera pas lors d'un envoyer/recevoir sous pop3, mais pourra retourner dans sa boite mail via un service webmail ou IMAP pour contrôler s'il n'y a pas eu de faux classement. Voici un nouveau réglage à votre disposition.
Si la règle s'applique, le processus s'arrête. Sinon il passe à la dernière règle :

0w

| /home/vpopmail/bin/vdelivermail bounce-no-mailbox On retrouve la ligne d'origine dans .qmail-default : le mail est transmis à l'utilisateur.
Remarque 1 : Il se peut que le mail soit transmis tagué s'il a obtenu une note supérieure au 'required_hits' de spamassassin et une note inférieur à la règle 2 de procmail.

Pour surveiller le travail de procmail, vous pouvez scruter les logs dans le répertoire /home/vpopmail/domains/domain1.tld (A condition d'avoir reçu au moins un mail depuis l'installation):

Code : Surveiller le comportement de procmail
# tail -n 100 -f procmail-log 

Remarque 2 : Faudrait gérer un peu mieux les logs pour limiter l'inflation. Avis aux amateurs.
Remarque 3 : Une tâche cron permettant de supprimer les spam ayant un certain âge dans les dossier .Spam de toutes les adresses emails serait à développer. Avis aux amateurs. Sinon cette configuration peut très bien servir uniquement pendant la phase de mise en route pour déterminer un "level" à partir duquel on va jeter les mails et transmettre tout le reste.


Bon travail
--Stéphane 8 avril 2008 à 08:06 (UTC)


---