Amavisd¶
Inhalt¶
- Amavisd 2.14.0
- PostgreSQL für Lookups, Logging und Quarantäne
- optionale DKIM-Signierung
- optionale p0f-Analyse
- amavisd-milter 1.7.0
- Milter-Anbindung für Postfix
- AM.PDP-Verbindung zu amavisd-new
- Unix-Sockets zwischen Postfix, amavisd-milter und amavisd-new
Der aktuelle FreeBSD-Port security/amavisd-new steht auf 2.14.0. Relevante Portoptionen für dieses Setup sind insbesondere PGSQL für Lookups/Logging/Quarantäne und optional P0F für den p0f-Analyzer. Der Port bringt außerdem Beispielkonfigurationen unter /usr/local/etc mit. (FreshPorts)
Einleitung¶
Dieses HowTo beschreibt die Installation und Konfiguration von Amavisd und von amavisd-milter auf FreeBSD 15+.
Amavisd ist die Schnittstelle zwischen MTA und Inhaltsprüfern wie Virenscannern und SpamAssassin. In diesem Setup wird Amavisd mit PostgreSQL für Policy-Lookups sowie für Logging und optional Quarantäne betrieben. Die dafür relevanten Konfigurationsvariablen sind @lookup_sql_dsn für Lookups und @storage_sql_dsn für Reporting/Quarantäne; beide sind unabhängig voneinander. Die PostgreSQL-spezifischen Schemas werden upstream in README.sql-pg dokumentiert. (IJS)
amavisd-milter ist ein separater Milter-Adapter für amavisd-new. Er spricht auf der einen Seite das Milter-Protokoll mit dem MTA und auf der anderen Seite das AM.PDP-Protokoll mit amavisd-new. Der aktuelle FreeBSD-Port security/amavisd-milter steht bei 1.7.0. Der Port installiert das Binary sbin/amavisd-milter, das rc.d-Skript amavisd-milter und legt /var/run/amavis an. (FreshPorts)
Dieses HowTo beschreibt bewusst die Milter-Anbindung von Postfix an Amavis. Die klassische content_filter-Kette Postfix -> amavisd-new -> Postfix wird hier nicht behandelt. Postfix unterstützt den Sendmail-Milter-Standard ausdrücklich als before-queue-Filtermechanismus. (Postfix)
Voraussetzungen¶
Zu den Voraussetzungen für dieses HowTo siehe bitte: Hosting System
Zusätzlich gilt für dieses HowTo:
- Postfix ist bereits installiert und als Content-Filter-Frontend vorbereitet.
- PostgreSQL ist bereits installiert und erreichbar.
- Mindestens ein Virenscanner ist installiert, zum Beispiel
security/clamav. - Falls Spam-Prüfung genutzt werden soll, ist SpamAssassin bereits installiert.
- Für die optionale DKIM-Signierung muss DNS für die Maildomain gepflegt werden können.
amavisd-newist für AM.PDP konfiguriert.- Postfix ist bereits installiert und für Milter vorbereitet.
- Der Postfix-Prozess kann den Milter-Socket erreichen.
Der FreeBSD-Port weist ausdrücklich darauf hin, dass amavisd-new mindestens einen Virenscanner benötigt. Außerdem unterstützt der Port SpamAssassin-Integration. (FreshPorts)
Für amavisd-milter muss amavisd-new auf AM.PDP umgestellt sein. Die offizielle Doku nennt dafür in amavisd.conf insbesondere $protocol = "AM.PDP"; und einen Unix-Socket wie $unix_socketname = "$MYHOME/var/amavisd.sock";. Der Socket zwischen amavisd-milter und amavisd-new muss dabei denselben Wert haben wie $unix_socketname in amavisd.conf. (Amavisd Milter)
Vorbereitungen¶
DNS Records¶
Für dieses HowTo sind zunächst keine zusätzlichen DNS-Records zwingend erforderlich.
Für die optionale DKIM-Signierung wird später jedoch ein TXT-Record für den verwendeten Selector benötigt. Amavis kann diesen Record nach der Schlüsselerzeugung selbst mit showkeys ausgeben. (Amavis)
Gruppen / Benutzer / Passwörter¶
Für dieses HowTo müssen keine zusätzlichen Systemgruppen oder Systembenutzer angelegt werden.
Der Amavisd-Port verwendet auf FreeBSD die bestehenden Amavis-Benutzer- und Gruppenpfade unter /var/amavis; das rc.d-Skript erwartet standardmäßig die Konfigurationsdatei /usr/local/etc/amavisd.conf und die PID-Datei unter /var/amavis/amavisd.pid. (FreeBSD Git)
Verzeichnisse / Dateien¶
Für diese HowTos müssen zuvor folgende Verzeichnisse angelegt werden, sofern sie noch nicht existieren, oder entsprechend geändert werden, sofern sie bereits existieren.
Für diese HowTos müssen zuvor folgende Dateien angelegt werden, sofern sie noch nicht existieren, oder entsprechend geändert werden, sofern sie bereits existieren.
Installation¶
Wir installieren security/amavisd-new und dessen Abhängigkeiten.¶
mkdir -p /var/db/ports/archivers_7-zip
cat <<'EOF' > /var/db/ports/archivers_7-zip/options
_OPTIONS_READ=7-zip-26.00
_FILE_COMPLETE_OPTIONS_LIST=ASM DOCS
OPTIONS_FILE_SET+=ASM
OPTIONS_FILE_UNSET+=DOCS
EOF
mkdir -p /var/db/ports/archivers_arc
cat <<'EOF' > /var/db/ports/archivers_arc/options
_OPTIONS_READ=arc-5.21q
_FILE_COMPLETE_OPTIONS_LIST=DOCS
OPTIONS_FILE_UNSET+=DOCS
EOF
mkdir -p /var/db/ports/archivers_arj
cat <<'EOF' > /var/db/ports/archivers_arj/options
_OPTIONS_READ=arj-3.10.22
_FILE_COMPLETE_OPTIONS_LIST=DOCS LOCALE_DE LOCALE_EN LOCALE_RU
OPTIONS_FILE_UNSET+=DOCS
OPTIONS_FILE_UNSET+=LOCALE_DE
OPTIONS_FILE_SET+=LOCALE_EN
OPTIONS_FILE_UNSET+=LOCALE_RU
EOF
mkdir -p /var/db/ports/archivers_cabextract
cat <<'EOF' > /var/db/ports/archivers_cabextract/options
_OPTIONS_READ=cabextract-1.11
_FILE_COMPLETE_OPTIONS_LIST=DOCS
OPTIONS_FILE_UNSET+=DOCS
EOF
mkdir -p /var/db/ports/archivers_lzop
cat <<'EOF' > /var/db/ports/archivers_lzop/options
_OPTIONS_READ=lzop-1.04
_FILE_COMPLETE_OPTIONS_LIST=DOCS
OPTIONS_FILE_UNSET+=DOCS
EOF
mkdir -p /var/db/ports/archivers_lzo2
cat <<'EOF' > /var/db/ports/archivers_lzo2/options
_OPTIONS_READ=lzo2-2.10
_FILE_COMPLETE_OPTIONS_LIST=DOCS EXAMPLES
OPTIONS_FILE_UNSET+=DOCS
OPTIONS_FILE_UNSET+=EXAMPLES
EOF
mkdir -p /var/db/ports/archivers_unrar
cat <<'EOF' > /var/db/ports/archivers_unrar/options
_OPTIONS_READ=unrar-7.13
_FILE_COMPLETE_OPTIONS_LIST=OPENSSL_AES
OPTIONS_FILE_SET+=OPENSSL_AES
EOF
mkdir -p /var/db/ports/security_amavisd-new
cat <<'EOF' > /var/db/ports/security_amavisd-new/options
_OPTIONS_READ=amavisd-new-2.14.0
_FILE_COMPLETE_OPTIONS_LIST=7ZIP ARC ARJ BDB CAB DOCS FILE IPV6 LDAP LHA LZOP MSWORD MYSQL NOMARCH P0F PGSQL RAR RPM SASL SNMP SPAMASSASSIN SQLITE TNEF UNARJ UNRAR UNZOO ZOO
OPTIONS_FILE_SET+=7ZIP
OPTIONS_FILE_SET+=ARC
OPTIONS_FILE_SET+=ARJ
OPTIONS_FILE_SET+=BDB
OPTIONS_FILE_SET+=CAB
OPTIONS_FILE_UNSET+=DOCS
OPTIONS_FILE_SET+=FILE
OPTIONS_FILE_SET+=IPV6
OPTIONS_FILE_UNSET+=LDAP
OPTIONS_FILE_UNSET+=LHA
OPTIONS_FILE_SET+=LZOP
OPTIONS_FILE_SET+=MSWORD
OPTIONS_FILE_SET+=MYSQL
OPTIONS_FILE_UNSET+=NOMARCH
OPTIONS_FILE_UNSET+=P0F
OPTIONS_FILE_SET+=PGSQL
OPTIONS_FILE_UNSET+=RAR
OPTIONS_FILE_SET+=RPM
OPTIONS_FILE_UNSET+=SASL
OPTIONS_FILE_UNSET+=SNMP
OPTIONS_FILE_SET+=SPAMASSASSIN
OPTIONS_FILE_UNSET+=SQLITE
OPTIONS_FILE_UNSET+=TNEF
OPTIONS_FILE_UNSET+=UNARJ
OPTIONS_FILE_SET+=UNRAR
OPTIONS_FILE_UNSET+=UNZOO
OPTIONS_FILE_SET+=ZOO
EOF
portmaster -w -B -g -U --force-config security/amavisd-new -n
Seit dem Port-Update 2022 verwendet Amavis auf FreeBSD archivers/7-zip und nicht mehr das alte p7zip/7zr. Falls bestehende Konfigurationen noch alte Aufrufnamen enthalten, müssen diese angepasst werden. (FreshPorts)
Wir installieren security/amavisd-milter und dessen Abhängigkeiten.¶
mkdir -p /var/db/ports/security_amavisd-milter
cat <<'EOF' > /var/db/ports/security_amavisd-milter/options
EOF
portmaster -w -B -g -U --force-config security/amavisd-milter -n
mkdir -p /var/spool/postfix/amavis
chown vscan:vscan /var/spool/postfix/amavis
chmod 770 /var/spool/postfix/amavis
pw groupmod vscan -m postfix
Dienst in rc.conf eintragen¶
Der Dienst wird mittels sysrc in der rc.conf eingetragen und dadurch beim Systemstart automatisch gestartet.
sysrc amavisd_enable="YES"
sysrc amavisd_pidfile="/var/amavis/amavisd.pid"
sysrc amavisd_ram="512m"
Das FreeBSD-rc-Skript heißt amavisd-milter, die rc.conf-Variable dazu heißt aber amavisd_milter_enable. Zusätzlich kennt das Skript unter anderem die Variablen amavisd_milter_socket, amavisd_milter_socket_perm, amavisd_am_pdp_socket und optional amavisd_milter_pidfile. Die Standardwerte sind /var/run/amavis/amavisd-milter.sock, 0666, /var/amavis/amavisd.sock und /var/run/amavis/amavisd-milter.pid. (GitHub)
sysrc amavisd_milter_enable="YES"
sysrc amavisd_milter_socket="/var/spool/postfix/amavis/amavisd-milter.sock"
sysrc amavisd_am_pdp_socket="/var/spool/postfix/amavis/amavisd.sock"
Konfiguration¶
Konfigurationsdatei¶
Der Port installiert die Vorlagen amavisd.conf.sample, amavisd.conf-default und amavisd-custom.conf.sample unter /usr/local/etc. Für dieses Setup verwenden wir die produktive Konfigurationsdatei /usr/local/etc/amavisd.conf. (FreeBSD Git)
cat <<'EOF' > /usr/local/etc/amavisd.conf
use strict;
# =========================================================================
# SYSTEM & PATHS
# =========================================================================
$myprogram_name = $0;
$myhostname = 'mail.example.com';
$mydomain = 'example.com';
$daemon_user = 'vscan';
$daemon_group = 'vscan';
$MYHOME = '/var/amavis';
$TEMPBASE = "$MYHOME/tmp"; # Highly recommended to mount as tmpfs in FreeBSD
$ENV{TMPDIR} = $TEMPBASE;
$db_home = "$MYHOME/db";
$pid_file = "$MYHOME/amavisd.pid";
$lock_file = "$MYHOME/amavisd.lock";
$helpers_home = "$MYHOME";
# Matches Postfix's amavisfeed maxproc (2)
$max_servers = 10;
# =========================================================================
# LOGGING (Optimized for Production)
# =========================================================================
$log_level = 0; # Changed from 3 to 0 (or 1) to save I/O
$logfile = "$MYHOME/amavisd.log";
$log_templ = $log_verbose_templ;
$sa_debug = 0; # Changed from 1 to 0 (Critical for performance)
# =========================================================================
# NETWORKING & BINDING
# =========================================================================
@local_domains_maps = 1;
@mynetworks = qw(
127.0.0.0/8 [::1]/128
10.0.0.0/8 [fe80::]/10
__IPADDR4__/32 [__IPADDR6__]/64
);
#$X_HEADER_LINE = "by $myhostname";
$unix_socketname = "/var/spool/postfix/amavis/amavisd.sock";
$inet_socket_port = [ 10024, 10026 ];
$inet_socket_bind = [ '127.0.0.1', '[::1]' ];
@inet_acl = qw( 127.0.0.1 [::1] );
$smtp_connection_cache_enable = 1;
$localhost_name = $myhostname;
# Default forward (Reinject back to Postfix after checking)
$forward_method = 'smtp:[127.0.0.1]:10025';
$notify_method = 'smtp:[127.0.0.1]:10025';
# =========================================================================
# DATABASES (FreeBSD PostgreSQL Socket Optimization)
# =========================================================================
$enable_db = 0; # Internal BDB disabled, using pgsql
$nanny_details_level = 2;
# Switched to Unix Socket (/tmp) for much faster query performance
@lookup_sql_dsn = ([ 'DBI:Pg:dbname=mail_prefs;host=localhost', 'vscan', '__PASSWORD_VSCAN__' ]);
@storage_sql_dsn = ([ 'DBI:Pg:dbname=mail_log;host=localhost', 'vscan', '__PASSWORD_VSCAN__' ]);
$timestamp_fmt_mysql = 1;
$sql_allow_8bit_address = 1;
# =========================================================================
# DESTINY & POLICIES
# =========================================================================
$final_virus_destiny = D_DISCARD;
$final_banned_destiny = D_DISCARD;
$final_spam_destiny = D_PASS; # Passes spam to Dovecot (Sieve typically handles it)
$final_bad_header_destiny = D_PASS;
$virus_quarantine_method = 'sql:';
$spam_quarantine_method = 'sql:';
$banned_files_quarantine_method = 'sql:';
$bad_header_quarantine_method = 'sql:';
$QUARANTINEDIR = '/var/virusmails';
$quarantine_subdir_levels = 2;
$mailfrom_to_quarantine = '';
$virus_admin = "virusalert\@$mydomain";
$mailfrom_notify_admin = "virusalert\@$mydomain";
$mailfrom_notify_recip = "virusalert\@$mydomain";
$mailfrom_notify_spamadmin = "spam.police\@$mydomain";
$defang_virus = 1;
$defang_banned = 1;
%defang_maps_by_ccat = (
CC_VIRUS, sub { c('defang_virus') },
CC_BANNED, sub { c('defang_banned') },
CC_UNCHECKED, sub { c('defang_undecipherable') },
CC_SPAM, sub { c('defang_spam') },
CC_SPAMMY, sub { c('defang_spam') },
CC_BADH.',3', 1,
CC_BADH.',5', 1,
CC_BADH.',6', 1,
CC_UNCHECKED.',3', 1,
CC_BADH, sub { c('defang_bad_header') },
);
%admin_maps_by_ccat = (
CC_VIRUS, sub { ca('virus_admin_maps') },
CC_BANNED, sub { ca('banned_admin_maps') },
CC_SPAM, sub { ca('spam_admin_maps') },
CC_BADH, sub { ca('bad_header_admin_maps') },
);
# =========================================================================
# DKIM SETTINGS
# =========================================================================
$enable_dkim_verification = 1;
$enable_dkim_signing = 0; # Global off, enabled only in ORIGINATING bank
$myauthservid = $myhostname;
dkim_key('example.com', "20260321", "$MYHOME/db/keys/example.com/20260321.pem");
@dkim_signature_options_bysender_maps = ({
"example.com" => { d => "example.com", a => 'rsa-sha256', c => 'relaxed/simple', ttl => 10*24*3600, s => 20260321 },
'.' => { d => 'example.com', a => 'rsa-sha256', c => 'relaxed/simple', ttl => 30*24*3600, s => 20260321 },
});
for (qw(Received)) { $signed_header_fields{lc $_} = 0 }
for (qw(Accept-Language Archived-At Auto-Submitted Content-Alternative
Content-Base Content-Class Content-Description Content-Disposition
Content-Duration Content-Features Content-Id Content-Language
Content-Location Content-MD5 Content-Transfer-Encoding In-Reply-To
List-Archive List-Help List-Id List-Owner List-Post List-Subscribe
List-Unsubscribe Message-Context Message-ID MIME-Version
Organisation Organization Original-Message-ID Pics-Label
Precedence References Reply-To Resent-Date Resent-From
Resent-Message-ID Resent-Sender Sensitivity Solicitation
User-Agent VBR-Info X-Mailer)) { $signed_header_fields{lc $_} = 1 }
for (qw(From Date Subject Content-Type)) { $signed_header_fields{lc $_} = 2 }
# =========================================================================
# SPAMASSASSIN CONFIGURATION
# =========================================================================
$remove_existing_spam_headers = 0;
$sa_mail_body_size_limit = 2048*1024;
@bypass_spam_checks_maps = (0);
$sa_tag_level_deflt = -999;
$sa_tag2_level_deflt = 6.2; # 5.0
$sa_kill_level_deflt = 6.9; # 6.5
$sa_dsn_cutoff_level = 10.0; # 8.0
$sa_crediblefrom_dsn_cutoff_level = 18.0; # 15.0
$penpals_threshold_high = $sa_kill_level_deflt;
$sa_spam_modifies_subj = 1;
$sa_spam_subject_tag = '[SPAM] ';
# Scores and rules...
@score_sender_maps = ({
'.' => [ # 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],
),
{ # 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,
'sender@example.net' => 3.0,
'.example.net' => 1.0,
},
],
});
# =========================================================================
# DISCLAIMERS & EXTENSIONS
# =========================================================================
$altermime = '/usr/local/bin/altermime';
@altermime_args_disclaimer = qw(--disclaimer=/usr/local/etc/postfix/disclaimer/_OPTION_.txt --disclaimer-html=/usr/local/etc/postfix/disclaimer/_OPTION_.txt --force-for-bad-html);
@disclaimer_options_bysender_maps = ({
'.' => 'default',
},);
$undecipherable_subject_tag = undef;
$recipient_delimiter = '+';
@addr_extension_virus_maps = ('virus');
@addr_extension_banned_maps = ('banned');
@addr_extension_spam_maps = ('spam');
@addr_extension_bad_header_maps = ('badh');
# =========================================================================
# FILE PARSING & DECODING
# =========================================================================
$MAXLEVELS = 20;
$MAXFILES = 5000;
$MIN_EXPANSION_QUOTA = 100*1024;
$MAX_EXPANSION_QUOTA = 500*1024*1024;
$bypass_decode_parts = 1;
$path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin';
$pax = 'pax';
@keep_decoded_original_maps = (new_RE(
qr'^MAIL$',
qr'^MAIL-UNDECIPHERABLE$',
qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i,
));
@decoders = (
['mail', \&do_mime_decode],
['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'],
['xz', \&do_uncompress, ['xzdec', 'xz -dc', 'unxz -c', 'xzcat'] ],
['lzma', \&do_uncompress, ['lzmadec', 'xz -dc --format=lzma', 'lzma -dc', 'unlzma -c', 'lzcat', 'lzmadec'] ],
['lrz', \&do_uncompress, ['lrzip -q -k -d -o -', 'lrzcat -q -k'] ],
['lzo', \&do_uncompress, 'lzop -d'],
['lzip', \&do_uncompress, ['lzip -d'] ],
['lz4', \&do_uncompress, ['lz4c -d'] ],
['rpm', \&do_uncompress, ['rpm2cpio.pl', 'rpm2cpio'] ],
[['cpio','tar'], \&do_pax_cpio, ['pax', 'gcpio', 'cpio'] ],
['deb', \&do_ar, 'ar'],
['rar', \&do_unrar, ['unrar', 'rar'] ],
['arj', \&do_unarj, ['unarj', 'arj'] ],
['arc', \&do_arc, ['nomarch', 'arc'] ],
['zoo', \&do_zoo, ['zoo', 'unzoo'] ],
['doc', \&do_ole, 'ripole'],
['cab', \&do_cabextract, 'cabextract'],
['tnef', \&do_tnef_ext, 'tnef'],
['tnef', \&do_tnef],
[['zip','kmz'], \&do_7zip, ['7za', '7zz', '7z'] ],
[['zip','kmz'], \&do_unzip],
['zst', \&do_uncompress, ['unzstd'] ],
[[qw(7z lzma xz)], \&do_7zip, ['7zr', '7za', '7zz', '7z'] ],
[[qw(bz2 Z cab gz tar zst)], \&do_7zip, ['7za', '7zz', '7z'] ],
[[qw(arj cpio deb iso jar lha rar rpm swf)], \&do_7zip, ['7zz', '7z'] ],
['exe', \&do_executable, ['unrar','rar'], 'lha', ['unarj','arj'] ],
);
# =========================================================================
# ANTIVIRUS & BANNED SCANNERS
# =========================================================================
@av_scanners = (
['ClamAV-clamdscan', 'clamdscan', "--fdpass --stdout --no-summary {}",
[0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
);
@av_scanners_backup = (
['ClamAV-clamscan', 'clamscan', "--stdout --no-summary -r --tempdir=$TEMPBASE {}",
[0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
);
@bypass_virus_checks_maps = (0);
$allowed_header_tests{'multiple'} = 0;
$allowed_header_tests{'missing'} = 0;
%banned_rules = (
'ALLOW_MS_OFFICE' => new_RE([qr'.\.(doc|docx|xls|xlsx|ppt|pptx)$'i => 0]),
'ALLOW_MS_WORD' => new_RE([qr'.\.(doc|docx)$'i => 0]),
'ALLOW_MS_EXCEL' => new_RE([qr'.\.(xls|xlsx)$'i => 0]),
'ALLOW_MS_PPT' => new_RE([qr'.\.(ppt|pptx)$'i => 0]),
'DEFAULT' => $banned_filename_re,
);
$banned_filename_re = new_RE(
qr'^\.(exe-ms|dll)$',
qr'.\.(pif|scr|msi|msp|iso|img)$'i,
qr'^application/x-msdownload$'i,
qr'^application/x-msdos-program$'i,
qr'^application/hta$'i,
qr'^application/x-ms-shortcut$'i,
qr'^(?!cid:).*\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll|js|jar)[.\s]*$'i,
qr'.\.(exe|vbs|pif|scr|cpl|js|jar|wsf|wsh)$'i,
);
@virus_name_to_spam_score_maps =(new_RE(
[ qr'^Structured\.(SSN|CreditCardNumber)\b' => 0.1 ],
[ qr'^(Heuristics\.)?Phishing\.' => 0.1 ],
[ qr'^(Email|HTML)\.Phishing\.(?!.*Sanesecurity)' => 0.1 ],
[ qr'^Sanesecurity\.(Malware|Badmacro|Foxhole|Rogue|Trojan)\.' => undef ],
[ qr'^Sanesecurity\.Foxhole\.Zip_exe' => 0.1 ], # F.P.
[ qr'^Sanesecurity\.MalwareHash\.' => undef ],
[ qr'^Sanesecurity.TestSig_' => undef ],
[ qr'^Sanesecurity\.' => 0.1 ],
[ qr'^Email\.Spam\.Bounce(\.[^., ]*)*\.Sanesecurity\.' => 0 ],
[ qr'^Email\.Spammail\b' => 0.1 ],
[ qr'^MSRBL-(Images|SPAM)\b' => 0.1 ],
[ qr'^VX\.Honeypot-SecuriteInfo\.com\.Joke' => 0.1 ],
[ qr'^VX\.not-virus_(Hoax|Joke)\..*-SecuriteInfo\.com(\.|\z)' => 0.1 ],
[ qr'^Email\.Spam.*-SecuriteInfo\.com(\.|\z)' => 0.1 ],
[ qr'^Safebrowsing\.' => 0.1 ],
[ qr'^winnow\.(Exploit|Trojan|malware)\.' => undef ],
[ qr'^winnow\.(botnet|compromised|trojan)' => undef ],
[ qr'^winnow\.(exe|ms|JS)\.' => undef ],
[ qr'^winnow\.(phish|spam)\.' => 3.0 ],
[ qr'^winnow\.' => 0.1 ],
[ qr'^INetMsg\.SpamDomain' => 0.1 ],
[ qr'^Doppelstern\.(Spam|Scam|Phishing|Junk|Lott|Loan)'=> 0.1 ],
[ qr'^Bofhland\.Malware\.' => undef ],
[ qr'^BofhlandMWFile' => undef ],
[ qr'^Bofhland\.Phishing\.' => 3.0 ],
[ qr'^Bofhland\.' => 0.1 ],
[ qr'^ScamNailer\.' => 0.1 ],
[ qr'^HTML/Bankish' => 0.1 ],
[ qr'^Porcupine\.(Malware|Trojan)\.' => undef ],
[ qr'^Porcupine\.(Junk|Spammer)\.' => 3.0 ],
[ qr'^Porcupine\.Phishing\.' => 3.0 ],
[ qr'^Porcupine\.' => 0.01 ],
[ qr'^PhishTank\.Phishing\.' => 3.0 ],
[ qr'^SecuriteInfo\.com\.Spam' => 3.0 ],
[ qr'(-)?SecuriteInfo\.com(\.|\z)' => undef ],
[ qr'^MBL_NA\.UNOFFICIAL' => 0.1 ],
[ qr'^MBL_' => undef ],
));
$banned_namepath_re = new_RE(
[qr'T=x-(msdownload|msdos-program|msmetafile)(,|\t)'xmi => 'DISCARD'],
[qr'T=(hta)(,|\t)'xmi => 'DISCARD'],
[qr'T=(9|386|LeChiffre|aaa|abc|aepl|ani|aru|atm|aut|b64|bat|bhx|bkd|blf|bll|bmw|boo|bps|bqf|breaking_bad|buk|bup|bxz|cc|ccc|ce0|ceo|cfxxe|chm|cih|cla|class|cmd|com|cpl|crinf|crjoker|crypt|cryptolocker|cryptowall|ctbl|cxq|cyw|dbd|delf|dev|dlb|dli|dll|dllx|dom|drv|dx|dxz|dyv|dyz|ecc|exe|exe-ms|exe1|exe_renamed|exx|ezt|ezz|fag|fjl|fnr|fuj|good|gzquar|hlp|hlw|hqx|hsq|hts|iva|iws|jar|js|kcd|keybtc@inbox_com|let|lik|lkh|lnk|locky|lok|lol!|lpaq5|magic|mfu|micro|mim|mjg|mjz|nls|oar|ocx|osa|ozd|pcx|pgm|php2|php3|pid|pif|plc|pr|pzdc|qit|qrn|r5a|rhk|rna|rsc_tmp|s7p|scr|shs|ska|smm|smtmp|sop|spam|ssy|swf|sys|tko|tps|tsa|tti|ttt|txs|upa|uu|uue|uzy|vb|vba|vbe|vbs|vbx|vexe|vxd|vzr|wlpginstall|ws|wsc|wsf|wsh|wss|xdu|xir|xlm|xlv|xnt|xnxx|xtbl|xxe|xxx|xyz|zix|zvz|zzz)(,|\t)'xmi => 'DISCARD'],
[qr'N=.*\.(9|386|LeChiffre|aaa|abc|aepl|ani|aru|atm|aut|b64|bat|bhx|bkd|blf|bll|bmw|boo|bps|bqf|breaking_bad|buk|bup|bxz|cc|ccc|ce0|ceo|cfxxe|chm|cih|cla|class|cmd|com|cpl|crinf|crjoker|crypt|cryptolocker|cryptowall|ctbl|cxq|cyw|dbd|delf|dev|dlb|dli|dll|dllx|dom|drv|dx|dxz|dyv|dyz|ecc|exe|exe-ms|exe1|exe_renamed|exx|ezt|ezz|fag|fjl|fnr|fuj|good|gzquar|hlp|hlw|hqx|hsq|hts|iva|iws|jar|js|kcd|keybtc@inbox_com|let|lik|lkh|lnk|locky|lok|lol!|lpaq5|magic|mfu|micro|mim|mjg|mjz|nls|oar|ocx|osa|ozd|pcx|pgm|php2|php3|pid|pif|plc|pr|pzdc|qit|qrn|r5a|rhk|rna|rsc_tmp|s7p|scr|shs|ska|smm|smtmp|sop|spam|ssy|swf|sys|tko|tps|tsa|tti|ttt|txs|upa|uu|uue|uzy|vb|vba|vbe|vbs|vbx|vexe|vxd|vzr|wlpginstall|ws|wsc|wsf|wsh|wss|xdu|xir|xlm|xlv|xnt|xnxx|xtbl|xxe|xxx|xyz|zix|zvz|zzz)$'xmi => 'DISCARD'],
);
# =========================================================================
# ADDITIONAL HEADERS
# =========================================================================
$allowed_added_header_fields{lc('X-SPAM*')} = 1;
# =========================================================================
# POLICY BANKS (Port Bindings)
# =========================================================================
$policy_bank{'MYNETS'} = {
originating => 1,
os_fingerprint_method => undef,
};
$interface_policy{'SOCK'} = 'AM.PDP-SOCK';
$policy_bank{'AM.PDP-SOCK'} = {
protocol => 'AM.PDP',
auth_required_release => 0,
};
# Port 10026 -> Outbound originating mail
$interface_policy{'10026'} = 'ORIGINATING';
$policy_bank{'ORIGINATING'} = {
originating => 1,
allow_disclaimers => 1,
enable_dkim_signing => 0,
warnbadhsender => 1,
# CRITICAL: Since Amavis is signing DKIM above, pass it to 10025 (reinjection).
# Sending to 10027 (OpenDKIM) causes double-signing or broken DKIM hashes.
forward_method => 'smtp:[127.0.0.1]:10025',
smtpd_discard_ehlo_keywords => ['8BITMIME'],
bypass_banned_checks_maps => [1],
terminate_dsn_on_notify_success => 0,
};
1; # ensure a defined return value
EOF
# 1. Get Default Interface
DEF_IF="$(route -n get -inet default | awk '/interface:/ {print $2}')"
# 2. Get IPv4 IP
IP4="$(ifconfig "$DEF_IF" inet | awk '/inet / && $2 !~ /^127\./ {print $2}' | head -n 1)"
[ -n "$IP4" ] && sed -e "s|__IPADDR4__|$IP4|g" -i '' /usr/local/etc/amavisd.conf
# 3. Get IPv6 IP
IP6="$(ifconfig "$DEF_IF" inet6 | awk '/inet6 / && $2 !~ /^fe80:/ && $2 !~ /^::1/ {print $2}' | head -n 1)"
[ -n "$IP6" ] && sed -e "s|__IPADDR6__|$IP6|g" -i '' /usr/local/etc/amavisd.conf
cat /var/db/passwords/postgresql_user_vscan | xargs -I % \
sed -e "s|__PASSWORD_VSCAN__|%|g" -i '' /usr/local/etc/amavisd.conf
mkdir -p /var/amavis/tmp
chown vscan:vscan /var/amavis/tmp
echo 'tmpfs /var/amavis/tmp tmpfs rw,noexec,nosuid,size=512m,mode=1750,uid=vscan,gid=vscan 0 0' >> /etc/fstab
Optionale DKIM-Signierung¶
Amavis kann selbst DKIM-Schlüssel erzeugen, öffentliche Schlüssel für DNS ausgeben und veröffentlichte Schlüssel testen. Upstream empfiehlt für DKIM-Signing mindestens 1024 Bit; 2048 Bit ist heute der saubere Standard. genrsa erzeugt den privaten Schlüssel, showkeys erzeugt den DNS-geeigneten Public-Key-Output, und testkeys prüft die Veröffentlichung gegen DNS. (Amavis)
mkdir -p /var/amavis/db/keys
chown vscan:vscan /var/amavis/db/keys
mkdir -p /var/amavis/db/keys/example.com
chown vscan:vscan /var/amavis/db/keys/example.com
su -m vscan -c 'amavisd genrsa /var/amavis/db/keys/example.com/20260321.pem 2048'
amavisd showkeys
Wenn der DNS-Record veröffentlicht ist, kann die DKIM-Konfiguration anschließend geprüft werden.
Optionale Policy-Banks¶
amavisd-milter kann optional mit -B arbeiten. Dann verwendet es den Milter-Makrowert {daemon_name} als Namen einer Amavis-Policy-Bank. Für authentifizierte Clients kann es zusätzlich Policy-Banks wie SMTP_AUTH oder SMTP_AUTH_<MECH> verwenden. Das ist nur dann sinnvoll, wenn du in amavisd-new bewusst mit Policy-Banks arbeitest. (Amavisd Milter)
Optional:
Konfiguration prüfen¶
Für den ersten Test empfiehlt die offizielle Installationsanleitung ausdrücklich einen Start im Debug-Modus. Das ist der saubere Weg, um Konfigurations- oder Rechteprobleme vor dem produktiven Daemon-Start zu sehen. (Amavis)
Vor dem ersten Start sollte geprüft werden, ob amavisd-new läuft, der AM.PDP-Socket erreichbar ist und Postfix den Milter-Socket korrekt eingetragen hat.
postconf smtpd_milters non_smtpd_milters
/usr/local/sbin/amavisd debug
service amavisd status
service amavisd-milter start
sockstat -4 -6 -l | egrep 'amavisd|10024|10025|milter|amavis'
Einen eigenen configtest-Subcommand bringt amavisd-milter nicht mit. Die saubere Funktionsprüfung besteht hier darin, dass amavisd-new bereits läuft, amavisd-milter seinen Milter-Socket anlegt und Postfix auf diesen Socket zeigt. Die Dokumentation von amavisd-milter unterscheidet dabei explizit zwischen dem Milter-Socket (-s) und dem AM.PDP-Socket (-S). (FreeBSD Manual Pages)
Datenbanken¶
Amavis trennt SQL-seitig zwischen Lookups und Storage.
@lookup_sql_dsn ist für die read-only Lookup-Datenbank gedacht, @storage_sql_dsn für Reporting/Quarantäne mit Schreibzugriff. Upstream dokumentiert dafür auf PostgreSQL typischerweise mail_prefs als Lookup-Datenbank und mail_log als Storage-Datenbank. Für Lookups genügt SELECT; für Storage werden SELECT, INSERT und UPDATE benötigt. (GitHub)
PostgreSQL-Benutzer vscan anlegen¶
# Passwort für PostgreSQL-Benutzer "vscan" erzeugen und
# in /var/db/passwords/postgresql_user_vscan speichern
install -b -m 0600 -o postgres -g postgres /dev/null /var/db/passwords/postgresql_user_vscan
openssl rand -hex 64 | openssl passwd -5 -stdin | tr -cd '[[:print:]]' | \
cut -c 2-17 | tee /var/db/passwords/postgresql_user_vscan
# PostgreSQL-Benutzer "vscan" mit Passwort anlegen
su -l postgres -c "psql <<'EOF'
\set content `cat /var/db/passwords/postgresql_user_vscan`
DROP ROLE IF EXISTS \"vscan\";
CREATE ROLE \"vscan\";
ALTER ROLE \"vscan\" WITH NOSUPERUSER INHERIT CREATEROLE CREATEDB LOGIN NOREPLICATION NOBYPASSRLS PASSWORD :'content';
\unset content
EOF"
Das Passwort bitte sicher notieren, du wirst es bei jeder externen Verbindung (TCP) benötigen.
PostgreSQL-Datenbank mail_prefs für vscan anlegen¶
Die Lookup-Datenbank enthält die Tabellen für Richtlinien, Benutzer und White-/Blacklist-Zuordnungen. Das ist der read-only Teil des von Amavis dokumentierten SQL-Schemas. (GitHub)
su -l postgres -c "psql <<'EOF'
DROP DATABASE IF EXISTS \"mail_prefs\";
CREATE DATABASE \"mail_prefs\";
ALTER DATABASE \"mail_prefs\" OWNER TO \"vscan\";
EOF"
su -l postgres -c "psql <<'EOF'
\connect "mail_prefs"
CREATE TABLE \"public\".\"mailaddr\" (
\"id\" integer NOT NULL,
\"priority\" integer DEFAULT 9 NOT NULL,
\"email\" \"bytea\" NOT NULL
);
ALTER TABLE \"public\".\"mailaddr\" OWNER TO \"vscan\";
CREATE SEQUENCE \"public\".\"mailaddr_id_seq\"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE \"public\".\"mailaddr_id_seq\" OWNER TO \"vscan\";
ALTER SEQUENCE \"public\".\"mailaddr_id_seq\" OWNED BY \"public\".\"mailaddr\".\"id\";
CREATE TABLE \"public\".\"policy\" (
\"id\" integer NOT NULL,
\"policy_name\" character varying(32),
\"virus_lover\" character(1) DEFAULT NULL::\"bpchar\",
\"spam_lover\" character(1) DEFAULT NULL::\"bpchar\",
\"unchecked_lover\" character(1) DEFAULT NULL::\"bpchar\",
\"banned_files_lover\" character(1) DEFAULT NULL::\"bpchar\",
\"bad_header_lover\" character(1) DEFAULT NULL::\"bpchar\",
\"bypass_virus_checks\" character(1) DEFAULT NULL::\"bpchar\",
\"bypass_spam_checks\" character(1) DEFAULT NULL::\"bpchar\",
\"bypass_banned_checks\" character(1) DEFAULT NULL::\"bpchar\",
\"bypass_header_checks\" character(1) DEFAULT NULL::\"bpchar\",
\"virus_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"spam_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"banned_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"unchecked_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"bad_header_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"clean_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"archive_quarantine_to\" character varying(64) DEFAULT NULL::character varying,
\"spam_tag_level\" real,
\"spam_tag2_level\" real,
\"spam_tag3_level\" real,
\"spam_kill_level\" real,
\"spam_dsn_cutoff_level\" real,
\"spam_quarantine_cutoff_level\" real,
\"addr_extension_virus\" character varying(64) DEFAULT NULL::character varying,
\"addr_extension_spam\" character varying(64) DEFAULT NULL::character varying,
\"addr_extension_banned\" character varying(64) DEFAULT NULL::character varying,
\"addr_extension_bad_header\" character varying(64) DEFAULT NULL::character varying,
\"warnvirusrecip\" character(1) DEFAULT NULL::\"bpchar\",
\"warnbannedrecip\" character(1) DEFAULT NULL::\"bpchar\",
\"warnbadhrecip\" character(1) DEFAULT NULL::\"bpchar\",
\"newvirus_admin\" character varying(64) DEFAULT NULL::character varying,
\"virus_admin\" character varying(64) DEFAULT NULL::character varying,
\"banned_admin\" character varying(64) DEFAULT NULL::character varying,
\"bad_header_admin\" character varying(64) DEFAULT NULL::character varying,
\"spam_admin\" character varying(64) DEFAULT NULL::character varying,
\"spam_subject_tag\" character varying(64) DEFAULT NULL::character varying,
\"spam_subject_tag2\" character varying(64) DEFAULT NULL::character varying,
\"spam_subject_tag3\" character varying(64) DEFAULT NULL::character varying,
\"message_size_limit\" integer,
\"banned_rulenames\" character varying(64) DEFAULT NULL::character varying,
\"disclaimer_options\" character varying(64) DEFAULT NULL::character varying,
\"forward_method\" character varying(64) DEFAULT NULL::character varying,
\"sa_userconf\" character varying(64) DEFAULT NULL::character varying,
\"sa_username\" character varying(64) DEFAULT NULL::character varying
);
ALTER TABLE \"public\".\"policy\" OWNER TO \"vscan\";
CREATE SEQUENCE \"public\".\"policy_id_seq\"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE \"public\".\"policy_id_seq\" OWNER TO \"vscan\";
ALTER SEQUENCE \"public\".\"policy_id_seq\" OWNED BY \"public\".\"policy\".\"id\";
CREATE TABLE \"public\".\"users\" (
\"id\" integer NOT NULL,
\"priority\" integer DEFAULT 7 NOT NULL,
\"policy_id\" integer DEFAULT 1 NOT NULL,
\"email\" \"bytea\" NOT NULL,
\"fullname\" character varying(255) DEFAULT NULL::character varying,
CONSTRAINT \"users_policy_id_check\" CHECK ((\"policy_id\" >= 0))
);
ALTER TABLE \"public\".\"users\" OWNER TO \"vscan\";
CREATE SEQUENCE \"public\".\"users_id_seq\"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE \"public\".\"users_id_seq\" OWNER TO \"vscan\";
ALTER SEQUENCE \"public\".\"users_id_seq\" OWNED BY \"public\".\"users\".\"id\";
CREATE TABLE \"public\".\"wblist\" (
\"rid\" integer NOT NULL,
\"sid\" integer NOT NULL,
\"wb\" character varying(10) NOT NULL,
CONSTRAINT \"wblist_rid_check\" CHECK ((\"rid\" >= 0)),
CONSTRAINT \"wblist_sid_check\" CHECK ((\"sid\" >= 0))
);
ALTER TABLE \"public\".\"wblist\" OWNER TO \"vscan\";
ALTER TABLE ONLY \"public\".\"mailaddr\" ALTER COLUMN \"id\" SET DEFAULT \"nextval\"('\"public\".\"mailaddr_id_seq\"'::\"regclass\");
ALTER TABLE ONLY \"public\".\"policy\" ALTER COLUMN \"id\" SET DEFAULT \"nextval\"('\"public\".\"policy_id_seq\"'::\"regclass\");
ALTER TABLE ONLY \"public\".\"users\" ALTER COLUMN \"id\" SET DEFAULT \"nextval\"('\"public\".\"users_id_seq\"'::\"regclass\");
SELECT pg_catalog.setval('\"public\".\"mailaddr_id_seq\"', 1, false);
SELECT pg_catalog.setval('\"public\".\"policy_id_seq\"', 1, false);
SELECT pg_catalog.setval('\"public\".\"users_id_seq\"', 1, false);
ALTER TABLE ONLY \"public\".\"mailaddr\"
ADD CONSTRAINT \"mailaddr_email_key\" UNIQUE (\"email\");
ALTER TABLE ONLY \"public\".\"mailaddr\"
ADD CONSTRAINT \"mailaddr_pkey\" PRIMARY KEY (\"id\");
ALTER TABLE ONLY \"public\".\"policy\"
ADD CONSTRAINT \"policy_pkey\" PRIMARY KEY (\"id\");
ALTER TABLE ONLY \"public\".\"users\"
ADD CONSTRAINT \"users_email_key\" UNIQUE (\"email\");
ALTER TABLE ONLY \"public\".\"users\"
ADD CONSTRAINT \"users_pkey\" PRIMARY KEY (\"id\");
ALTER TABLE ONLY \"public\".\"wblist\"
ADD CONSTRAINT \"wblist_pkey\" PRIMARY KEY (\"rid\", \"sid\");
ALTER TABLE ONLY \"public\".\"users\"
ADD CONSTRAINT \"users_policy_id_fkey\" FOREIGN KEY (\"policy_id\") REFERENCES \"public\".\"policy\"(\"id\");
ALTER TABLE ONLY \"public\".\"wblist\"
ADD CONSTRAINT \"wblist_rid_fkey\" FOREIGN KEY (\"rid\") REFERENCES \"public\".\"users\"(\"id\");
ALTER TABLE ONLY \"public\".\"wblist\"
ADD CONSTRAINT \"wblist_sid_fkey\" FOREIGN KEY (\"sid\") REFERENCES \"public\".\"mailaddr\"(\"id\");
EOF"
Verbindung als vscan testen¶
PostgreSQL-Datenbank mail_log für vscan anlegen¶
Die Storage-Datenbank ist der Schreibteil des Amavis-Schemas und wird für Logging, Reporting und optional Quarantäne verwendet. Upstream weist ausdrücklich darauf hin, dass dieser Teil Transaktionen und Schreibrechte benötigt. (GitHub)
su -l postgres -c "psql <<'EOF'
DROP DATABASE IF EXISTS \"mail_log\";
CREATE DATABASE \"mail_log\";
ALTER DATABASE \"mail_log\" OWNER TO \"vscan\";
EOF"
su -l postgres -c "psql <<'EOF'
\connect "mail_log"
CREATE TABLE \"public\".\"maddr\" (
\"id\" integer NOT NULL,
\"partition_tag\" integer DEFAULT 0,
\"email\" \"bytea\" NOT NULL,
\"domain\" character varying(255) NOT NULL
);
ALTER TABLE \"public\".\"maddr\" OWNER TO \"vscan\";
CREATE SEQUENCE \"public\".\"maddr_id_seq\"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE \"public\".\"maddr_id_seq\" OWNER TO \"vscan\";
ALTER SEQUENCE \"public\".\"maddr_id_seq\" OWNED BY \"public\".\"maddr\".\"id\";
CREATE TABLE \"public\".\"msgrcpt\" (
\"partition_tag\" integer DEFAULT 0 NOT NULL,
\"mail_id\" \"bytea\" NOT NULL,
\"rseqnum\" integer DEFAULT 0 NOT NULL,
\"rid\" integer NOT NULL,
\"is_local\" character(1) DEFAULT ' '::\"bpchar\" NOT NULL,
\"content\" character(1) DEFAULT ' '::\"bpchar\" NOT NULL,
\"ds\" character(1) NOT NULL,
\"rs\" character(1) NOT NULL,
\"bl\" character(1) DEFAULT ' '::\"bpchar\",
\"wl\" character(1) DEFAULT ' '::\"bpchar\",
\"bspam_level\" real,
\"smtp_resp\" character varying(255) DEFAULT ''::character varying
);
ALTER TABLE \"public\".\"msgrcpt\" OWNER TO \"vscan\";
CREATE TABLE \"public\".\"msgs\" (
\"partition_tag\" integer DEFAULT 0 NOT NULL,
\"mail_id\" \"bytea\" NOT NULL,
\"secret_id\" \"bytea\" DEFAULT '\x'::\"bytea\",
\"am_id\" character varying(20) NOT NULL,
\"time_num\" integer NOT NULL,
\"time_iso\" timestamp with time zone NOT NULL,
\"sid\" integer NOT NULL,
\"policy\" character varying(255) DEFAULT ''::character varying,
\"client_addr\" character varying(255) DEFAULT ''::character varying,
\"size\" integer NOT NULL,
\"originating\" character(1) DEFAULT ' '::\"bpchar\" NOT NULL,
\"content\" character(1),
\"quar_type\" character(1),
\"quar_loc\" character varying(255) DEFAULT ''::character varying,
\"dsn_sent\" character(1),
\"spam_level\" real,
\"message_id\" character varying(255) DEFAULT ''::character varying,
\"from_addr\" character varying(255) DEFAULT ''::character varying,
\"subject\" character varying(255) DEFAULT ''::character varying,
\"host\" character varying(255) NOT NULL,
CONSTRAINT \"msgs_sid_check\" CHECK ((\"sid\" >= 0)),
CONSTRAINT \"msgs_size_check\" CHECK ((\"size\" >= 0)),
CONSTRAINT \"msgs_time_num_check\" CHECK ((\"time_num\" >= 0))
);
ALTER TABLE \"public\".\"msgs\" OWNER TO \"vscan\";
CREATE TABLE \"public\".\"quarantine\" (
\"partition_tag\" integer DEFAULT 0 NOT NULL,
\"mail_id\" \"bytea\" NOT NULL,
\"chunk_ind\" integer NOT NULL,
\"mail_text\" \"bytea\" NOT NULL,
CONSTRAINT \"quarantine_chunk_ind_check\" CHECK ((\"chunk_ind\" >= 0))
);
ALTER TABLE \"public\".\"quarantine\" OWNER TO \"vscan\";
ALTER TABLE ONLY \"public\".\"maddr\" ALTER COLUMN \"id\" SET DEFAULT \"nextval\"('\"public\".\"maddr_id_seq\"'::\"regclass\");
SELECT pg_catalog.setval('\"public\".\"maddr_id_seq\"', 283, true);
ALTER TABLE ONLY \"public\".\"maddr\"
ADD CONSTRAINT \"maddr_pkey\" PRIMARY KEY (\"id\");
ALTER TABLE ONLY \"public\".\"msgrcpt\"
ADD CONSTRAINT \"msgrcpt_partition_mail_rseq\" PRIMARY KEY (\"partition_tag\", \"mail_id\", \"rseqnum\");
ALTER TABLE ONLY \"public\".\"msgs\"
ADD CONSTRAINT \"msgs_partition_mail\" PRIMARY KEY (\"partition_tag\", \"mail_id\");
ALTER TABLE ONLY \"public\".\"maddr\"
ADD CONSTRAINT \"part_email\" UNIQUE (\"partition_tag\", \"email\");
ALTER TABLE ONLY \"public\".\"quarantine\"
ADD CONSTRAINT \"quarantine_pkey\" PRIMARY KEY (\"partition_tag\", \"mail_id\", \"chunk_ind\");
CREATE INDEX \"msgrcpt_idx_mail_id\" ON \"public\".\"msgrcpt\" USING \"btree\" (\"mail_id\");
CREATE INDEX \"msgrcpt_idx_rid\" ON \"public\".\"msgrcpt\" USING \"btree\" (\"rid\");
CREATE INDEX \"msgs_idx_mess_id\" ON \"public\".\"msgs\" USING \"btree\" (\"message_id\");
CREATE INDEX \"msgs_idx_sid\" ON \"public\".\"msgs\" USING \"btree\" (\"sid\");
CREATE INDEX \"msgs_idx_time_iso\" ON \"public\".\"msgs\" USING \"btree\" (\"time_iso\");
CREATE INDEX \"msgs_idx_time_num\" ON \"public\".\"msgs\" USING \"btree\" (\"time_num\");
EOF"
Verbindung als vscan testen¶
Zusatzsoftware¶
Optional: p0f-Analyzer¶
Der aktuelle Port liefert ein separates rc.d-Skript amavis_p0fanalyzer mit. Dieses ist optional und nur sinnvoll, wenn dein Port auch wirklich mit P0F gebaut wurde. Das rc.d-Skript verwendet die Variablen amavis_p0fanalyzer_enable, amavis_p0fanalyzer_p0f_filter und optional amavis_p0fanalyzer_flags. (FreeBSD Git)
Optional: Amavis-Milter¶
Nicht Bestandteil dieses HowTos.
Für einen Milter-basierten Betrieb gibt es heute auf FreeBSD den separaten Port security/amavisd-milter. Das aktuelle security/amavisd-new liefert dafür kein eigenes rc.d-Skript mehr mit. (FreshPorts)
Aufräumen¶
Überflüssige oder temporäre Verzeichnisse und Dateien entsorgen.
Zusatzsoftware Installation¶
Nicht erforderlich.
Zusatzsoftware Konfiguration¶
Nicht erforderlich.
Abschluss¶
Wichtig ist die Reihenfolge: zuerst amavisd-new, danach amavisd-milter, anschließend Postfix neu laden.
Für spätere Änderungen:
Optional bei aktiviertem p0f-Analyzer:
service amavisd start
service amavis_p0fanalyzer start
service amavisd-milter start
service postfix reload
Für spätere Änderungen:
service amavisd restart
service amavis_p0fanalyzer restart
service amavisd-milter restart
service postfix reload
Referenzen¶
- FreshPorts:
security/amavisd-new— Portstand, Optionen, Sample-Konfigurationen, pkg-message. (FreshPorts) - FreshPorts:
security/amavisd-milter - FreeBSD Ports Tree: rc.d-Skripte
amavisd,amavis_p0fanalyzer,amavisd_snmp. (FreeBSD Git) - FreeBSD Ports rc-Skript:
security/amavisd-milter/files/amavisd-milter.in - FreeBSD Manpage:
amavisd-milter(8) - Amavis Dokumentation: Allgemeine Einführung und Postfix-Integration. (IJS)
- Amavis SQL-Dokumentation:
README.sqlundREADME.sql-pgfür@lookup_sql_dsn,@storage_sql_dsn, Rechte und PostgreSQL-Schema. (GitHub) - Amavis DKIM-Dokumentation:
genrsa,showkeys,testkeys. (Amavis) - Amavis INSTALL: erster Start mit
debug. (Amavis) - Postfix:
MILTER_README