Spam filters are, nowadays a necessity. I have built many spam filters, and this below is not exactly the most advanced, but it should cut spam down quite effectively.
Its based on CentOS, and uses Postfix as its MTA, Clam for antivirus, Amavis and Spamassassin for spam filtering.
This is going to be one of those times where some knowledge of Linux would be handy. Drop me an email if you want some help…
Prerequisites
Install a new repository:
rpm -Uhv http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
This is needed because the standard CentOS repos do not contain Amavis
Install everything we need and dependencies:
yum -y install amavisd-new spamassassin clamd sendmail-cf sendmail-devel gcc postfix system-switch-mail
Switch across to using Postfix:
system-switch-mail
Configuring Postfix
Add to bottom of /etc/postfix/master.cf:
smtp inet n – n – – smtpd
-o smtpd_proxy_filter=127.0.0.1:10024
127.0.0.1:24 unix – – – – 2 smtp
-o smtp_data_done_timeout=1200
-o disable_dns_lookups=yes
127.0.0.1:10025 inet n – – – – smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=permit_mynetworks
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o strict_rfc821_envelopes=yes
in /etc/postfix/main.cf, find mynetworks_style
Add line:
mynetworks_style = host
Set the domains to check in the relay_domains option, comma-space separated
edit /etc/postfix/transport:
Add (to block specific inbound email addresses)
email@address.com error:Failed
and for each domain name specified in the relay_domains (all the domains you want to cater for):
domain.com smtp:[destination.mail.server.address]
(include square brackets, replacing domain.com with a domain name)
for as many domains as required.
Once saved, run:
postmap /etc/postfix/transport
Configuring Amavis
replace /etc/amavisd.conf with this block of text, omitting the cut-lines:
——————————-8<——————————————————-
use strict;
$max_servers = 5; # number of pre-forked children (2..15 is common)
$daemon_user = ‘amavis’; # (no default; customary: vscan or amavis)
$daemon_group = ‘amavis’; # (no default; customary: vscan or amavis)
$insert_received_line = 0;
$mydomain = ‘****INSERT YOUR DOMAIN HERE****’; # a convenient default for other settings
$MYHOME = ‘/var/amavis’; # a convenient default for other settings
$TEMPBASE = “$MYHOME/tmp”; # working directory, needs to be created manually
$ENV{TMPDIR} = $TEMPBASE; # environment variable TMPDIR
$QUARANTINEDIR = ‘/var/virusmails’;
# $quarantine_subdir_levels = 1; # add level of subdirs to disperse quarantine
# add .gz to compress spam files
$spam_quarantine_method = ‘local:spam-%m’;
# $daemon_chroot_dir = $MYHOME; # chroot directory or undef
# $db_home = “$MYHOME/db”;
# $helpers_home = “$MYHOME/var”; # prefer $MYHOME clean and owned by root?
# $pid_file = “$MYHOME/var/amavisd.pid”;
# $lock_file = “$MYHOME/var/amavisd.lock”;
#NOTE: create directories $MYHOME/tmp, $MYHOME/var, $MYHOME/db manually
@local_domains_maps = ( [".$mydomain"] );
@mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10
84.45.94.109 );
$log_level = 0; # verbosity 0..5
$log_recip_templ = undef; # disable by-recipient level-0 log entries
$DO_SYSLOG = 1; # log via syslogd (preferred)
$syslog_facility = ‘mail’; # Syslog facility as a string
# e.g.: mail, daemon, user, local0, … local7
$syslog_priority = ‘debug’; # Syslog base (minimal) priority as a string,
# choose from: emerg, alert, crit, err, warning, notice, info, debug
$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny)
$enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1
$inet_socket_port = 10024; # listen on this local TCP port(s) (see $protocol)
$unix_socketname = “$MYHOME/amavisd.sock”; # amavisd-release or amavis-milter
$interface_policy{’SOCK’}=’AM.PDP-SOCK’; # only relevant with $unix_socketname
# Use with amavis-release over a socket or with Petr Rehor’s amavis-milter.c
# (with amavis-milter.c from this package or old amavis.c client use ‘AM.CL’):
$policy_bank{’AM.PDP-SOCK’} = { protocol=>’AM.PDP’ };
$sa_tag_level_deflt = 1.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 5; # add ’spam detected’ headers at that level
$sa_kill_level_deflt = 5.5; # triggers spam evasive actions
$sa_dsn_cutoff_level = 6; # spam level beyond which a DSN is not sent
$sa_quarantine_cutoff_level = 9; # spam level beyond which quarantine is off
$sa_mail_body_size_limit = 524288; # don’t waste time on SA if mail is larger
$sa_local_tests_only = 0; # only tests which do not require internet access?
# @lookup_sql_dsn =
# ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'user1', 'passwd1'],
# ['DBI:mysql:database=mail;host=host2', 'username2', 'password2'],
# ["DBI:SQLite:dbname=$MYHOME/sql/mail_prefs.sqlite", '', ''] );
# @storage_sql_dsn = @lookup_sql_dsn; # none, same, or separate database
$virus_admin = “virusadmin\@$mydomain”; # notifications recip.
$mailfrom_notify_admin = “virusadmin\@$mydomain”; # notifications sender
$mailfrom_notify_recip = “virusadmin\@$mydomain”; # notifications sender
$mailfrom_notify_spamadmin = “virusadmin\@$mydomain”; # notifications sender
$mailfrom_to_quarantine = ”; # null return path; uses original sender if undef
@addr_extension_virus_maps = (’virus’);
@addr_extension_spam_maps = (’spam’);
@addr_extension_banned_maps = (’banned’);
@addr_extension_bad_header_maps = (’badh’);
# $recipient_delimiter = ‘+’; # undef disables address extensions altogether
# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+
$path = ‘/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin’;
# $dspam = ‘dspam’;
$MAXLEVELS = 14;
$MAXFILES = 1500;
$MIN_EXPANSION_QUOTA = 100*1024; # bytes (default undef, not enforced)
$MAX_EXPANSION_QUOTA = 300*1024*1024; # bytes (default undef, not enforced)
$sa_spam_subject_tag = ‘***SPAM*** ‘;
$defang_virus = 1; # MIME-wrap passed infected mail
$defang_banned = 1; # MIME-wrap passed mail containing banned name
# OTHER MORE COMMON SETTINGS (defaults may suffice):
$myhostname = ‘****REPLACE WITH SERVER HOSTNAME****’; # must be a fully-qualified domain name!
# $notify_method = ’smtp:[127.0.0.1]:10025′;
# $forward_method = ’smtp:[127.0.0.1]:10025′; # set to undef with milter!
$final_virus_destiny = D_BOUNCE;
$final_banned_destiny = D_BOUNCE;
$final_spam_destiny = D_BOUNCE;
$final_bad_header_destiny = D_PASS;
# REMAINING IMPORTANT VARIABLES ARE LISTED HERE BECAUSE OF LONGER ASSIGNMENTS
@keep_decoded_original_maps = (new_RE(
# qr’^MAIL$’, # retain full original message for virus checking (can be slow)
qr’^MAIL-UNDECIPHERABLE$’, # recheck full mail if it contains undecipherables
qr’^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)’i,
# qr’^Zip archive data’, # don’t trust Archive::Zip
));
# for $banned_namepath_re, a new-style of banned table, see amavisd.conf-sample
$banned_filename_re = new_RE(
# qr’^UNDECIPHERABLE$’, # is or contains any undecipherable components
# block certain double extensions anywhere in the base name
qr’\.[^./]*[A-Za-z][^./]*\.(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)\.?$’i,
# qr’\{[0-9a-z]{4,}(-[0-9a-z]{4,}){0,7}\}?’i, # Class ID extensions – CLSID
qr’^application/x-msdownload$’i, # block these MIME types
qr’^application/x-msdos-program$’i,
qr’^application/hta$’i,
# qr’^(application/x-msmetafile|image/x-wmf)$’i, # Windows Metafile MIME
# qr’^\.wmf$’, # Windows Metafile file(1) type
# qr’^message/partial$’i, # rfc2046 MIME type
# qr’^message/external-body$’i, # rfc2046 MIME type
# [ qr'^\.(Z|gz|bz2)$' => 0 ], # allow any in Unix-compressed
[ qr'^\.(rpm|cpio|tar)$' => 0 ], # allow any in Unix-type archives
# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ], # allow any within such archives
# [ qr'^\.(zip|bz2|gz|tgz|tbz)$'=> 0 ], # allow any within such archives
qr’.\.(exe|vbs|pif|scr|bat|cmd|com|cpl)$’i, # banned extension – basic
# qr’.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
# inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
# ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
# wmf|wsc|wsf|wsh)$’ix, # banned ext – long
# qr’.\.(mim|b64|bhx|hqx|xxe|uu|uue)$’i, # banned extension – WinZip vulnerab.
qr’^\.(exe-ms)$’, # banned file(1) types
# qr’^\.(exe|lha|tnef|cab|dll)$’, # banned file(1) types
);
# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631
# and http://www.cknow.com/vtutor/vtextensions.htm
# ENVELOPE SENDER SOFT-WHITELISTING / SOFT-BLACKLISTING
@score_sender_maps = ({ # a by-recipient hash lookup table,
# results from all matching recipient tables are summed
## per-recipient personal tables (NOTE: positive: black, negative: white)
## site-wide opinions about senders (the ‘.’ matches any recipient)
‘.’ => [ # the _first_ matching sender determines the score boost
new_RE( # regexp-type lookup table, just happens to be all soft-blacklist
[qr'^(bulkmail|offers|cheapbenefits|earnmoney|foryou)@'i => 5.0],
[qr'^(penis|increased\.growth|replica\.watches|cunt|slut|fucked|herba1|meds|poker|craps|blackjack|bingo|porno|viagra|manhood)@'i =>99.0],
[qr'^(greatcasino|investments|lose_weight_today|market\.alert)@'i=> 5.0],
[qr'^(money2you|MyGreenCard|new\.tld\.registry|opt-out|opt-in)@'i=> 5.0],
[qr'^(optin|saveonlsmoking2002k|specialoffer|specialoffers)@'i => 5.0],
[qr'^(stockalert|stopsnoring|wantsome|workathome|yesitsfree)@'i => 5.0],
[qr'^(your_friend|greatoffers)@'i => 5.0],
[qr'^(inkjetplanet|marketopt|MakeMoney)\d*@'i => 5.0],
),
# read_hash(”/var/amavis/sender_scores_sitewide”),
{ # a hash-type lookup table (associative array)
‘nobody@cert.org’ => -3.0,
‘cert-advisory@us-cert.gov’ => -3.0,
‘owner-alert@iss.net’ => -3.0,
’slashdot@slashdot.org’ => -3.0,
‘bugtraq@securityfocus.com’ => -3.0,
‘ntbugtraq@listserv.ntbugtraq.com’ => -3.0,
’security-alerts@linuxsecurity.com’ => -3.0,
‘mailman-announce-admin@python.org’ => -3.0,
‘amavis-user-admin@lists.sourceforge.net’=> -3.0,
‘notification-return@lists.sophos.com’ => -3.0,
‘owner-postfix-users@postfix.org’ => -3.0,
‘owner-postfix-announce@postfix.org’ => -3.0,
‘owner-sendmail-announce@lists.sendmail.org’ => -3.0,
’sendmail-announce-request@lists.sendmail.org’ => -3.0,
‘donotreply@sendmail.org’ => -3.0,
‘ca+envelope@sendmail.org’ => -3.0,
‘noreply@freshmeat.net’ => -3.0,
‘owner-technews@postel.acm.org’ => -3.0,
‘ietf-123-owner@loki.ietf.org’ => -3.0,
‘cvs-commits-list-admin@gnome.org’ => -3.0,
‘rt-users-admin@lists.fsck.com’ => -3.0,
‘clp-request@comp.nus.edu.sg’ => -3.0,
’surveys-errors@lists.nua.ie’ => -3.0,
‘emailnews@genomeweb.com’ => -5.0,
‘yahoo-dev-null@yahoo-inc.com’ => -3.0,
‘returns.groups.yahoo.com’ => -3.0,
‘clusternews@linuxnetworx.com’ => -3.0,
‘.wiley.com’ => 99.0,
lc(’lvs-users-admin@LinuxVirtualServer.org’) => -3.0,
lc(’owner-textbreakingnews@CNNIMAIL12.CNN.COM’) => -5.0,
# soft-blacklisting (positive score)
’sender@example.net’ => 3.0,
‘.example.net’ => 1.0,
},
], # end of site-wide tables
});
@decoders = (
['mail', \&do_mime_decode],
['asc', \&do_ascii],
['uue', \&do_ascii],
['hqx', \&do_ascii],
['ync', \&do_ascii],
['F', \&do_uncompress, ['unfreeze','freeze -d','melt','fcat'] ],
['Z', \&do_uncompress, ['uncompress','gzip -d','zcat'] ],
['gz', \&do_gunzip],
['gz', \&do_uncompress, 'gzip -d'],
['bz2', \&do_uncompress, 'bzip2 -d'],
['lzo', \&do_uncompress, 'lzop -d'],
['rpm', \&do_uncompress, ['rpm2cpio.pl','rpm2cpio'] ],
['cpio', \&do_pax_cpio, ['pax','gcpio','cpio'] ],
['tar', \&do_pax_cpio, ['pax','gcpio','cpio'] ],
['tar', \&do_tar],
['deb', \&do_ar, 'ar'],
# ['a', \&do_ar, 'ar'], # unpacking .a seems an overkill
['zip', \&do_unzip],
['rar', \&do_unrar, ['rar','unrar'] ],
['arj', \&do_unarj, ['arj','unarj'] ],
['arc', \&do_arc, ['nomarch','arc'] ],
['zoo', \&do_zoo, 'zoo'],
['lha', \&do_lha, 'lha'],
# ['doc', \&do_ole, 'ripole'],
['cab', \&do_cabextract, 'cabextract'],
['tnef', \&do_tnef_ext, 'tnef'],
['tnef', \&do_tnef],
['exe', \&do_executable, ['rar','unrar'], ‘lha’, ['arj','unarj'] ],
);
@av_scanners = (
['ClamAV-clamd',
\&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ]
);
@av_scanners_backup = (
### http://www.clamav.net/ – backs up clamd or Mail::ClamAV
['ClamAV-clamscan', 'clamscan',
"--stdout --disable-summary -r --tempdir=$TEMPBASE {}",
[0], qr/:.*\sFOUND$/, qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
### http://www.f-prot.com/ – backs up F-Prot Daemon
['FRISK F-Prot Antivirus', ['f-prot','f-prot.sh'],
‘-dumb -archive -packed {}’, [0,8], [3,6],
qr/Infection: (.+)|\s+contains\s+(.+)$/ ],
### http://www.trendmicro.com/ – backs up Trophie
['Trend Micro FileScanner', ['/etc/iscan/vscan','vscan'],
‘-za -a {}’, [0], qr/Found virus/, qr/Found virus (.+) in/ ],
### http://www.sald.com/, http://drweb.imshop.de/ – backs up DrWebD
['drweb - DrWeb Antivirus',
['/usr/local/drweb/drweb', '/opt/drweb/drweb', 'drweb'],
‘-path={} -al -go -ot -cn -upn -ok-’,
[0,32], [1,9,33], qr’ infected (?:with|by)(?: virus)? (.*)$’],
['KasperskyLab kavscanner', ['/opt/kav/bin/kavscanner','kavscanner'],
‘-i1 -xp {}’, [0,10,15], [5,20,21,25],
qr/(?:CURED|INFECTED|CUREFAILED|WARNING|SUSPICION) (.*)/ ,
sub {chdir(’/opt/kav/bin’) or die “Can’t chdir to kav: $!”},
sub {chdir($TEMPBASE) or die “Can’t chdir back to $TEMPBASE $!”},
],
);
1; # insure a defined return
——————————->8——————————————————-
Replace your domain name and hostname where applicable.
Make sure everything starts on boot
At the prompt, type these in:
chkconfig amavisd on
chkconfig clamd on
chkconfig postfix on
One Last thing…
Disable selinux
nano /etc/selinux/config
Finally
reboot.