xref: /netbsd-src/external/ibm-public/postfix/dist/proto/FILTER_README.html (revision 059c16a85b0b39d60ad6d18f53c09510815afa2b)
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 After-Queue Content Filter </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 After-Queue Content Filter </h1>
18
19<hr>
20
21<h2>Introduction</h2>
22
23<p> This document requires Postfix version 2.1 or later. </p>
24
25<p> Normally, Postfix receives mail, stores it in the mail queue
26and then delivers it. With the external content filter described
27here, mail is filtered AFTER it is queued. This approach decouples
28mail receiving processes from mail filtering processes, and gives
29you maximal control over how many filtering processes you are
30willing to run in parallel.  </p>
31
32<p> The after-queue content filter is meant to be used as follows: </p>
33
34<blockquote>
35
36<table>
37
38<tr>
39
40        <td bgcolor="#f0f0ff" align="center" valign="middle">
41        Network or<br> local users </td>
42
43    <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
44
45        <td bgcolor="#f0f0ff" align="center" valign="middle">
46        Postfix<br> queue </td>
47
48    <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
49
50        <td bgcolor="#f0f0ff" align="center" valign="middle">
51        <b>Content<br> filter</b> </td>
52
53    <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
54
55        <td bgcolor="#f0f0ff" align="center" valign="middle">
56        Postfix<br> queue </td>
57
58    <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
59
60        <td bgcolor="#f0f0ff" align="center" valign="middle">
61        Network or<br> local mailbox </td>
62
63</tr>
64
65</table>
66
67</blockquote>
68
69<p> This document describes implementations that use a single
70Postfix instance for everything: receiving, filtering and delivering
71mail.  Applications that use two separate Postfix instances will
72be covered by a later version of this document.  </p>
73
74<p> The after-queue content filter is not to be confused with the
75approaches described in the SMTPD_PROXY_README or MILTER_README
76documents,
77where incoming SMTP mail is filtered BEFORE it is stored into the
78Postfix queue.  </p>
79
80<p> This document describes two approaches to content filter
81all email, as well as several options to filter mail selectively: </p>
82
83<ul>
84
85<li><a href="#principles">Principles of operation</a>
86
87<li>Simple content filter
88
89<ul>
90
91<li><a href="#simple_filter">Simple content filter example</a>
92
93<li><a href="#simple_performance">Simple content filter performance</a>
94
95<li><a href="#simple_limitations">Simple content filter limitations</a>
96
97<li><a href="#simple_turnoff">Turning off the simple content filter</a>
98
99</ul>
100
101<li>Advanced content filter
102
103<ul>
104
105<li><a href="#advanced_filter">Advanced content filter example</a>
106
107<li><a href="#performance">Advanced content filter performance</a>
108
109<li><a href="#advanced_turnoff">Turning off the advanced content filter</a>
110
111</ul>
112
113<li>Selective content filtering
114
115<ul>
116
117<li><a href="#remote_only">Filtering mail from outside users only</a>
118
119<li><a href="#domain_dependent">Different filters for different domains</a>
120
121<li><a href="#dynamic_filter">FILTER actions in access or header/body tables</a>
122
123</ul>
124
125</ul>
126
127
128<h2><a name="principles">Principles of operation</a> </h2>
129
130<p> An after-queue content filter receives unfiltered mail from Postfix
131(as described further below) and can do one of the following: </p>
132
133<ol>
134
135<li> <p> Re-inject the mail back into Postfix, perhaps after changing
136    content and/or destination. </p>
137
138<li> <p> Discard or quarantine the mail. </p>
139
140<li> <p> Reject the mail (by sending a suitable status code back to
141    Postfix). Postfix will send the mail back to the sender address. </p>
142
143</ol>
144
145<p> NOTE: in this time of mail worms and forged spam, it is a VERY
146BAD IDEA to send viruses back to the sender address, because the
147sender address is almost certainly not the originator. It is better
148to discard known viruses, and to quarantine material that is
149suspect so that a human can decide what to do with it. </p>
150
151<h2><a name="simple_filter">Simple content filter example</a></h2>
152
153<p> The first example is simple to set up, but has major limitations
154that will be addressed in a second example.  Postfix receives
155unfiltered mail from the network with the smtpd(8) server, and
156delivers unfiltered mail to a content filter with the Postfix
157pipe(8) delivery agent.  The content filter injects filtered mail
158back into Postfix with the Postfix sendmail(1) command, so that
159Postfix can deliver it to the final destination. </p>
160
161<p> This means that mail submitted via the Postfix sendmail(1)
162command cannot be content filtered. </p>
163
164<p> In the figure below, names followed by a number represent
165Postfix commands or daemon programs. See the OVERVIEW
166document for an introduction to the Postfix architecture. </p>
167
168<blockquote>
169
170<table>
171
172<tr>
173
174        <td align="center" valign="top"> Unfiltered<br> <br> </td>
175
176    <td align="center" valign="top"> <tt> -&gt;</tt><br> <br> </td>
177
178       <td bgcolor="#f0f0ff" align="center" valign="middle">
179       smtpd(8)<br> <br> pickup(8) </td>
180
181   <td align="center" valign="middle"> <tt> &gt;- </tt> </td>
182
183       <td bgcolor="#f0f0ff" align="center" valign="middle">
184       cleanup(8) </td>
185
186   <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
187
188       <td bgcolor="#f0f0ff" align="center" valign="middle">
189       qmgr(8)<br> Postfix <br> queue </td>
190
191   <td align="center" valign="middle"> <tt> -&lt; </tt> </td>
192
193       <td bgcolor="#f0f0ff" align="center" valign="middle">
194       local(8)<br> smtp(8)<br> pipe(8) </td>
195
196   <td align="center" valign="top"> <tt> -&gt;</tt><br> <tt>
197   -&gt;</tt><br> </td>
198
199       <td align="center" valign="top"> Filtered<br> Filtered<br>
200       </td>
201
202</tr>
203
204<tr>
205
206   <td colspan="2"> </td>
207
208       <td align="center" valign="middle"> ^<br> <tt> | </tt> </td>
209
210   <td colspan="5"> </td>
211
212       <td align="center" valign="middle"> <tt> |<br> v </tt> </td>
213
214   <td colspan="2"> </td>
215
216</tr>
217
218<tr>
219
220   <td colspan="2"> </td>
221
222        <td bgcolor="#f0f0ff" align="center" valign="middle">
223        <a href="QSHAPE_README.html#maildrop_queue"> maildrop <br>
224        queue </a> </td>
225
226   <td align="center" valign="middle"> <tt> &lt;- </tt> </td>
227
228        <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br>
229        postdrop(1) </td>
230
231   <td align="center" valign="middle"> <tt> &lt;- </tt> </td>
232
233        <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br>
234        sendmail(1) </td>
235
236   <td align="center" valign="middle"> <tt> &lt;- </tt> </td>
237
238        <td bgcolor="#f0f0ff" align="center" valign="middle">Content
239        <br> filter </td>
240
241   <td colspan="2"> </td>
242
243</tr>
244
245</table>
246
247</blockquote>
248
249<p> The content filter can be a simple shell script like this: </p>
250
251<blockquote>
252<pre>
253 1 #!/bin/sh
254 2
255 3 # Simple shell-based filter. It is meant to be invoked as follows:
256 4 #       /path/to/script -f sender recipients...
257 5
258 6 # Localize these. The -G option does nothing before Postfix 2.3.
259 7 INSPECT_DIR=/var/spool/filter
260 8 SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here.
261 9
26210 # Exit codes from &lt;sysexits.h&gt;
26311 EX_TEMPFAIL=75
26412 EX_UNAVAILABLE=69
26513
26614 # Clean up when done or when aborting.
26715 trap "rm -f in.$$" 0 1 2 3 15
26816
26917 # Start processing.
27018 cd $INSPECT_DIR || {
27119     echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }
27220
27321 cat &gt;in.$$ || {
27422     echo Cannot save mail to file; exit $EX_TEMPFAIL; }
27523
27624 # Specify your content filter here.
27725 # filter &lt;in.$$ || {
27826 #   echo Message content rejected; exit $EX_UNAVAILABLE; }
27927
28028 $SENDMAIL "$@" &lt;in.$$
28129
28230 exit $?
283</pre>
284</blockquote>
285
286<p> Notes: </p>
287
288<ul>
289
290<li> <p> Line 8: The -G option says the filter output is not a local
291mail submission: don't do silly things like appending the local
292domain name to addresses in message headers.  This option does
293nothing before Postfix version 2.3.  </p>
294
295<li> <p> Line 8: The -i option says don't stop reading input when
296a line contains "." only.  </p>
297
298<li> <p> Line 8: NEVER NEVER NEVER use the "-t" command-line option
299here. It will mis-deliver mail, like sending messages from a mailing
300list back to the mailing list. </p>
301
302<li> <p> Line 21: The idea is to first capture the message to
303file and then run the content through a third-party content filter
304program. </p>
305
306<li> <p> Line 22: If the message cannot be captured to file, mail
307delivery is deferred by terminating with exit status 75 (EX_TEMPFAIL).
308Postfix places the message in the deferred mail queue and tries
309again later.  </p>
310
311<li> <p> Line 25: You will need to specify a real content filter
312program here that receives the content on standard input. </p>
313
314<li> <p> Line 26: If the content filter program finds a problem,
315the mail is bounced by terminating with exit status 69 (EX_UNAVAILABLE).
316Postfix will send the message back to the sender as undeliverable
317mail.
318</p>
319
320<li> <p> NOTE: in this time of mail worms and spam, it is a BAD
321IDEA to send known viruses or spam back to the sender, because that
322address is likely to be forged. It is safer to discard known viruses
323and to quarantine suspicious content so that it can
324be inspected by a human being. </p>
325
326<li> <p> Line 28: If the content is OK, it is given as input to
327the Postfix sendmail command, and the exit status of the filter
328command is whatever exit status the Postfix sendmail command
329produces. Postfix will deliver the message as usual. </p>
330
331<li> <p> Line 30: Postfix returns the exit status of the Postfix
332sendmail command. </p>
333
334</ul>
335
336<p> I suggest that you first run this script by hand until you are
337satisfied with the results. Run it with a real message (headers+body)
338as input: </p>
339
340<blockquote>
341<pre>
342% /path/to/script -f sender -- recipient... &lt;message-file
343</pre>
344</blockquote>
345
346<p> Once you're satisfied with the content filtering script: </p>
347
348<ul>
349
350<li> <p> Create a dedicated local user account called "filter".  This
351user handles all potentially dangerous mail content - that is
352why it should be a separate account. Do not use "nobody", and
353most certainly do not use "root" or "postfix". </p>
354
355<li> <p> Create a directory /var/spool/filter that is accessible only
356to the "filter" user. This is where the content filtering script
357is supposed to store its temporary files. </p>
358
359<li> <p> Configure Postfix to deliver mail to the content filter
360with the pipe(8) delivery agent (see the pipe(8) manpage for a
361description of the command syntax below). </p>
362
363<pre>
364/etc/postfix/master.cf:
365  # =============================================================
366  # service type  private unpriv  chroot  wakeup  maxproc command
367  #               (yes)   (yes)   (yes)   (never) (100)
368  # =============================================================
369  filter    unix  -       n       n       -       10      pipe
370    flags=Rq user=filter null_sender=
371    argv=/path/to/script -f ${sender} -- ${recipient}
372</pre>
373
374<p> This runs up to 10 content filters in parallel. Instead of a
375limit of 10 concurrent processes, use whatever process limit is
376feasible for your machine.  Content inspection software can gobble
377up a lot of system resources, so you don't want to have too much
378of it running at the same time. The empty null_sender setting is
379required with Postfix 2.3 and later. </p>
380
381<li> <p> To turn on content filtering for mail arriving via SMTP
382only, append "-o content_filter=filter:dummy" to the master.cf
383entry that defines the Postfix SMTP server: </p>
384
385<pre>
386/etc/postfix/master.cf:
387  # =============================================================
388  # service type  private unpriv  chroot  wakeup  maxproc command
389  #               (yes)   (yes)   (yes)   (never) (100)
390  # =============================================================
391  smtp      inet  ...other stuff here, do not change...   smtpd
392        -o content_filter=filter:dummy
393</pre>
394
395<p> The "-o content_filter" line causes Postfix to add one content
396filter request record to each incoming mail message, with content
397"filter:dummy". This record overrides the normal mail routing
398and causes mail to be given to the content filter instead. </p>
399
400<p> The content_filter configuration parameter expects a value of
401the form <i>transport:destination</i>. The <i>transport</i> name
402specifies the first field of a mail delivery agent definition in
403master.cf; the syntax of the next-hop <i>destination</i> is described
404in the manual page of the corresponding delivery agent. </p>
405
406<p> The meaning of an empty next-hop filter <i>destination</i> is
407version dependent.  Postfix 2.7 and later will use the recipient
408domain; earlier versions will use $myhostname.  Specify
409"default_filter_nexthop = $myhostname" for compatibility with Postfix
4102.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>.
411</p>
412
413<p> The content_filter setting has lower precedence than a FILTER
414action that is specified in an access(5), header_checks(5) or
415body_checks(5) table. </p>
416
417<li> <p> Execute "<b>postfix reload</b>" to complete the change.
418</p>
419
420</ul>
421
422<h2> <a name="simple_performance">Simple content filter performance</a> </h2>
423
424<p> With the shell script as shown above you will lose a factor of
425four in Postfix performance for transit mail that arrives and leaves
426via SMTP. You will lose another factor in transit performance for
427each additional temporary file that is created and deleted in the
428process of content filtering.  The performance impact is less for
429mail that is submitted or delivered locally, because such deliveries
430are already slower than SMTP transit mail. </p>
431
432<h2><a name="simple_limitations">Simple content filter limitations</a></h2>
433
434<p> The problem with content filters like the one above is that
435they are not very robust. The reason is that the software does not
436talk a well-defined protocol with Postfix. If the filter shell
437script aborts because the shell runs into some memory allocation
438problem, the script will not produce a nice exit status as defined
439in the file /usr/include/sysexits.h.  Instead of going to the
440deferred queue, mail will bounce.  The same lack of robustness can
441happen when the content filtering software itself runs into a
442resource problem. </p>
443
444<p> The simple content filter method is not suitable for content
445filter actions that are invoked via header_checks or body_checks
446patterns.  These patterns will be applied again after mail is
447re-injected with the Postfix sendmail command, resulting in a mail
448filtering loop.  The advanced content filtering method (see below)
449makes it possible to turn off header_checks or body_checks patterns
450for filtered mail. </p>
451
452<h2><a name="simple_turnoff">Turning off the simple content filter</a> </h2>
453
454<p> To turn off "simple" content filtering: </p>
455
456<ul> <li> <p> Edit the master.cf file, remove the "-o
457content_filter=filter:dummy" text from the entry that defines the
458Postfix SMTP server. </p>
459
460<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content
461filter request records from existing queue files. </p>
462
463<li> <p> Execute another "<b>postfix reload</b>". </p>
464
465</ul>
466
467<h2><a name="advanced_filter">Advanced content filter example</a></h2>
468
469<p> The second example is more complex, but can give better
470performance, and is less likely to bounce mail when the machine
471runs into some resource problem.  This content filter receives
472unfiltered mail with SMTP on localhost port 10025, and sends filtered
473mail back into Postfix with SMTP on localhost port 10026. </p>
474
475<p> For non-SMTP capable content filtering software, Bennett Todd's
476SMTP proxy implements a nice PERL/SMTP content filtering framework.
477See: https://web.archive.org/web/20151022025756/http://bent.latency.net/smtpprox/. </p>
478
479<p> In the figure below, names followed by a number represent
480Postfix commands or daemon programs. See the OVERVIEW
481document for an introduction to the Postfix architecture. </p>
482
483<blockquote>
484
485<table>
486
487<tr>
488
489       <td align="center" valign="middle"> Unfiltered<br> <br>
490       Unfiltered</td>
491
492    <td align="center" valign="middle"> <tt> -&gt;</tt><br> <br>
493    <tt> -&gt; </tt> </td>
494
495       <td bgcolor="#f0f0ff" align="center" valign="middle">
496       smtpd(8)<br> <br> pickup(8) </td>
497
498   <td align="center" valign="middle"> <tt> &gt;- </tt> </td>
499
500       <td bgcolor="#f0f0ff" align="center" valign="middle">
501       cleanup(8) </td>
502
503   <td align="center" valign="middle"> <tt> -&gt; </tt> </td>
504
505       <td bgcolor="#f0f0ff" align="center" valign="middle">
506       qmgr(8)<br> Postfix <br> queue </td>
507
508   <td align="center" valign="middle"> <tt> -&lt; </tt> </td>
509
510       <td bgcolor="#f0f0ff" align="center" valign="middle">
511       smtp(8)<br> <br> local(8) </td>
512
513   <td align="center" valign="middle"> <tt> -&gt;</tt><br> <br>
514   <tt> -&gt; </tt></td>
515
516       <td align="center" valign="middle"> Filtered<br> <br>
517       Filtered</td>
518
519</tr>
520
521<tr>
522
523   <td colspan="4"> </td>
524
525       <td align="center" valign="middle"> ^<br> <tt> | </tt> </td>
526
527   <td> </td>
528
529       <td align="center" valign="middle"> <tt> |<br> v </tt> </td>
530
531   <td colspan="4"> </td>
532
533</tr>
534
535<tr>
536
537   <td colspan="4"> </td>
538
539       <td bgcolor="#f0f0ff" align="center" valign="middle">
540       smtpd(8)<br> 10026 </td>
541
542   <td> </td>
543
544       <td bgcolor="#f0f0ff" align="center" valign="middle">
545       smtp(8)<br> </td>
546
547   <td colspan="4"> </td>
548
549</tr>
550
551<tr>
552
553   <td colspan="4"> </td>
554
555       <td align="center" valign="middle"> ^<br> <tt> | </tt> </td>
556
557   <td> </td>
558
559       <td align="center" valign="middle"> <tt> |<br> v </tt> </td>
560
561   <td colspan="4"> </td>
562
563</tr>
564
565<tr>
566
567   <td colspan="4"> </td>
568
569        <td colspan="3" bgcolor="#f0f0ff" align="center"
570        valign="middle">content filter 10025</td>
571
572   <td colspan="4"> </td>
573
574</tr>
575
576</table>
577
578</blockquote>
579
580<p> The example given here filters all mail, including mail that
581arrives via SMTP and mail that is locally submitted via the Postfix
582sendmail command (local submissions enter Postfix via the pickup(8)
583server; to keep the figure simple we omit local submission details).
584See examples near the end of this document for
585how to exclude local users from filtering, or how to configure a
586destination dependent content filter. </p>
587
588<p> You can expect to lose about a factor of two in Postfix
589performance for mail that arrives and leaves via SMTP, provided
590that the content filter creates no temporary files. Each temporary
591file created by the content filter adds another factor to the
592performance loss. </p>
593
594<h3>Advanced content filter: requesting that all mail is filtered</h3>
595
596<p> To enable the advanced content filter method for all mail,
597specify in main.cf:  </p>
598
599<blockquote>
600<pre>
601/etc/postfix/main.cf:
602    content_filter = scan:localhost:10025
603    receive_override_options = no_address_mappings
604</pre>
605</blockquote>
606
607<ul>
608
609<li> <p> The "receive_override_options" line disables address
610manipulation before the content filter, so that the content filter
611sees the original mail addresses instead of the result of virtual
612alias expansion, canonical mapping, automatic bcc, address
613masquerading, etc. </p>
614
615<li> <p> The "content_filter" line causes Postfix to add one content
616filter request record to each incoming mail message, with content
617"scan:localhost:10025".  The content filter request records are
618added by the smtpd(8) and pickup(8) servers (and qmqpd(8) if you
619decide to enable this service). </p>
620
621<li> <p> Content filter requests are stored in queue files; this
622is how Postfix keeps track of what mail needs filtering.  When a
623queue file contains a content filter request, the queue manager
624will deliver the mail to the specified content filter regardless
625of its final destination. </p>
626
627<li> <p> The content_filter configuration parameter expects a value
628of the form <i>transport:destination</i>. The <i>transport</i> name
629specifies the first field of a mail delivery agent definition in
630master.cf; the syntax of the next-hop <i>destination</i> is described
631in the manual page of the corresponding delivery agent. </p>
632
633<li> <p> The meaning of an empty next-hop filter <i>destination</i>
634is version dependent.  Postfix 2.7 and later will use the recipient
635domain; earlier versions will use $myhostname.  Specify
636"default_filter_nexthop = $myhostname" for compatibility with Postfix
6372.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>.
638
639<li> <p> The content_filter setting has lower precedence than a
640FILTER action that is specified in an access(5), header_checks(5)
641or body_checks(5) table. </p>
642
643</ul>
644
645<h3> Advanced content filter: sending unfiltered mail to the content
646filter</h3>
647
648<p> In this example, "scan" is an instance of the Postfix SMTP
649client with slightly different configuration parameters. This is
650how one would set up the service in the Postfix master.cf file:
651</p>
652
653<blockquote>
654<pre>
655/etc/postfix/master.cf:
656    # =============================================================
657    # service type  private unpriv  chroot  wakeup  maxproc command
658    #               (yes)   (yes)   (yes)   (never) (100)
659    # =============================================================
660    scan      unix  -       -       n       -       10      smtp
661        -o smtp_send_xforward_command=yes
662        -o disable_mime_output_conversion=yes
663        -o smtp_generic_maps=
664</pre>
665</blockquote>
666
667<ul>
668
669<li> <p> This runs up to 10 content filters in parallel. Instead
670of a limit of 10 concurrent processes, use whatever process limit
671is feasible for your machine.  Content inspection software can
672gobble up a lot of system resources, so you don't want to have too
673much of it running at the same time. </p>
674
675<li> <p> With "-o smtp_send_xforward_command=yes", the scan transport
676will try to forward the original client name and IP address
677through the content filter to the
678after-filter smtpd process, so that filtered mail is logged with
679the real client name IP address. See smtp(8) and XFORWARD_README
680for more information. </p>
681
682<li> <p> The "-o disable_mime_output_conversion=yes" is a workaround
683that prevents the breaking of domainkeys and other digital signatures.
684This is needed because some SMTP-based content filters don't announce
6858BITMIME support, even though they can handle 8-bit mail. </p>
686
687<li> <p> The "-o smtp_generic_maps=" is a workaround that prevents
688local address rewriting with generic(5) maps. Such rewriting should
689happen only when mail is sent out to the Internet.  </p>
690
691</ul>
692
693<h3>Advanced content filter: running the content filter</h3>
694
695<p> The content filter can be set up with the Postfix spawn service,
696which is the Postfix equivalent of inetd. For example, to instantiate
697up to 10 content filtering processes on localhost port 10025: </p>
698
699<blockquote>
700<pre>
701/etc/postfix/master.cf:
702    # ===================================================================
703    # service       type  private unpriv  chroot  wakeup  maxproc command
704    #                     (yes)   (yes)   (yes)   (never) (100)
705    # ===================================================================
706    localhost:10025 inet  n       n       n       -       10      spawn
707        user=filter argv=/path/to/filter localhost 10026
708</pre>
709</blockquote>
710
711<ul>
712
713<li> <p> "filter" is a dedicated local user account.  The user will
714never log in, and can be given a "*" password and non-existent
715shell and home directory.  This user handles all potentially
716dangerous mail content - that is why it should be a separate account.
717</p>
718
719<li> <p> By default, Postfix will terminate a command that runs
720longer than command_time_limit seconds (default: 1000s). This is a
721safety measure that prevents filters from running forever. </p>
722
723</ul>
724
725<p> If you want to have your filter listening on port localhost:10025
726instead of Postfix, then you must run your filter as a stand-alone
727program, and must not use the Postfix spawn service.  </p>
728
729<h3>Advanced filter: injecting mail back into Postfix</h3>
730
731<p> The job of the content filter is to either bounce mail with a
732suitable diagnostic, or to feed the mail back into Postfix through
733a dedicated listener on port localhost 10026. </p>
734
735<p> The simplest content filter just copies SMTP commands and data
736between its inputs and outputs. If it has a problem, all it has to
737do is to reply to an input of `.' from Postfix with `550 content
738rejected', and to disconnect without sending `.' on the connection
739that injects mail back into Postfix. </p>
740
741<blockquote>
742<pre>
743/etc/postfix/master.cf:
744    # ===================================================================
745    # service       type  private unpriv  chroot  wakeup  maxproc command
746    #                     (yes)   (yes)   (yes)   (never) (100)
747    # ===================================================================
748    localhost:10026 inet  n       -       n       -       10      smtpd
749        -o content_filter=
750        -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_milters
751        -o smtpd_helo_restrictions=
752        -o smtpd_client_restrictions=
753        -o smtpd_sender_restrictions=
754        # Postfix 2.10 and later: specify empty smtpd_relay_restrictions.
755        -o smtpd_relay_restrictions=
756        -o smtpd_recipient_restrictions=permit_mynetworks,reject
757        -o mynetworks=127.0.0.0/8
758        -o smtpd_authorized_xforward_hosts=127.0.0.0/8
759</pre>
760</blockquote>
761
762<ul>
763
764<li> <p> NOTE: do not use spaces around the "=" or "," characters. </p>
765
766<li> <p> NOTE: the SMTP server must not have a smaller process
767limit than the "filter" master.cf entry. </p>
768
769<li> <p> The "-o content_filter=" overrides main.cf settings, and
770requests no content filtering for mail from the content filter.
771This is required or else mail will loop. </p>
772
773<li> <p> The "-o receive_override_options" overrides main.cf settings
774to avoid duplicating work that was already done before the content
775filter. These options are complementary to the options that are
776specified in main.cf: </p>
777
778<ul>
779
780    <li> <p> We specify "no_unknown_recipient_checks" to disable
781    attempts to find out if a recipient is unknown. </p>
782
783    <li> <p> We specify "no_header_body_checks" to disable header/body
784    checks.  </p>
785
786    <li> <p> We specify "no_milters" to disable Milter applications
787    (this option is available only in Postfix 2.3 and later).  </p>
788
789    <li> <p> We don't specify "no_address_mappings" here.  This
790    enables virtual alias expansion, canonical mappings, address
791    masquerading, and other address mappings after the content
792    filter. The main.cf setting of "receive_override_options"
793    disables these mappings before the content filter.  </p>
794
795</ul>
796
797  <p> These receive override options are either implemented by the
798  SMTP server itself, or they are passed on to the cleanup server.
799  </p>
800
801<li> <p> The "-o smtpd_xxx_restrictions" and "-o mynetworks=127.0.0.0/8"
802override main.cf settings. They turn off junk mail controls that
803would only waste time here.
804
805<li> <p> With "-o smtpd_authorized_xforward_hosts=127.0.0.0/8",
806the scan transport will try to forward the original client name
807and IP address to the after-filter smtpd process, so that filtered
808mail is logged with the real client name and IP address.  See
809XFORWARD_README and smtpd(8). </p>
810
811</ul>
812
813<h2><a name="performance">Advanced content filter performance</a></h2>
814
815<p> With the "sandwich" approach to content filtering described
816here, it is important to match the filter concurrency to the
817available CPU, memory and I/O resources.  Too few content filter
818processes and mail accumulates in the active queue even with low
819traffic volume; too much concurrency and Postfix ends up deferring
820mail destined for the content filter because processes fail due to
821insufficient resources. </p>
822
823<p> Currently, content filter performance tuning is a process of
824trial and error; analysis is handicapped because filtered and
825unfiltered messages share the same queue.  As mentioned in the
826introduction of this document, content filtering with multiple
827Postfix instances will be covered in a future version.  </p>
828
829<h2><a name="advanced_turnoff">Turning off the advanced content filter</a> </h2>
830
831<p> To turn off "advanced" content filtering: </p>
832
833<ul> <li> <p> Delete or comment out the two following main.cf lines.
834The other changes made for advanced content filtering have no effect
835when content filtering is turned off. </p>
836
837<blockquote>
838<pre>
839/etc/postfix/main.cf:
840    content_filter = scan:localhost:10025
841    receive_override_options = no_address_mappings
842</pre>
843</blockquote>
844
845<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content
846filter request records from existing queue files. </p>
847
848<li> <p> Execute another "<b>postfix reload</b>". </p>
849
850</ul>
851
852<h2><a name="remote_only">Filtering mail from outside users only</a></h2>
853
854<p> The easiest approach is to configure ONE Postfix instance with
855multiple SMTP server IP addresses in master.cf: </p>
856
857<ul>
858
859<li> <p> Two SMTP server IP addresses for mail from inside users only,
860with content filtering turned off. </p>
861
862<pre>
863/etc/postfix.master.cf:
864    # ==================================================================
865    # service      type  private unpriv  chroot  wakeup  maxproc command
866    #                    (yes)   (yes)   (yes)   (never) (100)
867    # ==================================================================
868    1.2.3.4:smtp   inet  n       -       n       -       -       smtpd
869        -o smtpd_client_restrictions=permit_mynetworks,reject
870    127.0.0.1:smtp inet  n       -       n       -       -       smtpd
871        -o smtpd_client_restrictions=permit_mynetworks,reject
872</pre>
873
874<li> <p> One SMTP server address for mail from outside users with
875content filtering turned on. </p>
876
877<pre>
878/etc/postfix.master.cf:
879    # =================================================================
880    # service     type  private unpriv  chroot  wakeup  maxproc command
881    #                   (yes)   (yes)   (yes)   (never) (100)
882    # =================================================================
883    1.2.3.5:smtp  inet  n       -       n       -       -       smtpd
884        -o content_filter=filter-service:filter-destination
885        -o receive_override_options=no_address_mappings
886</pre>
887
888</ul>
889
890<p> After this, you can follow the same procedure as outlined in
891the "advanced" or "simple" content filtering examples above, except
892that you must not specify "content_filter" or "receive_override_options"
893in the main.cf file. </p>
894
895<h2><a name="domain_dependent">Different filters for different
896domains</a></h2>
897
898<p> If you are an MX service provider and want to apply different
899content filters for different domains, you can configure ONE Postfix
900instance with multiple SMTP server IP addresses in master.cf. Each
901address provides a different content filter service. </p>
902
903<blockquote>
904<pre>
905/etc/postfix.master.cf:
906    # =================================================================
907    # service     type  private unpriv  chroot  wakeup  maxproc command
908    #                   (yes)   (yes)   (yes)   (never) (100)
909    # =================================================================
910    # SMTP service for domains that are filtered with service1:dest1
911    1.2.3.4:smtp  inet  n       -       n       -       -       smtpd
912        -o content_filter=service1:dest1
913        -o receive_override_options=no_address_mappings
914
915    # SMTP service for domains that are filtered with service2:dest2
916    1.2.3.5:smtp  inet  n       -       n       -       -       smtpd
917        -o content_filter=service2:dest2
918        -o receive_override_options=no_address_mappings
919</pre>
920</blockquote>
921
922<p> After this, you can follow the same procedure as outlined in
923the "advanced" or "simple" content filtering examples above, except
924that you must not specify "content_filter" or "receive_override_options"
925in the main.cf file. </p>
926
927<p> Set up MX records in the DNS that route each domain to the
928proper SMTP server instance. </p>
929
930<h2><a name="dynamic_filter">FILTER actions in access or header/body
931tables</a></h2>
932
933<p> The above filtering configurations are static. Mail that follows
934a given path is either always filtered or it is never filtered. As
935of Postfix 2.0 you can also turn on content filtering on the fly.
936</p>
937
938<p> To turn on content filtering with an access(5) table rule: </p>
939
940<blockquote>
941<pre>
942/etc/postfix/access:
943    <i>whatever</i>       FILTER foo:bar
944</pre>
945</blockquote>
946
947<p> To turn on content filtering with a header_checks(5) or
948body_checks(5) table pattern: </p>
949
950<blockquote>
951<pre>
952/etc/postfix/header_checks:
953    /<i>whatever</i>/     FILTER foo:bar
954</pre>
955</blockquote>
956
957<p> You can do this in smtpd access maps as well as the cleanup
958server's header/body_checks.  This feature must be used with great
959care:  you must disable all the UCE features in the after-filter
960smtpd and cleanup daemons or else you will have a content filtering
961loop. </p>
962
963<p> Limitations: </p>
964
965<ul>
966
967<li> <p> FILTER actions from smtpd access maps and header/body_checks
968take precedence over filters specified with the main.cf content_filter
969parameter. </p>
970
971<li> <p> If a message triggers more than one filter action, only
972the last one takes effect. </p>
973
974<li> <p> The same content filter is applied to all the recipients
975of a given message. </p>
976
977</ul>
978
979</body>
980
981</html>
982