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