wiki.ipfire.org

The community-maintained documentation platform of IPFire

User Tools

Site Tools


en:optimization:mailproxy:start

Mailproxy with IPFire

This wiki describes how you can setup a mail proxy with Postfix on IPFire, which filters virus and spam mails in forefield hence infested mails won´t belong to your internal mailserver.

Required addons

Findable in Pakfire

Postfix
Amavis
SpamAssassin
ClamAV
7Zip

Additional addons:

IP-Country-2.28-1
Mail-DKIM-0.40-1
Mail-SPF-v2.9.0-1
NetAddr-IP-4.071-1
Net-Ident-1.23-1
lzop-1.03-1
tnef-1.4.10-1
cabextract-1.4
pax-3.4
nomarch-1.4
razor-agents-sdk-2.04
razor-agents-2.84     # Ist abhängig zu razor-agents-sdk
unrar-5.0.14
zoo-2.10

INFO: The additional addons are provided under this address http://people.ipfire.org/~ummeegge/Spamassassin/

Installation of Postfix

The installation can easily be done with Pakfire over the IPFire WUI.

Configuration of Posfix

Postfix should be installed with the presetting Internet with smarthost. After the basic installation has been done, the appropriate properties on main.cf should be indicated. A backup of the original file are strongly recommended!

###
### main.cf for IPFire
###
queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/lib/postfix
manpage_directory = /usr/share/man
sample_directory = /etc/postfix
html_directory = no
readme_directory = no
 
sendmail_path = /usr/sbin/sendmail
newaliases_path = /usr/bin/newaliases
mailq_path = /usr/bin/mailq
 
strict_rfc821_envelopes = yes
biff = no
append_dot_mydomain = no
readme_directory = no
 
mail_owner = postfix
setgid_group = postdrop
 
myhostname = my.ipfire.domain
myorigin = $myhostname
 
inet_interfaces = all
#proxy_interfaces =
#mydestination = $myhostname, localhost, mysql:/etc/postfix/mysql-mydestination.cf
mydestination = my.mailserver.domain, my.domain
#relay_domains = my.mailserver.domain, my.domain
unknown_local_recipient_reject_code = 550
local_recipient_maps =
local_transport = error:local mail delivery is disabled
transport_maps = hash:/etc/postfix/transport
 
 
mynetworks_style = host
mynetworks = 127.0.0.0/8, 192.168.xxx.xxx/24, 192.168.xxx.xxx/24
 
relay_domains = $mydestination
#relayhost = $mydomain
#relayhost = [gateway.my.domain]
#relayhost = [mailserver.isp.tld]
#relayhost = uucphost
#relayhost = [an.ip.add.ress]
#relay_recipient_maps = hash:/etc/postfix/relay_recipients
#in_flow_delay = 1s
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
recipient_delimiter = +
 
mailbox_size_limit = 0
message_size_limit = 10240000
 
#mailbox_transport = cyrus
#cyrus_destination_recipient_limit=1
 
header_checks = regexp:/etc/postfix/header_checks
#fast_flush_domains = $relay_domains
 
smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
#local_destination_concurrency_limit = 2
#default_destination_concurrency_limit = 20
 
#virtual_alias_maps = mysql:/etc/postfix/mysql-virtual.cf
#sender_canonical_maps = mysql:/etc/postfix/mysql-canonical.cf
 
#smtpd_sasl_type = cyrus
#smtpd_sasl_auth_enable = yes
#smtpd_sasl_security_options = noanonymous
#smtpd_sasl_local_domain = $myhostname
#broken_sasl_auth_clients = yes
 
#smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
 
soft_bounce = yes
content_filter=amavis:[127.0.0.1]:10024
 
smtpd_helo_required = yes
mime_header_checks=pcre:/etc/postfix/body_checks
smtpd_recipient_restrictions =
            reject_invalid_hostname,
            reject_non_fqdn_hostname,
            #reject_non_fqdn_sender,
            #reject_non_fqdn_recipient,
            #reject_unknown_sender_domain,
            #reject_unknown_recipient_domain,
            #reject_unauth_pipelining,
            permit_mynetworks,
            #permit_sasl_authenticated,
            reject_unauth_destination
            #reject_rbl_client zombie.dnsbl.sorbs.net,
            #reject_rbl_client opm.blitzed.org,
            #reject_rbl_client list.dsbl.org,
            #reject_rbl_client sbl.spamhaus.org,
            #permit
 
smtpd_helo_restrictions =
	    permit_mynetworks,
            reject_invalid_hostname,
            reject_non_fqdn_hostname
 
smtpd_client_restrictions =
            permit_mynetworks,
	    reject_rbl_client ix.dnsbl.manitu.net,
            reject_rbl_client zombie.dnsbl.sorbs.net,
            reject_rbl_client list.dsbl.org,
            reject_rbl_client sbl.spamhaus.org,
            permit

Adjust the lookup-table /etc/postfix/transport to announce the destination:

my.domain  smtp:192.168.xxx.xxx

To write the changes into the database, the following command should be executed:

postmap /etc/postfix/transport

Now restart Postfix:

/etc/init.d/postfix restart

Optimize Postfix

Since Postfix is a extension and no standard on IPFire there is currently no logrotate configured for Postfix logs (they can be found under /var/log/mail ) which should be done subsequently. This prevents a fast increase of the mail logs.

The following lines should be deposit under /etc/logrotate.conf.

# Postfix
/var/log/mail {
    weekly
    rotate 4
    copytruncate
    compress
    notifempty
    missingok
}

Here the same, a backup of the original files are your best friend! ;-)

Installation of ClamAV

The installation can also be done over IPFires WUI via Pakfire. At this point there is for now nothing else to be done.

Installation of Amavis and SpamAssassin

The installation of Amavis and SpamAssassin (which is a part of the Amavis installation) are provided also over Pakfire .

Configure Amavis

After installation of Amavis, the configuration file which is located under /etc/amavisd.conf should be adapted.

Content of amavisd.conf:

amavisd.conf
use strict;
 
# a minimalistic configuration file for amavisd-new with all necessary settings
#
#   see amavisd.conf-default for a list of all variables with their defaults;
#   see amavisd.conf-sample for a traditional-style commented file;
#   for more details see documentation in INSTALL, README_FILES/*
#   and at http://www.ijs.si/software/amavisd/amavisd-new-docs.html
 
 
# COMMONLY ADJUSTED SETTINGS:
 
# @bypass_virus_checks_maps = (
#	%bypass_virus_checks, @bypass_virus_checks_acl, $bypass_virus_checks_re);  # controls running of anti-virus code
#@bypass_spam_checks_maps  = (
#	%bypass_spam_checks, @bypass_spam_checks_acl, $bypass_spam_checks_re);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders&dearchivers
 
$max_servers = 2;            # num of pre-forked children (2..15 is common), -m
$daemon_user  = 'amavis';    # (no default;  customary: vscan or amavis), -u
$daemon_group = 'amavis';    # (no default;  customary: vscan or amavis), -g
 
$mydomain = 'my.local.domain';   # a convenient default for other settings
 
# $MYHOME = '/var/amavis';   # a convenient default for other settings, -H
$TEMPBASE = "$MYHOME/tmp";   # working directory, needs to exist, -T
$ENV{TMPDIR} = $TEMPBASE;    # environment variable TMPDIR, used by SA, etc.
$QUARANTINEDIR = '/var/virusmails';  # -Q
# $quarantine_subdir_levels = 1;  # add level of subdirs to disperse quarantine
 
# $daemon_chroot_dir = $MYHOME;   # chroot directory or undef, -R
 
# $db_home   = "$MYHOME/db";      # dir for bdb nanny/cache/snmp databases, -D
# $helpers_home = "$MYHOME/var";  # working directory for SpamAssassin, -S
# $lock_file = "$MYHOME/var/amavisd.lock";  # -L
# $pid_file  = "$MYHOME/var/amavisd.pid";   # -P
#NOTE: create directories $MYHOME/tmp, $MYHOME/var, $MYHOME/db manually
 
$log_level = 2;              # verbosity 0..5, -d
$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
$nanny_details_level = 2;    # nanny verbosity: 1: traditional, 2: detailed
 
@local_domains_maps = ( ".$mydomain" );  # list of all local domains
 
@mynetworks = qw( 127.0.0.0/8 10.0.0.0/8 172.16.xxx.xxx/12 192.168.xxx.xxx/16 );
 
$unix_socketname = "$MYHOME/amavisd.sock";  # amavisd-release or amavis-milter
               # option(s) -p overrides $inet_socket_port and $unix_socketname
 
$inet_socket_port = 10024;   # listen on this local TCP port(s)
# $inet_socket_port = [10024,10026];  # listen on multiple TCP ports
 
$policy_bank{'MYNETS'} = {   # mail originating from @mynetworks
  originating => 1,  # is true in MYNETS by default, but let's make it explicit
  os_fingerprint_method => undef,  # don't query p0f for internal clients
};
 
# it is up to MTA to re-route mail from authenticated roaming users or
# from internal hosts to a dedicated TCP port (such as 10026) for filtering
$interface_policy{'10026'} = 'ORIGINATING';
 
$policy_bank{'ORIGINATING'} = {  # mail supposedly originating from our users
  originating => 1,  # declare that mail was submitted by our smtp client
  allow_disclaimers => 1,  # enables disclaimer insertion if available
  # notify administrator of locally originating malware
  virus_admin_maps => ["virusalert\@$mydomain"],
  spam_admin_maps  => ["spamalert\@$mydomain"],
  warnbadhsender   => 1,
  # forward to a smtpd service providing DKIM signing service
  forward_method => 'smtp:[127.0.0.1]:10027',
  # force MTA conversion to 7-bit (e.g. before DKIM signing)
  smtpd_discard_ehlo_keywords => ['8BITMIME'],
  bypass_banned_checks_maps => [1],  # allow sending any file names and types
  terminate_dsn_on_notify_success => 0,  # don't remove NOTIFY=SUCCESS option 
};
 
$interface_policy{'SOCK'} = 'AM.PDP-SOCK'; # only applies 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',
  auth_required_release => 0,  # do not require secret_id for amavisd-release
};
 
$sa_tag_level_deflt  = undef;  # 2.0 add spam info headers if at, or above that level
$sa_tag2_level_deflt = 4.2;  # 6.2 add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.9;  # 6.9 triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 18;   # 10 spam level beyond which a DSN is not sent
# $sa_quarantine_cutoff_level = 25; # spam level beyond which quarantine is off
$penpals_bonus_score = 8;    # (no effect without a @storage_sql_dsn database)
$penpals_threshold_high = $sa_kill_level_deflt;  # don't waste time on hi spam
 
$sa_mail_body_size_limit = 400*1024; # don't waste time on SA if mail is larger
$sa_local_tests_only = 0;    # only tests which do not require internet access?
 
$virus_admin               = "virusalert\@$mydomain";  # notifications recip.
 
$mailfrom_notify_admin     = "virusalert\@$mydomain";  # notifications sender
$mailfrom_notify_recip     = "virusalert\@$mydomain";  # notifications sender
$mailfrom_notify_spamadmin = "spam.police\@$mydomain"; # notifications sender
$mailfrom_to_quarantine = ''; # null return path; uses original sender if undef
 
@addr_extension_virus_maps      = ('virus');
@addr_extension_banned_maps     = ('banned');
@addr_extension_spam_maps       = ('spam');
@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
# for defanging bad headers only turn on certain minor contents categories:
$defang_by_ccat{+CC_BADH.",3"} = 1;  # NUL or CR character in header
$defang_by_ccat{+CC_BADH.",5"} = 1;  # header line longer than 998 characters
$defang_by_ccat{+CC_BADH.",6"} = 1;  # header field syntax error
 
 
# OTHER MORE COMMON SETTINGS (defaults may suffice):
 
$myhostname = 'my.ipfire.local';  # 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_DISCARD;
$final_banned_destiny     = D_BOUNCE;
$final_spam_destiny       = D_PASS;
$final_bad_header_destiny = D_PASS;
 
 
# Notify virus sender?  Bloß nicht!
$warnvirussender = 0; 
# Notify spam sender?   Bloß nicht!
$warnspamsender = 0;  
 
# Notify sender of banned files?  Kann man machen.
$warnbannedsender = 0;
# Notify sender of syntactically invalid header containing non-ASCII characters? Bloß nicht!
#$warnbadsender = 0;
# Notify virus (or banned files) RECIPIENT? Wie man möchte, ich finde es sinnvoll.
$warnvirusrecip = 1;
$warnbannedrecip = 1;
$warnbadhrecip = 1;
 
# SOME OTHER VARIABLES WORTH CONSIDERING (see amavisd.conf-default for all)
 
# $warnbadhsender,
# $warnvirusrecip, $warnbannedrecip, $warnbadhrecip, (or @warn*recip_maps)
 
# @bypass_virus_checks_maps, @bypass_spam_checks_maps,
 
# @bypass_banned_checks_maps, @bypass_header_checks_maps,
 
# @virus_lovers_maps, @spam_lovers_maps,
# @banned_files_lovers_maps, @bad_header_lovers_maps,
#
# @blacklist_sender_maps, @score_sender_maps,
#
# $clean_quarantine_method, $virus_quarantine_to, $banned_quarantine_to,
# $bad_header_quarantine_to, $spam_quarantine_to,
#
# $defang_bad_header, $defang_undecipherable, $defang_spam
 
 
# 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(
 
### BLOCKED ANYWHERE
# qr'^UNDECIPHERABLE$',  # is or contains any undecipherable components
  qr'^\.(exe-ms|dll)$',                   # banned file(1) types, rudimentary
# qr'^\.(exe|lha|tnef|cab|dll)$',         # banned file(1) types
 
### BLOCK THE FOLLOWING, EXCEPT WITHIN UNIX ARCHIVES:
# [ qr'^\.(gz|bz2)$'             => 0 ],  # allow any in gzip or bzip2
  [ qr'^\.(rpm|cpio|tar)$'       => 0 ],  # allow any in Unix-type archives
 
  qr'.\.(pif|scr)$'i,                     # banned extensions - rudimentary
# qr'^\.zip$',                            # block zip type
 
### BLOCK THE FOLLOWING, EXCEPT WITHIN ARCHIVES:
# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ],  # allow any within these archives
 
  qr'^application/x-msdownload$'i,        # block these MIME types
  qr'^application/x-msdos-program$'i,
  qr'^application/hta$'i,
 
# qr'^message/partial$'i,         # rfc2046 MIME type
# qr'^message/external-body$'i,   # rfc2046 MIME type
 
# qr'^(application/x-msmetafile|image/x-wmf)$'i,  # Windows Metafile MIME type
# qr'^\.wmf$',                            # Windows Metafile file(1) type
 
  # block certain double extensions in filenames
  qr'\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)[.\s]*$'i,
 
# qr'\{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?'i, # Class ID CLSID, strict
# qr'\{[0-9a-z]{4,}(-[0-9a-z]{4,}){0,7}\}?'i, # Class ID extension CLSID, loose
 
  qr'.\.(exe|vbs|pif|scr|cpl)$'i,             # banned extension - basic
# qr'.\.(exe|vbs|pif|scr|cpl|bat|cmd|com)$'i, # banned extension - basic+cmd
# 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'.\.(ani|cur|ico)$'i,                 # banned cursors and icons filename
# qr'^\.ani$',                            # banned animated cursor file(1) type
 
# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i,  # banned extension - WinZip vulnerab.
);
# 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)
# 'user1@example.com'  => [{'bla-mobile.press@example.com' => 10.0}],
# 'user3@example.com'  => [{'.ebay.com'                 => -3.0}],
# 'user4@example.com'  => [{'cleargreen@cleargreen.com' => -7.0,
#                           '.cleargreen.com'           => -5.0}],
 
  ## 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'^(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,
     '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,
     'amavis-user-bounces@lists.sourceforge.net' => -3.0,
     'spamassassin.apache.org'                => -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,
     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_uncompress,  'gzip -d'],
  ['gz',   \&do_gunzip],
  ['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'] ],
  ['deb',  \&do_ar,          'ar'],
# ['a',    \&do_ar,          'ar'],  # unpacking .a seems an overkill
  ['zip',  \&do_unzip],
  ['7z',   \&do_7zip,       ['7zr','7za','7z'] ],
  ['rar',  \&do_unrar,      ['rar','unrar'] ],
  ['arj',  \&do_unarj,      ['arj','unarj'] ],
  ['arc',  \&do_arc,        ['nomarch','arc'] ],
  ['zoo',  \&do_zoo,        ['zoo','unzoo'] ],
  ['lha',  \&do_lha,         'lha'],
# ['doc',  \&do_ole,         'ripole'],
  ['cab',  \&do_cabextract,  'cabextract'],
  ['tnef', \&do_tnef_ext,    'tnef'],
  ['tnef', \&do_tnef],
# ['sit',  \&do_unstuff,     'unstuff'],  # broken/unsafe decoder
  ['exe',  \&do_executable, ['rar','unrar'], 'lha', ['arj','unarj'] ],
);
 
 
@av_scanners = (
 
#	### http://www.clamav.net/
	['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
	qr/\bOK$/, qr/\bFOUND$/,
	 qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
#	# NOTE: run clamd under the same user as amavisd, or run it under its own
#	#   uid such as clamav, add user clamav to the amavis group, and then add
#	#   AllowSupplementaryGroups to clamd.conf;
#	# NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
#	#   this entry; when running chrooted one may prefer socket "$MYHOME/clamd".
 
# ### http://www.f-prot.com/
# ['FRISK F-Prot Daemon',
#   \&ask_daemon,
#   ["GET {}/*?-dumb%20-archive%20-packed HTTP/1.0\r\n\r\n",
#     ['127.0.0.1:10200','127.0.0.1:10201','127.0.0.1:10202',
#      '127.0.0.1:10203','127.0.0.1:10204'] ],
#   qr/(?i)<summary[^>]*>clean<\/summary>/,
#   qr/(?i)<summary[^>]*>infected<\/summary>/,
#   qr/(?i)<name>(.+)<\/name>/ ],
 
  ### http://www.kaspersky.com/  (kav4mailservers)
  ['KasperskyLab AVP - aveclient',
    ['/usr/local/kav/bin/aveclient','/usr/local/share/kav/bin/aveclient',
     '/opt/kav/5.5/kav4mailservers/bin/aveclient','aveclient'],
    '-p /var/run/aveserver -s {}/*',
    [0,3,6,8], qr/\b(INFECTED|SUSPICION|SUSPICIOUS)\b/,
    qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.+)/,
  ],
  # NOTE: one may prefer [0],[2,3,4,5], depending on how suspicious,
  # currupted or protected archives are to be handled
 
  ### http://www.avira.com/
  ### Avira AntiVir (formerly H+BEDV) or (old) CentralCommand Vexira Antivirus
  ['Avira AntiVir', ['antivir','vexira'],
    '--allfiles -noboot -nombr -rs -s -z {}', [0], qr/ALERT:|VIRUS:/,
    qr/(?x)^\s* (?: ALERT: \s* (?: \[ | [^']* ' ) |
         (?i) VIRUS:\ .*?\ virus\ '?) ( [^\]\s']+ )/ ],
    # NOTE: if you only have a demo version, remove -z and add 214, as in:
    #  '--allfiles -noboot -nombr -rs -s {}', [0,214], qr/ALERT:|VIRUS:/,
 
# ### http://www.avast.com/
# ['avast! Antivirus daemon',
#   \&ask_daemon,	# greets with 220, terminate with QUIT
#   ["SCAN {}\015\012QUIT\015\012", '/var/run/avast4/mailscanner.sock'],
#   qr/\t\[\+\]/, qr/\t\[L\]\t/, qr/\t\[L\]\t([^[ \t\015\012]+)/ ],
 
# ### http://www.avast.com/
# ['avast! Antivirus - Client/Server Version', 'avastlite',
#   '-a /var/run/avast4/mailscanner.sock -n {}', [0], [1],
#   qr/\t\[L\]\t([^[ \t\015\012]+)/ ],
 
  ### http://www.avast.com/
  ['avast! Antivirus', ['/usr/bin/avastcmd','avastcmd'],
    '-a -i -n -t=A {}', [0], [1], qr/\binfected by:\s+([^ \t\n\[\]]+)/ ],
 
  ### http://www.bitdefender.com/
  ['BitDefender', 'bdc',
    '--arc --mail {}', qr/^Infected files *:0+(?!\d)/,
    qr/^(?:Infected files|Identified viruses|Suspect files) *:0*[1-9]/,
    qr/(?:suspected|infected): (.*)(?:\033|$)/ ],
  # consider also: --all --nowarn --alev=15 --flev=15.  The --all argument may
  # not apply to your version of bdc, check documentation and see 'bdc --help'
 
);
 
 
@av_scanners_backup = (
 
  ### http://www.clamav.net/   - backs up clamd or Mail::ClamAV
  ['ClamAV-clamscan', 'clamscan',
    "--stdout --no-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],   # or: [0], [3,6,8],
    qr/(?:Infection:|security risk named) (.+)|\s+contains\s+(.+)$/ ],
 
   ### http://www.kaspersky.com/
   ['Kaspersky Antivirus v5.5',
     ['/opt/kaspersky/kav4fs/bin/kav4fs-kavscanner',
      '/opt/kav/5.5/kav4unix/bin/kavscanner',
      '/opt/kav/5.5/kav4mailservers/bin/kavscanner', 'kavscanner'],
     '-i0 -xn -xp -mn -R -ePASBME {}/*', [0,10,15], [5,20,21,25],
     qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.*)/ ,
#    sub {chdir('/opt/kav/bin') or die "Can't chdir to kav: $!"},
#    sub {chdir($TEMPBASE) or die "Can't chdir back to $TEMPBASE $!"},
   ],
 
# always succeeds (uncomment to consider mail clean if all other scanners fail)
# ['always-clean', sub {0}],
 
);
 
 
1;  # insure a defined return

Proove the ClamAV path

It is important that ClamAV uses the correct path, which will be checked in here:

$myhostname = 'ipfire.localdomain';  # must be a fully-qualified domain name! 
          #       ### http://www.clamav.net/ 
	        ['ClamAV-clamd', 
	  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"], 
	        qr/\bOK$/, qr/\bFOUND$/, 
	         qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],

Amavis and ClamAV group assignment

Amavis should have the correct permission for ClamAV:

# usermod -a -G clamav amavis
# usermod -a -G clamav clamav
# usermod -a -G amavis clamav
# usermod -a -G amavis amavis

Adapt SpamAssassin

Spamassassins configuration file are located under /var/ipfire/mail/spamassassin/ in here the following values can be changed if needed:

# This is the right place to customize your installation of SpamAssassin.
#
# See 'perldoc Mail::SpamAssassin::Conf' for details of what can be
# tweaked.
#
# Only a small subset of options are listed below
#
###########################################################################
 
# add_header all Report _REPORT_
 
#   Add *****SPAM***** to the Subject header of spam e-mails
#
 rewrite_header Subject *****SPAM*****
 
 
#   Save spam messages as a message/rfc822 MIME attachment instead of
#   modifying the original message (0: off, 2: use text/plain instead)
#
 report_safe 1
 
 
#   Set which networks or hosts are considered 'trusted' by your mail
#   server (i.e. not spammers)
#
 trusted_networks 192.168.xxx.
 
 
#   Set file-locking method (flock is not safe over NFS, but is faster)
#
# lock_method flock
 
 
#   Set the threshold at which a message is considered spam (default: 5.0)
#
 required_score 5.0
 
 
#   Use Bayesian classifier (default: 1)
#
 use_bayes 1
 
 
#   Bayesian classifier auto-learning (default: 1)
#
 bayes_auto_learn 1
 
 
#   Set headers which may provide inappropriate cues to the Bayesian
#   classifier
#
 bayes_ignore_header X-Bogosity
 bayes_ignore_header X-Spam-Flag
 bayes_ignore_header X-Spam-Status

Optimize Amavis

To prevent a high amount of temporary files and directories produced by Amavis, the documentation of Amavisd-new recommends to delete dispensable data from time to time.

The following command are an advice for doing this:

find /var/amavis -type d -name 'amavis-20??????T*' \
    -prune -mtime +1 -exec rm -rf {} \;

While executing this command, amavisd should be deactivated.

This can also be integrated for example in the START|STOP routines (init script) of Amavis. For this, the following lines can be used in /etc/init.d/amavis.d.

It should be another time said: A backup of the file are your best friend ;-)

#!/bin/sh
########################################################################
# Begin $rc_base/init.d/amavisd
#
# Description : Amavisd Init Script
#
# Authors     : Michael Tremer (ms@ipfire.org)
#
# Version     : 01.00
#
# Notes       :
#
########################################################################
 
. /etc/sysconfig/rc
. ${rc_functions}
 
 
case "${1}" in
        start)
                boot_mesg "Starting AMaViS Daemon..."
                find /var/amavis/tmp -type d -name 'amavis-20??????T*' \
    -prune -mtime +1 -exec rm -rf {} \;
                loadproc /usr/bin/amavisd
                ;;
 
        stop)
                boot_mesg "Stopping AMaViS Daemon..."
                killproc /usr/bin/amavisd
                ;;
 
        restart)
                ${0} stop
                sleep 1
                ${0} start
                ;;
 
        status)
                statusproc /usr/bin/amavisd
                ;;
 
        *)
                echo "Usage: ${0} {start|stop|restart|status}"
                exit 1
                ;;
esac

Adapt IPTables

iptables -A CUSTOMINPUT -p tcp -s 0/0 --sport 1024:65535 -d 192.168.ip.red0 --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT

Autostart SpamAssassin and Amavis

For a automatic START|STOP|RESTART of SpamAssassin and Amavis, you can set the following symlinks:

ln -s ../init.d/amavisd /etc/rc.d/rc3.d/S38amavisd
ln -s ../init.d/spamassassin /etc/rc.d/rc3.d/S38spamassassin
ln -s ../init.d/amavisd /etc/rc.d/rc0.d/K25amavisd
ln -s ../init.d/amavisd /etc/rc.d/rc6.d/K25amavisd
ln -s ../init.d/spamassassin /etc/rc.d/rc0.d/K25spamassassin
ln -s ../init.d/spamassassin /etc/rc.d/rc6.d/K25spamassassin

Prevent NDR via LDAP-Proofe

First, thanks to botribun for his hint. Here, you have the possibility to connect the mail proxy against an LDAP to generate a receiver list.

Thereby, the mailsystem can be relieved and a NDR can be prevented. It is your own decision if you´d like to implement this feature.

The following Perl script can be used for this, also a appropriate cronjob should be applied, which updates this list in a configured time.

Integrate the following line in /etc/postfix/main.cf (or remove # if the directives are already present):

relay_recipient_maps = hash:/etc/postfix/relay_recipients

Now integrate the script and adapt it to your needs.

getadsmtp.pl
#!/usr/bin/perl -T -w
 
# Version 1.02
 
# This script will pull all users' SMTP addresses from your Active Directory
# (including primary and secondary email addresses) and list them in the
# format "user@example.com OK" which Postfix uses with relay_recipient_maps.
# Be sure to double-check the path to perl above.
 
# This requires Net::LDAP to be installed.  To install Net::LDAP, at a shell
# type "perl -MCPAN -e shell" and then "install Net::LDAP"
 
use Net::LDAP;
use Net::LDAP::Control::Paged;
use Net::LDAP::Constant ( "LDAP_CONTROL_PAGED" );
 
# Enter the path/file for the output
$VALID = "/etc/postfix/transport_maps";
 
# Enter the FQDN of your Active Directory domain controllers below
$dc1="10.10.10.2";
$dc2="10.10.10.3";
 
# Enter the LDAP container for your userbase.
# The syntax is CN=Users,dc=example,dc=com
# This can be found by installing the Windows 2000 Support Tools
# then running ADSI Edit.
# In ADSI Edit, expand the "Domain NC [domaincontroller1.example.com]" &
# you will see, for example, DC=example,DC=com (this is your base).
# The Users Container will be specified in the right pane as
# CN=Users depending on your schema (this is your container).
# You can double-check this by clicking "Properties" of your user
# folder in ADSI Edit and examining the "Path" value, such as:
# LDAP://domaincontroller1.example.com/CN=Users,DC=example,DC=com
# which would be $hqbase="cn=Users,dc=example,dc=com"
# Note:  You can also use just $hqbase="dc=example,dc=com"
$hqbase="dc=DOMAIN,dc=LOCAL";
 
# Enter the username & password for a valid user in your Active Directory
# with username in the form cn=username,cn=Users,dc=example,dc=com
# Make sure the user's password does not expire.  Note that this user
# does not require any special privileges.
# You can double-check this by clicking "Properties" of your user in
# ADSI Edit and examining the "Path" value, such as:
# LDAP://domaincontroller1.example.com/CN=user,CN=Users,DC=example,DC=com
# which would be $user="cn=user,cn=Users,dc=example,dc=com"
# Note: You can also use the UPN login: "user\@example.com"
$user="USER\@DOAMIN.LOCAL";
$passwd="USERPW";
 
# Connecting to Active Directory domain controllers
$noldapserver=0;
$ldap = Net::LDAP->new($dc1) or
   $noldapserver=1;
if ($noldapserver == 1)  {
   $ldap = Net::LDAP->new($dc2) or
      die "Error connecting to specified domain controllers $@ \n";
}
 
$mesg = $ldap->bind ( dn => $user,
                     password =>$passwd);
if ( $mesg->code()) {
    die ("error:", $mesg->code(),"\n","error name: ",$mesg->error_name(),
        "\n", "error text: ",$mesg->error_text(),"\n");
}
 
# How many LDAP query results to grab for each paged round
# Set to under 1000 for Active Directory
$page = Net::LDAP::Control::Paged->new( size => 990 );
 
@args = ( base     => $hqbase,
# Play around with this to grab objects such as Contacts, Public Folders, etc.
# A minimal filter for just users with email would be:
# filter => "(&(sAMAccountName=*)(mail=*))"
         filter => "(& (mailnickname=*) (| (&(objectCategory=person)
                    (objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))
                    (&(objectCategory=person)(objectClass=user)(|(homeMDB=*)
                    (msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))
                    (objectCategory=group)(objectCategory=publicFolder)(objectClass=msExchDynamicDistributionList) ))",
          control  => [ $page ],
          attrs  => [ "proxyAddresses" ],
);
 
my $cookie;
while(1) {
  # Perform search
  my $mesg = $ldap->search( @args );
 
# Filtering results for proxyAddresses attributes  
  foreach my $entry ( $mesg->entries ) {
    my $name = $entry->get_value( "cn" );
    # LDAP Attributes are multi-valued, so we have to print each one.
    foreach my $mail ( $entry->get_value( "proxyAddresses" ) ) {
     # Test if the Line starts with one of the following lines:
     # proxyAddresses: [smtp|SMTP]:
     # and also discard this starting string, so that $mail is only the
     # address without any other characters...
     if ( $mail =~ s/^(smtp|SMTP)://gs ) {
       push(@valid, $mail." OK\n"); 
     }
    }
  }
 
  # Only continue on LDAP_SUCCESS
  $mesg->code and last;
 
  # Get cookie from paged control
  my($resp)  = $mesg->control( LDAP_CONTROL_PAGED ) or last;
  $cookie    = $resp->cookie or last;
 
  # Set cookie in paged control
  $page->cookie($cookie);
}
 
if ($cookie) {
  # We had an abnormal exit, so let the server know we do not want any more
  $page->cookie($cookie);
  $page->size(0);
  $ldap->search( @args );
  # Also would be a good idea to die unhappily and inform OP at this point
     die("LDAP query unsuccessful");
}
# Only write the file once the query is successful
open VALID, ">$VALID" or die "CANNOT OPEN $VALID $!";
print VALID @valid;
# Add additional restrictions, users, etc. to the output file below.
#print VALID "user\@example.com OK\n";
#print VALID "user1\@example.com 550 User unknown.\n";
#print VALID "bad.example.com 550 User does not exist.\n";
 
close VALID;

Prepare the cronjob with the following script which also writes the LDAP list into a database while execution.

update-relay-recipients.sh
#!/bin/sh
/etc/postfix/getadsmtp.pl
cd /etc/postfix
postmap relay_recipients

to execute it continuously, apply the cronjob by typing:

fcrontab -e

Hints & tricks

Adept the mail queue

List the queue:

mailq | cat

Delete mail in queue with the corresponding Mail-ID:

postsuper -d 38A9580045

Further informations

Translations of this page?:
en/optimization/mailproxy/start.txt · Last modified: 2014/08/05 14:33 by ummeegge