1<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
2        "http://www.w3.org/TR/html4/loose.dtd">
3
4<html>
5
6<head>
7
8<title>Postfix Backscatter Howto</title>
9
10<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
11
12</head>
13
14<body>
15
16<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix
17Backscatter Howto</h1>
18
19<hr>
20
21<h2>Overview </h2>
22
23<p> This document describes features that require Postfix version
242.0 or later. </p>
25
26<p> Topics covered in this document: </p>
27
28<ul>
29
30<li><a href="#wtf">What is backscatter mail?</a>
31
32<li><a href="#random">How do I block backscatter mail to random
33recipient addresses?</a>
34
35<li><a href="#real">How do I block backscatter mail to real
36recipient addresses?</a>
37
38<ul>
39
40<li><a href="#forged_helo">Blocking backscatter mail with forged
41mail server information</a>
42
43<li><a href="#forged_sender">Blocking backscatter mail with forged
44sender information</a>
45
46<li><a href="#forged_other">Blocking backscatter mail with other
47forged information</a>
48
49<li><a href="#scanner">Blocking backscatter mail from virus
50scanners</a>
51
52</ul>
53
54</ul>
55
56<p> The examples use Perl Compatible Regular Expressions (Postfix
57<a href="pcre_table.5.html">pcre</a>: tables), but also provide a translation to POSIX regular
58expressions (Postfix <a href="regexp_table.5.html">regexp</a>: tables). PCRE is preferred primarily
59because the implementation is often faster.</p>
60
61<h2><a name="wtf">What is backscatter mail?</a></h2>
62
63<p> When a spammer or worm sends mail with forged sender addresses,
64innocent sites are flooded with undeliverable mail notifications.
65This is called backscatter mail.  With Postfix, you know that you're
66a backscatter victim when your logfile goes on and on like this:
67</p>
68
69<blockquote>
70<pre>
71Dec  4 04:30:09 hostname postfix/smtpd[58549]: NOQUEUE: reject:
72RCPT from xxxxxxx[x.x.x.x]: 550 5.1.1 &lt;yyyyyy@your.domain.here&gt;:
73Recipient address rejected: User unknown; from=&lt;&gt;
74to=&lt;yyyyyy@your.domain.here&gt; proto=ESMTP helo=&lt;zzzzzz&gt;
75</pre>
76</blockquote>
77
78<p> What you see are lots of "user unknown" errors with "from=&lt;&gt;".
79These are error reports from MAILER-DAEMONs elsewhere on the Internet.
80</p>
81
82<h2><a name="random">How do I block backscatter mail to random
83recipient addresses?</a></h2>
84
85<p> If your machine receives backscatter mail to random addresses,
86configure Postfix to reject all mail for non-existent recipients
87as described in the <a href="LOCAL_RECIPIENT_README.html">LOCAL_RECIPIENT_README</a> and
88<a href="STANDARD_CONFIGURATION_README.html">STANDARD_CONFIGURATION_README</a> documentation.  </p>
89
90<p> If your machine runs Postfix 2.0 and earlier, disable the "pause
91before reject" feature in the SMTP server. If your system is under
92stress then it should not waste time. </p>
93
94<blockquote>
95<pre>
96/etc/postfix/<a href="postconf.5.html">main.cf</a>:
97    # Not needed with Postfix 2.1 and later.
98    <a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> = 0
99
100    # Not needed with Postfix 2.4 and later.
101    <a href="postconf.5.html#unknown_local_recipient_reject_code">unknown_local_recipient_reject_code</a> = 550
102</pre>
103</blockquote>
104
105<h2><a name="real">How do I block backscatter mail to real
106recipient addresses?</a></h2>
107
108<p> When backscatter mail passes the "unknown recipient" barrier,
109there still is no need to despair.  Many mail systems are kind
110enough to attach the message headers of the undeliverable mail in
111the non-delivery notification. These message headers contain
112information that you can use to recognize and block forged mail.
113</p>
114
115<h3><a name="forged_helo">Blocking backscatter mail with forged
116mail server information</a></h3>
117
118<p> Although my email address is "wietse@porcupine.org", all my
119mail systems announce themselves with the SMTP HELO command as
120"hostname.porcupine.org".  Thus, if returned mail has a Received:
121message header like this: </p>
122
123<blockquote>
124<pre>
125Received: from porcupine.org ...
126</pre>
127</blockquote>
128
129<p> Then I know that this is almost certainly forged mail (almost;
130see <a href="#caveats">next section</a> for the fly in the ointment).
131Mail that is really
132sent by my systems looks like this: </p>
133
134<blockquote>
135<pre>
136Received: from hostname.porcupine.org ...
137</pre>
138</blockquote>
139
140<p> For the same reason the following message headers are very likely
141to be the result of forgery:</p>
142
143<blockquote>
144<pre>
145Received: from host.example.com ([1.2.3.4] helo=porcupine.org) ...
146Received: from [1.2.3.4] (port=12345 helo=porcupine.org) ...
147Received: from host.example.com (HELO porcupine.org) ...
148Received: from host.example.com (EHLO porcupine.org) ...
149</pre>
150</blockquote>
151
152<p> Some forgeries show up in the way that a mail server reports
153itself in Received: message headers. Keeping in mind that all my
154systems have a mail server name of <i>hostname</i>.porcupine.org,
155the following is definitely a forgery:</p>
156
157<blockquote>
158<pre>
159Received: by porcupine.org ...
160Received: from host.example.com ( ... ) by porcupine.org ...
161</pre>
162</blockquote>
163
164<p> Another frequent sign of forgery is the Message-ID: header. My
165systems produce a Message-ID: of
166&lt;<i>stuff</i>@<i>hostname</i>.porcupine.org&gt;.  The following
167are forgeries, especially the first one:
168
169<blockquote>
170<pre>
171Message-ID: &lt;1cb479435d8eb9.2beb1.qmail@porcupine.org&gt;
172Message-ID: &lt;yulszqocfzsficvzzju@porcupine.org&gt;
173</pre>
174</blockquote>
175
176<p> To block such backscatter I use <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>
177patterns like this: </p>
178
179<blockquote>
180<pre>
181/etc/postfix/<a href="postconf.5.html">main.cf</a>:
182    <a href="postconf.5.html#header_checks">header_checks</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/header_checks
183    <a href="postconf.5.html#body_checks">body_checks</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/body_checks
184
185/etc/postfix/header_checks:
186    if /^Received:/
187    /^Received: +from +(porcupine\.org) +/
188        reject forged client name in Received: header: $1
189    /^Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
190        reject forged client name in Received: header: $2
191    /^Received:.* +by +(porcupine\.org)\b/
192        reject forged mail server name in Received: header: $1
193    endif
194    /^Message-ID:.* &lt;!&amp;!/ DUNNO
195    /^Message-ID:.*@(porcupine\.org)/
196	reject forged domain name in Message-ID: header: $1
197
198/etc/postfix/body_checks:
199    if /^[&gt; ]*Received:/
200    /^[&gt; ]*Received: +from +(porcupine\.org) /
201        reject forged client name in Received: header: $1
202    /^[&gt; ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
203        reject forged client name in Received: header: $2
204    /^[&gt; ]*Received:.* +by +(porcupine\.org)\b/
205        reject forged mail server name in Received: header: $1
206    endif
207    /^[&gt; ]*Message-ID:.* &lt;!&amp;!/ DUNNO
208    /^[&gt; ]*Message-ID:.*@(porcupine\.org)/
209	reject forged domain name in Message-ID: header: $1
210</pre>
211</blockquote>
212
213<p> Notes: </p>
214
215<ul>
216
217<li> <p> The example uses <a href="pcre_table.5.html">pcre</a>: tables mainly for speed; with minor
218modifications, you can use <a href="regexp_table.5.html">regexp</a>: tables as explained below. </p>
219
220<li> <p> The example is simplified for educational purposes.  In
221reality my patterns list multiple domain names, as
222"<tt>(domain|domain|...)</tt>".  </p>
223
224<li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
225the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
226
227<li> <p> The "<tt>\(</tt>" and "<tt>\)</tt>" match "<tt>(</tt>"
228and "<tt>)</tt>" literally. Without the "<tt>\</tt>", the "<tt>(</tt>"
229and "<tt>)</tt>" would be grouping operators.  </p>
230
231<li> <p> The "<tt>\b</tt>" is used here to match the end of a word.
232If you use <a href="regexp_table.5.html">regexp</a>: tables, specify "<tt>[[:&gt;:]]</tt>" (on some
233systems you should specify "<tt>\&gt;</tt>" instead; for details
234see your system documentation).
235
236<li> <p> The "if /pattern/" and "endif" eliminate unnecessary
237matching attempts. DO NOT indent lines starting with /pattern/
238between the "if" and "endif"! </p>
239
240<li> <p> The two "<tt>Message-ID:.* &lt;!&amp;!</tt>" rules are
241workarounds for some versions of Outlook express, as described in
242the <a href="#caveats"> caveats </a> section below.
243
244</ul>
245
246<p><a name="caveats"><strong>Caveats</strong></a></p>
247
248<ul>
249
250<li>
251
252<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
253that is identical to the sender address domain part. If you have
254such clients then the above patterns would block legitimate email.
255</p>
256
257<p> My network has only one such machine, and to prevent its mail
258from being blocked I have configured it to send mail as
259user@hostname.porcupine.org. On the Postfix server, a canonical
260mapping translates this temporary address into user@porcupine.org.
261</p>
262
263<blockquote>
264<pre>
265/etc/postfix/<a href="postconf.5.html">main.cf</a>:
266    <a href="postconf.5.html#canonical_maps">canonical_maps</a> = hash:/etc/postfix/canonical
267
268/etc/postfix/canonical:
269    @hostname.porcupine.org @porcupine.org
270</pre>
271</blockquote>
272
273<p> This is of course practical only when you have very few systems
274that send HELO commands like this, and when you never have to send
275mail to a user on such a host. </p>
276
277<p> An alternative would be to remove the hostname from
278"hostname.porcupine.org" with address
279masquerading, as described in the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> document.
280</p>
281
282<li> <p> Reportedly, Outlook 2003 (perhaps Outlook Express, and
283other versions as well) present substantially different Message-ID
284headers depending upon whether or not a DSN is requested (via Options
285"Request a delivery receipt for this message"). </p>
286
287<p> When a DSN is requested, Outlook 2003 uses a Message-ID string
288that ends in the sender's domain name: </p>
289
290<blockquote>
291<pre>
292Message-ID: &lt;!&amp;! ...very long string... ==@example.com&gt;
293</pre>
294</blockquote>
295
296<p> where <i>example.com</i> is the domain name part of the email
297address specified in Outlook's account settings for the user.  Since
298many users configure their email addresses as <i>username@example.com</i>,
299messages with DSN turned on will trigger the REJECT action in the
300previous section. </p>
301
302<p> If you have such clients then you can to exclude their Message-ID
303strings with the two "<tt>Message-ID:.* &lt;!&amp;!</tt>" patterns
304that are shown in the previous section.  Otherwise you will not be
305able to use the two backscatter rules to stop forged Message ID
306strings.  Of course this workaround may break the next time Outlook
307is changed.  </p>
308
309</ul>
310
311<h3><a name="forged_sender">Blocking backscatter mail with forged
312sender information</a></h3>
313
314Like many people I still have a few email addresses in domains that
315I used in the past. Mail for those addresses is forwarded to my
316current address.  Most of the backscatter mail that I get claims
317to be sent from these addresses.  Such mail is obviously forged
318and is very easy to stop.
319
320<blockquote>
321<pre>
322/etc/postfix/<a href="postconf.5.html">main.cf</a>:
323    <a href="postconf.5.html#header_checks">header_checks</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/header_checks
324    <a href="postconf.5.html#body_checks">body_checks</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/body_checks
325
326/etc/postfix/header_checks:
327    /^(From|Return-Path):.*\b(user@domain\.tld)\b/
328        reject forged sender address in $1: header: $2
329
330/etc/postfix/body_checks:
331    /^[&gt; ]*(From|Return-Path):.*\b(user@domain\.tld)\b/
332        reject forged sender address in $1: header: $2
333</pre>
334</blockquote>
335
336<p> Notes: </p>
337
338<ul>
339
340<li> <p> The example uses <a href="pcre_table.5.html">pcre</a>: tables mainly for speed; with minor
341modifications, you can use <a href="regexp_table.5.html">regexp</a>: tables as explained below. </p>
342
343<li> <p> The example is simplified for educational purposes.  In
344reality, my patterns list multiple email addresses as
345"<tt>(user1@domain1\.tld|user2@domain2\.tld)</tt>".  </p>
346
347<li> <p> The two "<tt>\b</tt>" as used in "<tt>\b(user@domain\.tld)\b</tt>"
348match the beginning and end of a word, respectively.  If you use
349<a href="regexp_table.5.html">regexp</a>: tables, specify "<tt>[[:&lt;:]]</tt> and <tt>[[:&gt;:]]</tt>"
350(on some systems you should specify "<tt>\&lt;</tt> and <tt>\&gt;</tt>"
351instead; for details see your system documentation).  </p>
352
353<li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
354the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
355
356</ul>
357
358<h3><a name="forged_other">Blocking backscatter mail with other
359forged information</a></h3>
360
361<p> Another sign of forgery can be found in the IP address that is
362recorded in Received: headers next to your HELO host or domain name.
363This information must be used with care, though. Some mail servers
364are behind a network address translator and never see the true
365client IP address.  </p>
366
367<h3><a name="scanner">Blocking backscatter mail from virus
368scanners</a></h3>
369
370<p> With all the easily recognizable forgeries eliminated, there
371is one category of backscatter mail that remains, and that is
372notifications from virus scanner software. Unfortunately, some
373virus scanning software doesn't know that viruses forge sender
374addresses. To make matters worse, the software also doesn't know
375how to report a mail delivery problem, so that we cannot use the
376above techniques to recognize forgeries.  </p>
377
378<p> Recognizing virus scanner mail is an error prone process,
379because there is a lot of variation in report formats.  The following
380is only a small example of message header patterns.  For a large
381collection of header and body patterns that recognize virus
382notification email, see <a href="http://www.dkuug.dk/keld/virus/">http://www.dkuug.dk/keld/virus/</a>
383or <a href="http://www.t29.dk/antiantivirus.txt">http://www.t29.dk/antiantivirus.txt</a>.  </p>
384
385<blockquote>
386<pre>
387/etc/postfix/header_checks:
388    /^Subject: *Your email contains VIRUSES/ DISCARD virus notification
389    /^Content-Disposition:.*VIRUS1_DETECTED_AND_REMOVED/
390        DISCARD virus notification
391    /^Content-Disposition:.*VirusWarning.txt/ DISCARD virus notification
392</pre>
393</blockquote>
394
395<p> Note: these documents haven't been updated since 2004, so they
396are useful only as a starting point. </p>
397
398<p> A plea to virus or spam scanner operators: please do not make
399the problem worse by sending return mail to forged sender addresses.
400You're only harassing innocent people. If you must return mail to
401the purported sender, please return the full message headers, so
402that the sender can filter out the obvious forgeries. </p>
403
404</body>
405
406</html>
407