Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
[TIP] Postfix tricks, Antispam on demand
View unanswered posts
View posts from last 24 hours
View posts from last 7 days

 
Reply to topic    Gentoo Forums Forum Index Forum italiano (Italian) Risorse italiane (documentazione e tools)
View previous topic :: View next topic  
Author Message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Fri Nov 04, 2005 5:09 pm    Post subject: [TIP] Postfix tricks, Antispam on demand Reply with quote

Innanzitutto una premessa: questo non è un howto.

Raccolgo in questo post una serie di tips, più o meno noti, inerenti la configurazione di un server mail basato su postfix.

Il setup utilizzato:
- Postfix e domini virtuali su database Mysql
- Maildrop per il delivery
- Dspam per l'antispam
- Courier per IMAP e POP3

Alcune soluzioni proposte sono prelevate dalle numerose guide presenti sulla rete, altre sono frutto di mie personali sperimentazioni per le quali vale il seguente disclaimer:
Quote:
a me funzionano, se il tuo sistema implodesse e/o i tuoi utenti dovessero rincorrerti forconi alla mano gridando "al rogo! al rogo!", non mi ritengo responsabile.

Requisito fondamentale è che il lettore abbia una certa familiarità con postfix nel tipico setup domini virtuali + mysql. Ci sono già ottimi howto sull'argomento, per cui darò per scontato che si disponga di un sistema correttamente configurato.

Questo è il punto di non ritorno, se ritieni che quanto hai letto finora sia sufficiente per mandarmi a cagare, è arrivato il momento di passare a letture più interessanti.

Ci sei ancora ? ok, allora andiamo a cominciare.

nota:
nella definizione della mappe, saranno omessi i campi relativi a db, user, password, etc

Gli alias catch-all
Un alias catch-all ha la forma
Code:
@dominio   nome@dominio

il suo fine è quello di veicolare all'indirizzo nome@dominio tutte le email spedite a qualsiasicosa@dominio
Sebbene il suo utilizzo possa trasformare l'account catch-all in un ricettacolo di spam, alcuni clienti lo richiedono e tanto basta.

Veniamo al problema: che succede se ho altri account tipo acc1@dominio, acc2@dominio ?
Gli account in questione non riceveranno mai posta perchè, causa catch-all, saranno considerati alias di nome@dominio
Il problema si risolve inserendo un alias per ogni malibox
Code:
acc@dominio acc@dominio

nella tabella contenente gli alias.
Come si può ottimizzare la cosa ?
Si crea una nuova mappa mysql_virtual_email2email.cf
Code:
table = mailbox
select_field = username
where_field = username

// mailbox:  tabella che contiene le mailbox
// username: campo che contiene l'indirizzo

e la si aggiunge alle virtual_alias_maps.
La mappa trasforma ogni mailbox nell'alias di se stesso, problema risolto.

Allegati pericolosi
Gran parte dei virus/worm si diffonde grazie ad allegati che, eseguiti più o meno con il consenso dell'utente (ogni riferimento ad outlook è puramente intenzionale), provvedono ad infettare il sistema.
Come proteggere l'utente dall'allegato killer ?
Prima ancora dell'antivirus, è possibile configurare postfix per rifiutare le email contenenti allegati "eseguibili".
header_checks è tuo amico, nel main.cf
Code:
header_checks = regexp:/etc/postfix/mime_header_checks

/etc/postfix/mime_header_checks
Code:
/^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+\.(ad[ep]|asd|ba[st]|
c[ho]m|cmd|cpl|crt|dbx|dll|exe|hlp|hta|in[fs]|isp|js|jse|lnk|md[etw]|ms[cipt]|
nws|ocx|ops|pcd|pi|pif|prf|reg|scf|scr|sct|sh[bms]|swf|uue|vb|vb[esx]|vxd|wab|ws[cfh]))"?\s*$/   
REJECT I files allegati alle email che contengono (o terminano) in "$3" sono rifiutati da questo
server perchè potrebbero contenere virus. Il file "$2" è stato rifiutato.
Per risolvere il problema basta includere tali files in un archivio zip.

nota: ho spezzato il codice in più linee per motivi di leggibilità, ma va tutto in una linea.

Antispam on demand
Quasi tutte le soluzioni proposte negli howto, prevedono lo schema
Code:
Mail server esterno -> content filter -> Mail server interno (127.0.0.1)

Alcuni setup utilizzano anche 3 istanze di postfix (smtpd) in esecuzione sulla stessa macchina, ma a me, sto fatto delle istanze multiple, non è mai piaciuto.

In più, ho la necessità di abilitare i controlli antispam solo per quei clienti che pag... che richiedono il servizio.
Nell'esempio che andrò a proporre ho utilizzato dspam, ma modificarlo per SA non dovrebbe essere difficile.

Prerequisito fondamentale è che si utilizzi maildrop per il virtual delivery, cioè che nel main.cf si abbia
Code:
virtual_transport = maildrop

Per prima cosa, nella tabella che contiene i domini, si aggiunge un altro campo
Code:
option    tinyint(3) unsigned

e si setta option=3 per tutti i domini che necessitano di controlli antispam.
successivamente, si crea una nuova mappa mysql_virtual_antispam_maps.cf
Code:
table = domain
select_field = 'maildrop:spamcheck'
where_field = domain
additional_conditions = and domain.option = 3

e la si aggiunge alle transport_maps, mentre nel master.cf si definisce
Code:
maildrop  unix  -       n       n       -       10       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} $nexthop

come funziona l'accrocchio ?

quando viene processato un messaggio, postfix controlla se nelle trasport map sia definito un particolare trasporto per quel recipient o dominio.
Nel caso in cui, per il dominio in esame, si abbia option=3, la mappa appena creata restituisce il valore maildrop(trasporto):spamcheck(nexthop)

Nel master.cf abbiamo configurato maildrop per ricevere come parametro l'argomeno $nexthop
Modificando /etc/maildroprc, aggiungiamo il controllo
Code:
SPAMCHECK=(("$1" eq "spamcheck") && ($SIZE < 250000))

if ($SPAMCHECK)
{
    xfilter "/usr/bin/dspamc --user $LOGNAME --mode=toe --stdout --feature=chained,noise --deliver=innocent,spam"
    # Se è spam, ciao.
    if (/^X-DSPAM-Result: Spam.*$/)
    {
        to "$HOME/$DEFAULT.Spam/"
    }
}

Se maildrop è eseguito con il parametro "spamcheck" (e il messaggio è sotto i 250kb) viene invocato il controllo antispam.

Semplice no ? la vostra soddisfazione è il nostro miglior premio .... piripiripì! snack! snack! hihooo hihooo *
* chi capisce questa, possiede una solida cultura in fatto di B-Movies all'italiana (gugle non vale, cheater)

Bene, volevo aggiungere altre cosucce ma il post sta diventando troppo lungo, per cui mi fermo e ringrazio quei due o tre utenti (me compreso) che hanno avuto la pazienza di leggersi tutta la sbobba.

Sperando che quanto scritto possa essere d'aiuto a qualcuno, vi saluto e vado a cercare un'altra scusa per non lavorare.


Last edited by makoomba on Fri Nov 04, 2005 5:41 pm; edited 1 time in total
Back to top
View user's profile Send private message
xchris
Advocate
Advocate


Joined: 10 Jul 2003
Posts: 2824

PostPosted: Fri Nov 04, 2005 5:23 pm    Post subject: Reply with quote

interessante...
peccato che non usi questo tipo di setup.
(soprattutto l'antispam on demand)

ti consiglio di specificare un po' meglio il tipo di setup adottato all'inizio del post.

tempo fa ho provato dspam con postfix ma non mi era parso molto stabile.
(capitava di vedere la cpu al 99% con dspam inchiodato)
ora come va?

complimenti cmq per un post di TIPS inusuali :)
ciao
_________________
while True:Gentoo()
Back to top
View user's profile Send private message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Fri Nov 04, 2005 5:35 pm    Post subject: Reply with quote

xchris wrote:
ti consiglio di specificare un po' meglio il tipo di setup adottato all'inizio del post.

ok, ora edito
xchris wrote:
tempo fa ho provato dspam con postfix ma non mi era parso molto stabile.

considera che sono passato a dspam perchè SA stava uccidendo un dual xeon.
va configurato attentamente, soprattutto la fase di training.
il load è sceso ad 1/4 e falcia lo spam con un'accuratezza micidiale.
xchris wrote:
complimenti cmq per un post di TIPS inusuali :)

ci ho messo un pò a scriverlo, fa piacere constatare che qualcuno lo ha letto ;)
Back to top
View user's profile Send private message
FonderiaDigitale
Veteran
Veteran


Joined: 06 Nov 2003
Posts: 1710
Location: Rome, Italy

PostPosted: Thu Dec 08, 2005 3:31 pm    Post subject: Reply with quote

L'ho letto anche io, in effetti e' raro vedere setup di postfix + dspam in giro.

Mi interesserebbe vedere come hai configurato e allenato dspam, l'output di dspam_stats, et al.
sopratutto per fare un confronto col mio.

ciao e grazie
_________________
Come disse un amico, i sistemisti sono un po' come gli artigiani per l'informatica :)
Back to top
View user's profile Send private message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Thu Dec 08, 2005 4:12 pm    Post subject: Reply with quote

TOE per tutti gli utenti.
ho fatto il train di un gruppo globale con qualche migliaio di messaggi già suddivisi in SPAM/HAM.
poi più passaggi con gli stessi msg + altri segnalando a dspam falsi positivi e missed spam.

ogni utente è in merged group con il gruppo globale ma resta indipendente per il training successivo.
per le stats, ti posso postare quelle del mio server che ha un traffico molto più moderato rispetto al dual xeon citato nel tip.
Code:
global            TS:  4518 TI:  6471 SM:   318 IM:     0 SC:  3137 IC:   959
utente@dominio    TS:   246 TI:  1622 SM:     7 IM:     5 SC:    0 IC:    0

appena l'assistenza restituisce il big server al cliente, ho intenzione di aggiornare dspam alla nuova versione e migrare da mysql a CSS.

per quanto riguarda il setup, buona parte è già riportata nel tip.
nel master.cf ho
Code:
dspam-retrain   unix    -       n       n       -       10      pipe
  flags=Ru user=vmail argv=/usr/bin/dspam-multiple.pl $nexthop $sender

dspam-multiple.pl permette di inviare più msg come allegati e si occupa di richiamare dspam per il retrain.
in una transport maps è definito
Code:
spam@dominio dspam-retrain:spam
nospam@dominio   dspam-retrain:innocent

spam@dominio e nospam@dominio vengono utilizzate dagli utenti per segnalare rispettivamente missed spam e falsi positivi.

questo è quello che ricordo più o meno a memoria, se ti interessano alcuni dettagli in particolare, fammi sapere.
_________________
When all else fails, read the instructions.
Back to top
View user's profile Send private message
FonderiaDigitale
Veteran
Veteran


Joined: 06 Nov 2003
Posts: 1710
Location: Rome, Italy

PostPosted: Thu Dec 08, 2005 10:55 pm    Post subject: Reply with quote

ok, grazie.

due domande:
a. da che versione a che versione migri?
b. che intendi con la sigla 'CSS'?
_________________
Come disse un amico, i sistemisti sono un po' come gli artigiani per l'informatica :)
Back to top
View user's profile Send private message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Fri Dec 09, 2005 11:39 am    Post subject: Reply with quote

3.4.9 -> 3.6.x

CSS = CRM Sparse Spectra algorithm
Quote:
In general, MySQL is one of the faster solutions with a smaller storage
footprint, and is well suited for both small and large-scale implementations.

The hash driver (inspired by Bill Yerazunis' CRM Sparse Spectra algorithm)
is the fastest solution by far and requires no dependencies, supports
an auto-extend feature to grow the file size as needed, and is very
fast and compact. It does, however, lack some features (such as merged
groups support) and uses a lot of memory to mmap() users.

_________________
When all else fails, read the instructions.
Back to top
View user's profile Send private message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Fri Dec 09, 2005 12:01 pm    Post subject: Reply with quote

visto che ci sono, aggiungo alcuni script che ho creato gestire il sistema.
magari possono servire a qualcuno

dspam-multiple.pl gestisce il retrain
Code:
#! /usr/bin/perl -w

use strict;

my $class  = $ARGV[0] || die; shift;
my $sender = $ARGV[0] || die; shift;

my $user = "";
my $subj = "";
my $from = "";

if ($sender =~ /^([\w|\@|\.|\-]+)$/) {
    # username is in the sender
    $user = $1;
} else {
    print "Can't determine user\n";
    exit 75;                    # EX_TEMPFAIL
}

# Pull out DSPAM signatures and send them to the dspam program
while (<>) {
    if (/^Subject: /) {
        $subj = $_;
    } elsif (/^From: /) {
        $from = $_;
    } elsif ((/(!DSPAM:[a-f0-9]+!)/) || (/(X-DSPAM-Signature: [a-f0-9]+)/)) {
        open(F, "|/usr/bin/dspamc --source=error --class=$class --user $user");
   #open(F,">>/tmp/fabio.log");
        #print F "user: $user\n";
   print F "$from$subj$1";
        close(F);
   $subj = "";
   $from = "";
    }
}


spamreport.pl crea un report in html dello spam e lo invia al cliente.
molti utenti usano esclusivamente pop3, in questo modo non sono costretti ad utilizzare il webmail per visionare lo spam.
Code:
#!/usr/bin/perl -w
use strict;
   
my $mailroot = "/data/mail";
my $mail = 'AntiSpam@Azienda.it';
my $head = <<HERE;
<p>
Report Servizio AntiSpam<br>
<br>
I seguenti messaggi sono stati identificati come spam e saranno eliminati entro i prossimi 7 giorni<br><br>
</p>
HERE
my $foot = <<HERE;
<p>
Utilizzando l'interfaccia <b><a href="http://webmail.Azienda.it">WebMail</a></b> potrai visualizzare i messaggi sopra riportati.
<br><br>
Servizio AntiSpam Azienda snc.<br>
Tel 434234334234<br>
email $mail<br>
</p>
HERE

my @maildirs;

if ($ARGV[0]) {
   my $u;
   my $d;
   ($u,$d)=split(/\@/,$ARGV[0]);
   push @maildirs,"$mailroot/$d/$u";
} else {
   # becco tutte le maildir che contengono spam recente
   @maildirs = `find $mailroot/*/*/.Spam/{new,cur} -type f -mtime -1 | cut -d'/' -f1,2,3,4,5 | sort | uniq`;
}

my $date=`date -R`;
chomp($date);

foreach my $maildir (@maildirs) {
   chomp($maildir);
   my $user = "";
   if ($maildir =~ /([^\/]+)\/([^\/]+)$/) { $user =  "$2\@$1"}
   # per ogni maildir, becco le prime 100 righe di ogni messaggio spam
   open (SPAM,"find $maildir/.Spam/{cur,new} -type f -mtime -1 | sort -r | xargs -n 100 head -q -n 150 | grep -P '^From:|^Subject:|^X-DSPAM-Confidence:'|");
   my @from;
   my @subject;
   my @prob;
   my $count = 0;
   my $msg = "";
   while(<SPAM>) {
      if (/^From:\s*(.+)/i) {
         my $f = $1;
         $f =~ s/</&lt;/i;
         $f =~ s/>/&gt;/i;
         push @from,$f;
         $count++;
      } elsif (/^X-DSPAM-Confidence: 0\.(\d\d)/i) {
         push @prob,$1;
      } elsif (($count>0) && /^Subject:\s*(.+)/i) {
         my $s = $1;
         $s =~ s/</&lt;/i;
         $s =~ s/>/&gt;/i;
            $subject[$count-1] = $s;
        }
   }
   if ($count > 0) {
      $msg = <<HERE;
Return-Path: <$mail>
From: "Servizio Antispam" <$mail>
To: $user
Subject: Report Spam su $user
Date: $date
MIME-Version: 1.0
Content-Type: text/html ; charset="ISO-8859-15"
Content-Transfer-Encoding: flowed

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>
<HEAD>
<TITLE>Spam Report</TITLE>
<style>
body { font-family: Verdana; font-size: 11px; }
td { font-size: 11px; }
table.report tr.head { font-weight:bold; background-color: #00066F; color: white; }
table.report { background-color: #EAEAEA; }
table.report tr.gray { background-color: #CACACA; }
</style>
</HEAD>
<BODY>
$head
<table cellpadding=2 cellspacing=1 class="report">
<tr class="head"><td>n</td><td>Prob</td><td>Oggetto</td><td>Mittente</td></tr>
HERE
      for (my $i=0; $i < $count; $i++) {
         $subject[$i] = ($subject[$i] ? $subject[$i] : "-");
         $msg .= ($i % 2) ? "<tr class=\"gray\">" : "<tr>";
         $msg .= "<td>".($i+1)."</td><td>".$prob[$i]."%</td><td><b>".$subject[$i]."</b></td><td>".$from[$i]."</td></tr>\n";
      }
      $msg .= <<HERE;
</table>
$foot
</BODY>
</HTML>
HERE
      open (MAIL,"|deliverquota $maildir");
      print MAIL $msg;
      close MAIL;
      printf "%-30s %3d\n",$user,$count
   }
   close (SPAM);
   undef @from;
   undef @subject;
}



clean.sh si occupa di ripulire le caselle di posta.
Code:
#!/bin/sh

mailroot=/data/mail
oldINBOX=30
oldSpam=7
oldTrash=3
oldSent=14
oldDrafts=14


cmd="rm -f &>/dev/null"
maxargs=500

name=`basename $0`

# Bail if already running (in case we are slammed with spam to train from):
processes=$(ps ax)
if [ `echo "${processes}" | grep $name | grep -v nano | wc -l` -gt 1 ]; then
        echo "ERROR: $name is already running!"
        exit 1
fi

function cleanOld() {
   folder=$1
   olderthen=$2
   find $mailroot -type f -mtime +$olderthen -ipath "$mailroot/*/.$folder/*/*" | xargs -n $maxargs $cmd
}

function cleanUnusedINBOX() {
   olderthen=$1
   find $mailroot -type f  -mtime +$olderthen -mindepth 4 -ipath "$mailroot/*/*/*" -name '*.mail,*' | xargs -n $maxargs $cmd
}

cleanOld Spam $oldSpam
cleanOld Trash $oldTrash
cleanOld Sent $oldSent
cleanOld Drafts $oldDrafts
cleanUnusedINBOX $oldINBOX


updateMailboxes.sh sincronizza le maildir con il db mysql: crea le maildir per i nuovi utenti, cancella quelle degli utenti rimossi dal db.
Code:
#!/bin/sh
mailroot=/data/mail
dbhost="localhost"
dbname="mail"
dbuser="vmailuser"
dbpass="s30w:r4;x.a10f"
dbtable="mailbox"
uid="vmail"
gid=$uid

function existing() {
   find $mailroot -type d -mindepth 2 -maxdepth 2 |  sed -e "s|$mailroot/||" | sort
}

function getFromDB() {
   mailbox="CONCAT(RIGHT(username, LENGTH(username) - LOCATE('@', username)), '/', LEFT(username, LOCATE('@', username)-1))"
   mysql -u "$dbuser" --password="$dbpass" -h $dbhost $dbname --skip-column-names -se "SELECT $mailbox FROM $dbtable " | sort
}

function findDiffs() {
   extFile=`tempfile 2>/dev/null`
   existing > $extFile
   dbFile=`tempfile 2>/dev/null`
   getFromDB > $dbFile
   diff $extFile $dbFile | grep -P '^<|^>' | sed -e 's|<\s\+|D:|' |  sed -e 's|>\s\+|C:|'
   rm -f $extFile $dbFile
}

function makeMailDir() {
   local MKMDIR="/usr/bin/maildirmake"
   MAILDIR=$mailroot/$1
   #QUOTA=$2
   /bin/mkdir -p $MAILDIR
   /bin/rmdir $MAILDIR
   $MKMDIR $MAILDIR
   #$MKMDIR -q $QUOTA $MAILDIR
   $MKMDIR -f Drafts $MAILDIR
   $MKMDIR -f Sent   $MAILDIR
   $MKMDIR -f Spam   $MAILDIR
   $MKMDIR -f Trash  $MAILDIR
   echo -e "INBOX.Drafts\nINBOX.Sent\nINBOX.Trash\nINBOX.Spam" > ${MAILDIR}/courierimapsubscribed
   chown -R $uid:$gid $MAILDIR
}



function update() {
   for line in `findDiffs`
   do
      action=${line:0:1}
      mbox=${line:2}
      if [ "$action" = "C" ]
      then
         echo "Create: $mbox"
         makeMailDir $mbox
      else
         echo "Delete: $mbox"
         rm -rf $mailroot/$mbox
      fi
   done
}

update

_________________
When all else fails, read the instructions.
Back to top
View user's profile Send private message
FonderiaDigitale
Veteran
Veteran


Joined: 06 Nov 2003
Posts: 1710
Location: Rome, Italy

PostPosted: Mon Dec 12, 2005 1:32 pm    Post subject: Reply with quote

molto utile, grazie.

Riguardo CSS, mi inquieta un po' l'idea di usare un file come database.. quantomeno per un discorso di stabilita' operativa.

che filesystem usi?
hai casistiche di utilizzo di questo CSS in produzione?
_________________
Come disse un amico, i sistemisti sono un po' come gli artigiani per l'informatica :)
Back to top
View user's profile Send private message
makoomba
Bodhisattva
Bodhisattva


Joined: 03 Jun 2004
Posts: 1856

PostPosted: Mon Dec 12, 2005 2:55 pm    Post subject: Reply with quote

FonderiaDigitale wrote:
Riguardo CSS, mi inquieta un po' l'idea di usare un file come database.. quantomeno per un discorso di stabilita' operativa.
che filesystem usi?
hai casistiche di utilizzo di questo CSS in produzione?

considera che è un formato di storage concepito appositamente per operare con in token e non necessita di server esterni.
ancora non l'ho provato ma, dai commenti sulle mailing lists, pare sia estremamente veloce.
_________________
When all else fails, read the instructions.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Forum italiano (Italian) Risorse italiane (documentazione e tools) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum