Tag: Système

Synology 207+ (linux) et rsync

Posted by – July 7, 2008

Objectif : sauver les bases, les répertoires /etc, /var/www et autres fichiers.

More

NAS Synology 207+, alarme, alarme

Posted by – July 1, 2008

Quelle fut ma surprise hier soir aux alentours de 23h00 d’entendre ce drôle de bip , et ce voyant orange qui clignotait : le NAS me prévenait que le 2ème disque était défaillant, plus de RAID-1 donc, seul 1 disque restait en fonction.

C’est bien pour ça que j’ai choisi ce type matériel, tout inclus, dédié et pensé pour réagir en cas de difficultés (du matériel pro) : sauvegarde, stockage en RAID-1, avec tous les outils ad-hoc pour gérer à bien ses données (c’est une obsession chez moi, sauvegarder les données, cela n’a pas de prix).

La méthode que j’ai appliquée :

  • j’ai un ancien disque externe USB de 250 Go qui m’a servi de spare, le NAS permet de brancher des disques tiers pour augmenter la capacité de stockage, en USB ou eSATA : avec la (merveilleuse) interface Web, j’ai activé de suite la sauvegarde du NAS vers le disque externe afin d’avoir une copie si jamais le 2ème disque du NAS tombait. Par le passé, cela m’est déjà arrivé : RAID-5 sur un serveur, 1 disque en panne, puis…1 deuxième, et là, c’est la catastrophe. L’USB reste lent, penser à acquérir un disque eSATA, bien plus rapide.
  • par l’interface, reconstruction du RAID-1, apparemment, le disque est encore physiquement là (coup de chaud ?). J’ai acheté 2 même disques Samsung, petite erreur. Il est plutôt conseillé d’investir dans des disques de marque différente, dans le cas d’une mauvaise série (au bureau on a eu…8 PC qui ont eu des problèmes disques, PC de même série…), le risque est réduit de tomber sur le même problème.

Conclusion : le Synology a un prix, mais cela en vaut la peine, belle machine.

A faire : installer le dernier firmware v. 0640. Ce que j’aime chez Synology, c’est qu’ils ne produisent pas tous les 6 mois de nouveaux modèles, leur parc est assez stable, ce qui permet d’avoir de (vraies) mises à jour des firmware, chose que l’on voit un peu trop rarement.

EDIT1 : le disque est bien mort.

EDIT2 : grâce à rsync, je peux sauvegarde le blog sur le NAS.

Debian, FreeTDS et SQL Server

Posted by – January 17, 2008

Contexte

Lorsqu’on travaille dans un environnement hétérogène composé de plateformes Windows et Linux, il peut s’avérer utile d’accéder à partir d’un serveur Unix à un serveur de base de données de type SQL Server (2000, 2005, …), j’aime l’interop…

Le développement de SQL Server est notamment né à l’origine de la collaboration entre Microsoft et Sybase. Le protocole de communication utilisé pour les échanges clients/serveur se nomme TDS, et sa version Opensource FreeTDS, avec une communauté toujours active.

Dans notre environnement, nous utilisons le serveur de listes SYMPA. Ce dernier permet de synchroniser les [emails des] membres des listes qu’il gère avec une base externe (synchro automatique toutes les n minutes, ou lors de l’envoi d’un message). Dans notre système d’information, celle-ci est une base SQL Server qui est utilisé par la plateforme d’applications mais aussi par le serveur de listes (en consultation ou en insertion).

Debian, installation

Sous Debian, le paquetage à installer est libct3 :

apt-get install libct3

Le paquetage installe le tout dans le répertoire /etc/freetds.

Configuration

Le fichier freetds.conf est une base de départ. Parmi les paramétrages intéressants, nous avons la section globale ([global]), où l’on peut varier la version du protocole à utiliser (selon le serveur SQL Server en face), fixer explicitement l’encodage à utiliser pour la communication client/serveur, ou créer des sections (de la forme [masection]) spécifiques à vos serveurs SGBD (IP d’accès, protocole, port, …).

Pour un dialogue avec un SQL Server 2000, en UTF, ci-après, un exemple de configuration freetds.conf :

$ less /etc/freetds.conf

[global]
# TDS protocol version
tds version = 8.0
client charset = UTF-8
# si besoin de traces
; dump file = /var/log/freetds.log
; debug level = 10

# si besoin de gérer les timeout d'exécution des commandes SQL et du timeout de connexion
; timeout = 10
; connect timeout = 10

[monserveur-sql]
host = 10.75.40.31
port = 1433
tds version = 8.0

Dans le client (Perl, PHP, …) qui utilisera FreeTDS, celui-ci fera appelle au libellé du serveur défini dans freetds.conf, ici monserveur-sql, cela a l’avantage d’abstraire l’IP réelle.

Exemple de client en Perl

Le but de ce programme est de lire un mail stocké sur le disque, de le parser, et d’inscrire les divers éléments (entêtes, corps, …) qui le composent dans une table en base SQL Server.

 use DBI; use Encode; use lib '/home/sympa/bin'; use Log; # infos. sql # le nom du serveur du freetds.conf my $server = "monserveur-sql"; my $user = "loginsql"; my $pwd = "pwdsql"; my $bdd = "mabase"; sub encoding { my $body = shift; &Encode::encode_utf8($body); } sub msgtosql { my $file = $ENV{'PATHMSG'}; my $adrlist = $ENV{'LISTADDR'}; my $listname=''; my $domain=''; my $bodyencode=''; if ($adrlist =~ /^(.*)\\@(.*)$/) { $listname = $1; $domain = $2; } else { &do_log('err',"Match of list address '$adrlist' failed"); return undef; } # lecture du message (fichier texte) # et prise en compte des champs a inserer dans la base my $parser = new MIME::Parser; $parser -> output_to_core(1); my $msg = $parser -> parse_open("$file"); my $head = $msg -> head; my $body = $msg -> body_as_string; my $hdrall = $msg -> header_as_string; my $hdrdate = $head->get('Date'); my $hdrfrom = $head->get('From'); my $hdrsubject = $head->get('Subject'); my $hdrto = $head->get('To'); my $messageid = $head->get('Message-Id'); $bodyencode = $body; $dbh = DBI->connect("dbi:Sybase:$server","$user","$pwd") or die 'connect'; $dbh->do("use $bdd"); # insertion du message en base $SQL = sprintf "INSERT INTO msgs (body,creatstamp,hdrall,hdrdate,hdrfrom,hdrfromspc,hdrsubject,hdrto,list) VALUES (%s,getdate(),%s,%s,%s,%s,%s,%s,%s)", $dbh->quote($bodyencode),$dbh->quote($hdrall), $dbh->quote($hdrdate), $dbh->quote($hdrfrom), $dbh->quote($hdrfrom),$dbh->quote($hdrsubject),$dbh->quote($hdrto),$dbh->quote($listname); # on test l'insert, si catch alors on force l'encodage a utf-8 # l'erreur vient de freeTDS qui ne pt encoder (via iconv) directement en UTF-8, ne connaissant pas parfois l'encodage origine # pas d'encoding automatique car des msgs peuvent etre deja en utf-8 { # trap die pour logguer l'erreur SQL local $SIG{'__DIE__'} = sub { do_log('err',$_[0]); die $_[0]; }; eval { $dbh->do($SQL) || die "Error SQL $DBI::errstr"; }; if($@) { do_log('notice',"[catch sql] try to encode in utf-8..."); $bodyencode = &Encode::encode_utf8($body); $SQL = sprintf "INSERT INTO msgs (body,creatstamp,hdrall,hdrdate,hdrfrom,hdrfromspc,hdrsubject,hdrto,list) VALUES (%s,getdate(),%s,%s,%s,%s,%s,%s,%s)", $dbh->quote($bodyencode),$dbh->quote($hdrall), $dbh->quote($hdrdate), $dbh->quote($hdrfrom), $dbh->quote($hdrfrom),$dbh->quote($hdrsubject),$dbh->quote($hdrto),$dbh->quote($listname); unless($dbh->do($SQL)) { do_log('err',"Error $DBI::errstr for $SQL"); } } } $dbh->disconnect; return 1; } do_openlog("LOCAL2", "unix", 'archivetosql'); &msgtosql();  

Au passage, un excellent site sur Perl, sur tous les sujets du langage.

Conclusion

Lorsque dans un système d’information, il cohabite un grand nombre de serveurs hétérogènes, le portage de protocoles peut-être un moyen de faire communiquer les systèmes. Une autre solution, de plus en plus répandue, est l’utilisation des services Web (SOAP, REST, …), dans une approche SOA.

Ressources

Quelques ressources sur le sujet.

JRES 2007 : l’ensemble des sessions : PDF, vidéos

Posted by – December 28, 2007

Les JRES 2007 livre le résultat des rencontres de novembre 2007.

Les sessions abordent bon nombre de sujets : opensource, réseau, système, sécurité, standards, disponibles au format PDF (diapo, article), ou en vidéo MPG4.

Pour rappel, les JRES sont les journées réseaux de l’enseignement supérieur.

smtp, dns, listes : des communautés d’experts

Posted by – October 16, 2007

Depuis de nombreuses années, je suis abonné à une multitude de listes de diffusion sur le serveur du CRU qui aborde un tas de sujets passionnants.

3 listes retiennent mon attention, par leur contenu techniquement élevé et riche d’expertise, je ne peux que conseiller, si le sujet vous intéresse, de vous y abonner ou au moins de parcourir les archives :

  • smtp (archives)
  • dns (archives)
  • sympa (archives) : un coup de coeur pour ce moteur de listes ;) : le CRU distribue environ de 600 000 à 1 million de mails par jour, rien que pour ça, ça mérite d’être cité.

Bonne lecture.

UTF-8 : linux, windows, mac, everything, everywhere

Posted by – October 9, 2007

Hier, un ami m’a demandé un coup de pouce pour déboguer un problème d’appel Ajax qui ne fonctionnait pas sous IE (alors que sur la page de démo cela marchait, et sur FF également, damned !) : champ de saisie, propositions de mots, autrement dit de l’autocomplétion.

Voyant les caractères renvoyés par la requête Ajax, c’est à dire des ”?” ou tout autre caractère ésotérique, ni une ni deux, l’origine fut trouvée : l’ISO-8859-1. A défaut, l’usage de la fonction utf8_encode a été la parade pour convertir la donnée à la volée.

La majorité des librairies Ajax (Prototype par exemple) ont un encodage par défaut à UTF-8 (et c’est bien !).

Une parade c’est bien, prendre l’habitude d’utiliser l’UTF c’est mieux. C’est la norme actuelle et future, fini les codespages à n’en plus finir. Tout logiciel sérieux devrait le gérer, on trouve encore trop souvent l’usage de l’encodage ISO-8859-1 (ou 8859-15 pour les windowsistes). Autant que faire se peut (un lourd existant peut l’empêcher par ex.), l’usage de l’UTF devrait être naturel.

Quelques trucs et astuces afin d’obtenir sur la majeure partie de la chaine de production une compatibilité UTF-8 :

  • pour le Web, cela passe par un document enregistré en utf-8, et un charset à utf-8 :
 <meta http-equiv="Content-type" content="text/html; charset=utf-8" />  
  • sous Apache, la directive AddDefaultCharset utf-8 peut s’avérer utile
  • un équivalent en ASP.NET pour forcer l’encodage de sortie, ou d’entrée, dans la section du web.config, la directive globalization :
 <globalization requestEncoding="utf-8" responseEncoding="utf-8"/>  
  • accès SSH : fixer sous puTTY l’UTF-8 (Windows / translation)
  • Debian : installer les locales qui vont bien et les positionner à UTF-8 (un excellent article pour Unix) :
 $ locale : affiche les locales pour le terminal $ dpkg-reconfigure locales : pour installer et fixer la locale par défaut $ export LC_ALL=fr_FR.UTF-8 pour fixer manuellement  
  • vim : un :set fileencoding vous indiquera si vous enregistrez en UTF, ou vous permettra de fixer l’encodage du fichier.
  • iconv sera votre compagnon pour la convertion de fichiers ISO-8859-1 en UTF-8
  • mysql >= 4.1 gère l’UTF en natif. Un “SET NAMES utf-8” indique l’encodage d’échange entre le client et le serveur. MySQL 5.0 charsets et collations (MySQL 4.1)
  • SQL Server : ntype (nvarchar, ntext, …) est ton ami

Quelques ressources que j’ai pu glaner sur le Net.

Ami PHPiste, Rubyiste, Javaiste, .NETiste, Perliste, kayakiste (euh non), à bon entendeur…

top like

Posted by – September 28, 2007

Vous gérez des systèmes sous Linux, alors 2 utilitaires bien pratiques :

  • htop : un avatar de la commande top mais qui vous donnera la taille réelle de la mémoire consommée ou restante totale (ou par processus), c’est à dire sans prendre en compte le cache par exemple, ce qui est tout de même plus parlant. En plus htop accepte l’utilisation de la souris ;)

Sous top :

Sous htop :

  • mtop : un utilitaire mysql qui permet de tracer et de diagnostiquer des requêtes longues. mtop affiche les requêtes en cours et leur déroulement, ce qui aidera à la résolution d’éventuelles requêtes mal écrites.

Installation sous Debian :

  • apt-get install htop
  • apt-get install mtop

..trop dur.

Comment ça marche memcached ?

Posted by – July 17, 2007

Comme le dit le site Danga qui maintient le projet

memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

On peut faire l’analogie avec les IPC sous Un*x : mémoire partagée et gestion des sémaphores, mais memcached permet le partage de données entre plusieurs machines ou processus à partir d’un cache serveur(s).

Memcached est utilisé par de gros sites tels que Live Journal, Facebook, Digg ou Slashdot. Le plus de memcached est qu’il est fournit avec de nombreuses API : Perl, .NET, Php, Ruby, …, ce qui facilite l’interopérabilité entre les systèmes.

  • Installation sous Debian : apt-get install memcached
  • Fichier de configuration : /etc/memcached.conf

Quelques ressources sur memcached

Dans le cadre d’un projet, j’en ai eu besoin afin de partager des URLs1 entre un serveur Linux et un serveur Windows 2003, ces 2 derniers effectuant des traitements sur des mails. Le service memcached2 étant installé sur le serveur Debian. L’affichage du résultat des 2 traitements Linux/Windows s’effectue sur une simple page ASP.NET d’un 3ème serveur.

memcached pourrait remplacer tout système de cache pour le Web (l’objet Cache d’ASP.NET compris). Le cache est primordial pour tout site un tant soit peu sérieux. 2 implémentations de la librairie C# pour le client memcached : Memcacheddotnet, EnyimMemcached (non testé).

Ci-après le code des 2 scripts à titre d’exemples, ils ne sont pas opérationnels tels que.

Script Perl

Dans le script Perl, les méthodes à connaître :

  • le constructeur, le cache peut être géré par plusieurs serveur de façon transparent : my $memd = new Cache::Memcached { ‘servers’ => [ “localhost:11211” ], };
  • stocker une valeur, $expire (expiration de la donnée en sec.) est optionnel : $memd->set($cle,$valeur,$expire);
  • obtenir une valeur : $val = $memd->get(“macle”);

Code complet du script Perl de traitement. Il a pour but de traiter des mails (bounces) provenant d’une douane anti-spams afin d’en extraire les URLs d’accès à l’interface Web de la quarantaine pour le mail concerné.


#!/usr/bin/perl
use lib '/home/sympa/bin';
use List;
use Conf;
use Log;
use Message;
use DBI;
use MIME::Parser;
use Cache::Memcached;
# email de notifications de la douane anti-spam
my $fromdouane="no-reply\\@xxxx.net";
my $regexp = "^(http://.+)";
my $expire = 8*60*60;
&Conf::load('/etc/sympa.conf') || die 'config_error';
my $spool = $Conf{'queue'};
my $memd = new Cache::Memcached { 'servers' => [ "localhost:11211" ], };
# traitement d'un message
# sortir l'URL d'accès à la quarantaine de la douane
# pour le mail concerné
sub TraiteMessage {
($message) = @_;
my $msg = $message->{'msg'};
my $hdr = $msg->head;
my $rcpt = $message->{'rcpt'};
my $sender = $message->{'sender'};
($listname, $robot) = split(/\\@/,$rcpt);
$listname = lc($listname);
if ($msg->is_multipart()) {
my $status = &tools::as_singlepart($msg, 'text/plain');
unless (defined $status) {
&do_log('err', 'Could not change multipart to singlepart');
return undef;
}
}
if (defined $msg->bodyhandle) {
my $mime = $hdr->get('Mime-Version') ;
my $content_type = $hdr->get('Content-type');
my $transfert_encoding = $hdr->get('Content-transfer-encoding');
unless (($content_type =~ /text/i and !$mime)
or !($content_type)
or ($content_type =~ /text\\/plain/i)) {
return $success;
}
my @body = $msg->bodyhandle->as_lines();
foreach $i (@body) {
#if ($transfert_encoding =~ /quoted-printable/i) {
# $i = MIME::QuotedPrint::decode($i);
#}
$i =~ s/^\\s*>?\\s*(.*)\\s*$/$1/g;
next if ($i =~ /^$/); ## skip empty lines
next if ($i =~ /^\\s*\\#/) ;
if( $i =~ /^$regexp/m ) {
$memd->set($listname,$i,$expire);
}
}
}
}
sub TraiteSpams {
my ($spool_dir) = @_;
unless (opendir(DIR, $spool_dir)) {
return undef;
}
my @qfile = sort grep (!/^\\.+$/,readdir(DIR));
closedir DIR;
foreach my $f (sort @qfile) {
my $message = new Message("$spool_dir/$f");
my $sender = $message->{'sender'};
if(defined $sender && "$sender" eq "$fromdouane") {
TraiteMessage($message);
}
}
}
&TraiteSpams("$spool/bad");

code de la classe C#

Code complet de la classe C# pour le traitement :


using Memcached.ClientLibrary;
using LumiSoft.Net.Mime;
public class DetectSpams : ITask
{
SockIOPool pool = null;
MemcachedClient mc = null;
Regex regex = new Regex("(http://.+[^\ ])",
RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
DataTable dt;
DBContext CurrentContext;
string fromdouane = CcinetConfig.Application["emailDouane"];
bool debug = CcinetConfig.Application["debug"] == "true";
string sqldouane = "";
/// <summary>
/// Init DB Lyris
/// </summary>
private void initDb()
{
CurrentContext = new DBContext();
CurrentContext.InitConfig(CcinetConfig.Global, "DbConfigLyris");
// extraction de la requête à exécuter : retrouve les messages de notifications de quarantaine
XmlDocument xsql = new XmlDocument();
xsql.Load(CcinetConfig.Application["SQLdouane"]);
XmlNode sqln = xsql.SelectSingleNode("//SQLdouane");
sqldouane = string.Format(sqln.InnerText, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, fromdouane);
}
/// <summary>
/// Init memcached
/// </summary>
private void initMemcached()
{
String[] serverlist = CcinetConfig.Application["memcachedServers"].Split(new char[] {';',',',' '});
pool = SockIOPool.GetInstance();
pool.SetServers(serverlist);
pool.InitConnections = 3;
pool.MinConnections = 3;
pool.MaxConnections = 5;
pool.SocketConnectTimeout = 1000;
pool.SocketTimeout = 3000;
// évite la maintenance des threads du pool : pb. pour la tâche lancée dans son propre thread
pool.MaintenanceSleep = 0;
pool.Failover = true;
pool.Nagle = false;
pool.Initialize();
mc = new MemcachedClient();
mc.EnableCompression = false;
mc.PrimitiveAsString = true;
}
private void shutdownMemcached()
{
SockIOPool.GetInstance().Shutdown();
}
private void getUrl(Stream msg)
{
Mime message = Mime.Parse(msg);
// traitement du message pour extraire l'URL puis sotckage dans le cache
if (message.MainEntity.From.Mailboxes.Length > 0 &&
message.MainEntity.From.Mailboxes[0].EmailAddress == fromdouane &&
message.MainEntity.To.Mailboxes.Length > 0)
{
string lstname = message.MainEntity.To.Mailboxes[0].EmailAddress.Split('@')[0];
foreach (MimeEntity mime in message.MimeEntities)
{
/// on prend uniquement le texte contenu dans la partie text/plain
if (mime.ContentType == MediaType_enum.Text_plain)
{
Match m = regex.Match(mime.DataText);
if (m.Success)
mc.Set(lstname, m.Value, DateTime.Now.AddHours(double.Parse(CcinetConfig.Application["expireHours"])));
}
}
}
}
/// <summary>
/// Transforme les \ en \ \ pour respect RFC 2822
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
private string FoldField(string field)
{
string stmp = field.Replace("\ \ ", "\ ");
return stmp.Replace("\ ", "\ ").Replace("\ ", "\ \ ");
}
/// <summary>
/// Stream pour LumiSoft.Mime
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private Stream getStream(string s)
{
byte[] b = Encoding.Default.GetBytes(s);
MemoryStream ms = new MemoryStream(b);
return (Stream)ms;
}

public void detectSpams()
{
initDb();
initMemcached();

try
{
CurrentContext.AddQueryResult(sqldouane, "NOTIFSSPAMS", true,false,true);
dt = CurrentContext.dataSet.Tables["NOTIFSSPAMS"];

// construction du message entêtes + corps
for (int i = 0; i < dt.Rows.Count; i++)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}\ \ \ \ ", FoldField((string)dt.Rows[i]["hdrall_"]));
sb.Append(FoldField((string)dt.Rows[i]["body_"]));

getUrl(getStream(sb.ToString()));
}
}
catch (Exception e)
{
LogManager.WriteLog("WebArcSvc", string.Format("DetectSpams : {0}\ {1}", e.Message, e.StackTrace), LogType.ERROR);
}

shutdownMemcached();
}

#region ITask Members

public void Execute(TaskCallback taskCallback, object[] args)
{
detectSpams();
}

#endregion
}

consommation des données dans le cache

Il reste à afficher ce que je souhaite sur le serveur Web, sur une page de gestion, le code pour afficher les données contenues dans le cache sur un “repeater” :


void AfficheNotifsSpams_PreRender(object sender, EventArgs e)
{
Hashtable ht = new Hashtable();
ListeDiffusionCollection lddcoll = ListeDiffusion.GetAllLists();
for (int i = 0; i < lddcoll.Count; i++)
{
string ldd = ((ListeDiffusion)lddcoll[i]).Libelle.ToLower();
string url = (string) mc.Get(ldd);
if (url != null &&
!ht.ContainsKey(ldd))
ht[ldd] = url;
}
rpNotifs.DataSource = ht;
rpNotifs.DataBind();
}

1 trouvés après des traitements dans des mails par un script Perl sous Debian et un service Windows C#

2 disponible aussi pour windows

Comment ça marche mon réseau ?

Posted by – July 11, 2007

Cela fait suite à l’article VServer : une mise en place sous Debian. Il est toujours intéressant de schématiser les écrits, cela résume bien l’architecture générale mise en place.

Architecture od’s home

Avec une seule IP (fixe), c’est toujours amusant de voir ce que l’on arrive à faire :

Les avantages de son hébergement :

  • liberté de mettre en place ce que l’on souhaite
  • et de sa gestion
  • économie d’un hébergement

Les défauts de s’héberger :

  • upload faible : 75 ko/s 100 ko/s, il peut donc y avoir des ralentissements pour les visites
  • pas à l’abri d’une panne du fournisseur d’accès
  • ni d’un changement de l’IP [EDIT] sous free dégroupé, l’IP est fixe
  • l’infrastructure n’est pas optimum : onduleurs, sauvegardes, etc, etc.

Connaissez-vous qpsmtpd ?…

Posted by – June 21, 2007

On connaît les milters et autres méthodes pour effectuer des vérifications toujours plus en amont de la transaction SMTP pour la messagerie, ceci afin de lutter encore plus efficacement le SPAM. Bien souvent, cela reste assez fastidieux à mettre en oeuvre et rajoute une complexité supplémentaire au MTA, le serveur de messagerie final ne devrait être là que pour délivrer les (vrais) mails, et non de s’occuper à 100 % de la sécurité.

qpsmtpd est un serveur SMTP très léger et très modulaire qui se base sur le principe des plugins et des hooks qu’il peut appeller à chaque instant du protocole SMTP : mail from, rcpt to, data, … Le principe est de lancer qpsmtpd à l’écoute du port SMTP (25), charge à lui ensuite de faire les vérifications d’usage (beaucoup de plugins sont livrés dans le produit de base pour ce type d’opérations) pour ensuite relayer au serveur de messagerie qui écoutera sur un autre port (2525) par exemple. En gros qpsmtpd joue le rôle de firewall ou de frontal mail avant d’entrer dans l’infrastructure de la messagerie interne.

L’avantage de cette technique est de pouvoir développer un plugin maison, avec des hooks à appeler selon ses besoins : on peut introduire des règles métiers sur les mails : vérification de l’existence du compte, vérification de l’expéditeur selon des règles qui nous sont propres, etc…et de couper la transaction SMTP avant même de recevoir le message : gain de temps et de ressources pour le serveur MTA en bout de chaîne.

mail -> qpsmtpd (25) -> smtp (2525) -> délivre

Des plugins Postfix, Exim, Qmail…et un transfert simple smtp est aussi prévu (pour Sendmail notamment).

Il faut connaître Perl, mais les plugins sont simples à développer. Un exemple qui vérifie que le “to” existe bien (pour la démo, mais on pourra penser à une consultation LDAP, base de données, …) :



use Qpsmtpd::DSN;

sub hook_rcpt {
my ($self, $transaction, $recipient) = @_;
#my @badrcptto = $self->qp->config("badrcptto") or return (DECLINED);
return (DECLINED) unless $recipient->host && $recipient->user;
my $host = lc $recipient->host;
my $from = lc($recipient->user) . '@' . $host;

return Qpsmtpd::DSN->no_such_user("mail to $from not accepted here") if $recipient->user ne 'newsland';

return (DECLINED);
}

A découvrir en tout cas pour rajouter une brique de sécurité à votre plateforme.

Une présentation du produit.