Hlavní navigace

Stavíme mailový server (4)

8. 12. 2003
Doba čtení: 12 minut

Sdílet

V dnešním, závěrečném dílu seriáku o stavbě mailového serveru nainstalujeme samoučící se skripty, antivirus Clamav a celou instalaci dokončíme. Nakonec si ukážeme ještě pár "vychytávek".

Příprava chrootu

Připravíme adresář /var/amavisd pro chroot:

# cd /var/amavisd
# mkdir -p etc dev tmp var/run
# mkdir -p usr/bin usr/share/zoneinfo usr/lib usr/libexec
# mkdir -p usr/share/spamassassin etc/mail/spamassassin 

Vytvoříme základní potřebné devicy. Musíme vytvořit všechny, v dokumentu anti-spam.html sice vytvářejí pouze dev/null, ale když se nevytvoří stdin, stdout a stderr, tak antispam nefunguje. Pokud máte/var (nebo partition, kde je umístěn chrootový adresář) na zvláštním disku nebo partition, nezapomeňte v /etc/fstab odstranit případný flag nodev, aby bylo možno na disku speciální devicy vytvořit a používat.

# mknod dev/null c 2 2
# mknod dev/zero c 2 12
# mknod dev/stdin c 22 0
# mknod dev/stdout c 22 1
# mknod dev/stderr c 22 2
# mknod dev/urandom c 45 2

V chrootu vytvoříme symlink var/amavisd:

#  ln -s  /   var/amavisd

A nakopírujeme do usr/bin v chrootu potřebné programy (stále jsme v adresáři /var/amavisd):

# cp /usr/bin/file usr/bin
# cp /usr/bin/gzip usr/bin
# cp /usr/local/bin/arc usr/bin
# cp /usr/local/bin/bzip2 usr/bin
# cp /usr/local/bin/zoo usr/bin
# cp /usr/local/bin/unrar usr/bin
# cp /usr/local/bin/unarj usr/bin
# cp /usr/local/bin/lha usr/bin
# cp /usr/local/bin/gcpio usr/bin
# cp /usr/local/bin/lzop usr/bin
# cp /usr/local/bin/freeze usr/bin

Dále do chrootového etc nakopírujeme potřebné konfigurační soubory:

# cp /etc/protocols etc
# cp /etc/services etc
# cp /etc/hosts etc
# cp /etc/magic etc
# cp /etc/resolv.conf etc
# cp /etc/group etc
# cp /etc/passwd etc

Pozor, pokud od této chvíle provedete v uvedených souborech v /etc/ nějakou změnu, musíte změny okopírovat do chrootu! Pokud máte /var na stejné partition jako /etc, můžete na soubory vytvořit hardlinky. Toto řešení však skrývá nebezpečí, pokud někdo získá v chrootu neoprávněně rootovská práva, bude moci zapisovat do systémových konfiguráků. Z toho důvodu řešení s hardlinky nedoporučuji.

Do chrootu nakopírujeme soubory SpamAssassinu:

# cp /etc/mail/spamassassin/local.cf etc/mail/spamassassin/
# cp -r /usr/share/spamassassin usr/share 

A nastavíme minimální přístupová práva:

# chown -R root:wheel etc dev tmp usr var
# chown -R _amavisd:_amavisd .spamassassin .razor quarantine var/dcc
# chmod 1777 tmp
# chmod 666 dev/null dev/zero dev/stdin dev/stderr dev/stdout
# chmod 644 dev/urandom 

Otevřeme v editoru soubor /usr/local/sbin/a­mavisd a upravíme ho tak, aby perl načetl všechny potřebné moduly ještě před chrootováním. Zhruba kolem řádku 100 najdeme sub fetch_modules a o pár řádků níž volání této procedury s moduly, které se nahrávají. Do seznamu modulů přidáme následující:

  • Net::DNS::RR::MX
  • Net::DNS::RR::NS
  • Net::DNS::RR::A
  • Net::Ping
  • Net::DNS::RR::CNAME
  • Net::DNS::RR::SOA
  • Mail::SpamAssas­sin::PerMsgLe­arner

Perlové moduly v chrootovém adresáři nejsou z bezpečnostního důvodu, aby je případný záškodník nemohl modifikovat. Proto pokud bychom výše uvedenou úpravu neprovedli, Amavis by po startu před chrootováním moduly nenačetl, a jakmile by některý z modulů byl zavolán odkudkoliv z kódu, nebyl by v chrootu nalezen, a tudíž by došlo k chybě.

Vytvořte soubory /var/amavisd/whi­telist, /var/amavisd/blac­klist a /var/amavisd/spam­lovers. Soubory obsahují v pořadí, v jakém jsou uvedeny, seznam adres nebo domén, odkud nikdy nepřicházejí spamy, odkud vždy přicházejí spamy, a poslední soubor obsahuje adresy uživatelů, kteří chtějí spamy doručovat. Na každém řádku souboru je uvedena doména nebo mailová adresa. Pokud nemáte žádné adresy, můžete soubory nechat prázdné, ale musejí existovat (protože jsme je uvedli v konfiguračním souboru).

V souboru /var/amavisd/no­tify_spam_sen­der.txt vytvořte zprávu, kterou Amavis bude posílat původcům spamu. Zde je příklad, jak může zpráva vypadat. Podobně vytvořte notifikaci/var/a­mavisd/notify_vi­rus_sender.txt pro odesilatele virů.

Oživování Amavisu

Vše je nakonfigurováno, tak zkusíme spustit Amavis:

# /usr/local/sbin/amavisd debug

Zjistíme, jestli se na výstupu objeví nějaké chybové hlášky. Pomocí CTRL-C proces ukončíme. Pokud ve výpisu najdete hlášku Net::Server: Couldn't POSIX::setuid to „3000“ [], je nutné aplikovat patch na perlový modul Net::Server:

# cd /usr/local/libdata/perl5/site_perl/Net
# ftp http://www.ijs.si/software/amavisd/net-server.patch
# patch <net-server.patch 

Pokud je vše v pořádku, můžeme přidat Amavis do startup scriptů. Do souboru /etc/rc.local přidáme:

# Start amavisd spam filter
/usr/local/sbin/amavisd

V souboru /etc/postfix/ma­in.cf odstraníme komentář před řádkem

#content_filter = smtp-amavis:[127.0.0.1]:10024

Poté restartujeme Postfix, spustíme Amavis v debugovacím módu a zkusíme poslat testovací maily:

# /usr/local/sbin/postfix stop
# /usr/local/sbin/postfix start
# /usr/local/sbin/amavisd debug

Amavis nám sebere konzoli, proto si pro odeslání testovacích mailů musíme otevřít novou. Součástí balíku Amavisu, který jsme stáhli, jsou též testovací maily. Vlezeme do adresáře s Amavisem a maily pošleme na svoji adresu:

# cd /root/amavisd-new-20030314/test-messages
# cat sample-spam.txt | sendmail ja@mojedomena.cz
# cat sample-nonspam.txt | sendmail ja@mojedomena.cz

Amavisd na výstup vypíše debugovací hlášky, co který mail obsahoval. Jakmile ozkoušíme, že vše chodí správně, Amavisd ukončíme a pustíme ho v normálním režimu.

# /usr/local/sbin/amavisd

Do souboru /etc/rc.local přidáme spouštění Amavisu při startu systému:

if [ -x /usr/local/sbin/amavisd ]; then
   rm -rf /var/amavisd/tmp/*
   echo -n ' amavisd';  /usr/local/sbin/amavisd
fi

Bayesian Learning Script

Jednou z posledních věcí pro instalaci antispamu je nastavení a spuštění samoučících se skriptů SpamAssassinu. Nejprve vysvětlíme princip. Když uživatel pošle mail na adresu _spam@mailserver.mojedomena.cz (uživatel _spam na našem mailovém serveru), respektive na adresu_notspam@mailserver.mojedomena.cz, mail se uloží do lokální schránky /var/mail/_spam, respektive /var/mail/_not­spam. Jednou za čas se z Cronu zavolá samoučící skript, který projde tyto schránky a uloží maily do „Bayesiánské“ statistické databáze.

Zde si stáhněte shellový skript my-sa-learn.sh a uložte ho do /usr/local/sbin. Přístupová práva nastavte na 500. Do crontabu přidejte následující řádku:

# spamassassin bayesian learning script
05 0 * * * /usr/local/sbin/my-sa-learn.sh

Učící skript se tedy bude spouštět každých 5 minut po půlnoci.

Pokud uživatel dostane nějaký spam a bude ho chtít zařadit do databáze, pošle jej na danou adresu a spammer bude zařazen do databáze. Stejně tak když nějaký mail bude neprávem označen za spam, uživatel ho může poslat na adresu _notspam, aby příště mail tohoto druhu označen již nebyl. Pozor, pokud posíláte na dané adresy mail, musí obsahovat původní hlavičku. Proto je nejlepší mail „bouncnout“. Druhé upozornění: databáze se používá, pouze když obsahuje více než 200 položek.

Clamav

Posledním velkým úkolem je instalace antiviru Clamav. Zdomácí stránky Clamav stáhneme a rozbalíme balík s poslední verzí. Clamav je stále ve vývoji a podle mých zkušeností není stabilní. Proto je lepší nainstalovat poslední „devel“ balík než „stable“, protože „devel“ obsahuje nejnovější patche a bugfixy (ale bohužel také nejnovější chyby). Verze „stable“ je tedy celkově méně funkční než verze „devel“.

# cd /root
# ftp http://clamav.sourceforge.net/snapshot/clamav-devel-latest.tar.gz
# tar xzvf clamav-devel-latest.tar.gz
# cd clamav-devel-20030923 

Nakonfigurujeme, zkompilujeme a nainstalujeme.

# export LDFLAGS=-lpthread
# ./configure --prefix=/var/amavisd/usr --with-user=_clamav \
--with-group=_clamav --enable-debug --disable-cr --sysconfdir=/etc \
--mandir=/usr/local/man --includedir=/usr/local/include \
--oldincludedir=/usr/local/include
# make
# mkdir -p /var/amavisd/usr/share/clamav/
# touch /var/amavisd/usr/share/clamav/viruses.db
# touch /var/amavisd/usr/share/clamav/viruses.db2
# make install 

Programem ldd zjistíme, které knihovny vyžaduje clamd, a tyto soubory zkopírujeme do chrootu.

# ldd /var/amavisd/usr/sbin/clamd
/var/amavisd/usr/sbin/clamd:
        Start    End      Type Ref Name
        00000000 00000000
exe   1  /var/amavisd/usr/sbin/clamd
        0cde9000 2cdf4000
rlib  1  /var/amavisd/usr/lib/libclamav.so.1.3
        0f5df000 2f5e9000
rlib  2  /usr/lib/libpthread.so.2.1
        0456e000 24574000
rlib  2  /usr/lib/libz.so.2.0
        0bfa6000 2bfdf000
rlib  1  /var/amavisd/usr/lib/libc.so.30.1
        0c595000 0c595000
rtld  1  /usr/libexec/ld.so
# cp /usr/lib/libpthread.so.2.1 /var/amavisd/usr/lib
# cp /usr/lib/libz.so.2.0 /var/amavisd/usr/lib 

Konfigurační soubor /etc/clamav.conf přestěhujeme do chrootu do /var/amavisd/etc, otevřeme v editoru, odstraníme řádek

Example a nakonfigurujeme na následující hodnoty. Konfigurační proměnné, které zde nejsou uvedeny, nechte zakomentované. Detailní popis jednotlivých proměnných lze najít v manuálové stránce clamav.conf(5).

# Logování: hlášky jsou verbose a jdou do syslogu,
# uvádíme čas
LogTime
LogSyslog
LogVerbose

# Socket, pid a adresář s daty
PidFile /var/clamav/clamd.pid
DataDirectory /usr/share/clamav
LocalSocket /var/clamav/clamav.socket

# Požadavky a thready
MaxConnectionQueueLength 30
MaxThreads 50
ThreadTimeout 300
MaxDirectoryRecursion 15

# kontrola databází každých 10 minut
SelfCheck 600

# Scanujeme maily
ScanMail

# Nastavení scanování archivů
ScanArchive
ArchiveMaxFileSize 10M
ArchiveMaxRecursion 5
ArchiveMaxFiles 4000

Pro případ potřeby ladění jsou k dispozici následující proměnné:

#LogFile /var/amavisd/log/clamd.log
#LogFileMaxSize 0
#Foreground
#Debug

Clamav máme nainstalovaný i nakonfigurovaný, tak zkusíme jeho funkčnost. Nejprve ale popíšeme princip používání. Ke scannování virů slouží dva programy: clamscan a clamdscan. První program vezme soubor, oscannuje jej, vypíše výsledek a skončí. Druhý program je pouze klient, který pošle data daemonu clamd, ten data oscannuje, odpoví klientu výsledkem a klient tento výsledek vrátí. Obě varianty dělají totéž, ale pro scannování většího množství dat je výhodnější varianta s daemonem (není potřeba při každém scanu složitě nahrávat databáze virů atd.). Pro případ, že daemon z nějakého důvodu přestane fungovat, můžeme jako zálohu spouštět pomalejší clamscan. Toto chování jsme nastavili vamavisd.conf.

Otestujeme tedy funkčnost obou programů:

# clamscan -r -l scan.txt ~/clamav-devel-latest.tar.gz
# clamd
# clamdscan -l scan_d.txt ~/clamav-devel-latest.tar.gz 

Výsledek testování bude uložen do souborů scan.txt, respektivescan_d­.txt. Pokud vše dobře funguje, výstup by měl vypadat nějak takto:

clamav-devel-latest.tar.gz: ClamAV-Test-Signature FOUND

----------- SCAN SUMMARY -----------
Known viruses: 9586
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 2.44 MB
I/O buffer size: 131072 bytes
Time: 2.516 sec (0 m 2 s) 

Součástí Clamav je též program freshclam pro automatické updatování virové databáze. To budeme potřebovat, neboť bez pravidelné aktualizace databáze je antivirus k ničemu. Freshclam může běžet buď jako daemon, který několikrát denně databázi updatuje, nebo ho můžeme pravidelně spouštět z Cronu. Nevýhodou daemonu je, že pokud z nějakého důvodu spadne, databáze se nebude updatovat. Z toho důvodu doporučuji pouštět z Cronu.

Ke spuštění freshclamu vyt­voříme ve /var/log log:

# touch /var/log/clam-update.log
# chown _clamav /var/log/clam-update.log
# chmod 600 /var/log/clam-update.log

A přidame záznam do crontabu:

# update Clam databáze (každou hodinu)
0 * * * * /var/amavisd/usr/bin/freshclam --quiet -l /var/log/clam-update.log 

Jelikož před spouštěním clamd je pokaždé potřeba smazat komunikační socket a soubor s PID a chrootovat, napsal jsem wrapper, který toto udělá. Původníclamd přejmenujeme na clamd.bin a tento wrapper umístíme do /var/amavisd/us­r/sbin/clamd.

Problémy s clamd

Když jsem poprvé nainstaloval Clamav a testoval jsem ho, ze začátku se vše zdálo být funkční a v pořádku. Tak jsem server nechal běžet a druhý den jsem zjistil, že mi nepřichází maily, protože neběží daemon clamd. Několik dní jsem hledal, proč clamd padá. Ukázalo se, že čas od času daemon spadne, vygeneruje core, na zásobníku je adresa 0 a nejde nic debugovat.

Zkoušel jsem zapnout debugovací hlášky, abych dostal přesný popis činností, které antivir provádí. Jenže ouha, po zapnutí logování do souboru byl soubor hned plný, a to hlášek o překročení hloubky adresáře. Clamav umožňuje při rozbalování a scannování příloh mailů omezit hloubku adresářů, do které se bude scannovat, aby se zamezilo DoS útoku. Ale hloubka byla nastavena dostatečná a navíc jsem posílal testovací maily bez příloh. Když jsem hloubku zvětšil a program restartoval, antivir způsobil DoS útok a počítač byl neovladatelný.

Nějakou dobu jsem tápal a hledal, kde je problém. Nakonec jsem někde na webu našel podobný popis závady s tím, že je nutné zvýšit hodnotu proměnné MaxConnection­QueueLength. Když jsem ji zvýšil z původních 15 na 30, problém zmizel. Je to naprosto logické, ne? ;-)

Občas se mi též stalo, že daemon spadnul po updatování databáze. Přestože v kódu se zdá být zamykání databáze ošetřené, daemonu zjevně nesvědčí, když mu někdo změní databázi pod rukama. Neměl jsem čas hledat v kódu chybu a opravovat ji, proto jsem problém obešel lehce nečistou metodou – do crontabu jsem přidal pravidelné spouštění daemonu každých 5 minut:

# Kdyz clamd scipne tak ho nastartujeme
*/5 * * * * /var/amavisd/usr/sbin/clamd

Jestliže daemon běží, tak se díky wrapperu nic nestane. Pokud daemon neběží, je znovu nastartován.

Dokončení instalace a různé vychytávky

Po instalaci serveru jsem časem zjistil, že je potřeba vyřešit a dodělat různé drobnosti – například disk se zaplňoval dočasnými soubory, potřeboval jsem získávat informace o spamech atd. Proto jsem vytvořil různé skripty, které zde popíši.

Zaplňování disku dočasnými soubory

Tento problém se objevil velice záhy po spuštění serveru „na ostro“. Řešení bylo poměrně jednoduché – stačilo do crontabu přidat tento řádek:

# Smazat chciplotinky
36 * * * * find /var/amavisd/tmp -type d -ctime +1 -exec rm -rf {} \;
>/dev/null 2>&1 

Což každou hodinu projde všechny dočasné soubory a smaže ty, které jsou starší než 1 den.

Desinfekce karantény

Po čase běhu serveru zjistíte, že se disk zaplňuje nejen tmp soubory, ale také začne růst karanténa (adresář /var/amavisd/qu­arantine), kde se uchovávají všechny došlé spamy a zavirované maily. Pro úsporu místa jsou maily v karanténě gzipované, ale stejně po čase začnou zabírat moc místa.

Karanténu můžete pravidelně „desinfikovat“ podobně, jako se mažou dočasné soubory. Pochopitelně interval čištění bude delší. Uživatelé však mají tendence vzpomenout si, že před čtvrt rokem jim nepřišel mail a místo toho skončil v karanténě. Proto je možná lepší obsah karantény archivovat – například soubory po měsíci zatarovat a uložit do nějakého jiného adresáře (a třeba až po roce archiv smazat). Součástí jména souboru v karanténě je i datum přijetí, čehož lze využít při psaní „uklízecího“ skriptu.

Posílání statistik o zpracovaných mailech

Je dobré vědět, kolik procent mailů jsou spamy, jak často mi chodí zavirované maily, od koho mi chodí nejvíce spamů atd. Proto jsem nainstaloval reportovací skript:

# cd /root
# ftp http://jimsun.linxnet.com/downloads/pflogsumm-1.0.4.pl
# mv pflogsumm-1.0.4.pl /usr/local/sbin/
# chmod 500 /usr/local/sbin/pflogsumm-1.0.4.pl 

Podobně stáhneme skript my-spamreport.pl(pů­vodně získaný z http://lawmon­key.org/) a umístíme ho také do /usr/local/sbin. Skript my-postfix-report.sh umístíme tamtéž.

Do crontabu přidáme řádku:

# Reportovani mailu
0 4 * * * /usr/local/sbin/my-postfix-report.sh 

Skript každý den ve 4:00 ráno vytvoří souhrnnou zprávu o zpracovaných mailech a došlých spamech a pošle ji na adresu mailreport. Proto ještě vytvoříme mailový alias mailreport pro adresu, kam mají reporty chodit (tedy asi adresu správce).

Debugovací hlášky

Při instalaci je dobré mít zapnuté ladící hlášky z jednotlivých programů, abychom mohli lépe najít, proč něco nefunguje. Po dokončení instalace je vhodné ladění vypnout. Pro přehled jsem sepsal, kde všude se v konfiguračních souborech nastavují ladící výpisy:

  • /etc/amavisd.conf
    $log_level = 0;
    $sa_debug = 0;
  • /var/amavisd/et­c/clamav.conf
    #LogFile /var/log/clamd.log
    #LogFileMaxSize 0
    #Foreground
    #Debug
    #LogVerbose
  • /var/amavisd/­.razor/razor-agent.conf
    debuglevel=0
    Razor ukládá log do /var/amavisd/­.razor/razor-agent.log.
  • /etc/postfix/ma­in.cf
    debug_peer_level=2