Archive for the ‘ Spamassassin ’ Category

SA failed: Can’t locate object method “READ” via package “Amavis::IO::FileHandle

Ich habe gestern Abend Spamassassin von Version 3.2.5-2+lenny2 auf 3.3.1-1. Beim anschließenden testen habe ich im Header der festgestellt, dass eingehende E-Mails nicht mehr durch den Spam-Filter laufen.

X-Spam-Flag: NO
X-Spam-Score: 0
X-Spam-Level:
X-Spam-Status: No, score=x tagged_above=-100 required=14.31 tests=[]

Eine erhöhung das Amavis Log Levels auf 4 brachte den Fehler zu Tage.

Aug 26 10:02:04 mx02.o-o-s.de prequeue_filter[28157]: (28157-01) (!!)SA failed: Can't locate object method "READ" via package "Amavis::IO::FileHandle" at /usr/local/share/perl/5.10.0/Mail/SpamAssassin/Message.pm line 143, <GEN71> line 169. at (eval 104) line 420, <GEN71> line 169.

Dre Grund dafür ist

package Amavis::IO::FileHandle now supports a method READ (i.e. invoked
by a perl functions sysread through a tied hash), which is needed by
SpamAssassin revisions since 2008-09-25 (3.3), bringing a little speedup
to transferring a message from amavisd to SpamAssassin, and avoiding a
Perl I/O bug (perl bug 39060; SA: bug 5985) on some installations;

Dieser Fehler ist in amavisd-new 2.6.2+ behoben, jedoch lässt sich amavisd-new nicht ohne Konflikte aus dem sid Zweig installieren, daher muss die Datei /usr/sbin/amavisd-new manuell  angepasst werden. Dazu muss die Zeile nach SA prepare von

my($data_representation) = 'GLOB';  # pass data to SA as ARRAY or a GLOB

auf

my($data_representation) = 'ARRAY';  # pass data to SA as ARRAY or a GLOB

geändert werden.

Aufbau einer eigenen SBL (Spam Blacklist)

Ich habe mich rein aus interesse die Tage mit dem Aufbau einer eigenen SBL beschäftigt. Eine SBL ist eine DNS-Zone, in der IP Adressen von Spammern imReverse Format eingetragen werden. Dies ermöglich Postfix, policyd-weight und Spamassassin anschließend die Sender IP Adressen bei eingehenden Mails gegen diese DNS-Zone zu prüfen. Wurde ein entsprechender Eintrag gefunden, kann die E-Mail als Spam behandelt werden.

Beispiel: Meldet sich ein Server mit der IP Adresse 192.168.0.1 und möchte eine E-Mails bei uns los werden, so prüft das ensprechende Programm (Postfix, policyd-weight oder Spamassassin) ob diese IP Adresse in der SBL sbl.o-o-s.de eingetragen ist.

nslookup 1.0.168.192.sbl.o-o-s.de

Ist dies der Fall, wird eine IP aus dem 127.0.0.x Netz zurück geliefert, die jedoch nicht 127.0.0.1 sein darf. Ist dies der Fall, weiß das Programm, dass diese IP Adresse auf der Blackliste steht und behandelt die E-Mails entsprechend.

Im Internet gibt es schon zig SBLs, von denen einige besser als andere Funktionieren. Wie gesagt, ich wollte rein aus Interesse eine eigene SBL aufbauen.

das Script

Um eine SBL füttern zu können, benötigt man zu aller erst Spam Mails. Ich hab schon länger zum testen zwei Domains, die nur genau dem Zweck dienen, Spam Mails ein zu sammeln.

Sobald Spam Mails vorhanden sind, müssen die IP Adressen aus den Mails extrahiert werden. Dazu habe ich ein reaöltiv simples Script geschrieben, dass nur die im header vorhandenen IPs heraus filtert. Ursprünglich war mein Gedanke, die Hostnamen aus dem Header per dig aufzulösen, jedoch ist dies relativ schwierig, da die Header Zeilen nicht immer identisch aussehen. Da ich jedoch keine Professionelle SBL aufbauen wollte, reichte es mir die vorhandenen IP Adressen zu filtern.

Das Script kann hier herunter  geladen werden. Im Kopfbereich des Scriptes muss der Pfad zum Mailverzeichniss mit dem Spam Mails sowie der Pfad zum sbl zone file angegeben werden.

die DNS-Zone

Da meine sbl eine Dubdomain der Domain o-o-s.de ist, muss zuerst in der Zone o-o-s.de.zone ein Eintrag für die Subomain hinzugefügt werden.

sbl                     10800   IN      NS      ns.o-o-s.de.

Anschließend kann die Subdomain sbl.o-o-s.de eingerichtet werden.

$TTL 10800
@                       2560    IN      SOA     ns.o-o-s.de.       postmaster.o-o-s.de. (
 2010082404   ; serial YYYYMMDDnn
 3600         ; refresh ( 1 h)
 900          ; retry   ( 15 min)
 1209600      ; expire  ( 14 day)
 10800 )      ; minimum ( 3 hours)

@                       10800   IN      NS      ns.o-o-s.de.
@                       10800   IN      A       83.169.42.112

Wird nun das Script ausgeführt, so werden die IP Adressen aus dem Header der Spam Mails wiefolgt in der Zone eingetragen.

100.124.78.80   IN      A       127.0.0.10

Wenn alles richtig funktioniert, ist es nun an der Zeit, die SBL auszuwerten. Es gibt dafür mehrere Möglichkeiten.

  • policyd-weight
  • Spamassassin
  • Postfix

Auswertung mittels policyd-weight

Um die SBL mittels policyd-weight abzufragen, muss in der Datei /etc/policyd-weight.conf die SBL aktiviert werden.

[...]
@dnsbl_score = (
#    HOST,                    HIT SCORE,  MISS SCORE,  LOG NAME
'pbl.spamhaus.org',       3.25,          0,        'DYN_PBL_SPAMHAUS',
'sbl-xbl.spamhaus.org',   4.35,       -1.5,        'SBL_XBL_SPAMHAUS',
'bl.spamcop.net',         3.75,       -1.5,        'SPAMCOP',
'dnsbl.njabl.org',        4.25,       -1.5,        'BL_NJABL',
'ix.dnsbl.manitu.net',    4.35,          0,        'IX_MANITU',
'sbl.o-o-s.de',           3.35,          0,        'OOS_DE'
);
[...]

Sollte die Konfigurationsdatei nicht exisiteren, kann diese mittels

policyd-weight defaults > /etc/policyd-weight.conf

angelegt werden.

Auswertung durch postfix

Postfix kann die SBL ebenfalls auswerten. Jedoch ist dabei zu beachten, dass Postfix die E-Mails anhand der SBL nicht bewertet, sondern direkt rejected.

/etc/postfix/main.cf

smtpd_recipient_restrictions =
[...]
                 reject_rbl_client sbl.o-o-s.de
[...]

Auswertung durch Spamassassin

Zu guter letzt noch die Auswertung durch Spamassassin. Hierzu muss eine neue Konfigurationsdatei angelegt werden, in der die Regeln definiert werden.

/etc/mail/spamassassin/99_local_bl.cf

header   RCVD_IN_OOSBL      eval:check_rbl('oos', 'sbl.o-o-s.de.')
describe RCVD_IN_OOSBL      Received via IP listed by sbl.o-o-s.de
tflags   RCVD_IN_OOSBL      net
score    RCVD_IN_OOSBL      2.5

Links

Spamassassin: Testregel erstellen

Bei der Einrichtung und Administration einer Anti-Spam  Lösung kann es hin und wieder hilfreich sein, das Verhalten von als Spam erkannten E-Mails zu simulieren, z.B. wenn man gerade einen Prequeue-Filter eingebunden hat und nun Spam E-Mails rejecten möchte.

Ich habe dies über die Betreff Zeile realisiert, dazu habe ich in der /etc/spamassassin/local.cf folgende Zeilen ergänzt.

header TEST_BLOCK             Subject =~ /mark_as_spam/
describe TEST_BLOCK           From: does not include a real name
score TEST_BLOCK              5000

Nach einem Neustart werden E-Mails mit dem Betreff “mark_as_spam” mit einer Spambewertung von 5000 versehen.

Fingerprint Spamfilterung

Spamfilteurng ist ein permanenter Kampf in dem man seine Ansatzpunkte immer wieder neu überdenken bzw. anpassen muss.

Aktuell bin ich auf den Möglichkeit gestoßen (die es bestimmt schon länger gibt ;-) ), die Spam Filterung von amavisd-new/spamassassin anhand von Fingerprints zu verfeinern. Viele der Spam E-Mails werden von Botznetzwerken verschickt. Dies lässt sich mit p0f in die Bewertung von Spam E-Mails mit einbeziehen. P0f ist in der Lage, passive anhand der Verbindungskriterien das Betriebssystem der Gegenstelle zu bestimmen. Das Betriebssystem wiederrum ermöglicht Rückschlüsse auf die wahrscheinlichkeit das die eingehende E-Mail eine Spam E-Mail ist.

Installation von p0f

Installieren lässt sich p0f unter Debian netterweise wieder über apt-get (Ich liebe die Menge an verfügbaren Paketen)

apt-get install p0f

Start/Stop Skript

Um p0f beim booten mit den entsprechenden Parametern zu starten habe ich ein Skript unter /etc/init.d/ abgelegt welches dann über das antsprechende Runlevel gestartet wird. Anschließend muss dieses noch fürs entsprechende Runlevel verlinkt werden.

ln -s /etc/init.d/p0f.sh /etc/rc2.d/S99p0f

Amavisd-New anpassen

Nun muss der Filter noch über amavisd-new aktiviert werden. Da ich verschiedene Policies einsetzt, habe ich es in den entsprechenden Policies aktiviert.

/etc/amavis/conf.d/50-user

$policy_bank{'o-o-s.de'} = {
 [...]
 os_fingerprint_method => 'p0f:127.0.0.1:2345',        # p0f aktivieren
 [...]

Spamassasin anpassen

Damit Spamassassin die  E-Mail nun auch entsprechend bewerten kann, müssen wir noch die Header-Felder und Score Werte festlegen. Dazu habe ich unter /etc/spamassasin/ eine eigene Datei Namens p0f.cf angelegt.

header L_P0F_OS_WINDOWSXP   X-Amavis-OS-Fingerprint =~ /^Windows XP/
score  L_P0F_OS_WINDOWSXP   3.5
header L_P0F_OS_WINDOWS_OTHER X-Amavis-OS-Fingerprint =~ /^Windows(?! XP)/
score  L_P0F_OS_WINDOWS_OTHER 1.7
header L_P0F_OS_UNKOWN  X-Amavis-OS-Fingerprint =~ /^UNKNOWN/
score  L_P0F_OS_UNKOWN  0.8
header L_P0F_OS_LINUX  X-Amavis-OS-Fingerprint =~ /^Linux/
score  L_P0F_OS_LINUX  -0.3
header L_P0F_OS_UNIX  X-Amavis-OS-Fingerprint =~ /^((Free|Open|Net)BSD)|Solaris|HP-UX|Tru64/
score  L_P0F_OS_UNIX  -1.0
header L_P0F_D_1_4 X-Amavis-OS-Fingerprint =~ /\bdistance [1-4](?![0-9])/
header L_P0F_D_5_6 X-Amavis-OS-Fingerprint =~ /\bdistance [5-6](?![0-9])/
header L_P0F_D_7_9 X-Amavis-OS-Fingerprint =~ /\bdistance [7-9](?![0-9])/
header L_P0F_D_15_25 X-Amavis-OS-Fingerprint =~ /\bdistance [15-25](?![0-9])/
score  L_P0F_D_1_4 -0.7
score  L_P0F_D_5_6 -0.5
score  L_P0F_D_7_9 -0.3
score  L_P0F_D_15_25 0.3

Nun sollte nach einem Neustart der Dienste die Bewertung anhand von Fingerprints funtkionieren. Ob dies der Fall ist, erkennt man am Header der betreffenden E-Mails.

X-Spam-Score: 10.78
X-Spam-Level: **********
X-Spam-Status: No, score=10.78 tagged_above=-100 required=14.31
 tests=[HELO_DYNAMIC_DIALIN=3.995, L_P0F_D_7_9=-0.3,
 L_P0F_OS_WINDOWSXP=3.5, MISSING_SUBJECT=1.285, NO_REAL_NAME=1.2,
 RDNS_DYNAMIC=0.1, UNDISC_RECIPS=1]
X-Amavis-OS-Fingerprint: Windows XP/2000 (RFC1323+, w+, tstamp-) [GENERIC]
 Signature: [65535:121:1:52:M1260,N,W3,N,N,S:.:Windows:?], (distance 7,
 link: PIX, SMC, sometimes wireless), [80.141.48.85:]
header L_P0F_OS_WINDOWSXP   X-Amavis-OS-Fingerprint =~ /^Windows XP/
score  L_P0F_OS_WINDOWSXP   3.5
header L_P0F_OS_WINDOWS_OTHER X-Amavis-OS-Fingerprint =~ /^Windows(?! XP)/
score  L_P0F_OS_WINDOWS_OTHER 1.7
header L_P0F_OS_UNKOWN  X-Amavis-OS-Fingerprint =~ /^UNKNOWN/
score  L_P0F_OS_UNKOWN  0.8
header L_P0F_OS_LINUX  X-Amavis-OS-Fingerprint =~ /^Linux/
score  L_P0F_OS_LINUX  -0.3
header L_P0F_OS_UNIX  X-Amavis-OS-Fingerprint =~ /^((Free|Open|Net)BSD)|Solaris|HP-UX|Tru64/
score  L_P0F_OS_UNIX  -1.0

header L_P0F_D_1_4 X-Amavis-OS-Fingerprint =~ /\bdistance [1-4](?![0-9])/
header L_P0F_D_5_6 X-Amavis-OS-Fingerprint =~ /\bdistance [5-6](?![0-9])/
header L_P0F_D_7_9 X-Amavis-OS-Fingerprint =~ /\bdistance [7-9](?![0-9])/
header L_P0F_D_15_25 X-Amavis-OS-Fingerprint =~ /\bdistance [15-25](?![0-9])/

score  L_P0F_D_1_4 -0.7
score  L_P0F_D_5_6 -0.5
score  L_P0F_D_7_9 -0.3
score  L_P0F_D_15_25 0.3

Nachtrag

Wie ich gerade gesehen habe, gibt es p0f auch als Spamassassin Plugin ;-)

Debian: Ressourcen Einsparung

Ich hab mich heute mal daran gemacht und versucht auf meinem System Ressourcen einzusparen. Als mögliche Ansatzpunkten boten sich

  • Spamassassin
  • amavisd-new
  • Apache2
  • MySQL
  • vmware
  • sysctl

Wichtig: Bei den hier gezeigten Optimierungen muss jeder für sich selbst entscheiden ob dies für ihn Sinnvoll ist. Ich übernehme keinerlei Haftung für etwaige Schäden!!

Spamassassin

Die Anzahl der eMails die auf meinem Server auflaufen ist relativ überschaubar. Selbst wenn mal mehrere eMails gleichzeitig reinkommen, ist es nicht weiter schlimm wenn diese ein paar Minuten in der queue liegen. Da spamassassin doch schon einiges an RAM verbraucht (5 child Prozesse) habe ich mich dazu entschieden die Anzahl der child Prozesse auf einen zu reduzieren. Dazu habe ich in der /etc/default/spamassassin unter options die Anzahl der child Porzesse vorgegeben

/etc/default/spamassassin
OPTIONS="-s /var/lib/spamassassin/spamd.log --create-prefs --max-children 1

Die Einsparung sieht danch wiefolgt aus:

USER       PID %CPU %MEM    VSZ   RSS
root     24164  0.8  0.4  86776  4180 (5 child Prozesse)
root      2783 77.3  5.4  62028 54616 (1 child Prozess)

Es ist nicht die Welt, aber warten wir erstmal ab…

Amavisd-new

Da amavisd-new auch schon einiges verbraucht habe ich auch hier die Anzahl der Prozesse reduziert.

USER       PID %CPU %MEM    VSZ   RSS
amavis    4296 26.1  9.4 105636 93944 (master)(0/5 Prozessen)
amavis    4563  0.0  9.3 106548 92896 (child) (1/5 Prozessen)
amavis    4564  0.0  9.3 106548 92920 (child) (2/5 Prozessen)
amavis    4565  0.0  9.3 106548 92880 (child) (3/5 Prozessen)
amavis    4566  0.0  9.3 106548 92880 (child) (4/5 Prozessen)
amavis    4567  0.0  9.3 106548 92876 (child) (5/5 Prozessen)
amavis    4877 44.7  9.4 105636 93948 (master)(0/5 Prozessen)
amavis    5131  0.0  9.3 106548 92892 (child) (1/1 Prozessen)

Dazu muss in der Datei /etc/amavis/conf.d/50-user die Variable $max_servers gesetzt werden.

/etc/amavis/conf.d/50-user
$max_servers  =  1;

Apache2

Um die Ressourcen des Apache2 zu limiterien, kann man die Anzahl der max. Clients reduzieren. Ein guter Mittelwert kann errechnet werden, indem man den RAM-Verbrauch des Apaches ermittelt und anschließend errechnet wieviele Prozesse vom apach2 laufe können bis der noch freie RAM verbraucht ist.

RSS=`ps -aylC apache2 |grep "apache2" |awk '{print $8'} |sort -n |tail -n 1`
RSS=`expr $RSS / 1024`
/etc/init.d/apache2 stop
MEM=`free -m |head -n 2 |tail -n 1 |awk '{free=($4); print free}'`
/etc/init.d/apache2 start
echo "MaxClients sollte bei" `expr $MEM / $RSS` "liegen"

Der so errechnete Wert kann anschließen in der /etc/apache2/apache2.conf unter MaxClients eingetragen werden. Anschießend den Apache2 einmal neustarten.

MySQL

Wenn MySQL benutzt wird aber die Anfragen an die vorhandenen Datenbanken reltiv gering ist, kann man hier auch nich etwas RAM einsparen. Dazu können in der /etc/mysql/my.cnf folgende Werte abgeändert werden.

query_cache_size        = 16M
query_cache_size        = 1M
key_buffer              = 16M
key_buffer              = 2M
USER       PID %CPU %MEM    VSZ   RSS
mysql    23340  0.2  0.9 130192  9388 (vorher)
mysql     9917  2.7  1.7  98596 17824 (hinterher)

VMWare

Wenn der VMWare Server auf einer Maschine installiert ist läuft auch immer die Management Oberfläche mit die einem den Webzugriff ermöglicht sowie die Administration mittels vmrun. Da man diese jedoch nicht immer benötigt kann man diese auch beenden. Wird in einem bash script später dann doch mal die vmrun benötigt, kann man den Dienst später immer noch nachstarten.

/etc/init.d/vmware-mgmt stop

Der Ressourcenverbrauch der Management Oberfläche sieht wiefolgt aus:

USER       PID %CPU %MEM    VSZ   RSS
root      2558  0.9  1.0 245668 10300

Des weiteren ist es Sinnvoll, die Priorität von Maschinen heunter zu setzten, damit der Host selbst noch genügend Ressourcen zur Verfügung hat.

ps -e |grep vmware | awk '{print $1}' > /tmp/vmware_process_list.tmp
for i in `cat /tmp/vmware_process_list.tmp `; do renice -19 $i; done

sysctl

In der /etc/sysctl.conf können noch Kernel spezifische Parameter definiert werden. Aus meiner Sicht Sinnvoll sind folgende.

vm.swappiness = 0
vm.overcommit_memory = 1
#The lower amount of memory (in percent) where a
#writeout of dirty data to disk is allowed to stop.
#This should be quite a bit lower than the above
#dirty_ratio to allow the kernel to write out
#chunksx of dirty data in one go.
vm.dirty_background_ratio = 5
#The maximum amount of memory (in percent) to be
#used to store dirty data before the process
#that generates the data will be forced to write
#it out. Setting this to a high value should not
#be a problem as writeouts will also occur if
#the system is low on memory.
vm.dirty_ratio = 10
#How old "dirty" data should be before the
#kernel considers it old enough to be written
#to disk. It is in general a good idea to set
#this to the same value as
#dirty_writeback_centisecs above.
vm.dirty_expire_centisecs = 1000
dev.rtc.max-user-freq = 1024