411 lines
14 KiB
HTML
411 lines
14 KiB
HTML
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
"https://www.w3.org/TR/html4/loose.dtd">
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>Postfix Backscatter Howto</title>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix
|
|
Backscatter Howto</h1>
|
|
|
|
<hr>
|
|
|
|
<h2>Overview </h2>
|
|
|
|
<p> This document describes features that require Postfix version
|
|
2.0 or later. </p>
|
|
|
|
<p> Topics covered in this document: </p>
|
|
|
|
<ul>
|
|
|
|
<li><a href="#wtf">What is backscatter mail?</a>
|
|
|
|
<li><a href="#random">How do I block backscatter mail to random
|
|
recipient addresses?</a>
|
|
|
|
<li><a href="#real">How do I block backscatter mail to real
|
|
recipient addresses?</a>
|
|
|
|
<ul>
|
|
|
|
<li><a href="#forged_helo">Blocking backscatter mail with forged
|
|
mail server information</a>
|
|
|
|
<li><a href="#forged_sender">Blocking backscatter mail with forged
|
|
sender information</a>
|
|
|
|
<li><a href="#forged_other">Blocking backscatter mail with other
|
|
forged information</a>
|
|
|
|
<li><a href="#scanner">Blocking backscatter mail from virus
|
|
scanners</a>
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
|
<p> The examples use Perl Compatible Regular Expressions (Postfix
|
|
pcre: tables), but also provide a translation to POSIX regular
|
|
expressions (Postfix regexp: tables). PCRE is preferred primarily
|
|
because the implementation is often faster.</p>
|
|
|
|
<h2><a name="wtf">What is backscatter mail?</a></h2>
|
|
|
|
<p> When a spammer or worm sends mail with forged sender addresses,
|
|
innocent sites are flooded with undeliverable mail notifications.
|
|
This is called backscatter mail. With Postfix, you know that you're
|
|
a backscatter victim when your logfile goes on and on like this:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Dec 4 04:30:09 hostname postfix/smtpd[58549]: NOQUEUE: reject:
|
|
RCPT from xxxxxxx[x.x.x.x]: 550 5.1.1 <yyyyyy@your.domain.here>:
|
|
Recipient address rejected: User unknown; from=<>
|
|
to=<yyyyyy@your.domain.here> proto=ESMTP helo=<zzzzzz>
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> What you see are lots of "user unknown" errors with "from=<>".
|
|
These are error reports from MAILER-DAEMONs elsewhere on the Internet,
|
|
about email that was sent with a false sender address in your domain.
|
|
</p>
|
|
|
|
<h2><a name="random">How do I block backscatter mail to random
|
|
recipient addresses?</a></h2>
|
|
|
|
<p> If your machine receives backscatter mail to random addresses,
|
|
configure Postfix to reject all mail for non-existent recipients
|
|
as described in the LOCAL_RECIPIENT_README and
|
|
STANDARD_CONFIGURATION_README documentation. </p>
|
|
|
|
<p> If your machine runs Postfix 2.0 and earlier, disable the "pause
|
|
before reject" feature in the SMTP server. If your system is under
|
|
stress then it should not waste time. </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
/etc/postfix/main.cf:
|
|
# Not needed with Postfix 2.1 and later.
|
|
smtpd_error_sleep_time = 0
|
|
|
|
# Not needed with Postfix 2.4 and later.
|
|
unknown_local_recipient_reject_code = 550
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<h2><a name="real">How do I block backscatter mail to real
|
|
recipient addresses?</a></h2>
|
|
|
|
<p> When backscatter mail passes the "unknown recipient" barrier,
|
|
there still is no need to despair. Many mail systems are kind
|
|
enough to attach the message headers of the undeliverable mail in
|
|
the non-delivery notification. These message headers contain
|
|
information that you can use to recognize and block forged mail.
|
|
</p>
|
|
|
|
<h3><a name="forged_helo">Blocking backscatter mail with forged
|
|
mail server information</a></h3>
|
|
|
|
<p> Although my email address is "wietse@porcupine.org", all my
|
|
mail systems announce themselves with the SMTP HELO command as
|
|
"hostname.porcupine.org". Thus, if returned mail has a Received:
|
|
message header like this: </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Received: from porcupine.org ...
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Then I know that this is almost certainly forged mail (almost;
|
|
see <a href="#caveats">next section</a> for the fly in the ointment).
|
|
Mail that is really
|
|
sent by my systems looks like this: </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Received: from hostname.porcupine.org ...
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> For the same reason the following message headers are very likely
|
|
to be the result of forgery:</p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Received: from host.example.com ([1.2.3.4] helo=porcupine.org) ...
|
|
Received: from [1.2.3.4] (port=12345 helo=porcupine.org) ...
|
|
Received: from host.example.com (HELO porcupine.org) ...
|
|
Received: from host.example.com (EHLO porcupine.org) ...
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Some forgeries show up in the way that a mail server reports
|
|
itself in Received: message headers. Keeping in mind that all my
|
|
systems have a mail server name of <i>hostname</i>.porcupine.org,
|
|
the following is definitely a forgery:</p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Received: by porcupine.org ...
|
|
Received: from host.example.com ( ... ) by porcupine.org ...
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Another frequent sign of forgery is the Message-ID: header. My
|
|
systems produce a Message-ID: of
|
|
<<i>stuff</i>@<i>hostname</i>.porcupine.org>. The following
|
|
are forgeries, especially the first one:
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org>
|
|
Message-ID: <yulszqocfzsficvzzju@porcupine.org>
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> To block such backscatter I use header_checks and body_checks
|
|
patterns like this: </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
/etc/postfix/main.cf:
|
|
header_checks = pcre:/etc/postfix/header_checks
|
|
body_checks = pcre:/etc/postfix/body_checks
|
|
|
|
/etc/postfix/header_checks:
|
|
# Do not indent the patterns between "if" and "endif".
|
|
if /^Received:/
|
|
/^Received: +from +(porcupine\.org) +/
|
|
reject forged client name in Received: header: $1
|
|
/^Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
|
|
reject forged client name in Received: header: $2
|
|
/^Received:.* +by +(porcupine\.org)\b/
|
|
reject forged mail server name in Received: header: $1
|
|
endif
|
|
/^Message-ID:.* <!&!/ DUNNO
|
|
/^Message-ID:.*@(porcupine\.org)/
|
|
reject forged domain name in Message-ID: header: $1
|
|
|
|
/etc/postfix/body_checks:
|
|
# Do not indent the patterns between "if" and "endif".
|
|
if /^[> ]*Received:/
|
|
/^[> ]*Received: +from +(porcupine\.org) /
|
|
reject forged client name in Received: header: $1
|
|
/^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
|
|
reject forged client name in Received: header: $2
|
|
/^[> ]*Received:.* +by +(porcupine\.org)\b/
|
|
reject forged mail server name in Received: header: $1
|
|
endif
|
|
/^[> ]*Message-ID:.* <!&!/ DUNNO
|
|
/^[> ]*Message-ID:.*@(porcupine\.org)/
|
|
reject forged domain name in Message-ID: header: $1
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Notes: </p>
|
|
|
|
<ul>
|
|
|
|
<li> <p> The example uses pcre: tables mainly for speed; with minor
|
|
modifications, you can use regexp: tables as explained below. </p>
|
|
|
|
<li> <p> The example is simplified for educational purposes. In
|
|
reality my patterns list multiple domain names, as
|
|
"<tt>(domain|domain|...)</tt>". </p>
|
|
|
|
<li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
|
|
the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
|
|
|
|
<li> <p> The "<tt>\(</tt>" and "<tt>\)</tt>" match "<tt>(</tt>"
|
|
and "<tt>)</tt>" literally. Without the "<tt>\</tt>", the "<tt>(</tt>"
|
|
and "<tt>)</tt>" would be grouping operators. </p>
|
|
|
|
<li> <p> The "<tt>\b</tt>" is used here to match the end of a word.
|
|
If you use regexp: tables, specify "<tt>[[:>:]]</tt>" (on some
|
|
systems you should specify "<tt>\></tt>" instead; for details
|
|
see your system documentation).
|
|
|
|
<li> <p> The "if /pattern/" and "endif" eliminate unnecessary
|
|
matching attempts. DO NOT indent lines starting with /pattern/
|
|
between the "if" and "endif"! </p>
|
|
|
|
<li> <p> The two "<tt>Message-ID:.* <!&!</tt>" rules are
|
|
workarounds for some versions of Outlook express, as described in
|
|
the <a href="#caveats"> caveats </a> section below.
|
|
|
|
</ul>
|
|
|
|
<p><a name="caveats"><strong>Caveats</strong></a></p>
|
|
|
|
<ul>
|
|
|
|
<li>
|
|
|
|
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
|
|
that is identical to the sender address domain part. If you have
|
|
such clients then the above patterns would block legitimate email.
|
|
</p>
|
|
|
|
<p> My network has only one such machine, and to prevent its mail
|
|
from being blocked I have configured it to send mail as
|
|
user@hostname.porcupine.org. On the Postfix server, a canonical
|
|
mapping translates this temporary address into user@porcupine.org.
|
|
</p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
/etc/postfix/main.cf:
|
|
canonical_maps = hash:/etc/postfix/canonical
|
|
|
|
/etc/postfix/canonical:
|
|
@hostname.porcupine.org @porcupine.org
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> This is of course practical only when you have very few systems
|
|
that send HELO commands like this, and when you never have to send
|
|
mail to a user on such a host. </p>
|
|
|
|
<p> An alternative would be to remove the hostname from
|
|
"hostname.porcupine.org" with address
|
|
masquerading, as described in the ADDRESS_REWRITING_README document.
|
|
</p>
|
|
|
|
<li> <p> Reportedly, Outlook 2003 (perhaps Outlook Express, and
|
|
other versions as well) present substantially different Message-ID
|
|
headers depending upon whether or not a DSN is requested (via Options
|
|
"Request a delivery receipt for this message"). </p>
|
|
|
|
<p> When a DSN is requested, Outlook 2003 uses a Message-ID string
|
|
that ends in the sender's domain name: </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
Message-ID: <!&! ...very long string... ==@example.com>
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> where <i>example.com</i> is the domain name part of the email
|
|
address specified in Outlook's account settings for the user. Since
|
|
many users configure their email addresses as <i>username@example.com</i>,
|
|
messages with DSN turned on will trigger the REJECT action in the
|
|
previous section. </p>
|
|
|
|
<p> If you have such clients then you can exclude their Message-ID
|
|
strings with the two "<tt>Message-ID:.* <!&!</tt>" patterns
|
|
that are shown in the previous section. Otherwise you will not be
|
|
able to use the two backscatter rules to stop forged Message ID
|
|
strings. Of course this workaround may break the next time Outlook
|
|
is changed. </p>
|
|
|
|
</ul>
|
|
|
|
<h3><a name="forged_sender">Blocking backscatter mail with forged
|
|
sender information</a></h3>
|
|
|
|
Like many people I still have a few email addresses in domains that
|
|
I used in the past. Mail for those addresses is forwarded to my
|
|
current address. Most of the backscatter mail that I get claims
|
|
to be sent from these addresses. Such mail is obviously forged
|
|
and is very easy to stop.
|
|
|
|
<blockquote>
|
|
<pre>
|
|
/etc/postfix/main.cf:
|
|
header_checks = pcre:/etc/postfix/header_checks
|
|
body_checks = pcre:/etc/postfix/body_checks
|
|
|
|
/etc/postfix/header_checks:
|
|
/^(From|Return-Path):.*\b(user@domain\.tld)\b/
|
|
reject forged sender address in $1: header: $2
|
|
|
|
/etc/postfix/body_checks:
|
|
/^[> ]*(From|Return-Path):.*\b(user@domain\.tld)\b/
|
|
reject forged sender address in $1: header: $2
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Notes: </p>
|
|
|
|
<ul>
|
|
|
|
<li> <p> The example uses pcre: tables mainly for speed; with minor
|
|
modifications, you can use regexp: tables as explained below. </p>
|
|
|
|
<li> <p> The example is simplified for educational purposes. In
|
|
reality, my patterns list multiple email addresses as
|
|
"<tt>(user1@domain1\.tld|user2@domain2\.tld)</tt>". </p>
|
|
|
|
<li> <p> The two "<tt>\b</tt>" as used in "<tt>\b(user@domain\.tld)\b</tt>"
|
|
match the beginning and end of a word, respectively. If you use
|
|
regexp: tables, specify "<tt>[[:<:]]</tt> and <tt>[[:>:]]</tt>"
|
|
(on some systems you should specify "<tt>\<</tt> and <tt>\></tt>"
|
|
instead; for details see your system documentation). </p>
|
|
|
|
<li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
|
|
the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
|
|
|
|
</ul>
|
|
|
|
<h3><a name="forged_other">Blocking backscatter mail with other
|
|
forged information</a></h3>
|
|
|
|
<p> Another sign of forgery can be found in the IP address that is
|
|
recorded in Received: headers next to your HELO host or domain name.
|
|
This information must be used with care, though. Some mail servers
|
|
are behind a network address translator and never see the true
|
|
client IP address. </p>
|
|
|
|
<h3><a name="scanner">Blocking backscatter mail from virus
|
|
scanners</a></h3>
|
|
|
|
<p> With all the easily recognizable forgeries eliminated, there
|
|
is one category of backscatter mail that remains, and that is
|
|
notifications from virus scanner software. Unfortunately, some
|
|
virus scanning software doesn't know that viruses forge sender
|
|
addresses. To make matters worse, the software also doesn't know
|
|
how to report a mail delivery problem, so that we cannot use the
|
|
above techniques to recognize forgeries. </p>
|
|
|
|
<p> Recognizing virus scanner mail is an error prone process,
|
|
because there is a lot of variation in report formats. The following
|
|
is only a small example of message header patterns. For a large
|
|
collection of header and body patterns that recognize virus
|
|
notification email, see
|
|
https://web.archive.org/web/20100317123907/http://std.dkuug.dk/keld/virus/
|
|
or https://www.t29.dk/antiantivirus.txt. </p>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
/etc/postfix/header_checks:
|
|
/^Subject: *Your email contains VIRUSES/ DISCARD virus notification
|
|
/^Content-Disposition:.*VIRUS1_DETECTED_AND_REMOVED/
|
|
DISCARD virus notification
|
|
/^Content-Disposition:.*VirusWarning.txt/ DISCARD virus notification
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p> Note: these documents haven't been updated since 2004, so they
|
|
are useful only as a starting point. </p>
|
|
|
|
<p> A plea to virus or spam scanner operators: please do not make
|
|
the problem worse by sending return mail to forged sender addresses.
|
|
You're only harassing innocent people. If you must return mail to
|
|
the purported sender, please return the full message headers, so
|
|
that the sender can filter out the obvious forgeries. </p>
|
|
|
|
</body>
|
|
|
|
</html>
|