Preparation de la page….
(Merci toniotonio que je copie colle depuis https://forum.ubuntu-fr.org/viewtopic.php?id=161292 )
L’ordre global d’application est le suivant :
Postfix établit 5 étapes de tests (stages) au niveau des SMTPD Restrictions qui correspondent chacune à une commande SMTP :
Test cote postfix | Vue SMTP |
---|---|
smtpd_client_restrictions | connection du client |
smtpd_helo_restrictions | HELO |
smtpd_sender_restrictions | MAIL FROM |
smtpd_recipient_restrictions | RCPT TO |
smtpd_data_restrictions | DATA |
Par defaut Postfix est configuré pour évaluer les tests au moment de la commande RCPT TO, donc dans la section smtpd_recipient_restrictions.
C’est à dire que le blocage n’interviendra qu’au moment ou le client envoie la dernière commande.
A l’intérieur d’un restriction stage il existe des access lists. Dès qu’une de ces access lists renvoient OK, on passe au stage suivant. (la fin d’un stage par défaut est PERMIT)
Si une access list renvoie REJECT le message est bloqué. Si une access list ne matche pas, on passe a l’access list suivante dans le stage. (DUNNO)
Dans certains cas on peut avoir besoin de loguer certaines caracteristiques des mails… (et voire meme faire d'autres actions Rejets…)
Ainsi tout les sujets des mail seront dans les logs Warning :)
A manier avec bcp de precaution (cela peu, forcement, quelque peu indisposer la signature et/ou le chiffrement des mails)
#option devant permettre de ne pas saturer le povre mx de wanadoo smtp_destination_concurrency_limit = 2
# à partir de 2 erreurs, chaque erreur impose un délai de 65 secondes smtpd_soft_error_limit = 1 smtpd_error_sleep_time = 65s # à la 4è erreur Postfix coupe la session smtpd_hard_error_limit = 3 # une adresse IP ne peut ouvrir que 3 sessions en parallèle smtpd_client_connection_count_limit = 3 # une adresse IP ne peut ouvrir que 3 sessions sur le délai de 2 minutes smtpd_client_connection_rate_limit = 3 smtpd_anvil_rate_time_limit = 2 ###unknown_address_reject_code = 550 # les clients qui ne respectent pas le protocole: dehors ! smtpd_helo_required = yes strict_rfc821_envelopes = yes ###smtpd_delay_reject = yes
Changement de queue d'un mail a l'entrée
Quelques Urls rigolotes:
A rajouter dans le main.cf
smtpd_recipient_restrictions = check_recipient_access hash:/etc/postfix/recipient_restrictionsCreer le fichier comme suit
moche@vilainpas.beau DISCARD mafia.gang REJECT gentilsdeconnecters HOLD
Etant donné que je prefere que ce serveur de decontamination/relayage soit indepedant, il n'appuirais pas son auth en local…
disable_vrfy_command = yes smtpd_sasl_auth_enable=yes broken_sasl_auth_clients=yes smtpd_sasl_local_domain = smtpd_sasl_application_name = smtpd smtpd_sasl_security_options = noanonymous ###smtp_sasl_mechanism_filter = PLAIN LOGIN ANONYMOUS smtp_sasl_mechanism_filter = PLAIN LOGIN smtpd_sasl_authenticated_header = yes
et maintenant expliquer sur quoi on base l'auth ;)
# sets gmail as relay relayhost = [smtp.gmail.com]:587 # use tls smtp_use_tls=yes # use sasl when authenticating to foreign SMTP servers smtp_sasl_auth_enable = yes # path to password map file smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd # list of CAs to trust when verifying server certificate smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt # eliminates default security options which are imcompatible with gmail smtp_sasl_security_options =
cat /etc/postfix/sasl_passwd [smtp.gmail.com]:587 username:password
postmap /etc/postfix/sasl_passwd chown postfix sasl_passwd* /etc/init.d/postfix reload
smtp_use_tls=yes in main.cf smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_security_level = may smtpd_tls_auth_only = no # Decommenter la ligne suivante pour accepter _uniquement_ le traffic en tls #smtpd_enforce_tls = yes
#smtpd_tls_CAfile = /etc/postfix/cacert.pem # Si on veut authentifier les autres, il faut indiquer ou trouver les certificats # des CA : #smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_received_header = yes smtpd_tls_loglevel = 1
smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom
tls_random_source = dev:/dev/urandom smtp_tls_session_cache_timeout = 3600s
smtp_use_tls = yes
smtp_tls_loglevel = 1
smtp_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtp_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
Nous ne forcons pas le traffic TLS sortant, car si la cible dysfonctionne… pour forcer le TLS en fonction de la destination
Le relayage pure peut induire des problematiques de NPAI, cad
A cela 2 parades…
Doc issue de http://forum.ubuntu-fr.org/viewtopic.php?id=299249, mais je recommande de lire les docs de postfix, notament pour mieux appréhender les TTL du cache…
De plus pour avoir teste, si un flux SMTP est a destination de plusieurs emails, et que l'une d'entre elle est inexistante, le mail n'est refusé _que_ pour celle si !
Prg issue de http://mail.pm.org/pipermail/za-pm/2005-June/000269.html Il s'agit d'un fichier de type “Berkeley DB (Btree, version 9, native byte-order)” Pour le lire en perl il sera agrable d'installer la lib libberkeleydb-perl
#!/usr/bin/perl # Filename: bdbmfile.pl # use BerkeleyDB; use Fcntl; die "Usage\n$0 dbmfile.pl\n" if (@ARGV < 1); my $filename = $ARGV [0]; my %h; tie %h, 'BerkeleyDB::Btree', -Filename => $filename, -Flags => DB_RDONLY or die "Cannot open $filename $!\n"; my ($status,$null,$time,$msg); my $init=0; my $mod=0; foreach (keys %h) { if(/^_LAST_CACHE_CLEANUP_COMPLETED_/) { $init=$h{$_}; } else { ($status,$null,$time,$msg)=split(/:/,$h{$_}); print scalar(localtime($time)); print " $status $_ =>".$h{$_}."\n"; if($time>$mod) { $mod=$time; } } } print "Last init ".scalar(localtime($init))."\n"; print "Last mod ".scalar(localtime($mod))."\n"; untie %h; exit;
nto unix - n n - - pipe flags= user=nobody argv=/usr/local/bin/nto.pl -s $sender -n $nexthop -r $recipient -u $user
Ici, c'est par rapport a mon transport…
domaine_ou_email nto:domaine_ou_email|rewrite,ressend,announce=/etc/postfix/announce.txt
From: __RECIPIENT__ To: __SENDER__ Subject: [MAIL LOST] __SUBJECT__ MIME-Version: 1.0 Reply-To: __NEXTHOP__ Content-Type: text/plain; charset=utf-8 Content-Disposition: inline User-Agent: Manual mail Bonjour __SENDER__, Nous sommes au regret de vous apprendre que __RECIPIENT__ a demenagé. Maintenant il reside à __NEXTHOP__. Cordialement, Le ReDirecteur.
#!/usr/bin/perl # License # GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt) # Authors # DELAPORTE Antoine use strict; use warnings; use Getopt::Std; use Net::SMTP; # Configuration dans /etc/postfix/master.cf # nto unix - n n - - pipe # flags= user=nobody argv=/usr/local/bin/nto.pl -s $sender -n $nexthop -r $recipient -u $user # # Configuration dans la transportable # email/domaine nto:email/domaine|ressend,announce=/etc/postfix/announce.txt # email/domaine email/domaine | parametres # Parametres: # ressend (par defaut, sauf si announce present), envoie le mail retravaillé pour le destinataire reel # annouce=fichier envoie au sender un mail comme quoi l'utilisateur a demenagé # Les entrees __SENDER__ __RECIPIENT__ __NEXTHOP__ et __SUBJECT__ seront automatiquement reecrite # TODO un lock pour ne pas renvoyer 2 fois au meme emetteur l'annonce de demenagement # rewrite (par defaut desactivé) reecris dans le header tout les recipient par des nexthop my %opt; getopts( "s:n:r:u:", \%opt ); my $subject; my $inbody=0; my $body=""; my $header=""; my $smtpserver="localhost"; my $smtpport=25; my %cfg; my ($nexthop,$params)=split(/\|/,$opt{n},2); $opt{n}=$nexthop; my $i=0; if(defined($params)) { foreach (split(/,/,$params)) { my ($clef,$val)=split(/=/); if(!defined($val)) { $val=1; } $cfg{$clef}=$val; $i++ } } if(($i==0) or defined($cfg{rewrite})) { $cfg{ressend}=1; } if(defined($cfg{announce}) and ($cfg{annouce}==1)) { $cfg{announce}="/etc/postfix/announce.txt"; } if(!($opt{n} =~ m/@/)) { $opt{n}=$opt{u}."@".$opt{n}; } while(<STDIN>) { if(/^$/) { $inbody++; } if(!$inbody) { $header.=$_; if(/^Subject/) { chomp(); $subject=$_; $subject=~s/^Subject: //g; } } else { $body.=$_; } } if($cfg{ressend}) { if($cfg{rewrite}) { $header=~s/$opt{r}/$opt{n}/g; } my $smtp = Net::SMTP->new($smtpserver, Port=>$smtpport, Timeout => 10, Debug => 1); die "Could not connect to server!\n" unless $smtp; ###$smtp->auth($smtpuser, $smtppassword); $smtp->mail($opt{s}); $smtp->to($opt{n}); $smtp->data(); $smtp->datasend($header."\n".$body); $smtp->quit; } if(defined($cfg{announce}) and (-r $cfg{announce})) { my $mail=""; open(ANN,"<".$cfg{announce}); while (<ANN>) { $mail.=$_; } close(ANN); $mail=~s/__SENDER__/$opt{s}/g; $mail=~s/__RECIPIENT__/$opt{r}/g; $mail=~s/__NEXTHOP__/$opt{n}/g; $mail=~s/__SUBJECT__/$subject/g; my $smtp = Net::SMTP->new($smtpserver, Port=>$smtpport, Timeout => 10, Debug => 1); die "Could not connect to server!\n" unless $smtp; ###$smtp->auth($smtpuser, $smtppassword); $smtp->mail($opt{n}); $smtp->to($opt{s}); $smtp->data(); $smtp->datasend($mail); $smtp->quit; }
La réecriture des emails va se faire au travers de regex, effectivement les tables de correspondance, c'est drole– a maintenir Donc a savoir :
Il existe 3 types de tables:
Ces 3 tables sont parametrables (modification et ou de l'envelope ou du header)
Que je ne recommande pas, vraiment pas, il reecrit _tout_ et par consequant ne sert plus a rien, generalement
Afin de reecrire les emails de la forme userX@domaine.tld en domaine.tld_userX la syntax est simple:
sender_dependent_default_transport_maps = hash:/etc/postfix/sender_relayhost
Evidement ce fichier peut en dehors d'etre renomé, etre hashé differement (en **regex** pex)
georges@oyesspamme.com smtpip:[smtp.free.fr]
Evidement //smtp.free.fr// peut pointer sur un smtp authentifé, etc. Bien sur on n'est pas obligé de mettre une email, un domaine, c'est faisable.
smtpip unix - - n - - smtp -o smtp_bind_address=10.0.12.31 -o smtp_helo_name=FelixBis -o syslog_name=Felix2 -o smtp_sasl_auth_enable=yes -o smtp_sasl_security_options=noanonymous -o smtp_sasl_password_maps=hash:/etc/postfix/sasl_passwd -o smtp_use_tls=yes -o smtp_tls_CAfile=/etc/ssl/certs/ca-certificates.crt
Et un grand merci à :
Et voici la recette miracle a mettre dans le .procmailrc ne pas oublier cependant de creer le fichier local/mail/procmail/echo-reply avec le joli texte que l'on veux…
:0Hhb * ^TOuser\+ping@domaine.tld.org * !^FROM_DAEMON * $!^X-Loop: $LOOP_TAG | (tempfile=`mktemp`; cat - > $tempfile; cat $tempfile | \ formail -r -k -A'Precedence: junk' \ -A'Auto-Submitted: auto-replied' \ -A'MIME-Version: 1.0' \ -A'Content-type: text/plain; charset=US-ASCII' \ -A"X-Loop: $LOOP_TAG" \ -A"From: postmaster@$MYDOMAIN (Echo automatic service)" ; \ cat $HOME/local/mail/procmail/echo-reply; \ echo ""; echo "Your original message:"; echo ""; \ cat $tempfile; rm $tempfile) \ | $SENDMAIL -t
Objectifs:
Donc, un fetchmailrc
server pop.fai.tld protocol POP3 username monuserchezlefai password motdepassesupercomplique fetchall mimedecode ssl is monuserdemondimaine+fai@mondomaine.tld smtphost smtp.mondomaine.tld
X50 !P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
#!/bin/bash email=$1 serversmtp=$2 domaine=`echo $email | cut -f2 -d"@"` vise=postmaster@domaine.tld if [ x$1 == x ]; then echo "Il faut au moins un parametre : l'email a tester" exit fi if [ x$2 != x ]; then echo "La foncionnalitee d'utiliser un autre MX n'est pas encore la" exit echo "MX utilisé : $serversmtp" fi echo "Envoie le virus a : $email" echo "Donc aux serveurs de : $domaine" echo " " echo "Emission" dig MX $domaine +noall +answer | grep "^$domaine" | tr -s "\t " " " | cut -d" " -f6 | while read serversmtp do echo " --> $serversmtp" expect 2>&1 >/dev/null <<__EOF__ spawn telnet $serversmtp smtp set timeout 60 expect "220 " send "helo eicar-test-adlp.org\r" expect "250 " send "mail from: <$vise>\r" expect "250 " send "rcpt to: <$email>\r" expect "250 " send "data\r" expect "354 " send "From: <$vise>\r" send "To: <$email>\r" send "Subject: Test virus sur relais $serversmtp\r" send "\r\r" send "Utilsation du relais $serversmtp" send "Debut d'emission du virus\r" ####### X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* send "\130\065\117\041\120\045\100\101\120\133\064\134\120\132\130\065" send "\064\050\120\136\051\067\103\103\051\067\175\044\105\111\103\101" send "\122\055\123\124\101\116\104\101\122\104\055\101\116\124\111\126" send "\111\122\125\123\055\124\105\123\124\055\106\111\114\105\041\044" send "\110\053\110\052" send "\r" send "Fin d'emission du virus\r" send "\r" send ".\r" close __EOF__ done
Script en 1 ligne, ultra simplifié
mailq | perl -ne 'chomp();s/^$/\n/g;s/^-.*//g;print $_;'
#!/usr/bin/perl # License # GPLv2 (http://www.gnu.org/licenses/gpl-2.0.txt) # Authors # DELAPORTE Antoine # Versions # 1.0 Make a first script who just transform the result of mailq # in a one line per mail # 2.0 Add hability to read mail data from postcat (from,to,subject,date) # 2.1 Add filtering options (from && to) # 2.2 Add --delete and --hold option # 2.3 Add first smtp server sender (and filtering) # 2.4 Add Help # 2.5 Add --stat options (who print information by from,to,smtp) # TODO: for stat option try to give msgid # cleaning the code, (variable name, frenglish, key hash name cf 'From: ') # adding an option to give information from logs # maybe add an option to do the postcat -q msgid ? use strict; use warnings; use Data::Dumper; use Getopt::Long; sub trait1msqid { my ($id,$tab,$del,$hol)=@_; print $id.";".$$tab{"Received"}.";".$$tab{"From: "}.";".$$tab{"To: "}.";".$$tab{"Date: "}.";".$$tab{"Subject: "}."\n"; if( (defined($del) and open(FR,"/usr/sbin/postsuper -d $id 2>/dev/null |")) or(defined($hol) and open(FR,"/usr/sbin/postsuper -h $id 2>/dev/null |")) ) { while(<FR>) {} close(FR); } } sub getheader { my ($ret,$msgid,@toget)=@_; my $cont=1; my $totest; my $ligne; $$ret{Received}=""; if(open(FR,"/usr/sbin/postcat -q $msgid 2>/dev/null |")) { while($cont and $ligne=<FR>) { if($ligne =~ /^$/) { $cont=0; } elsif($ligne =~ /^Received: from / and !($ligne =~ /localhost/)) { chomp($ligne); $ligne=~ s/^Received: from //g; $$ret{Received}=$ligne; } else { foreach $totest (@toget) { if($ligne =~ /^$totest/ and !defined($$ret{$totest})) { chomp($ligne); $ligne=~ s/^$totest//g; $$ret{$totest}=$ligne; } } } } close(FR); } foreach(@toget) { if(!defined($$ret{$_})) { $$ret{$_}=""; } } } sub testheader { my ($regex,$chaine)=@_; my $ret; if(defined($regex)) { if($chaine =~ /$regex/i) { $ret=1; } else { $ret=0; } } else { $ret=1; } return($ret); } sub dossomstat { my ($res,$id,$val)=@_; my $filtre; foreach $filtre (("Received","To: ","From: ")) { if(defined($$val{$filtre})) { # FIXME Coder l'integration des msgID if(!defined($$res{$filtre}{$$val{$filtre}}{Nb})) { $$res{$filtre}{$$val{$filtre}}{Nb}=1; } else { $$res{$filtre}{$$val{$filtre}}{Nb}++; } } } } open(MQ,"mailq 2>/dev/null |") or die "Impossible d'ouvrir la mailq...\n"; my $precline=<MQ>; $precline=""; my %tab; my $id; my @null; my %cou; my %resstat; my ($stat,$help,$SMTP,$FoT,$From,$To); my ($actdel,$acthol); GetOptions('Stat' => \$stat,'help' =>\$help,'SMTP=s'=> \$SMTP, 'FromOrTo=s' => \$FoT, 'From=s' => \$From, 'To=s' => \$To, 'Delete' => \$actdel, 'Hold' => \$acthol ); if(defined($actdel) and defined($acthol)) { print "Options incompatibles\n\n"; $help=1; } elsif((defined($actdel) or defined($acthol)) and !(defined($From) or defined($To) or defined($SMTP))) { print "On ne peux holder ou deleter sans filtre\n\n"; $help=1; } if($help) { print "Fonctions disponibles: ./mailqon1line [--SMTP <srv>] [--FromOrTo <email>|[--From <email> |& --To <email>] [--Delete || --Hold] --SMTP %s : Recherche les serveur SMTP emetteur --FromOrTo %s : Recheche dans le champs email from ou to --From %s : Recheche dans le champs email from --To %s : Recheche dans le champs email to --Delete : Supprime le mail de la mailq --Hold : Met dans la queue d'attente --Stat : Ne renvoie des statistiques sur les memes filtres (desactive les options hold et delete) "; exit(); } while(<MQ>) { chomp(); if(!/^--/) { tr/\t / /s; s/\*//g; if($precline eq "" and $_ ne "") { #On va commencer une nouvelle ligne ($id,@null)=split(/ /,$_,2); $tab{$id}{mq}=$_; } $tab{$id}{mq}.=$_; $precline=$_; } } close(MQ); foreach $id (keys(%tab)) { getheader($tab{$id},$id,("From: ","To: ","Date: ","Subject: ")); } if(defined($FoT)) { $From=$FoT; $To=$FoT; } # eviter la double boucle qui est inutil et ralenti trop l'affichage # surtout en cas de queue de messageries trop pleines foreach $id (keys(%tab)) { $cou{from}=testheader($From,$tab{$id}{"From: "}); $cou{to}=testheader($To,$tab{$id}{"To: "}); $cou{smtp}=testheader($SMTP,$tab{$id}{"Received"}); if($cou{smtp}) { # la recherche sur un champs non defini renvoie toujours ok if(defined($FoT)) { if($cou{from} or $cou{to}) { if($stat) { dossomstat(\%resstat,$id,$tab{$id}); } else { trait1msqid($id,$tab{$id},$actdel,$acthol); } } } elsif($cou{from} and $cou{to}) { if($stat) { dossomstat(\%resstat,$id,$tab{$id}); } else { trait1msqid($id,$tab{$id},$actdel,$acthol); } } } } if($stat) { foreach my $filtre (keys(%resstat)) { foreach my $val (keys($resstat{$filtre})) { print "$filtre;$val;".$resstat{$filtre}{$val}{Nb}."\n"; } } }
Script'n Co Ce Makefile est lancé via une crontab, il rehash les fichiers si necessaire, voire relance postifix… : pour le moment, pas de traitement d'erreure d'un hash….
*/5 7-19 * * * root /usr/bin/make -C /etc/postfix/ >/dev/null
#!/usr/bin/make -f MAPS=transport.db relayed-emails.db ALIASES= aliases RESTART= mynetwork CMDAL=/usr/bin/newaliases CMDPM=/usr/sbin/postmap ###peut etre voire du coté de VPATH # Je doute de l'utilitee aujourd'hui de cela, mais ca marche(tm) .SUFFIXES: . .db all: $(MAPS) /var/spool/postfix/pid/master.pid aliases.db /var/spool/postfix/pid/master.pid: $(RESTART) echo RESTART /etc/init.d/postfix restart aliases.db: aliases echo ALIASING $(CMDAL) || { rm -f $@ $.dir; exit 1; } %.db : % echo COMPILING $(CMDPM) $*
The initial telnet: > symbolises your shell prompt. telnet: > telnet imap.example.com imap [...] client: a1 LOGIN MyUsername MyPassword [...] server: a1 OK Logged in. client: a2 LIST "" "*" server: * LIST (\HasNoChildren) "." "INBOX" server: a2 OK List completed. client: a3 EXAMINE INBOX server: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) server: * OK [PERMANENTFLAGS ()] Read-only mailbox. server: * 1 EXISTS server: * 1 RECENT server: * OK [UNSEEN 1] First unseen. server: * OK [UIDVALIDITY 1257842737] UIDs valid server: * OK [UIDNEXT 2] Predicted next UID server: a3 OK [READ-ONLY] Select completed. client: a4 FETCH 1 BODY[] server: * 1 FETCH (BODY[] {405} server: Return-Path: sender@example.com [...] server: ) server: a4 OK Fetch completed. client: a5 LOGOUT