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 Built-in Content Inspection</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=""> 18Postfix Built-in Content Inspection</h1> 19 20<hr> 21 22<h2>Built-in content inspection introduction </h2> 23 24<p> Postfix supports a built-in filter mechanism that examines 25message header and message body content, one line at a time, before 26it is stored in the Postfix queue. The filter is usually implemented 27with POSIX or PCRE regular expressions, as described in the 28header_checks(5) manual page. </p> 29 30<p> The original purpose of the built-in filter is to stop an 31outbreak of specific email worms or viruses, and it does this job 32well. The filter has also helped to block bounced junk email, 33bounced email from worms or viruses, and notifications from virus 34detection systems. Information about this secondary application 35is given in the BACKSCATTER_README document. </p> 36 37<p> Because the built-in filter is optimized for stopping specific 38worms and virus outbreaks, it has <a href="#limitations">limitations</a> 39that make it NOT suitable for general junk email and virus detection. 40For that, you should use one of the external content inspection 41methods that are described in the FILTER_README, SMTPD_PROXY_README 42and MILTER_README documents. </p> 43 44<p> The following diagram gives an over-all picture of how Postfix 45built-in content inspection works: </p> 46 47<blockquote> 48 49<table> 50 51<tr> 52 53 <td colspan="4"> <td bgcolor="#f0f0ff" align="center" 54 valign="middle"> Postmaster<br> notifications </td> 55 56</tr> 57 58<tr> 59 60 <td colspan="4"> <td align="center"> <tt> |<br>v </tt></td> 61 62</tr> 63 64<tr> 65 66 <td bgcolor="#f0f0ff" align="center" valign="middle"> 67 Network or<br> local users </td> 68 69 <td align="center" valign="middle"> <tt> -> </tt> </td> 70 71 <td bgcolor="#f0f0ff" align="center" valign="middle"> 72 73 <b> Built-in<br> filter</b> </td> 74 75 <td align="center" valign="middle"> <tt> -> </tt> </td> 76 77 <td bgcolor="#f0f0ff" align="center" valign="middle"> 78 Postfix<br> queue </td> 79 80 <td align="center" valign="middle"> <tt> -> </tt> </td> 81 82 <td bgcolor="#f0f0ff" align="center" valign="middle"> 83 Delivery<br> agents </td> 84 85 <td align="center" valign="middle"> <tt> -> </tt> </td> 86 87 <td bgcolor="#f0f0ff" align="center" valign="middle"> 88 Network or<br> local mailbox </td> 89 90</tr> 91 92<tr> 93 94 <td colspan="4"> <td align="center"> ^<br> <tt> | </tt> </td> 95 <td> </td> <td align="center"> <tt> |<br>v </tt> </td> 96 97</tr> 98 99<tr> 100 101 <td colspan="4"> <td colspan="3" bgcolor="#f0f0ff" align="center" 102 valign="middle"> Undeliverable mail<br> Forwarded mail</td> 103 104</tr> 105 106</table> 107 108</blockquote> 109 110<p> The picture makes clear that the filter works while Postfix is 111receiving new mail. This means that Postfix can reject mail from 112the network without having to return undeliverable mail to the 113originator address (which is often spoofed anyway). However, this 114ability comes at a price: if mail inspection takes too much time, 115then the remote client will time out, and the client may send the 116same message repeatedly. </p> 117 118<p>Topics covered by this document: </p> 119 120<ul> 121 122<li><a href="#what">What mail is subjected to header/body checks </a> 123 124<li><a href="#limitations">Limitations of Postfix header/body checks </a> 125 126<li><a href="#daily">Preventing daily mail status reports from being blocked </a> 127 128<li><a href="#remote_only">Configuring header/body checks for mail from outside users only</a> 129 130<li><a href="#mx_submission">Configuring different header/body checks for MX service and submission service</a> 131 132<li><a href="#domain_except">Configuring header/body checks for mail to some domains only</a> 133 134</ul> 135 136<h2><a name="what">What mail is subjected to header/body checks </a></h2> 137 138<p> Postfix header/body checks are implemented by the cleanup(8) 139server before it injects mail into the incoming queue. The diagram 140below zooms in on the cleanup(8) server, and shows that this server 141handles mail from many different sources. In order to keep the 142diagram readable, the sources of postmaster notifications are not 143shown, because they can be produced by many Postfix daemon processes. 144</p> 145 146<blockquote> 147 148<table> 149 150<tr> <td colspan="2"> </td> <td bgcolor="#f0f0ff" align="center" 151valign="middle"> bounce(8)<br> (undeliverable) </td> </tr> 152 153<tr> <td bgcolor="#f0f0ff" align="center" valign="middle"> <b> 154smtpd(8)<br> (network)</b> </td> <td align="left" valign="bottom"> 155<tt> \ </tt> </td> <td align="center" valign="middle"> <tt> |<br>v 156</tt> </td> </tr> 157 158<tr> <td> </td> <td> </td> </tr> 159 160<tr> <td bgcolor="#f0f0ff" align="center" valign="middle"> <b> 161qmqpd(8)<br> (network)</b> </td> <td align="center" valign="middle"> 162<tt> -\<br>-/ </tt> </td> <td bgcolor="#f0f0ff" align="center" 163valign="middle"> cleanup(8) </td> <td align="center" valign="middle"> 164<tt> -> </tt> </td> <td bgcolor="#f0f0ff" align="center" 165valign="middle"> <a href="QSHAPE_README.html#incoming_queue"> 166incoming<br> queue </a> </td> </tr> 167 168<tr> <td bgcolor="#f0f0ff" align="center" valign="middle"> <b> 169pickup(8)<br> (local)</b> </td> <td align="left" valign="top"> <tt> 170/ </tt> </td> <td align="center" valign="middle"> ^<br> <tt> | 171</tt> </td> </tr> 172 173<tr> <td colspan="2"> </td> <td bgcolor="#f0f0ff" align="center" 174valign="middle"> local(8)<br> (forwarded) </td> </tr> 175 176</table> 177 178</blockquote> 179 180<p> For efficiency reasons, only mail that enters from outside of 181Postfix is inspected with header/body checks. It would be inefficient 182to filter already filtered mail again, and it would be undesirable 183to block postmaster notifications. The table below summarizes what 184mail is and is not subject to header/body checks. </p> 185 186<blockquote> 187 188<table border="1"> 189 190<tr> <th> Message type </th> <th> Source </th> <th> Header/body checks? </th> </tr> 191 192<tr> <td> Undeliverable mail </td> <td> bounce(8) </td> <td> No </td> </tr> 193 194<tr> <td> Network mail </td> <td> smtpd(8) </td> <td> Configurable </td> </tr> 195 196<tr> <td> Network mail </td> <td> qmqpd(8) </td> <td> Configurable </td> </tr> 197 198<tr> <td> Local submission </td> <td> pickup(8) </td> <td> Configurable </td> </tr> 199 200<tr> <td> Local forwarding </td> <td> local(8) </td> <td> No </td> </tr> 201 202<tr> <td> Postmaster notice </td> <td> many </td> <td> No </td> </tr> 203 204</table> 205 206</blockquote> 207 208<p> How does Postfix decide what mail needs to be filtered? It 209would be clumsy to make the decision in the cleanup(8) server, as 210this program receives mail from so many different sources. Instead, 211header/body checks are requested by the source. Examples of how 212to turn off header/body checks for mail received with smtpd(8), 213qmqpd(8) or pickup(8) are given below under "<a 214href="#remote_only">Configuring header/body checks for mail from 215outside users only</a>", "<a href="#mx_submission">Configuring 216different header/body checks for MX service and submission 217service</a>", and "<a href="#domain_except">Configuring 218header/body checks for mail to some domains only</a>". </p> 219 220<h2><a name="limitations">Limitations of Postfix header/body checks </a></h2> 221 222<ul> 223 224<li> <p> Header/body checks do not decode message headers or message 225body content. For example, if text in the message body is BASE64 226encoded (RFC 2045) then your regular expressions will have to match 227the BASE64 encoded form. Likewise, message headers with encoded 228non-ASCII characters (RFC 2047) need to be matched in their encoded 229form. </p> 230 231<li> <p> Header/body checks cannot filter on a combination of 232message headers or body lines. Header/body checks examine content 233one message header at a time, or one message body line at a time, 234and cannot carry a decision over to the next message header or body 235line. </p> 236 237<li> <p> Header/body checks cannot depend on the recipient of a 238message. </p> 239 240<ul> 241 242<li> <p> One message can have multiple recipients, and all recipients 243of a message receive the same treatment. Workarounds have been 244proposed that involve selectively deferring some recipients of 245multi-recipient mail, but that results in poor SMTP performance 246and does not work for non-SMTP mail. </p> 247 248<li> <p> Some sources of mail send the headers and content ahead 249of the recipient information. It would be inefficient to buffer up 250an entire message before deciding if it needs to be filtered, and 251it would be clumsy to filter mail and to buffer up all the actions 252until it is known whether those actions need to be executed. </p> 253 254</ul> 255 256<li> <p> Despite warnings, some people try to use the built-in 257filter feature for general junk email and/or virus blocking, using 258hundreds or even thousands of regular expressions. This can result 259in catastrophic performance failure. The symptoms are as follows: 260</p> 261 262<ul> 263 264<li> <p> The cleanup(8) processes use up all available CPU time in 265order to process the regular expressions, and/or they use up all 266available memory so that the system begins to swap. This slows down 267all incoming mail deliveries. </p> 268 269<li> <p> As Postfix needs more and more time to receive an email 270message, the number of simultaneous SMTP sessions increases to the 271point that the SMTP server process limit is reached. </p> 272 273<li> <p> While all SMTP server processes are waiting for the 274cleanup(8) servers to finish, new SMTP clients have to wait until 275an SMTP server process becomes available. This causes mail deliveries 276to time out before they have even begun. </p> 277 278</ul> 279 280<p> The remedy for this type of performance problem is simple: 281don't use header/body checks for general junk email and/or virus 282blocking, and don't filter mail before it is queued. When performance 283is a concern, use an external content filter that runs after mail 284is queued, as described in the FILTER_README document. </p> 285 286</ul> 287 288<h2><a name="daily">Preventing daily mail status reports from being blocked </a></h2> 289 290<p>The following is quoted from Jim Seymour's Pflogsumm FAQ at 291http://jimsun.linxnet.com/downloads/pflogsumm-faq.txt. Pflogsumm 292is a program that analyzes Postfix logs, including the logging from 293rejected mail. If these logs contain text that was rejected by 294Postfix body_checks patterns, then the logging is also likely to 295be rejected by those same body_checks patterns. This problem does 296not exist with header_checks patterns, because those are not applied 297to the text that is part of the mail status report. </p> 298 299<blockquote> 300 301<p>You configure Postfix to do body checks, Postfix does its thing, 302Pflogsumm reports it and Postfix catches the same string in the 303Pflogsumm report. There are several solutions to this. </p> 304 305<p> Wolfgang Zeikat contributed this: </p> 306 307<blockquote> 308<pre> 309#!/usr/bin/perl 310use MIME::Lite; 311 312### Create a new message: 313$msg = MIME::Lite->new( 314 From => 'your@send.er', 315 To => 'your@recipie.nt', 316 # Cc => 'some@other.com, some@more.com', 317 Subject => 'pflogsumm', 318 Date => `date`, 319 Type => 'text/plain', 320 Encoding => 'base64', 321 Path => '/tmp/pflogg', 322); 323 324$msg->send; 325</pre> 326</blockquote> 327 328<p> Where "/tmp/pflogg" is the output of Pflogsumm. This puts Pflogsumm's 329output in a base64 MIME attachment. </p> 330 331</blockquote> 332 333<p> Note by Wietse: if you run this on a machine that is accessible 334by untrusted users, it is safer to store the Pflogsumm report in 335a directory that is not world writable. </p> 336 337<blockquote> 338 339<p> In a follow-up to a thread in the postfix-users mailing list, Ralf 340Hildebrandt noted: </p> 341 342<blockquote> <p> "mpack does the same thing." </p> </blockquote> 343 344</blockquote> 345 346<p> And it does. Which tool one should use is a matter of preference. 347</p> 348 349<p> Other solutions involve additional body_checks rules that make 350exceptions for daily mail status reports, but this is not recommended. 351Such rules slow down all mail and complicate Postfix maintenance. 352</p> 353 354<h2><a name="remote_only">Configuring header/body checks for mail from outside users only</a></h2> 355 356<p> The following information applies to Postfix 2.1 and later. 357Earlier 358Postfix versions do not support the receive_override_options feature. 359</p> 360 361<p> The easiest approach is to configure ONE Postfix instance with 362multiple SMTP server IP addresses in master.cf: </p> 363 364<ul> 365 366<li> <p> Two SMTP server IP addresses for mail from inside users 367only, with header/body filtering turned off, and a local mail pickup 368service with header/body filtering turned off. </p> 369 370<pre> 371/etc/postfix.master.cf: 372 # ================================================================== 373 # service type private unpriv chroot wakeup maxproc command 374 # (yes) (yes) (yes) (never) (100) 375 # ================================================================== 376 1.2.3.4:smtp inet n - n - - smtpd 377 -o receive_override_options=no_header_body_checks 378 127.0.0.1:smtp inet n - n - - smtpd 379 -o receive_override_options=no_header_body_checks 380 pickup fifo n - n 60 1 pickup 381 -o receive_override_options=no_header_body_checks 382</pre> 383 384<li> <p> Add some firewall rule to prevent access to 1.2.3.4:smtp 385from the outside world. </p> 386 387<li> <p> One SMTP server address for mail from outside users with 388header/body filtering turned on via main.cf. </p> 389 390<pre> 391/etc/postfix.master.cf: 392 # ================================================================= 393 # service type private unpriv chroot wakeup maxproc command 394 # (yes) (yes) (yes) (never) (100) 395 # ================================================================= 396 1.2.3.5:smtp inet n - n - - smtpd 397</pre> 398 399</ul> 400 401<h2><a name="mx_submission">Configuring different header/body checks for MX service and submission service</a></h2> 402 403<p> If authorized user submissions require different header/body 404checks than mail from remote MTAs, then this is possible as long 405as you have separate mail streams for authorized users and for MX 406service. </p> 407 408<p> The example below assumes that authorized users connect to TCP 409port 587 (submission) or 465 (smtps), and that remote MTAs connect 410to TCP port 25 (smtp). </p> 411 412<p> First, we define a few "user-defined" parameters that will 413override settings for the submission and smtps services. </p> 414 415<blockquote> 416<pre> 417/etc/postfix/main.cf: 418 msa_cleanup_service_name = msa_cleanup 419 msa_header_checks = pcre:/etc/postfix/msa_header_checks 420 msa_body_checks = pcre:/etc/postfix/msa_body_checks 421</pre> 422</blockquote> 423 424<p> Next, we define msa_cleanup as a dedicated cleanup service that 425will be used only by the submission and smtps services. This service 426uses the header_checks and body_checks overrides that were defined 427above. </p> 428 429<blockquote> 430<pre> 431/etc/postfix.master.cf: 432 # ================================================================= 433 # service type private unpriv chroot wakeup maxproc command 434 # (yes) (yes) (yes) (never) (100) 435 # ================================================================= 436 smtp inet n - n - - smtpd 437 msa_cleanup unix n - n - 0 cleanup 438 -o header_checks=$msa_header_checks 439 -o body_checks=$msa_body_checks 440 submission inet n - n - - smtpd 441 -o cleanup_service_name=$msa_cleanup_service_name 442 -o syslog_name=postfix/submission 443 <i>...[see sample master.cf file for more]...</i> 444 smtps inet n - n - - smtpd 445 -o cleanup_service_name=$msa_cleanup_service_name 446 -o syslog_name=postfix/smtps 447 -o smtpd_tls_wrappermode=yes 448 <i>...[see sample master.cf file for more]...</i> 449</pre> 450</blockquote> 451 452<p> By keeping the "msa_xxx" parameter settings in main.cf, you 453keep your master.cf file simple, and you minimize the amount 454of duplication. </p> 455 456<h2><a name="domain_except">Configuring header/body checks for mail to some domains only</a></h2> 457 458<p> The following information applies to Postfix 2.1. Earlier 459Postfix versions do not support the receive_override_options feature. 460</p> 461 462<p> If you are an MX service provider and want to enable header/body 463checks only for some domains, you can configure ONE Postfix 464instance with multiple SMTP server IP addresses in master.cf. Each 465address provides a different service. </p> 466 467<blockquote> 468 469<pre> 470/etc/postfix.master.cf: 471 # ================================================================= 472 # service type private unpriv chroot wakeup maxproc command 473 # (yes) (yes) (yes) (never) (100) 474 # ================================================================= 475 # SMTP service for domains with header/body checks turned on. 476 1.2.3.4:smtp inet n - n - - smtpd 477 478 # SMTP service for domains with header/body checks turned off. 479 1.2.3.5:smtp inet n - n - - smtpd 480 -o receive_override_options=no_header_body_checks 481</pre> 482</blockquote> 483 484<p> Once this is set up you can configure MX records in the DNS 485that route each domain to the proper SMTP server instance. </p> 486 487</body> 488 489</html> 490