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=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 18Backscatter Howto</h1> 19 20<hr> 21 22<h2>Overview </h2> 23 24<p> This document describes features that require Postfix version 252.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 34recipient addresses?</a> 35 36<li><a href="#real">How do I block backscatter mail to real 37recipient addresses?</a> 38 39<ul> 40 41<li><a href="#forged_helo">Blocking backscatter mail with forged 42mail server information</a> 43 44<li><a href="#forged_sender">Blocking backscatter mail with forged 45sender information</a> 46 47<li><a href="#forged_other">Blocking backscatter mail with other 48forged information</a> 49 50<li><a href="#scanner">Blocking backscatter mail from virus 51scanners</a> 52 53</ul> 54 55</ul> 56 57<p> The examples use Perl Compatible Regular Expressions (Postfix 58pcre: tables), but also provide a translation to POSIX regular 59expressions (Postfix regexp: tables). PCRE is preferred primarily 60because 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, 65innocent sites are flooded with undeliverable mail notifications. 66This is called backscatter mail. With Postfix, you know that you're 67a backscatter victim when your logfile goes on and on like this: 68</p> 69 70<blockquote> 71<pre> 72Dec 4 04:30:09 hostname postfix/smtpd[58549]: NOQUEUE: reject: 73RCPT from xxxxxxx[x.x.x.x]: 550 5.1.1 <yyyyyy@your.domain.here>: 74Recipient address rejected: User unknown; from=<> 75to=<yyyyyy@your.domain.here> proto=ESMTP helo=<zzzzzz> 76</pre> 77</blockquote> 78 79<p> What you see are lots of "user unknown" errors with "from=<>". 80These are error reports from MAILER-DAEMONs elsewhere on the Internet, 81about 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 85recipient addresses?</a></h2> 86 87<p> If your machine receives backscatter mail to random addresses, 88configure Postfix to reject all mail for non-existent recipients 89as described in the LOCAL_RECIPIENT_README and 90STANDARD_CONFIGURATION_README documentation. </p> 91 92<p> If your machine runs Postfix 2.0 and earlier, disable the "pause 93before reject" feature in the SMTP server. If your system is under 94stress then it should not waste time. </p> 95 96<blockquote> 97<pre> 98/etc/postfix/main.cf: 99 # Not needed with Postfix 2.1 and later. 100 smtpd_error_sleep_time = 0 101 102 # Not needed with Postfix 2.4 and later. 103 unknown_local_recipient_reject_code = 550 104</pre> 105</blockquote> 106 107<h2><a name="real">How do I block backscatter mail to real 108recipient addresses?</a></h2> 109 110<p> When backscatter mail passes the "unknown recipient" barrier, 111there still is no need to despair. Many mail systems are kind 112enough to attach the message headers of the undeliverable mail in 113the non-delivery notification. These message headers contain 114information that you can use to recognize and block forged mail. 115</p> 116 117<h3><a name="forged_helo">Blocking backscatter mail with forged 118mail server information</a></h3> 119 120<p> Although my email address is "wietse@porcupine.org", all my 121mail systems announce themselves with the SMTP HELO command as 122"hostname.porcupine.org". Thus, if returned mail has a Received: 123message header like this: </p> 124 125<blockquote> 126<pre> 127Received: from porcupine.org ... 128</pre> 129</blockquote> 130 131<p> Then I know that this is almost certainly forged mail (almost; 132see <a href="#caveats">next section</a> for the fly in the ointment). 133Mail that is really 134sent by my systems looks like this: </p> 135 136<blockquote> 137<pre> 138Received: from hostname.porcupine.org ... 139</pre> 140</blockquote> 141 142<p> For the same reason the following message headers are very likely 143to be the result of forgery:</p> 144 145<blockquote> 146<pre> 147Received: from host.example.com ([1.2.3.4] helo=porcupine.org) ... 148Received: from [1.2.3.4] (port=12345 helo=porcupine.org) ... 149Received: from host.example.com (HELO porcupine.org) ... 150Received: 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 155itself in Received: message headers. Keeping in mind that all my 156systems have a mail server name of <i>hostname</i>.porcupine.org, 157the following is definitely a forgery:</p> 158 159<blockquote> 160<pre> 161Received: by porcupine.org ... 162Received: 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 167systems produce a Message-ID: of 168<<i>stuff</i>@<i>hostname</i>.porcupine.org>. The following 169are forgeries, especially the first one: 170 171<blockquote> 172<pre> 173Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org> 174Message-ID: <yulszqocfzsficvzzju@porcupine.org> 175</pre> 176</blockquote> 177 178<p> To block such backscatter I use header_checks and body_checks 179patterns like this: </p> 180 181<blockquote> 182<pre> 183/etc/postfix/main.cf: 184 header_checks = pcre:/etc/postfix/header_checks 185 body_checks = pcre:/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:.* <!&!/ 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 /^[> ]*Received:/ 204 /^[> ]*Received: +from +(porcupine\.org) / 205 reject forged client name in Received: header: $1 206 /^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/ 207 reject forged client name in Received: header: $2 208 /^[> ]*Received:.* +by +(porcupine\.org)\b/ 209 reject forged mail server name in Received: header: $1 210 endif 211 /^[> ]*Message-ID:.* <!&!/ DUNNO 212 /^[> ]*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 pcre: tables mainly for speed; with minor 222modifications, you can use regexp: tables as explained below. </p> 223 224<li> <p> The example is simplified for educational purposes. In 225reality 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 229the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p> 230 231<li> <p> The "<tt>\(</tt>" and "<tt>\)</tt>" match "<tt>(</tt>" 232and "<tt>)</tt>" literally. Without the "<tt>\</tt>", the "<tt>(</tt>" 233and "<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. 236If you use regexp: tables, specify "<tt>[[:>:]]</tt>" (on some 237systems you should specify "<tt>\></tt>" instead; for details 238see your system documentation). 239 240<li> <p> The "if /pattern/" and "endif" eliminate unnecessary 241matching attempts. DO NOT indent lines starting with /pattern/ 242between the "if" and "endif"! </p> 243 244<li> <p> The two "<tt>Message-ID:.* <!&!</tt>" rules are 245workarounds for some versions of Outlook express, as described in 246the <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 257that is identical to the sender address domain part. If you have 258such 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 262from being blocked I have configured it to send mail as 263user@hostname.porcupine.org. On the Postfix server, a canonical 264mapping translates this temporary address into user@porcupine.org. 265</p> 266 267<blockquote> 268<pre> 269/etc/postfix/main.cf: 270 canonical_maps = hash:/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 278that send HELO commands like this, and when you never have to send 279mail 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 283masquerading, as described in the ADDRESS_REWRITING_README document. 284</p> 285 286<li> <p> Reportedly, Outlook 2003 (perhaps Outlook Express, and 287other versions as well) present substantially different Message-ID 288headers 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 292that ends in the sender's domain name: </p> 293 294<blockquote> 295<pre> 296Message-ID: <!&! ...very long string... ==@example.com> 297</pre> 298</blockquote> 299 300<p> where <i>example.com</i> is the domain name part of the email 301address specified in Outlook's account settings for the user. Since 302many users configure their email addresses as <i>username@example.com</i>, 303messages with DSN turned on will trigger the REJECT action in the 304previous section. </p> 305 306<p> If you have such clients then you can exclude their Message-ID 307strings with the two "<tt>Message-ID:.* <!&!</tt>" patterns 308that are shown in the previous section. Otherwise you will not be 309able to use the two backscatter rules to stop forged Message ID 310strings. Of course this workaround may break the next time Outlook 311is changed. </p> 312 313</ul> 314 315<h3><a name="forged_sender">Blocking backscatter mail with forged 316sender information</a></h3> 317 318Like many people I still have a few email addresses in domains that 319I used in the past. Mail for those addresses is forwarded to my 320current address. Most of the backscatter mail that I get claims 321to be sent from these addresses. Such mail is obviously forged 322and is very easy to stop. 323 324<blockquote> 325<pre> 326/etc/postfix/main.cf: 327 header_checks = pcre:/etc/postfix/header_checks 328 body_checks = pcre:/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 /^[> ]*(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 pcre: tables mainly for speed; with minor 345modifications, you can use regexp: tables as explained below. </p> 346 347<li> <p> The example is simplified for educational purposes. In 348reality, 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>" 352match the beginning and end of a word, respectively. If you use 353regexp: tables, specify "<tt>[[:<:]]</tt> and <tt>[[:>:]]</tt>" 354(on some systems you should specify "<tt>\<</tt> and <tt>\></tt>" 355instead; for details see your system documentation). </p> 356 357<li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without 358the "<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 363forged information</a></h3> 364 365<p> Another sign of forgery can be found in the IP address that is 366recorded in Received: headers next to your HELO host or domain name. 367This information must be used with care, though. Some mail servers 368are behind a network address translator and never see the true 369client IP address. </p> 370 371<h3><a name="scanner">Blocking backscatter mail from virus 372scanners</a></h3> 373 374<p> With all the easily recognizable forgeries eliminated, there 375is one category of backscatter mail that remains, and that is 376notifications from virus scanner software. Unfortunately, some 377virus scanning software doesn't know that viruses forge sender 378addresses. To make matters worse, the software also doesn't know 379how to report a mail delivery problem, so that we cannot use the 380above techniques to recognize forgeries. </p> 381 382<p> Recognizing virus scanner mail is an error prone process, 383because there is a lot of variation in report formats. The following 384is only a small example of message header patterns. For a large 385collection of header and body patterns that recognize virus 386notification email, see 387https://web.archive.org/web/20100317123907/http://std.dkuug.dk/keld/virus/ 388or http://www.t29.dk/antiantivirus.txt. </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 401are useful only as a starting point. </p> 402 403<p> A plea to virus or spam scanner operators: please do not make 404the problem worse by sending return mail to forged sender addresses. 405You're only harassing innocent people. If you must return mail to 406the purported sender, please return the full message headers, so 407that the sender can filter out the obvious forgeries. </p> 408 409</body> 410 411</html> 412