Kampf gegen Spam mit Postfix und SpamassassinTechnischer Stand: Jahr 2005. Dieser Artikel wird nicht mehr aktualisiert. |
Fighting Spam with Postfix and SpamassassinTechnical status: year 2005. This article will not be updated. |
Neuigkeiten |
News |
|
Ein Jahr Statistik über eingegangenen Spam hat einige Erkenntnisse zutage gefördert. |
One year of spam statistics discovered some insight. |
Inhalt |
Contents |
|
Version: September 2004. Änderungen gegenüber den Vorversionen (Juli/August 2004):
|
Revision: September 2004. Changes since last version (July/August 2004):
|
Einleitung |
Preface |
|
Die Flut unerwünschter elektronischer Werbung (Spam, auch UCE = Unsolicited Commercial Email genannt) hat gigantische Ausmaße angenommen. Mein privater Posteingang (einschließlich einiger externer Postfächer) mit Adressen, die schon viele Jahre aktiv sind, war vor einigen Monaten auf mehrere hundert Nachrichten täglich angewachsen, wovon mehr als 95% Spam waren. Aber es gibt Netzbürger, die über tausende Spamnachrichten täglich klagen. Aber es geht noch schlimmer. Der Ausschnitt aus dem Maillog zeigt die zurückgewiesenen Nachrichten einer einzigen Stunde. Das Netz der Spammer hat meine Domain barnim.net zum Ziel seiner Wörterbuchattacken erkoren. Zwischen 3.000 und 5.000 Sendeversuche an nicht existierende Adressen registriere ich täglich. Und auffällig sind die fast zeitgleichen Anfragen an denselben Postfachnamen von verschiedenen Absendern. Das bedeutet: Hier ist eine Heerschar gekaperter PC in aller Welt mit sogenannten Spambots infiziert, und die Besitzer dieser Zombie-PC wissen nichts davon. |
A tremendous amount of unsolicited commercial email (UCE, spam) is flooding mailboxes. Because I use a number of addresses of which some are now active for years, a few months ago my private email entry hat grown to several hundred messages a day. More than 95% of those were spam. But some netizens complain about thousands of daily spam messages. But even worse: The mail log below shows refused messages from some randomly selected hour. The world wide network of spammers selected my domain barnim.net as a target for brute force dictionary attacks. The server logs between 3,000 and 5,000 attempts per day of sending to nonexisting adresses. You will notice coinciding requests for the same address from different servers. A horde of captured PC throughout the world is infected with so-called spambots and their unsuspecting owners are not even aware. |
Jul 12 20:01:40 reject: RCPT from bzq-82-81-192-6.cablep.bezeqint.net[82.81.192.6]: 550 <sdougal@barnim.net>: Recipient address rejected: Access denied Jul 12 20:02:19 reject: RCPT from smtp07.auna.com[62.81.186.17]: 450 <0002011402@mcimail.com>: Sender address rejected: Domain not found Jul 12 20:04:06 reject: RCPT from 24.213.57.147.static.up.mi.chartermi.net[24.213.57.147]: 550 <richard.akre@barnim.net>: Recipient address rejected: Access denied Jul 12 20:04:32 reject: RCPT from unknown[164.125.148.168]: 550 <mkrofchi@barnim.net>: Recipient address rejected: Access denied Jul 12 20:05:01 reject: RCPT from adsl-68-78-135-65.dsl.emhril.ameritech.net[68.78.135.65]: 550 <mkrofchi@barnim.net>: Recipient address rejected: Access denied Jul 12 20:05:53 reject: RCPT from c-24-30-101-39.we.client2.attbi.com[24.30.101.39]: 550 <rajagopalan_v@barnim.net>: Recipient address rejected: Access denied Jul 12 20:08:44 reject: RCPT from rwcrmxc20.comcast.net[204.127.198.46]: 554 <notify@barnim.net>: Recipient address rejected: Access denied Jul 12 20:09:19 reject: RCPT from cdm-66-76-192-127.mthm.cox-internet.com[66.76.192.127]: 550 <rrood@barnim.net>: Recipient address rejected: Access denied Jul 12 20:12:14 reject: RCPT from cliente-217216140195.uBRala01.supercable.es[217.216.140.195]: 550 <simonwilkinson@barnim.net>: Recipient address rejected: Access denied Jul 12 20:14:26 reject: RCPT from 24.229.166.105.res-cmts.mtp.ptd.net[24.229.166.105]: 550 <richard.bomber.lancaster@barnim.net>: Recipient address rejected: Access denied Jul 12 20:27:28 reject: RCPT from c-65-34-173-182.se.client2.attbi.com[65.34.173.182]: 550 <raines@barnim.net>: Recipient address rejected: Access denied Jul 12 20:40:54 reject: RCPT from 12-217-230-73.client.mchsi.com[12.217.230.73]: 550 <rainbowkevin@barnim.net>: Recipient address rejected: Access denied Jul 12 20:41:04 reject: RCPT from pool-151-202-111-175.ny325.east.verizon.net[151.202.111.175]: 550 <ntziorkas@barnim.net>: Recipient address rejected: Access denied Jul 12 20:41:32 reject: RCPT from 6.140.171.66.subscriber.vzavenue.net[66.171.140.6]: 550 <rainbowkevin@barnim.net>: Recipient address rejected: Access denied Jul 12 20:42:13 reject: RCPT from chello213047097076.5.12.vie.surfer.at[213.47.97.76]: 550 <ntziorkas@barnim.net>: Recipient address rejected: Access denied Jul 12 20:42:24 reject: RCPT from user-0ce2h7g.cable.mindspring.com[24.225.68.240]: 550 <ntziorkas@barnim.net>: Recipient address rejected: Access denied Jul 12 20:42:39 reject: RCPT from c-67-173-175-195.client.comcast.net[67.173.175.195]: 550 <ntziorkas@barnim.net>: Recipient address rejected: Access denied Jul 12 20:43:15 reject: RCPT from unknown[211.211.249.193]: 550 <nw-b5request@barnim.net>: Recipient address rejected: Access denied Jul 12 20:44:11 reject: RCPT from dsl-082-083-068-054.arcor-ip.net[82.83.68.54]: 550 <nw-b5request@barnim.net>: Recipient address rejected: Access denied Jul 12 20:45:39 reject: RCPT from 68-189-112-8.ca.charter.com[68.189.112.8]: 550 <nw-b5request@barnim.net>: Recipient address rejected: Access denied Jul 12 20:45:46 reject: RCPT from pcp660796pcs.prshng01.fl.comcast.net[68.35.245.48]: 550 <nw-b5request@barnim.net>: Recipient address rejected: Access denied Jul 12 20:45:55 reject: RCPT from c-24-14-225-53.client.comcast.net[24.14.225.53]: 550 <oerbeck@barnim.net>: Recipient address rejected: Access denied Jul 12 20:46:08 reject: RCPT from unknown[218.51.48.248]: 550 <oerbeck@barnim.net>: Recipient address rejected: Access denied Jul 12 20:46:48 reject: RCPT from wbar10.dal1-4-13-088-201.dsl-verizon.net[4.13.88.201]: 550 <oerbeck@barnim.net>: Recipient address rejected: Access denied Jul 12 20:47:48 reject: RCPT from 12-220-223-24.client.insightBB.com[12.220.223.24]: 550 <ollieweb@barnim.net>: Recipient address rejected: Access denied Jul 12 20:48:02 reject: RCPT from pcp08760834pcs.mtlrel01.nj.comcast.net[68.36.30.253]: 550 <ollieweb@barnim.net>: Recipient address rejected: Access denied Jul 12 20:48:13 reject: RCPT from S010600055d80a442.wp.shawcable.net[24.79.194.112]: 550 <ollieweb@barnim.net>: Recipient address rejected: Access denied Jul 12 20:49:35 reject: RCPT from unknown[218.22.149.229]: 550 <ollieweb@barnim.net>: Recipient address rejected: Access denied Jul 12 20:50:08 reject: RCPT from c-67-162-175-186.client.comcast.net[67.162.175.186]: 550 <popeyes@barnim.net>: Recipient address rejected: Access denied Jul 12 20:50:54 reject: RCPT from 212.199.144.202.forward.012.net.il[212.199.144.202]: 550 <popeyes@barnim.net>: Recipient address rejected: Access denied Jul 12 20:50:58 reject: RCPT from cpe-66-189-103-225.ma.charter.com[66.189.103.225]: 550 <ordersusa@barnim.net>: Recipient address rejected: Access denied Jul 12 20:51:06 reject: RCPT from d198-166-219-27.abhsia.telus.net[198.166.219.27]: 550 <popeyes@barnim.net>: Recipient address rejected: Access denied Jul 12 20:51:08 reject: RCPT from modemcable123.106-203-24.mc.videotron.ca[24.203.106.123]: 550 <ordersusa@barnim.net>: Recipient address rejected: Access denied Jul 12 20:51:29 reject: RCPT from adsl-69-104-81-136.dsl.pltn13.pacbell.net[69.104.81.136]: 550 <popeyes@barnim.net>: Recipient address rejected: Access denied Jul 12 20:51:37 reject: RCPT from adsl-67-37-184-18.dsl.chcgil.ameritech.net[67.37.184.18]: 550 <ordersusa@barnim.net>: Recipient address rejected: Access denied Jul 12 20:51:38 reject: RCPT from user-0c6sdlc.cable.mindspring.com[24.110.54.172]: 550 <popeyes@barnim.net>: Recipient address rejected: Access denied Jul 12 20:53:11 reject: RCPT from unknown[67.176.126.139]: 550 <orsi_vale@barnim.net>: Recipient address rejected: Access denied Jul 12 20:53:14 reject: RCPT from c-67-172-12-5.client.comcast.net[67.172.12.5]: 550 <pphp@barnim.net>: Recipient address rejected: Access denied Jul 12 20:53:29 reject: RCPT from 82-35-8-42.cable.ubr02.hari.blueyonder.co.uk[82.35.8.42]: 554 <82-35-8-42.cable.ubr02.hari.blueyonder.co.uk>: Helo command rejected: Access denied Jul 12 20:53:47 reject: RCPT from CPE-69-76-180-63.kc.rr.com[69.76.180.63]: 550 <sports4life8@barnim.net>: Recipient address rejected: Access denied Jul 12 20:53:49 reject: RCPT from ool-18bea0de.dyn.optonline.net[24.190.160.222]: 550 <orsi_vale@barnim.net>: Recipient address rejected: Access denied Jul 12 20:53:49 reject: RCPT from 12-220-223-24.client.insightBB.com[12.220.223.24]: 550 <pphp@barnim.net>: Recipient address rejected: Access denied Jul 12 20:54:24 reject: RCPT from adsl-68-72-126-25.dsl.chcgil.ameritech.net[68.72.126.25]: 550 <pphp@barnim.net>: Recipient address rejected: Access denied Jul 12 20:55:26 reject: RCPT from h004005a622fb.ne.client2.attbi.com[66.30.203.54]: 550 <outslay@barnim.net>: Recipient address rejected: Access denied Jul 12 20:55:54 reject: RCPT from c-66-229-148-167.we.client2.attbi.com[66.229.148.167]: 550 <outslay@barnim.net>: Recipient address rejected: Access denied Jul 12 20:56:07 reject: RCPT from c-24-126-159-19.we.client2.attbi.com[24.126.159.19]: 550 <outslay@barnim.net>: Recipient address rejected: Access denied Jul 12 20:56:18 reject: RCPT from unknown[61.105.79.105]: 550 <outslay@barnim.net>: Recipient address rejected: Access denied Jul 12 20:56:22 reject: RCPT from adsl-69-105-54-215.dsl.irvnca.pacbell.net[69.105.54.215]: 550 <prettyboy3@barnim.net>: Recipient address rejected: Access denied Jul 12 20:56:51 reject: RCPT from adsl-68-92-87-113.dsl.stlsmo.swbell.net[68.92.87.113]: 550 <outslay@barnim.net>: Recipient address rejected: Access denied Jul 12 20:57:36 reject: RCPT from dsl-aur5-b0b.dial.inet.fi[80.221.145.11]: 550 <smmaclean@barnim.net>: Recipient address rejected: Access denied Jul 12 20:57:48 reject: RCPT from va-spotsy-cuda2-c4b-179.frbgva.adelphia.net[68.70.169.179]: 550 <prettyboy3@barnim.net>: Recipient address rejected: Access denied Jul 12 20:57:50 reject: RCPT from lns-th2-7-82-64-99-134.adsl.proxad.net[82.64.99.134]: 550 <p0_ga@barnim.net>: Recipient address rejected: Access denied Jul 12 20:58:31 reject: RCPT from modemcable123.106-203-24.mc.videotron.ca[24.203.106.123]: 550 <p0_ga@barnim.net>: Recipient address rejected: Access denied Jul 12 20:59:26 reject: RCPT from M1927P029.adsl.highway.telekom.at[80.121.112.221]: 550 <prettyboy3@barnim.net>: Recipient address rejected: Access denied Jul 12 20:59:59 reject: RCPT from unknown[212.179.163.65]: 504 <OEMCOMPUTER>: Helo command rejected: need fully-qualified hostname
Anforderungen |
Requirements |
|
Meine Anforderungen an ein Mailsystem sind:
Die Lösung, die ich vorstelle, basiert auf dem Betrieb eines
eigenen |
These are my basic requirements on a mail server:
The solution presented here is based on an own dedicated |
Voraussetzungen |
Prerequisites |
Softwareinstallation |
Software Installation |
|
Der Mailserver wird auf einem Linux-System installiert, ich empfehle
In Ergänzung zu den sehr komfortablen Funktionen von Postfix werden wir einige Shellscripte einführen, die eine Spambehandlung näher an den individuellen Bedürfnissen jedes einzelnen Nutzers erlauben. Durch seinen modularen Aufbau ermöglicht Postfix hervorragend solche Ergänzungen. Einen Vergleich zwischen Postfix und Qmail kann ich nicht ziehen. Ich habe mich an Postfix gewöhnt und bin mit seinen Möglichkeiten zufrieden. Die Sicherheit scheint gut zu sein. Einige Denial-of-Service Attacken sind in 2003 bekannt geworden; inzwischen liegen neue Freigaben der Software vor. Ich gehe hier von Version 2.1 aus. Spamassassin liefert sehr gute Ergebnisse und wird ständig weiterentwickelt. Clam Antivirus ist ein freier serverbasierter Virenscanner. Die Software ist noch sehr jung, und die Aktualisierung der Virensignaturen hält (noch) nicht Schritt mit dem raschen Generationswechsel heutiger Viren und Würmer. C't Ausgabe 8/2004 liefert hierzu eine Auswertung. Clam AV kann derzeit nur als Ergänzung einer clientbasierten Lösung gesehen werden, sofern Sie nicht das Geld für einen kommerziellen serverbasierten Scanner ausgeben wollen. |
The mail server will be installed on a Linux
system, I recommend
We will add a number of own shell scripts that complement Postfix and allow to process spam very close to the needs of every user. The modular design of Postfix facilitates such extensions rather well. I will not compare Postfix with Qmail or other products. I got used to Postfix and am quite satisfied with the provided functionality. Security seems to be good. A few DoS attacks were published in 2003 but new software releases are now available. This description requires Postfix release 2.1 or newer. Spamassassin provides very good results and is continuously improved. Clam Antivirus is a free server based virus scanner. This software is quite fresh and not always reliable, since virus signatures are not updated that frequently as those of commercial products. Refer to C't issue 8/2004 for a detailed evaluation. Thus, Clam AV in its current state should be complemented by a client based solution. |
Schlüsselgenerierung |
Key Generation |
|
Bevor es mit dem Mailserver losgeht, brauchen Sie einige Schlüssel für die Sicherheit von Postfix und Courier. Die SSL-/TLS-Schlüssel zur Absicherung des Email-Verkehrs liegen je nach Linux-Distribution unter /etc/ssl oder unter /usr/share/ssl. Wir gehen hier vom ersten Fall aus; andernfalls sind einige der nachfolgenden Konfigurationsdateien sinngemäß anzupassen. Auf eine detaillierte Erläuterung der einzelnen Kommandos verzichte ich hier. Unter http://httpd.apache.org/docs-2.0/ssl/ssl_faq.html gibt es eine gute Erläuterung. Einige Anmerkungen stehen als Kommentar oder echo-Anweisung im folgenden Script. Dieses Script erzeugt eine Certification Authority (CA) und Zertifikate
für Webserver, SMTP-Server und POP3-Server. Außerdem werden
die .p12- und .crt-Schlüssel zum Export in Outlook/Internet Explorer
bzw. Netscape/Mozilla bereitgestellt. Für den Import von Zertifikaten
in Outlook/Internet Explorer siehe Die Bedienung von openssl ist alles andere als erfreulich. Das Script basiert in einigen Teilen auf sign.sh (Copyright 1998-1999 Ralf S. Engelschall) aus mod_ssl. Damit keine Abfrage einer Paßphrase beim Start des Mailservers kommt, wird sie aus dem privaten Serverschlüssel gelöscht. Der ungeschützte Schlüssel muß dann auf jeden Fall unlesbar für alle außer Root sein. Die Schlüssel gut sichern. Das Script verpackt die erzeugten Schlüssel in sslkeys.tar und gibt am Schluß noch einen Hinweis, auf welchem Server welche Schlüssel vorhanden sein sollten. Zertifikate (*.crt und *.p12) gehören immer in das Unterverzeichnis ./certs, private Schlüssel (*.key und *.pem) in ./private. Die nicht auf dem Server benötigten privaten Schlüssel sollten von dort gelöscht werden. Der Fingerprint, von dem im Script die Rede ist, wird weiter unten noch einmal eine Rolle spielen, sofern Sie auch einen "internen" Mailserver betreiben wollen. |
Before we start with the mailserver itself we need several keys to encrypt the mail traffic. SSL/TLS keys to protect the mail traffic are stored in /etc/ssl or/usr/share/ssl, depending on the Linux version. We assume the first case, otherwise some of the configurationsfiles to follow have to be adapted appropriately. If a detailed explanation of the commands is required, please refer to the documentation under http://httpd.apache.org/docs-2.0/ssl/ssl_faq.html. This script generates a Certification Authority (CA), together with
several certificates for web, SMTP and POP3 servers. Besides that,
.p12 and .crt keys for exporting to Outlook/Internet Explorer and Netscape/Mozilla
are provided. Refer to It is not really straightforward to use openssl. The script shown here has been derived from sign.sh (Copyright 1998-1999 by Ralf S. Engelschall) from mod_ssl. To avoid a passphrase request when the mailserver is started, we delete it from the private server key. This unprotected key has to be unreadable for everyone except root. Do not forget to store the keys safely. The script packs all keys in an archive sslkeys.tar and prints a notification which keys have to be installed on which server. Certificates (*.crt und *.p12) are always stored in the subdirectory ./certs, private keys (*.key und *.pem) in ./private. All unused keys should be deleted from the server If you also want to set up an "internal" mail server, the fingerprint mentioned in the script will be needed later. |
SMTP-Mailserver mit Postfix |
SMTP Mailserver with Postfix |
Postfix mit TLS und SASL |
Postfix with TLS and SASL |
In diesem Beispiel ist von den Postfächern
die Rede. Die ersten beiden gehören zu Nutzern, die einen Linux-Account besitzen. Die dritte gehört zu einem Nutzer, der einen sogenannten virtuellen Account hat: ein Postfach unter /home/hosted/hosteduser/Maildir. Das folgende Initialisierungsscript legt die Nutzereinträge für diese drei Nutzer bei Postfix und Courier an und startet Postfix neu. Nach Änderungen an Konfigurationsdateien sollte dieses Script immer aufgerufen werden. |
In this example we use the mailboxes
The first and second belong to users who have their own Linux avcount. The third belongs to a user with no Linux user name and a so-called virtual account. This is a mailbox under /home/hosted/hosteduser/Maildir. The following script adds these three users to Postfix and Courier and restarts the mail server. You should always call this script after changing any configuration file. |
#!/bin/sh
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/config.sh
cd /etc/postfix || exit 1
PATH=/etc/postfix:/usr/local/bin:/usr/sbin:$PATH; export PATH
SASLDB=/etc/sasldb2
SASL_REALM=mydomain.net
function remap
{
postmap $1
chmod 644 $1 $1.db
}
remap map_transport
remap map_sender_access_fakelocal
remap map_relay_clientcerts
remap map_smtpd_sender_login_maps
remap map_virtual_uid_gid
remap map_virtual_mailbox
remap map_virtual
remap map_recipient_access
remap map_alias
remap map_helo_access
remap map_sender_access_fromaddress
rm $SASLDB
function sasldbentry
{
echo $2 | saslpasswd2 -c -a smtpd -u $SASL_REALM $1
}
sasldbentry myself pAssWoRd
sasldbentry otheruser SeSaM
sasldbentry hosteduser@sub.mydomain.net PaRoLe
chmod 644 $SASLDB
cat >/usr/lib/sasl2/smtpd.conf <<-EOF
mech_list: login cram-md5 digest-md5
pwcheck_method: auxprop
log_level: 3
EOF
chmod 644 /usr/lib/sasl2/smtpd.conf
cp /usr/lib/sasl2/smtpd.conf /etc/postfix/sasl/smtpd.conf
postfix reload
USERDB=/etc/courier/userdb
rm -rf $USERDB
mkdir $USERDB
function userdbentry
{
userdb -f $USERDB/$1 $2 set uid=$3 gid=$4 home=$5 mail=$6
echo $7 | userdbpw -md5 | userdb -f $USERDB/$1 $2 set pop3pw
}
userdbentry mydomain.net myself 500 500 /home/myself /home/myself/Maildir pAssWoRd
userdbentry mydomain.net otheruser 501 500 /home/otheruser /home/otheruser/Maildir SeSaM
userdbentry sub.mydomain.net hosteduser@sub.mydomain.net 601 600 /home/hosted/hosteduser /home/hosted/hosteduser/Maildir PaRoLe
chmod 700 $USERDB
makeuserdb
exit 0
In main.cf wird die Grundkonfiguration des Mailservers festgelegt. |
The base configuration of the mail server is defined by main.cf. |
#
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/main.cf
command_directory = /usr/sbin
daemon_directory = /usr/lib/postfix
program_directory = /usr/lib/postfix
smtpd_banner = $myhostname ESMTP $mail_name
setgid_group = postdrop
biff = no
append_dot_mydomain = no
myorigin = mydomain.net
mydomain = mydomain.net
myhostname = mail.mydomain.net
mydestination = mydomain.net,
sub.mydomain.net,
otherdomain.net,
localhost
mynetworks = 275.184.307.3, 127.0.0.0/8
recipient_delimiter = +
virtual_mailbox_base = /
Die Konfiguationsdateien map_... werden weiter unten erläutert. |
The configuration files map_... will be explained later. |
relay_clientcerts = hash:/etc/postfix/map_relay_clientcerts transport_maps = hash:/etc/postfix/map_transport alias_maps = hash:/etc/postfix/map_alias alias_database = hash:/etc/postfix/map_alias virtual_mailbox_maps = hash:/etc/postfix/map_virtual_mailbox virtual_uid_maps = hash:/etc/postfix/map_virtual_uid_gid virtual_gid_maps = hash:/etc/postfix/map_virtual_uid_gid virtual_maps = hash:/etc/postfix/map_virtual local_recipient_maps = relay_domains = $mydestination home_mailbox = Maildir/ mailbox_size_limit = 150000000 message_size_limit = 134217728 virtual_mailbox_limit = 134217728 bounce_size_limit = 50000 header_size_limit = 102400 unknown_local_recipient_reject_code = 450 smtpd_sasl_auth_enable = yes smtpd_sasl_application_name = smtpd smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = mydomain.net broken_sasl_auth_clients = yes smtpd_use_tls = yes smtpd_tls_ask_ccert = yes smtpd_tls_key_file = /etc/ssl/private/mail.mydomain.net.key smtpd_tls_cert_file = /etc/ssl/certs/mail.mydomain.net.crt smtpd_tls_CAfile = /etc/ssl/certs/ca.crt smtpd_tls_CApath = /etc/ssl/certs smtpd_tls_loglevel = 1 smtpd_tls_received_header = no smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom
Manche schwören auf "Teergruben" (engl. Tarpits), um das Internet von Spam zu befreien. Die Idee ist so einfach wie wirkungslos. Durch verzögerte Reaktion des empfangenden Servers bei einer unerwünschten Nachricht (z.B. einer Nachricht, deren Empfänger nicht bekannt ist - siehe die Logdatei oben) soll der Absender ausgebremst werden. Doch das nützt nichts mehr in Zeiten, da Tausende und Abertausende Zombie-PC als absendende Mailserver fungieren. Die beste Maßnahme ist, nach dem ersten Fehler in der Kommunikation den Empfang sofort abzubrechen und die Wahrheit kundzutun: Empfänger nicht bekannt. Das vergeudet bei uns am wenigsten Ressourcen. Andere Methoden wie SPF werden zum beim Kampf gegen Spam mehr beitragen. |
Tarpits ("Teergruben" in German) are believed to clean the internet from spam and they are hence very popular. The idea is as simple as useless: The mail sender shall be slowed down by delayed responses of a receiving server that recognises an unwanted message. This could be a message for a unknown mailbox name, see above. But who cares in times of myriads of zombie PC if some of them become unable to deliver their messages? The best measure as often in life is to quit immediately and tell the truth: receiver unknown. This is a good way to save our own resources. There are better methods to fight spam, like SPF. |
reject_code = 550 smtpd_hard_error_limit = 1
Mit einem HELO nimmt der Absender die Verbindung zum Empfänger auf. Schon was in der HELO-Meldung steht, kann vollkommen erlogen sein. Wer keinen gültigen Namen angibt (das sollte ein vollständiger Domainname sein), darf gar nicht weitersprechen. Es lohnt allerdings nicht, auf die Existenz dieses Domainnamens im DNS zu prüfen, da viele (auch professionelle) Absender ihre Mailserver nachlässig konfigurieren und ihrem Mailserver keinen registrierten Sub-Domainnamen zuweisen. Wer sich bereits vor dem HELO durch ein SASL-Login ausgewiesen hat oder seine Nachricht über einen registrierten vertrauenswürdigen Mailserver abliefert, wird ohne weitere Prüfung vorgelassen. |
Saying HELO, the sender contacts the receivng mail server. Even the contents of the HELO line may be faked, but we can do a simple check. Who does provide a valid name (which in fact has to be a domain name), is not allowed to proceed. But I do not recomment to check this domain name for existence since many (also professional) configure their mail servers carelessly, not assigning a valid subdomain to their server. Who already identified by a SASL login ("permit_sasl_authenticated") or who delivered his message to a registered trusted mail server ("permit_tls_clientcerts") may pass without further checks.. |
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_tls_clientcerts
permit_sasl_authenticated
permit_mynetworks
reject_invalid_hostname
reject_non_fqdn_hostname
reject_unauth_pipelining
check_helo_access hash:/etc/postfix/map_helo_access
# sender restrictions (MAIL FROM) # 1. permit_mynetworks, permit_tls_clientcerts, permit_sasl_authenticated # Permit everyone who is certainly welcome. # Note: permit_mynetworks is necessary for fetchmail (contacting smtpd from localhost); # fetchmail will not notice our reject (code 450), hence not flush the mail and fetch it again the next run. # Everyone who tries to send from one of our domain names should not pass beyond this step 1. # 2. check_sender_access hash:/etc/postfix/map_sender_access_fakelocal # Check for our own domain names. Reject every faked MAIL FROM. # 3. reject_unknown_sender_domain, reject_non_fqdn_sender, reject_sender_login_mismatch # Common UCE criteria. # 4. check_sender_access hash:/etc/postfix/map_sender_access_fromaddress # To lock out anyone else whom we do not like. # No step beyond permit_sasl_authenticated+permit_tls_clientcerts with faked local addresses, # all local smtpd users have to be TLS or SASL authenticated. smtpd_sender_restrictions = permit_mynetworks permit_tls_clientcerts permit_sasl_authenticated reject_unknown_sender_domain reject_non_fqdn_sender reject_unauth_pipelining check_sender_access hash:/etc/postfix/map_sender_access_fakelocal reject_sender_login_mismatch check_sender_access hash:/etc/postfix/map_sender_access_fromaddress smtpd_sender_login_maps = hash:/etc/postfix/map_smtpd_sender_login_maps
Als nächstes schickt der Absender eine RCPT TO-Nachricht. Die Prüfungen hier dürften keine Überraschungen mehr bieten. Durch reject_unauth_destination ist der Mailserver nicht als Relay verwendbar, wenn der Absender sich nicht über SASL angemeldet hat. GreylistingGreylisting ist die gegenwärtig wirkungsvollste Methode Spam einzudämmen, das durch Netze von Spambots erzeugt wird. Jeder einzelne Absender von Spam führt sich auf wie ein Mailserver, ist aber kein vollständiger Mailserver. Ein echter Mailserver kann mit Übermittlungsfehlern umgehen und wenn nötig die Übertragung wiederholen. Spambots sind aber klein und einfach gehalten. Der Mehraufwand, eine Fehlerbehandlung zu implementieren, lohnt sich für Spammer erst, wenn die Technik des Greylisting sich stark verbreitet hat. Das Prinzip des Greylisting besteht darin, eine eingehende Mail beim ersten Sendeversuch mit einer fingierten Fehlermeldung (z.B. "Empfangsserver momentan nicht verfügbar") zurückzuweisen, sich den Vorgang aber zu merken. Erst beim zweiten Sendeversuch wird die Nachricht angenommen. Da "guter" Mailverkehr in der Regel über korrekt implementierte Mailserver abgewickelt wird, ist die einzige Auswirkung auf diesen, daß die Nachrichten jeweils etwa fünf Minuten verzögert werden. Der unter localhost:60000 laufende Policyservice verwendet den Daemon postgrey, der durch Debian automatisch auf diesem lokalen Port installiert wird. Das ist ein Unterschied zum SPF-Service, der nur als Perl-Script zur Verfügung steht und deshalb noch einen zusätzlichen Eintrag in master.cf benötigt. |
|
# recipient restrictions (RCPT TO)
# 1. permit_tls_clientcerts, permit_sasl_authenticated
# Permit everything for senders who are authenticated.
# 2. reject_unknown_recipient_domain, reject_non_fqdn_recipient
# Recipient domain checks.
# 3. reject_unauth_destination, reject_unauth_pipelining
# 4. check_recipient_access hash:/etc/postfix/map_recipient_access_grey, check_policy_service unix:private/spf
# SPF test only for destinations that are also in the positive list.
# Mail to unknown mailboxes is blocked here.
# 5. check_recipient_access hash:/etc/postfix/map_recipient_access_white, reject
# Process mails on after check of positive list
smtpd_recipient_restrictions = permit_tls_clientcerts
permit_sasl_authenticated
reject_unknown_recipient_domain
reject_non_fqdn_recipient
reject_unauth_destination
reject_unauth_pipelining
check_recipient_access hash:/etc/postfix/map_recipient_access_grey
check_policy_service inet:127.0.0.1:60000
check_policy_service unix:private/spf
check_recipient_access hash:/etc/postfix/map_recipient_access_white
reject
Vertrauenswürdige Partner-Mailserver weisen sich durch ein TLS-Zertifikat aus. Die Fingerprints aller akzeptierten Zertifikate stehen in map_relay_clientcerts. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_relay_clientcerts # fingerprints of trusted mailservers that are allowed to inject mails 4A:F6:1G:7B:2D:A2:FD:0B:80:D6:3A:5D:57:24:F8:EE mail.intra.mydomain.net
In map_transport wird für jeden Domainnamen festgelegt, ob er für lokale oder virtuelle Nutzer steht. Im DNS sollte allerdings nicht nur mydomain.net einen MX-Eintrag haben, sondern auch sub.mydomain.net. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_transport # all domains served by this mailserver mydomain.net local: otherdomain.net local: sub.mydomain.net virtual:
Die Postfächer und die Linux User-/Group-IDs der Nutzer. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_virtual_mailbox myself@mydomain.net /home/myself/Maildir/ otheruser@mydomain.net /home/otheruser/Maildir/ hosteduser@sub.mydomain.net /home/hosted/hosteduser/Maildir/
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_virtual_uid_gid myself@mydomain.net 500:500 otheruser@mydomain.net 501:500 hosteduser@sub.mydomain.net 601:600
Schließlich noch alle Alias-Namen. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_virtual # all registered receiver aliases # MYDOMAIN.NET ########################################################### # family myalias@mydomain.net myself@mydomain.net # special www@mydomain.net myself@mydomain.net info@mydomain.net myself@mydomain.net support@mydomain.net myself@mydomain.net postmaster@mydomain.net myself@mydomain.net abuse@mydomain.net myself@mydomain.net security@mydomain.net myself@mydomain.net hostmaster@mydomain.net myself@mydomain.net webmaster@mydomain.net myself@mydomain.net # OTHERDOMAIN.NET ########################################################### # special www@otherdomain.net myself@mydomain.net info@otherdomain.net myself@mydomain.net support@otherdomain.net myself@mydomain.net postmaster@otherdomain.net myself@mydomain.net abuse@otherdomain.net myself@mydomain.net security@otherdomain.net myself@mydomain.net hostmaster@otherdomain.net myself@mydomain.net webmaster@otherdomain.net myself@mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_alias MAILER-DAEMON root root myself
Es folgen einige Regeln zum Ablehnen oder Annehmen bestimmter Absende- und Empfangsadressen. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_helo_access # mailservers who may not even say HELO to us reallybadguys.com REJECT .reallybadguys.com REJECT
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_sender_access_fromaddress # MAIL FROM addresses to be rejected without additional checks reallybadguys.com REJECT
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_recipient_access_grey # local mail addresses to be accepted or rejected by postfix notify@mydomain.net REJECT # following entries according to map_virtual_mailbox: myself@mydomain.net DUNNO myself@otherdomain.net DUNNO otheruser@mydomain.net DUNNO hosteduser@sub.mydomain.net DUNNO # following entries according to map_virtual: myalias@mydomain.net DUNNO www@mydomain.net DUNNO info@mydomain.net DUNNO support@mydomain.net DUNNO postmaster@mydomain.net DUNNO abuse@mydomain.net DUNNO security@mydomain.net DUNNO hostmaster@mydomain.net DUNNO webmaster@mydomain.net DUNNO www@otherdomain.net DUNNO info@otherdomain.net DUNNO support@otherdomain.net DUNNO postmaster@otherdomain.net DUNNO abuse@otherdomain.net DUNNO security@otherdomain.net DUNNO hostmaster@otherdomain.net DUNNO webmaster@otherdomain.net DUNNO # reject for all other (unknown) mailboxes mydomain.net REJECT otherdomain.net REJECT sub.mydomain.net REJECT
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_recipient_access_white # local mail addresses to be accepted or rejected by postfix # following entries according to map_virtual_mailbox: myself@mydomain.net OK myself@otherdomain.net OK otheruser@mydomain.net OK hosteduser@sub.mydomain.net OK # following entries according to map_virtual: myalias@mydomain.net OK www@mydomain.net OK info@mydomain.net OK support@mydomain.net OK postmaster@mydomain.net OK abuse@mydomain.net OK security@mydomain.net OK hostmaster@mydomain.net OK webmaster@mydomain.net OK www@otherdomain.net OK info@otherdomain.net OK support@otherdomain.net OK postmaster@otherdomain.net OK abuse@otherdomain.net OK security@otherdomain.net OK hostmaster@otherdomain.net OK webmaster@otherdomain.net OK
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_sender_access_fakelocal # REJECT for all MAIL FROM addresses that claim to come from here but actually do not mydomain.net REJECT otherdomain.net REJECT sub.mydomain.net REJECT
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/map_smtpd_sender_login_maps # allowed MAIL FROM addresses with their respective SASL login names myself@mydomain.net myself myself@otherdomain.net myself otheruser@mydomain.net otheruser hosteduser@sub.mydomain.net hosteduser@sub.mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/authenticated.lst # users that are SASL or TLS authenticated if sending mails myself@mydomain.net myself@otherdomain.net otheruser@mydomain.net hosteduser@sub.mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/authorized.lst # users that are authorized to inject mail to postfix # authenticated addresses: myself@mydomain.net myself@otherdomain.net otheruser@mydomain.net hosteduser@sub.mydomain.net # addresses for server-generated messages: MAILER-DAEMON@mydomain.net MAILER-DAEMON@otherdomain.net # mimicry addresses: myself@mycompany.com # no need to include here: #postmaster@mydomain.net #notify@mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/mailboxes_family.lst # mailboxes of privileged (family) users myself@mydomain.net otheruser@mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/mailboxes_hosted.lst # mailboxes of hosted users hosteduser@sub.mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/sender_domains.lst # allowed sender domains mydomain.net otherdomain.net mycompany.com
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/spamc_individual.lst # users who do their individual spam filtering with own scoring schema myself@mydomain.net otheruser@mydomain.net myalias@mydomain.net www@mydomain.net info@mydomain.net support@mydomain.net postmaster@mydomain.net abuse@mydomain.net security@mydomain.net hostmaster@mydomain.net webmaster@mydomain.net myself@otherdomain.net www@otherdomain.net info@otherdomain.net support@otherdomain.net postmaster@otherdomain.net abuse@otherdomain.net security@otherdomain.net hostmaster@otherdomain.net webmaster@otherdomain.net # not: hosteduser@sub.mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/usernames_family.lst # receiver names that correspond to a family mailbox myself@mydomain.net myself@otherdomain.net otheruser@mydomain.net myalias@mydomain.net www@mydomain.net info@mydomain.net support@mydomain.net postmaster@mydomain.net abuse@mydomain.net security@mydomain.net hostmaster@mydomain.net webmaster@mydomain.net myself@otherdomain.net www@otherdomain.net info@otherdomain.net support@otherdomain.net postmaster@otherdomain.net abuse@otherdomain.net security@otherdomain.net hostmaster@otherdomain.net webmaster@otherdomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/usernames_hosted.lst hosteduser@sub.mydomain.net
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/own_domains.rxp ^mydomain\.net$ ^otherdomain\.net$ ^sub\.mydomain\.net$ ^.*\.mydomain\.net$ ^.*\.otherdomain\.net$ ^.*\.sub\.mydomain\.net$ ^275\.184\.307\.3$
Viren- und Spamfilter |
Virus and Spam Filter |
|
Jede ausgehende Email wird auf Viren geprüft und gegebenenfalls gar nicht erst hinausgelassen. EIngehende Mails werden einer SPF-Prüfung und einem Virentest unterzogen. Postfix prüft nach dem SPF-Verfahren ("Sender Permitted From" oder auch "Sender Policy Framework") durch den Aufruf eines Policy-Scripts, ob der Absender eine zulässige Absendeadresse angegeben hat. Das soll insbesondere vor gefälschten Mails von Freemail-Accounts schützen. Es funktioniert aber nur, wenn der Eigentümer des absendenden Mailservers einen entsprechenden Eintrag im DNS hinterlegt hat. Das ist leider selten der Fall. Wir geben ein gutes Beispiel und legen einen SPF-Eintrag für mydomain.net an. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/postfix/master.cf # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== smtp inet n - n - - smtpd -o content_filter=spamfilter:dummy #628 inet n - - - - qmqpd pickup fifo n - - 60 1 pickup cleanup unix n - - - 0 cleanup qmgr fifo n - - 300 1 qmgr #qmgr fifo n - - 300 1 nqmgr rewrite unix - - - - - trivial-rewrite bounce unix - - - - 0 bounce defer unix - - - - 0 bounce flush unix n - - 1000? 0 flush proxymap unix - - n - - proxymap smtp unix - - - - - smtp relay unix - - - - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - - - - showq error unix - - - - - error local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - n - - lmtp # interfaces to non-Postfix software spf unix - n n - - spawn user=nobody argv=/usr/bin/perl /etc/postfix/spf-policy.pl spamfilter unix - n n - - pipe flags=Rq user=spam argv=/etc/postfix/spamfilter.sh postfix none ${sender} ${recipient} # only used by postfix-tls #tlsmgr fifo - - n 300 1 tlsmgr #smtps inet n - n - - smtpd # -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes #587 inet n - n - - smtpd # -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes trace unix - - - - 0 bounce verify unix - - - - 1 verify
Das Kernstück allen weiteren Filterns ist das Shell-Script spamfilter.sh. Die Einstellungen in master.cf bewirken, daß spamfilter.sh die Nachricht zu sehen bekommt, nachdem der SMTP-Daemon die oben genannten ersten Prüfungen abgeschlossen hat. Auf besondere Effizienz habe ich bei diesem Script verzichtet. Es fallen große Mengen an temporären Dateien an. Für einen Server, der täglich Tausende Nachrichten verdauen muß, ist dieses Script also nicht geeignet. |
|
#!/bin/sh
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/spamfilter.sh
# parameter 1: modus (fetchmail, postfix)
# parameter 2: fetchmail box or "none"
# parameter 3: sender (MAIL FROM)
# parameter 4...n: recipients (RCPT TO)
#########################################################################################################
# flags
#########################################################################################################
check_virus=yes
log_spamstatus=no
debug=no
logheaders=yes
logverbose=yes
#########################################################################################################
# set up environment
#########################################################################################################
mydomain=mydomain.net
my_received_id="mail.$mydomain (Postfix)"
postmaster=myself@$mydomain
SPAMUSER=spam
cd /etc/postfix || { cat | sendmail -i -f $postmaster -- $postmaster; exit 0; }
PATH=/etc/postfix:/usr/local/bin:/usr/sbin:$PATH; export PATH
MAILHEADERS=/var/log/mailheaders
null=/dev/null
subjectlength=28
OPMODE="$1"
FETCHBOX="$2"
MAIL_FROM="$3"
shift; shift; shift
RCPT_TO="$@"
RCPT_COUNT=`echo "$RCPT_TO" | wc -w | tr -d ' '`
logname="spamfilter.sh/$OPMODE"
auth_magic=`auth_magic.sh $mydomain`
Zuerst werden die Kopfzeilen der Nachricht extrahiert. Ihre Auswertung gibt schon einige Information über die Herkunft der Email. Wir können insbesondere feststellen, welche Nachricht nicht direkt an diesen Mailserver geschickt wurde, sondern von einem externen Postfach eingesammelt wurde. An einigen Stellen müssen zum Schutz der Privatsphäre solche Nachrichten anders behandelt werden. In authorized.lst befindet sich eine Liste aller erlaubten Absendenamen. Wenn die hier geprüfte Mail von einem dieser Absender stammt, handelt es sich mit Sicherheit um eine ausgehende Mail, denn eingehende Mails mit derart gefälschten Absendenamen hätte bereits der SMTP-Daemon aussortiert. |
|
#########################################################################################################
# detect status of mail
#########################################################################################################
TMP_original=`mktemp -p /tmp` || { cat | sendmail -i -f "$MAIL_FROM" -- $postmaster; exit 0; }
cat >$TMP_original
TMP_oldheaders=`mktemp -p /tmp` || { cat $TMP_original | sendmail -i -f "$MAIL_FROM" -- $postmaster; exit 0; }
mawk -f extract_headers.awk <$TMP_original >$TMP_oldheaders
TMP_mail_plus=`mktemp -p /tmp` || { cat $TMP_original | sendmail -i -f "$MAIL_FROM" -- $postmaster; exit 0; }
LOGTEXT="mail_from=<$MAIL_FROM>"
from_authenticated=no
from_authorized=no
from_family=no
if [ $OPMODE = postfix ]
then
# authenticated: everyone authenticated by SASL or coming from trusted mailserver
# (e.g. internal mailserver, TLS fingerprint authenticated)
if match_plain.sh "$MAIL_FROM" authenticated.lst >$null 2>$null
then
from_authenticated=yes
LOGTEXT="$LOGTEXT authenticated"
fi
# authorized: superset of authenticated, comprising additionally:
# - automatically server-generated mails, e.g. from MAILER-DAEMON@*
# - registered mimicry addresses, e.g. faked corporate mail addresses
if match_plain.sh "$MAIL_FROM" authorized.lst >$null 2>$null
then
from_authorized=yes
[ $from_authenticated = no ] && LOGTEXT="$LOGTEXT authorized"
fi
# family: privileged users whose mails have to be automatically certified with Habeas stamp
if match_plain.sh "$MAIL_FROM" usernames_family.lst >$null 2>$null
then
from_family=yes
LOGTEXT="$LOGTEXT family"
fi
fi
LOGTEXT="$LOGTEXT rcpt_to=<$RCPT_TO>"
Einige Informationen, die der SMTP-Daemon leider nicht den Kopfzeilen hinzufügen kann, fügen wir hier selbst ein: Wer die Nachricht geschickt hat, wie er sich mit HELO gemeldet hat und so weiter. Diese Information wird später in weiteren Scripten nochmals benötigt, z.B. nondelivery.sh. |
|
#########################################################################################################
# identify basic SMTP envelope parameters
#########################################################################################################
HELO=""
CLIENT=""
if [ $OPMODE = postfix ]
then
heloline=`grep 'Received: from .* by '"$my_received_id"' with' $TMP_oldheaders`
if [ X"$heloline" != X ]
then
# 1=helo 2=client_ip 3=time
# Received: from $HELO ($CLIENT_REV [$CLIENT]) by $my_received_id with $PROTOCOL id $IDENT
# for <$DESTINATION>; $TIME
helopattern='^Received: from \([^ ]*\) ([^ ]* [[]\([^]]*\)]) by '"$my_received_id"' [^;]*; \(.*\)$'
HELO=`echo $heloline | sed -e 's/'"$helopattern"'/\1/'`
CLIENT=`echo $heloline | sed -e 's/'"$helopattern"'/\2/'`
TIME=`echo $heloline | sed -e 's/'"$helopattern"'/\3/'`
LOGTEXT="$LOGTEXT client=<$CLIENT> helo=<$HELO> time=<$TIME>"
new_helopattern='^\(Received: from [^ ]* ([^ ]* [[][^]]*]) by '"$my_received_id"
new_helopattern="$new_helopattern"' with [^ ]* id [^ ]*\)\( for <\([^>]*\)>\)\{0,1\}[^;]*;\(.*\)$'
new_heloline=`echo "$heloline" | \
sed -e 's/'"$new_helopattern"'/\1 for <\3> count '"$RCPT_COUNT"' from <'"$MAIL_FROM"'>; \4/'`
fi
fi
#########################################################################################################
# filter out more header information and rewrite headers
#########################################################################################################
subject=`grep -i '^Subject:' $TMP_oldheaders | sed -e 's/^[^:]*: //;s/</{/g;s/>/}/g' | tr -d '\n' | tr '[:cntrl:]' '?'`
[ `expr length "$subject"` -gt $subjectlength ] && subject=`expr substr "$subject" 1 $subjectlength`"..."
ident=`grep -i '^Message-ID:' $TMP_oldheaders | sed -e 's/^[^:]*: //;s/[><]//g' | tr -d '\n' | tr '[:cntrl:]' '?'`
mailsize=`wc -lc <$TMP_original | sed -e 's/ *\([^ ]*\) *\([^ ]*\)/\1 lines, \2 bytes/'`
LOGTEXT="$LOGTEXT subject=<$subject> ident=<$ident> size=<$mailsize>"
if [ X"$HELO" = X ]
then
date=`grep -i '^Date:' $TMP_oldheaders | sed -e 's/^[^:]*: //'`
LOGTEXT="$LOGTEXT date=<$date>"
fi
if [ X"$new_heloline" = X ]
then
cat <$TMP_oldheaders >$TMP_mail_plus
else
sed -ne ':a;/'"$helopattern"'/s/^.*$/'"$new_heloline"'/;tx;/^$/bx;p;n;ba;:x;p;n;bx' \
<$TMP_oldheaders >$TMP_mail_plus
fi
[ $from_authenticated = yes ] && echo "X-SASL-AUTHENTICATED: $MAIL_FROM by $auth_magic" >>$TMP_mail_plus
[ $OPMODE = fetchmail ] && echo "X-Fetchmail-Retrieved: $FETCHBOX" >>$TMP_mail_plus
sed -ne '/^$/,$p' <$TMP_original >>$TMP_mail_plus
Zum Virentest benutzen wir Clam Antivirus, einen Open Source Virenscanner. Die Virensignaturen, die Clam über das Internet zur Verfügung stellt, sind nicht besonders aktuell. Auf einen zweiten Virenscanner im Client PC sollte man nicht verzichten. Clam kann mit komplett MIME-codierten Emails umgehen. Das nochmalige Entpacken und einzelne Prüfen der Anlagen scheint überflüssig zu sein. Ich konnte bislang keinen Fall feststellen, in dem beide Prüfungen verschiedene Ergebnisse gebracht hätten. |
|
#########################################################################################################
# run spam and virus tests and write log summary
#########################################################################################################
infected=no
if [ $check_virus = yes ]
then
virusinfo=`clamscan --verbose --disable-summary $TMP_original 2>&1 1>$null`
if [ $? = 1 ]
then
infected=yes
LOGTEXT="$LOGTEXT virus=<`echo "$virusinfo" | sed -e 's/^[^:]*: //;s/ FOUND$//'`>"
fi
fi
if [ $log_spamstatus = yes -a $infected != yes -a $from_authenticated = no ]
then
spaminfo=`spamc -c -u $SPAMUSER <$TMP_original`
[ $? = 1 ] && LOGTEXT="$LOGTEXT spam=<$spaminfo>"
fi
logger -p mail.info -t $logname "$LOGTEXT"
if [ $logheaders = yes ]
then
cat $TMP_oldheaders >>$MAILHEADERS
echo " -----------------------------------------------------------------" >>$MAILHEADERS
fi
Ausgehende Mails werden gesendet, sofern sie nicht dem Virenscanner aufgefallen sind. Zu sendende Mails werden mit Kopfzeilen versehen, die die Virenprüfung bezeugen. Mails von privilegierten Familienmitgliedern werden außerdem mit urheberrechtlich geschützen Kopfzeilen von Habeas versehen, die einen heiligen Eid schwören, daß diese Mail kein Spam sei. Überflüssige Kopfzeilen werden entfernt, insbesondere solche, die Aufschluß über unsere interne Netzstruktur geben könnten. Damit das Script add_blackwhitelist.sh die Empfängeradresse zur Weißen Liste des Absenders hinzufügen kann, muß es mit den Privilegien des Absenders oder des Superusers (wie hier) ausgeführt werden. Sudo muß konfiguriert werden wie im Kommentar erläutert. |
|
#########################################################################################################
# process message per recipient
#########################################################################################################
while [ X"$1" != X ]
do
TO="$1"
#################################################################################################
# outbound
#################################################################################################
if [ $from_authorized = yes ]
then
# this branch is not taken for fetched mails
if [ $infected = yes ]
then
# never deliver infected mails
nondelivery.sh authorized null virus "$virusattach" \
"$MAIL_FROM" "$TO" "$RCPT_COUNT" "$HELO" \
"$CLIENT" "$TIME" <$TMP_mail_plus
elif [ $from_family = yes ]
then
# mails from family users are certified with Habeas stamp
mawk -f suppress_internals.awk <$TMP_mail_plus | \
mawk -f plus_habeas.awk | \
mawk -f plus_viruscheck.awk | \
sendmail -i -f "$MAIL_FROM" -- "$TO"
# current user is "spam", su to root in order to change user configuration files
sudo /etc/postfix/add_blackwhitelist.sh white "$MAIL_FROM" "$TO"
else
# from hosted user
mawk -f suppress_internals.awk <$TMP_mail_plus | \
mawk -f plus_viruscheck.awk | \
sendmail -i -f "$MAIL_FROM" -- "$TO"
sudo /etc/postfix/add_blackwhitelist.sh white "$MAIL_FROM" "$TO"
fi
Eingehende Mails werden verteilt. Kann die Mail nicht zugestellt werden, weil sie verseucht ist, oder ist sie als Spam aufgefallen, so wird nondelivery.sh aufgerufen. |
|
#################################################################################################
# inbound
#################################################################################################
else
to_family=no
match_plain.sh "$TO" usernames_family.lst >$null 2>$null && to_family=yes
to_hosted=no
match_plain.sh "$TO" usernames_hosted.lst >$null 2>$null && to_hosted=yes
if [ $to_family = $to_hosted ]
then
logger -p mail.info -t $logname -- \
"alert: <$TO> to_family=<$to_family> to_hosted=<$to_hosted>"
to_family=no
to_hosted=yes
fi
[ $to_family = yes ] && nondelivery_dest=family || nondelivery_dest=hosted
if [ $infected = yes ]
then
# never deliver infected mails
nondelivery.sh null $nondelivery_dest virus "$virusattach" \
"$MAIL_FROM" "$TO" "$RCPT_COUNT" "$HELO" \
"$CLIENT" "$TIME" <$TMP_mail_plus
elif match_plain.sh "$TO" spamc_individual.lst >$null 2>$null
then
# no spam check here, will be done per-user, initiated by .forward
mawk -f plus_viruscheck.awk <$TMP_mail_plus | \
sendmail -i -f "$MAIL_FROM" -- "$TO"
else
if TMP_spamchecked=`mktemp -p /tmp`
then
# spamc to set spam header tags only,
# procmail or the user client can filter by X-Spam-Status tags
mawk -f plus_viruscheck.awk <$TMP_mail_plus | \
spamc -f -u $SPAMUSER >$TMP_spamchecked
sendmail -i -f "$MAIL_FROM" -- "$TO" <$TMP_spamchecked
if grep -i '^X-Spam-Flag: YES' $TMP_spamchecked >$null 2>$null
then
nondelivery.sh null $nondelivery_dest spam "" \
"$MAIL_FROM" "$TO" "$RCPT_COUNT" "$HELO" \
"$CLIENT" "$TIME" <$TMP_spamchecked
fi
rm $TMP_spamchecked
else
sendmail -i -f "$MAIL_FROM" -- $TO <$TMP_mail_plus
fi
fi
fi
shift
done
rm -f $TMP_mail_plus $TMP_oldheaders $TMP_original
exit 0
SPF |
SPF |
Hier ein Perl-Programm, das den SPF-Test für eine Mailadresse durchführt. |
|
#!/usr/bin/perl
# mengwong@pobox.com
# Wed Dec 10 03:52:04 EST 2003
# postfix-policyd-spf
# version 1.06
# see http://spf.pobox.com/
use Fcntl;
use Sys::Syslog qw(:DEFAULT setlogsock);
use strict;
# ----------------------------------------------------------
# configuration
# ----------------------------------------------------------
# to use SPF, install Mail::SPF::Query from CPAN or from the SPF website at http://spf.pobox.com/downloads.html
my @HANDLERS;
push @HANDLERS, "testing";
push @HANDLERS, "sender_permitted_from"; use Mail::SPF::Query;
my $VERBOSE = 0;
my $DEFAULT_RESPONSE = "DUNNO";
#
# Syslogging options for verbose mode and for fatal errors.
# NOTE: comment out the $syslog_socktype line if syslogging does not
# work on your system.
#
my $syslog_socktype = 'unix'; # inet, unix, stream, console
my $syslog_facility = "mail";
my $syslog_options = "pid";
my $syslog_priority = "info";
my $syslog_ident = "postfix/policy-spf";
# ----------------------------------------------------------
# minimal documentation
# ----------------------------------------------------------
#
# Usage: smtpd-policy.pl [-v]
#
# Demo delegated Postfix SMTPD policy server.
# This server implements SPF.
# Another server implements greylisting.
# Postfix has a pluggable policy server architecture.
# You can call one or both from Postfix.
#
# The SPF handler uses Mail::SPF::Query to do the heavy lifting.
#
# This documentation assumes you have read Postfix's README_FILES/SMTPD_POLICY_README
#
# Logging is sent to syslogd.
#
# How it works: each time a Postfix SMTP server process is started
# it connects to the policy service socket, and Postfix runs one
# instance of this PERL script. By default, a Postfix SMTP server
# process terminates after 100 seconds of idle time, or after serving
# 100 clients. Thus, the cost of starting this PERL script is smoothed
# out over time.
#
# To run this from /etc/postfix/master.cf:
#
# policy unix - n n - - spawn
# user=nobody argv=/usr/bin/perl /usr/libexec/postfix/smtpd-policy.pl
#
# To use this from Postfix SMTPD, use in /etc/postfix/main.cf:
#
# smtpd_recipient_restrictions =
# ...
# reject_unknown_sender_domain
# reject_unauth_destination
# check_policy_service unix:private/policy
# ...
#
# NOTE: specify check_policy_service AFTER reject_unauth_destination
# or else your system can become an open relay.
#
# To test this script by hand, execute:
#
# % perl smtpd-policy.pl
#
# Each query is a bunch of attributes. Order does not matter, and
# the demo script uses only a few of all the attributes shown below:
#
# request=smtpd_access_policy
# protocol_state=RCPT
# protocol_name=SMTP
# helo_name=some.domain.tld
# queue_id=8045F2AB23
# sender=foo@bar.tld
# recipient=bar@foo.tld
# client_address=1.2.3.4
# client_name=another.domain.tld
# [empty line]
#
# The policy server script will answer in the same style, with an
# attribute list followed by a empty line:
#
# action=dunno
# [empty line]
#
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: client_address=208.210.125.227
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: client_name=newbabe.mengwong.com
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: helo_name=newbabe.mengwong.com
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: protocol_name=ESMTP
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: protocol_state=RCPT
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: queue_id=
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: recipient=mengwong@dumbo.pobox.com
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: request=smtpd_access_policy
# Jul 23 18:43:29 dumbo/dumbo policyd[21171]: Attribute: sender=mengwong@newbabe.mengwong.com
# ----------------------------------------------------------
# initialization
# ----------------------------------------------------------
#
# Log an error and abort.
#
sub fatal_exit {
syslog(err => "fatal_exit: @_");
syslog(warning => "fatal_exit: @_");
syslog(info => "fatal_exit: @_");
die "fatal: @_";
}
#
# Unbuffer standard output.
#
select((select(STDOUT), $| = 1)[0]);
#
# This process runs as a daemon, so it can't log to a terminal. Use
# syslog so that people can actually see our messages.
#
setlogsock $syslog_socktype;
openlog $syslog_ident, $syslog_options, $syslog_facility;
# ----------------------------------------------------------
# main
# ----------------------------------------------------------
#
# Receive a bunch of attributes, evaluate the policy, send the result.
#
my %attr;
while (<STDIN>) {
chomp;
if (/=/) { my ($k, $v) = split (/=/, $_, 2); $attr{$k} = $v; next }
elsif (length) { syslog(warning=>sprintf("warning: ignoring garbage: %.100s", $_)); next; }
if ($VERBOSE) {
for (sort keys %attr) {
syslog(debug=> "Attribute: %s=%s", $_, $attr{$_});
}
}
fatal_exit ("unrecognized request type: '$attr{request}'") unless $attr{request} eq "smtpd_access_policy";
my $action = $DEFAULT_RESPONSE;
my %responses;
foreach my $handler (@HANDLERS) {
no strict 'refs';
my $response = $handler->(attr=>\%attr);
syslog(debug=> "handler %s: %s", $handler, $response);
if ($response and $response !~ /^dunno/i) {
syslog(info=> "handler %s: %s is decisive.", $handler, $response);
$action = $response; last;
}
}
syslog(info=> "decided action=%s", $action);
print STDOUT "action=$action\n\n";
%attr = ();
}
# ----------------------------------------------------------
# plugin: SPF
# ----------------------------------------------------------
sub sender_permitted_from {
local %_ = @_;
my %attr = %{ $_{attr} };
my $query = eval { new Mail::SPF::Query (ip =>$attr{client_address},
sender=>$attr{sender},
helo =>$attr{helo_name}) };
if ($@) {
syslog(info=>"%s: Mail::SPF::Query->new(%s, %s, %s) failed: %s",
$attr{queue_id}, $attr{client_address}, $attr{sender}, $attr{helo_name}, $@);
return "DUNNO";
}
my ($result, $smtp_comment, $header_comment) = $query->result();
syslog(info=>"%s: SPF %s: smtp_comment=%s, header_comment=%s",
$attr{queue_id}, $result, $smtp_comment, $header_comment);
if ($result eq "pass") { return "DUNNO"; }
elsif ($result eq "fail") { return "REJECT " . ($smtp_comment || $header_comment); }
elsif ($result eq "error") { return "450 temporary failure: $smtp_comment"; }
else { return "DUNNO"; }
# unknown, softfail, neutral and none all return DUNNO
# TODO XXX: prepend Received-SPF header. Wietse says he will add that functionality soon.
}
# ----------------------------------------------------------
# plugin: testing
# ----------------------------------------------------------
sub testing {
local %_ = @_;
my %attr = %{ $_{attr} };
if (lc address_stripped($attr{sender}) eq
lc address_stripped($attr{recipient})
and
$attr{recipient} =~ /policyblock/) {
syslog(info=>"%s: testing: will block as requested",
$attr{queue_id});
return "REJECT smtpd-policy blocking $attr{recipient}";
}
else {
syslog(info=>"%s: testing: stripped sender=%s, stripped rcpt=%s",
$attr{queue_id},
address_stripped($attr{sender}),
address_stripped($attr{recipient}),
);
}
return "DUNNO";
}
sub address_stripped {
# my $foo = localpart_lhs('foo+bar@baz.com'); # returns 'foo@baz.com'
my $string = shift;
for ($string) {
s/[+-].*\@/\@/;
}
return $string;
}
Für den eigenen Mailserver tragen wir im DNS folgenden Wert ein: (Siehe bei SPF für weitere Informationen.) |
|
Bearbeitung von Kopfzeilen |
Processing of Mail Headers |
Das Filtern und Umgestalten der Kopfzeilen erfolgt mit awk. Es folgen die benötigten Steuerdateien. |
|
#
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/extract_headers.awk
BEGIN { RS="\n\n+"; }
/.*/ { gsub("\n\t"," "); print; exit 0; }
END { exit 0; }
#
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/plus_habeas.awk
/^$/ {
"/etc/postfix/auth_magic.sh mydomain.net" | getline signature
"date -R" | getline sendtime;
print "X-Server-Signature:", signature, ";", sendtime;
print "X-Habeas-SWE-1: winter into spring";
print "X-Habeas-SWE-2: brightly anticipated";
print "X-Habeas-SWE-3: like Habeas SWE (tm)";
print "X-Habeas-SWE-4: Copyright 2002 Habeas (tm)";
print "X-Habeas-SWE-5: Sender Warranted Email (SWE) (tm). The sender of this";
print "X-Habeas-SWE-6: email in exchange for a license for this Habeas";
print "X-Habeas-SWE-7: warrant mark warrants that this is a Habeas Compliant";
print "X-Habeas-SWE-8: Message (HCM) and not spam. Please report use of this";
print "X-Habeas-SWE-9: mark in spam to .";
print; exit 0; }
/.*/ { print; }
END { while (getline==1) print; }
#
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/plus_viruscheck.awk
/^$/ {
"/usr/sbin/clamd -V" | getline clamversion;
"date -R" | getline scantime;
"hostname" | getline scanhost;
print "X-Virus-Scanned: by", scanhost, "with", clamversion, ";", scantime;
print "X-Virus-Status: No";
print; exit 0; }
/.*/ { print; }
END { while (getline==1) print; }
#
# (c) Thomas Bez <bez@tedesca.net> 2004
# http://www.bez.tedesca.net/homeoff/antispam.html
#
# mail.mydomain.net:/etc/postfix/suppress_internals.awk
BEGIN { skipreceived=0; }
/^$/ { print; exit 0; }
/^X-Mailer: / { next; }
/^X-Fetchmail-Retrieved: / { next; }
/^Delivered-To: / { next; }
/^X-SASL-AUTHENTICATED: / { next; }
/^X-Spam-Report: / { next; }
/^X-Spam-Status: / { next; }
/^Received: from mail.intra.mydomain.net/ { skipreceived=1; next; }
/^Received: / { if (skipreceived==0) print; next; }
/^ / { if (skipreceived==0) print; next; }
/^ / { if (skipreceived==0) print; next; }
/.*/ { skipreceived=0; print; }
END { while (getline==1) print; }
|
Die globale Konfiguration von Spamassassin erfolgt mit folgender Datei. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/etc/spamassassin/local.cf report_safe 0 rewrite_subject 0 fold_headers 0 use_terse_report 0 spam_level_stars 1 check_mx_attempts 3 check_mx_delay 5 allow_user_rules 0 auto_whitelist_factor 0 use_bayes 1 bayes_auto_learn 0 required_hits 5.0 add_header spam Flag _YESNOCAPS_ add_header all Status _YESNO_, hits=_HITS_ required=_REQD_ tests=_TESTSSCORES(,)_ bayes=_BAYES_ relaysuntrusted=_RELAYSUNTRUSTED_ autolearn=_AUTOLEARN_ scanned=[_DATE_] version=_VERSION_ postmaster=_CONTACTADDRESS_ add_header all Level _STARS(*)_ add_header all Checker-Version SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_ header TO_undisclosed To =~ /undisclosed/i describe TO_undisclosed To: undisclosed header SASL_AUTHENTICATED X-SASL-AUTHENTICATED =~ /$auth_fingerprint/i describe SASL_AUTHENTICATED X-SASL-AUTHENTICATED: $auth_fingerprint body Postmaster_Magic /$auth_fingerprint/i describe Postmaster_Magic Postmaster_Magic ($auth_fingerprint) score Postmaster_Magic -100 score HABEAS_SWE -100 score HABEAS_VIOLATOR 16
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/home/myself/.fetchmailrc poll pop.gmx.net protocol pop3 timeout 30 username "myself@gmx.net" password "pAssWoRd" is "myself@mydomain.net" here smtpname "myself@mydomain.net" mda "/etc/postfix/spamfilter.sh fetchmail myself@gmx.net %F %T" antispam 450 flush nokeep
$ crontab -u myself -e
*/15 * * * * /usr/local/bin/fetchmail
Jeder Nutzer kann seine Mail nochmals nach eigenem Gutdünken bearbeiten und filtern. |
|
"| /usr/bin/procmail -t"
# # (c) Thomas Bez2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/home/myself/.procmailrc :0: * ^X-SASL-AUTHENTICATED Maildir/ :0fw * < 256000 | /usr/local/bin/spamc :0: * ^X-Spam-Flag: YES { :0 c | /etc/postfix/logspam.sh spam :0: * ^X-Spam-Status: .*USER_IN_BLACKLIST= | cat >/dev/null :0: | /etc/postfix/nondelivery.sh null family spam } :0: * ^X-Spam-Flag: YES | cat >/dev/null :0: Maildir/
Die Nutzer dürfen aus Sicherheitsgründen keine zusätzlichen Regeln für Spamassassin aufstellen, sondern nur vordefinierten Regeln neue Bewertungen zuordnen oder Absendeadressen zu Schwarzen und Weißen Listen zuordnen. |
|
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/home/myself/.spamassassin/user_prefs version_tag myself whitelist_from *@goodguys.org blacklist_from *@badguys.com
Wer seine Mails nicht nochmals behandeln will, legt sie gleich im Postfach ab. |
|
$ vi /home/hosted/hosteduser/.procmailrc
# # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.mydomain.net:/home/hosted/hosteduser/.procmailrc :0: Maildir/
#!/bin/sh # (c) Thomas Bez <bez@tedesca.net> 2004 # http://www.bez.tedesca.net/homeoff/antispam.html # # mail.myself.net:/etc/postfix/nondelivery.sh # parameter 1: from where (authorized or null) # parameter 2: where to (family, hosted or null) # (shift; shift) # parameter 1: reason "spam", "spf", "unknown" or "virus" # parameter 2: additional virus info (if reason=virus or reason=spf) # parameter 3: $MAIL_FROM or empty # parameter 4: $TO or empty # parameter 5: $RCPT_COUNT or empty # parameter 6: $HELO or empty # parameter 7: $CLIENT or empty # parameter 8: $TIME or empty ################################################################################################################ # initialize ################################################################################################################ cd /etc/postfix || exit 0 PATH=/etc/postfix:/usr/local/bin:/usr/sbin:$PATH; export PATH mydomain=mydomain.net my_received_id="mail.$mydomain (Postfix)" notifier=notify@$mydomain postmaster=postmaster@$mydomain logname=nondelivery.