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 <yyyyyy@your.domain.here>: 73Recipient address rejected: User unknown; from=<> 74to=<yyyyyy@your.domain.here> proto=ESMTP helo=<zzzzzz> 75</pre> 76</blockquote> 77 78<p> What you see are lots of "user unknown" errors with "from=<>". 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<<i>stuff</i>@<i>hostname</i>.porcupine.org>. The following 168are forgeries, especially the first one: 169 170<blockquote> 171<pre> 172Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org> 173Message-ID: <yulszqocfzsficvzzju@porcupine.org> 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:.* <!&!/ 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 /^[> ]*Received:/ 203 /^[> ]*Received: +from +(porcupine\.org) / 204 reject forged client name in Received: header: $1 205 /^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/ 206 reject forged client name in Received: header: $2 207 /^[> ]*Received:.* +by +(porcupine\.org)\b/ 208 reject forged mail server name in Received: header: $1 209 endif 210 /^[> ]*Message-ID:.* <!&!/ DUNNO 211 /^[> ]*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>[[:>:]]</tt>" (on some 236systems you should specify "<tt>\></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:.* <!&!</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: <!&! ...very long string... ==@example.com> 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:.* <!&!</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 /^[> ]*(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>[[:<:]]</tt> and <tt>[[:>:]]</tt>" 353(on some systems you should specify "<tt>\<</tt> and <tt>\></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