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