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 <yyyyyy (a] your.domain.here>: 74 Recipient address rejected: User unknown; from=<> 75 to=<yyyyyy (a] 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=<>". 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 <<i>stuff</i>@<i>hostname</i>.porcupine.org>. The following 169 are forgeries, especially the first one: 170 171 <blockquote> 172 <pre> 173 Message-ID: <1cb479435d8eb9.2beb1.qmail (a] porcupine.org> 174 Message-ID: <yulszqocfzsficvzzju (a] porcupine.org> 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:.* <!&!/ 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 <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>[[:>:]]</tt>" (on some 237 systems you should specify "<tt>\></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:.* <!&!</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: <!&! ...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 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:.* <!&!</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 /^[> ]*(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>[[:<:]]</tt> and <tt>[[:>:]]</tt>" 354 (on some systems you should specify "<tt>\<</tt> and <tt>\></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