diff options
Diffstat (limited to 'html/FILTER_README.html')
-rw-r--r-- | html/FILTER_README.html | 981 |
1 files changed, 981 insertions, 0 deletions
diff --git a/html/FILTER_README.html b/html/FILTER_README.html new file mode 100644 index 0000000..e40ac9a --- /dev/null +++ b/html/FILTER_README.html @@ -0,0 +1,981 @@ +<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> + +<html> + +<head> + +<title>Postfix After-Queue Content Filter </title> + +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<link rel='stylesheet' type='text/css' href='postfix-doc.css'> + +</head> + +<body> + +<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix After-Queue Content Filter </h1> + +<hr> + +<h2>Introduction</h2> + +<p> This document requires Postfix version 2.1 or later. </p> + +<p> Normally, Postfix receives mail, stores it in the mail queue +and then delivers it. With the external content filter described +here, mail is filtered AFTER it is queued. This approach decouples +mail receiving processes from mail filtering processes, and gives +you maximal control over how many filtering processes you are +willing to run in parallel. </p> + +<p> The after-queue content filter is meant to be used as follows: </p> + +<blockquote> + +<table> + +<tr> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + Network or<br> local users </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + Postfix<br> queue </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <b>Content<br> filter</b> </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + Postfix<br> queue </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + Network or<br> local mailbox </td> + +</tr> + +</table> + +</blockquote> + +<p> This document describes implementations that use a single +Postfix instance for everything: receiving, filtering and delivering +mail. Applications that use two separate Postfix instances will +be covered by a later version of this document. </p> + +<p> The after-queue content filter is not to be confused with the +approaches described in the <a href="SMTPD_PROXY_README.html">SMTPD_PROXY_README</a> or <a href="MILTER_README.html">MILTER_README</a> +documents, +where incoming SMTP mail is filtered BEFORE it is stored into the +Postfix queue. </p> + +<p> This document describes two approaches to content filter +all email, as well as several options to filter mail selectively: </p> + +<ul> + +<li><a href="#principles">Principles of operation</a> + +<li>Simple content filter + +<ul> + +<li><a href="#simple_filter">Simple content filter example</a> + +<li><a href="#simple_performance">Simple content filter performance</a> + +<li><a href="#simple_limitations">Simple content filter limitations</a> + +<li><a href="#simple_turnoff">Turning off the simple content filter</a> + +</ul> + +<li>Advanced content filter + +<ul> + +<li><a href="#advanced_filter">Advanced content filter example</a> + +<li><a href="#performance">Advanced content filter performance</a> + +<li><a href="#advanced_turnoff">Turning off the advanced content filter</a> + +</ul> + +<li>Selective content filtering + +<ul> + +<li><a href="#remote_only">Filtering mail from outside users only</a> + +<li><a href="#domain_dependent">Different filters for different domains</a> + +<li><a href="#dynamic_filter">FILTER actions in access or header/body tables</a> + +</ul> + +</ul> + + +<h2><a name="principles">Principles of operation</a> </h2> + +<p> An after-queue content filter receives unfiltered mail from Postfix +(as described further below) and can do one of the following: </p> + +<ol> + +<li> <p> Re-inject the mail back into Postfix, perhaps after changing + content and/or destination. </p> + +<li> <p> Discard or quarantine the mail. </p> + +<li> <p> Reject the mail (by sending a suitable status code back to + Postfix). Postfix will send the mail back to the sender address. </p> + +</ol> + +<p> NOTE: in this time of mail worms and forged spam, it is a VERY +BAD IDEA to send viruses back to the sender address, because the +sender address is almost certainly not the originator. It is better +to discard known viruses, and to quarantine material that is +suspect so that a human can decide what to do with it. </p> + +<h2><a name="simple_filter">Simple content filter example</a></h2> + +<p> The first example is simple to set up, but has major limitations +that will be addressed in a second example. Postfix receives +unfiltered mail from the network with the <a href="smtpd.8.html">smtpd(8)</a> server, and +delivers unfiltered mail to a content filter with the Postfix +<a href="pipe.8.html">pipe(8)</a> delivery agent. The content filter injects filtered mail +back into Postfix with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command, so that +Postfix can deliver it to the final destination. </p> + +<p> This means that mail submitted via the Postfix <a href="sendmail.1.html">sendmail(1)</a> +command cannot be content filtered. </p> + +<p> In the figure below, names followed by a number represent +Postfix commands or daemon programs. See the <a href="OVERVIEW.html">OVERVIEW</a> +document for an introduction to the Postfix architecture. </p> + +<blockquote> + +<table> + +<tr> + + <td align="center" valign="top"> Unfiltered<br> <br> </td> + + <td align="center" valign="top"> <tt> -></tt><br> <br> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="smtpd.8.html">smtpd(8)</a><br> <br> <a href="pickup.8.html">pickup(8)</a> </td> + + <td align="center" valign="middle"> <tt> >- </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="cleanup.8.html">cleanup(8)</a> </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="qmgr.8.html">qmgr(8)</a><br> Postfix <br> queue </td> + + <td align="center" valign="middle"> <tt> -< </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="local.8.html">local(8)</a><br> <a href="smtp.8.html">smtp(8)</a><br> <a href="pipe.8.html">pipe(8)</a> </td> + + <td align="center" valign="top"> <tt> -></tt><br> <tt> + -></tt><br> </td> + + <td align="center" valign="top"> Filtered<br> Filtered<br> + </td> + +</tr> + +<tr> + + <td colspan="2"> </td> + + <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> + + <td colspan="5"> </td> + + <td align="center" valign="middle"> <tt> |<br> v </tt> </td> + + <td colspan="2"> </td> + +</tr> + +<tr> + + <td colspan="2"> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="QSHAPE_README.html#maildrop_queue"> maildrop <br> + queue </a> </td> + + <td align="center" valign="middle"> <tt> <- </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br> + <a href="postdrop.1.html">postdrop(1)</a> </td> + + <td align="center" valign="middle"> <tt> <- </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br> + <a href="sendmail.1.html">sendmail(1)</a> </td> + + <td align="center" valign="middle"> <tt> <- </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle">Content + <br> filter </td> + + <td colspan="2"> </td> + +</tr> + +</table> + +</blockquote> + +<p> The content filter can be a simple shell script like this: </p> + +<blockquote> +<pre> + 1 #!/bin/sh + 2 + 3 # Simple shell-based filter. It is meant to be invoked as follows: + 4 # /path/to/script -f sender recipients... + 5 + 6 # Localize these. The -G option does nothing before Postfix 2.3. + 7 INSPECT_DIR=/var/spool/filter + 8 SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here. + 9 +10 # Exit codes from <sysexits.h> +11 EX_TEMPFAIL=75 +12 EX_UNAVAILABLE=69 +13 +14 # Clean up when done or when aborting. +15 trap "rm -f in.$$" 0 1 2 3 15 +16 +17 # Start processing. +18 cd $INSPECT_DIR || { +19 echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } +20 +21 cat >in.$$ || { +22 echo Cannot save mail to file; exit $EX_TEMPFAIL; } +23 +24 # Specify your content filter here. +25 # filter <in.$$ || { +26 # echo Message content rejected; exit $EX_UNAVAILABLE; } +27 +28 $SENDMAIL "$@" <in.$$ +29 +30 exit $? +</pre> +</blockquote> + +<p> Notes: </p> + +<ul> + +<li> <p> Line 8: The -G option says the filter output is not a local +mail submission: don't do silly things like appending the local +domain name to addresses in message headers. This option does +nothing before Postfix version 2.3. </p> + +<li> <p> Line 8: The -i option says don't stop reading input when +a line contains "." only. </p> + +<li> <p> Line 8: NEVER NEVER NEVER use the "-t" command-line option +here. It will mis-deliver mail, like sending messages from a mailing +list back to the mailing list. </p> + +<li> <p> Line 21: The idea is to first capture the message to +file and then run the content through a third-party content filter +program. </p> + +<li> <p> Line 22: If the message cannot be captured to file, mail +delivery is deferred by terminating with exit status 75 (EX_TEMPFAIL). +Postfix places the message in the deferred mail queue and tries +again later. </p> + +<li> <p> Line 25: You will need to specify a real content filter +program here that receives the content on standard input. </p> + +<li> <p> Line 26: If the content filter program finds a problem, +the mail is bounced by terminating with exit status 69 (EX_UNAVAILABLE). +Postfix will send the message back to the sender as undeliverable +mail. +</p> + +<li> <p> NOTE: in this time of mail worms and spam, it is a BAD +IDEA to send known viruses or spam back to the sender, because that +address is likely to be forged. It is safer to discard known viruses +and to quarantine suspicious content so that it can +be inspected by a human being. </p> + +<li> <p> Line 28: If the content is OK, it is given as input to +the Postfix sendmail command, and the exit status of the filter +command is whatever exit status the Postfix sendmail command +produces. Postfix will deliver the message as usual. </p> + +<li> <p> Line 30: Postfix returns the exit status of the Postfix +sendmail command. </p> + +</ul> + +<p> I suggest that you first run this script by hand until you are +satisfied with the results. Run it with a real message (headers+body) +as input: </p> + +<blockquote> +<pre> +% /path/to/script -f sender -- recipient... <message-file +</pre> +</blockquote> + +<p> Once you're satisfied with the content filtering script: </p> + +<ul> + +<li> <p> Create a dedicated local user account called "filter". This +user handles all potentially dangerous mail content - that is +why it should be a separate account. Do not use "nobody", and +most certainly do not use "root" or "postfix". </p> + +<li> <p> Create a directory /var/spool/filter that is accessible only +to the "filter" user. This is where the content filtering script +is supposed to store its temporary files. </p> + +<li> <p> Configure Postfix to deliver mail to the content filter +with the <a href="pipe.8.html">pipe(8)</a> delivery agent (see the <a href="pipe.8.html">pipe(8)</a> manpage for a +description of the command syntax below). </p> + +<pre> +/etc/postfix/<a href="master.5.html">master.cf</a>: + # ============================================================= + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ============================================================= + filter unix - n n - 10 pipe + flags=Rq user=filter null_sender= + argv=/path/to/script -f ${sender} -- ${recipient} +</pre> + +<p> This runs up to 10 content filters in parallel. Instead of a +limit of 10 concurrent processes, use whatever process limit is +feasible for your machine. Content inspection software can gobble +up a lot of system resources, so you don't want to have too much +of it running at the same time. The empty null_sender setting is +required with Postfix 2.3 and later. </p> + +<li> <p> To turn on content filtering for mail arriving via SMTP +only, append "-o <a href="postconf.5.html#content_filter">content_filter</a>=filter:dummy" to the <a href="master.5.html">master.cf</a> +entry that defines the Postfix SMTP server: </p> + +<pre> +/etc/postfix/<a href="master.5.html">master.cf</a>: + # ============================================================= + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ============================================================= + smtp inet ...other stuff here, do not change... smtpd + -o <a href="postconf.5.html#content_filter">content_filter</a>=filter:dummy +</pre> + +<p> The "-o <a href="postconf.5.html#content_filter">content_filter</a>" line causes Postfix to add one content +filter request record to each incoming mail message, with content +"filter:dummy". This record overrides the normal mail routing +and causes mail to be given to the content filter instead. </p> + +<p> The <a href="postconf.5.html#content_filter">content_filter</a> configuration parameter expects a value of +the form <i>transport:destination</i>. The <i>transport</i> name +specifies the first field of a mail delivery agent definition in +<a href="master.5.html">master.cf</a>; the syntax of the next-hop <i>destination</i> is described +in the manual page of the corresponding delivery agent. </p> + +<p> The meaning of an empty next-hop filter <i>destination</i> is +version dependent. Postfix 2.7 and later will use the recipient +domain; earlier versions will use $<a href="postconf.5.html#myhostname">myhostname</a>. Specify +"<a href="postconf.5.html#default_filter_nexthop">default_filter_nexthop</a> = $<a href="postconf.5.html#myhostname">myhostname</a>" for compatibility with Postfix +2.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>. +</p> + +<p> The <a href="postconf.5.html#content_filter">content_filter</a> setting has lower precedence than a FILTER +action that is specified in an <a href="access.5.html">access(5)</a>, <a href="header_checks.5.html">header_checks(5)</a> or +<a href="header_checks.5.html">body_checks(5)</a> table. </p> + +<li> <p> Execute "<b>postfix reload</b>" to complete the change. +</p> + +</ul> + +<h2> <a name="simple_performance">Simple content filter performance</a> </h2> + +<p> With the shell script as shown above you will lose a factor of +four in Postfix performance for transit mail that arrives and leaves +via SMTP. You will lose another factor in transit performance for +each additional temporary file that is created and deleted in the +process of content filtering. The performance impact is less for +mail that is submitted or delivered locally, because such deliveries +are already slower than SMTP transit mail. </p> + +<h2><a name="simple_limitations">Simple content filter limitations</a></h2> + +<p> The problem with content filters like the one above is that +they are not very robust. The reason is that the software does not +talk a well-defined protocol with Postfix. If the filter shell +script aborts because the shell runs into some memory allocation +problem, the script will not produce a nice exit status as defined +in the file /usr/include/sysexits.h. Instead of going to the +<a href="QSHAPE_README.html#deferred_queue">deferred queue</a>, mail will bounce. The same lack of robustness can +happen when the content filtering software itself runs into a +resource problem. </p> + +<p> The simple content filter method is not suitable for content +filter actions that are invoked via <a href="postconf.5.html#header_checks">header_checks</a> or <a href="postconf.5.html#body_checks">body_checks</a> +patterns. These patterns will be applied again after mail is +re-injected with the Postfix sendmail command, resulting in a mail +filtering loop. The advanced content filtering method (see below) +makes it possible to turn off <a href="postconf.5.html#header_checks">header_checks</a> or <a href="postconf.5.html#body_checks">body_checks</a> patterns +for filtered mail. </p> + +<h2><a name="simple_turnoff">Turning off the simple content filter</a> </h2> + +<p> To turn off "simple" content filtering: </p> + +<ul> <li> <p> Edit the <a href="master.5.html">master.cf</a> file, remove the "-o +<a href="postconf.5.html#content_filter">content_filter</a>=filter:dummy" text from the entry that defines the +Postfix SMTP server. </p> + +<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content +filter request records from existing queue files. </p> + +<li> <p> Execute another "<b>postfix reload</b>". </p> + +</ul> + +<h2><a name="advanced_filter">Advanced content filter example</a></h2> + +<p> The second example is more complex, but can give better +performance, and is less likely to bounce mail when the machine +runs into some resource problem. This content filter receives +unfiltered mail with SMTP on localhost port 10025, and sends filtered +mail back into Postfix with SMTP on localhost port 10026. </p> + +<p> For non-SMTP capable content filtering software, Bennett Todd's +SMTP proxy implements a nice PERL/SMTP content filtering framework. +See: <a href="https://web.archive.org/web/20151022025756/http://bent.latency.net/smtpprox/">https://web.archive.org/web/20151022025756/http://bent.latency.net/smtpprox/</a>. </p> + +<p> In the figure below, names followed by a number represent +Postfix commands or daemon programs. See the <a href="OVERVIEW.html">OVERVIEW</a> +document for an introduction to the Postfix architecture. </p> + +<blockquote> + +<table> + +<tr> + + <td align="center" valign="middle"> Unfiltered<br> <br> + Unfiltered</td> + + <td align="center" valign="middle"> <tt> -></tt><br> <br> + <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="smtpd.8.html">smtpd(8)</a><br> <br> <a href="pickup.8.html">pickup(8)</a> </td> + + <td align="center" valign="middle"> <tt> >- </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="cleanup.8.html">cleanup(8)</a> </td> + + <td align="center" valign="middle"> <tt> -> </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="qmgr.8.html">qmgr(8)</a><br> Postfix <br> queue </td> + + <td align="center" valign="middle"> <tt> -< </tt> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="smtp.8.html">smtp(8)</a><br> <br> <a href="local.8.html">local(8)</a> </td> + + <td align="center" valign="middle"> <tt> -></tt><br> <br> + <tt> -> </tt></td> + + <td align="center" valign="middle"> Filtered<br> <br> + Filtered</td> + +</tr> + +<tr> + + <td colspan="4"> </td> + + <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> + + <td> </td> + + <td align="center" valign="middle"> <tt> |<br> v </tt> </td> + + <td colspan="4"> </td> + +</tr> + +<tr> + + <td colspan="4"> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="smtpd.8.html">smtpd(8)</a><br> 10026 </td> + + <td> </td> + + <td bgcolor="#f0f0ff" align="center" valign="middle"> + <a href="smtp.8.html">smtp(8)</a><br> </td> + + <td colspan="4"> </td> + +</tr> + +<tr> + + <td colspan="4"> </td> + + <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> + + <td> </td> + + <td align="center" valign="middle"> <tt> |<br> v </tt> </td> + + <td colspan="4"> </td> + +</tr> + +<tr> + + <td colspan="4"> </td> + + <td colspan="3" bgcolor="#f0f0ff" align="center" + valign="middle">content filter 10025</td> + + <td colspan="4"> </td> + +</tr> + +</table> + +</blockquote> + +<p> The example given here filters all mail, including mail that +arrives via SMTP and mail that is locally submitted via the Postfix +sendmail command (local submissions enter Postfix via the <a href="pickup.8.html">pickup(8)</a> +server; to keep the figure simple we omit local submission details). +See examples near the end of this document for +how to exclude local users from filtering, or how to configure a +destination dependent content filter. </p> + +<p> You can expect to lose about a factor of two in Postfix +performance for mail that arrives and leaves via SMTP, provided +that the content filter creates no temporary files. Each temporary +file created by the content filter adds another factor to the +performance loss. </p> + +<h3>Advanced content filter: requesting that all mail is filtered</h3> + +<p> To enable the advanced content filter method for all mail, +specify in <a href="postconf.5.html">main.cf</a>: </p> + +<blockquote> +<pre> +/etc/postfix/<a href="postconf.5.html">main.cf</a>: + <a href="postconf.5.html#content_filter">content_filter</a> = scan:localhost:10025 + <a href="postconf.5.html#receive_override_options">receive_override_options</a> = <a href="postconf.5.html#no_address_mappings">no_address_mappings</a> +</pre> +</blockquote> + +<ul> + +<li> <p> The "<a href="postconf.5.html#receive_override_options">receive_override_options</a>" line disables address +manipulation before the content filter, so that the content filter +sees the original mail addresses instead of the result of virtual +alias expansion, canonical mapping, automatic bcc, address +masquerading, etc. </p> + +<li> <p> The "<a href="postconf.5.html#content_filter">content_filter</a>" line causes Postfix to add one content +filter request record to each incoming mail message, with content +"scan:localhost:10025". The content filter request records are +added by the <a href="smtpd.8.html">smtpd(8)</a> and <a href="pickup.8.html">pickup(8)</a> servers (and <a href="qmqpd.8.html">qmqpd(8)</a> if you +decide to enable this service). </p> + +<li> <p> Content filter requests are stored in queue files; this +is how Postfix keeps track of what mail needs filtering. When a +queue file contains a content filter request, the queue manager +will deliver the mail to the specified content filter regardless +of its final destination. </p> + +<li> <p> The <a href="postconf.5.html#content_filter">content_filter</a> configuration parameter expects a value +of the form <i>transport:destination</i>. The <i>transport</i> name +specifies the first field of a mail delivery agent definition in +<a href="master.5.html">master.cf</a>; the syntax of the next-hop <i>destination</i> is described +in the manual page of the corresponding delivery agent. </p> + +<li> <p> The meaning of an empty next-hop filter <i>destination</i> +is version dependent. Postfix 2.7 and later will use the recipient +domain; earlier versions will use $<a href="postconf.5.html#myhostname">myhostname</a>. Specify +"<a href="postconf.5.html#default_filter_nexthop">default_filter_nexthop</a> = $<a href="postconf.5.html#myhostname">myhostname</a>" for compatibility with Postfix +2.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>. + +<li> <p> The <a href="postconf.5.html#content_filter">content_filter</a> setting has lower precedence than a +FILTER action that is specified in an <a href="access.5.html">access(5)</a>, <a href="header_checks.5.html">header_checks(5)</a> +or <a href="header_checks.5.html">body_checks(5)</a> table. </p> + +</ul> + +<h3> Advanced content filter: sending unfiltered mail to the content +filter</h3> + +<p> In this example, "scan" is an instance of the Postfix SMTP +client with slightly different configuration parameters. This is +how one would set up the service in the Postfix <a href="master.5.html">master.cf</a> file: +</p> + +<blockquote> +<pre> +/etc/postfix/<a href="master.5.html">master.cf</a>: + # ============================================================= + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ============================================================= + scan unix - - n - 10 smtp + -o <a href="postconf.5.html#smtp_send_xforward_command">smtp_send_xforward_command</a>=yes + -o <a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a>=yes + -o <a href="postconf.5.html#smtp_generic_maps">smtp_generic_maps</a>= +</pre> +</blockquote> + +<ul> + +<li> <p> This runs up to 10 content filters in parallel. Instead +of a limit of 10 concurrent processes, use whatever process limit +is feasible for your machine. Content inspection software can +gobble up a lot of system resources, so you don't want to have too +much of it running at the same time. </p> + +<li> <p> With "-o <a href="postconf.5.html#smtp_send_xforward_command">smtp_send_xforward_command</a>=yes", the scan transport +will try to forward the original client name and IP address +through the content filter to the +after-filter smtpd process, so that filtered mail is logged with +the real client name IP address. See <a href="smtp.8.html">smtp(8)</a> and <a href="XFORWARD_README.html">XFORWARD_README</a> +for more information. </p> + +<li> <p> The "-o <a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a>=yes" is a workaround +that prevents the breaking of domainkeys and other digital signatures. +This is needed because some SMTP-based content filters don't announce +8BITMIME support, even though they can handle 8-bit mail. </p> + +<li> <p> The "-o <a href="postconf.5.html#smtp_generic_maps">smtp_generic_maps</a>=" is a workaround that prevents +local address rewriting with <a href="generic.5.html">generic(5)</a> maps. Such rewriting should +happen only when mail is sent out to the Internet. </p> + +</ul> + +<h3>Advanced content filter: running the content filter</h3> + +<p> The content filter can be set up with the Postfix spawn service, +which is the Postfix equivalent of inetd. For example, to instantiate +up to 10 content filtering processes on localhost port 10025: </p> + +<blockquote> +<pre> +/etc/postfix/<a href="master.5.html">master.cf</a>: + # =================================================================== + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # =================================================================== + localhost:10025 inet n n n - 10 spawn + user=filter argv=/path/to/filter localhost 10026 +</pre> +</blockquote> + +<ul> + +<li> <p> "filter" is a dedicated local user account. The user will +never log in, and can be given a "*" password and non-existent +shell and home directory. This user handles all potentially +dangerous mail content - that is why it should be a separate account. +</p> + +<li> <p> By default, Postfix will terminate a command that runs +longer than <a href="postconf.5.html#command_time_limit">command_time_limit</a> seconds (default: 1000s). This is a +safety measure that prevents filters from running forever. </p> + +</ul> + +<p> If you want to have your filter listening on port localhost:10025 +instead of Postfix, then you must run your filter as a stand-alone +program, and must not use the Postfix spawn service. </p> + +<h3>Advanced filter: injecting mail back into Postfix</h3> + +<p> The job of the content filter is to either bounce mail with a +suitable diagnostic, or to feed the mail back into Postfix through +a dedicated listener on port localhost 10026. </p> + +<p> The simplest content filter just copies SMTP commands and data +between its inputs and outputs. If it has a problem, all it has to +do is to reply to an input of `.' from Postfix with `550 content +rejected', and to disconnect without sending `.' on the connection +that injects mail back into Postfix. </p> + +<blockquote> +<pre> +/etc/postfix/<a href="master.5.html">master.cf</a>: + # =================================================================== + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # =================================================================== + localhost:10026 inet n - n - 10 smtpd + -o <a href="postconf.5.html#content_filter">content_filter</a>= + -o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_unknown_recipient_checks">no_unknown_recipient_checks</a>,<a href="postconf.5.html#no_header_body_checks">no_header_body_checks</a>,<a href="postconf.5.html#no_milters">no_milters</a> + -o <a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a>= + -o <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>= + -o <a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a>= + # Postfix 2.10 and later: specify empty <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>. + -o <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>= + -o <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a>=<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject + -o <a href="postconf.5.html#mynetworks">mynetworks</a>=127.0.0.0/8 + -o <a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a>=127.0.0.0/8 +</pre> +</blockquote> + +<ul> + +<li> <p> NOTE: do not use spaces around the "=" or "," characters. </p> + +<li> <p> NOTE: the SMTP server must not have a smaller process +limit than the "filter" <a href="master.5.html">master.cf</a> entry. </p> + +<li> <p> The "-o <a href="postconf.5.html#content_filter">content_filter</a>=" overrides <a href="postconf.5.html">main.cf</a> settings, and +requests no content filtering for mail from the content filter. +This is required or else mail will loop. </p> + +<li> <p> The "-o <a href="postconf.5.html#receive_override_options">receive_override_options</a>" overrides <a href="postconf.5.html">main.cf</a> settings +to avoid duplicating work that was already done before the content +filter. These options are complementary to the options that are +specified in <a href="postconf.5.html">main.cf</a>: </p> + +<ul> + + <li> <p> We specify "<a href="postconf.5.html#no_unknown_recipient_checks">no_unknown_recipient_checks</a>" to disable + attempts to find out if a recipient is unknown. </p> + + <li> <p> We specify "<a href="postconf.5.html#no_header_body_checks">no_header_body_checks</a>" to disable header/body + checks. </p> + + <li> <p> We specify "<a href="postconf.5.html#no_milters">no_milters</a>" to disable Milter applications + (this option is available only in Postfix 2.3 and later). </p> + + <li> <p> We don't specify "<a href="postconf.5.html#no_address_mappings">no_address_mappings</a>" here. This + enables virtual alias expansion, canonical mappings, address + masquerading, and other address mappings after the content + filter. The <a href="postconf.5.html">main.cf</a> setting of "<a href="postconf.5.html#receive_override_options">receive_override_options</a>" + disables these mappings before the content filter. </p> + +</ul> + + <p> These receive override options are either implemented by the + SMTP server itself, or they are passed on to the cleanup server. + </p> + +<li> <p> The "-o smtpd_xxx_restrictions" and "-o <a href="postconf.5.html#mynetworks">mynetworks</a>=127.0.0.0/8" +override <a href="postconf.5.html">main.cf</a> settings. They turn off junk mail controls that +would only waste time here. + +<li> <p> With "-o <a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a>=127.0.0.0/8", +the scan transport will try to forward the original client name +and IP address to the after-filter smtpd process, so that filtered +mail is logged with the real client name and IP address. See +<a href="XFORWARD_README.html">XFORWARD_README</a> and <a href="smtpd.8.html">smtpd(8)</a>. </p> + +</ul> + +<h2><a name="performance">Advanced content filter performance</a></h2> + +<p> With the "sandwich" approach to content filtering described +here, it is important to match the filter concurrency to the +available CPU, memory and I/O resources. Too few content filter +processes and mail accumulates in the <a href="QSHAPE_README.html#active_queue">active queue</a> even with low +traffic volume; too much concurrency and Postfix ends up deferring +mail destined for the content filter because processes fail due to +insufficient resources. </p> + +<p> Currently, content filter performance tuning is a process of +trial and error; analysis is handicapped because filtered and +unfiltered messages share the same queue. As mentioned in the +introduction of this document, content filtering with multiple +Postfix instances will be covered in a future version. </p> + +<h2><a name="advanced_turnoff">Turning off the advanced content filter</a> </h2> + +<p> To turn off "advanced" content filtering: </p> + +<ul> <li> <p> Delete or comment out the two following <a href="postconf.5.html">main.cf</a> lines. +The other changes made for advanced content filtering have no effect +when content filtering is turned off. </p> + +<blockquote> +<pre> +/etc/postfix/<a href="postconf.5.html">main.cf</a>: + <a href="postconf.5.html#content_filter">content_filter</a> = scan:localhost:10025 + <a href="postconf.5.html#receive_override_options">receive_override_options</a> = <a href="postconf.5.html#no_address_mappings">no_address_mappings</a> +</pre> +</blockquote> + +<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content +filter request records from existing queue files. </p> + +<li> <p> Execute another "<b>postfix reload</b>". </p> + +</ul> + +<h2><a name="remote_only">Filtering mail from outside users only</a></h2> + +<p> The easiest approach is to configure ONE Postfix instance with +multiple SMTP server IP addresses in <a href="master.5.html">master.cf</a>: </p> + +<ul> + +<li> <p> Two SMTP server IP addresses for mail from inside users only, +with content filtering turned off. </p> + +<pre> +/etc/postfix.<a href="master.5.html">master.cf</a>: + # ================================================================== + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ================================================================== + 1.2.3.4:smtp inet n - n - - smtpd + -o <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>=<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject + 127.0.0.1:smtp inet n - n - - smtpd + -o <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>=<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,reject +</pre> + +<li> <p> One SMTP server address for mail from outside users with +content filtering turned on. </p> + +<pre> +/etc/postfix.<a href="master.5.html">master.cf</a>: + # ================================================================= + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ================================================================= + 1.2.3.5:smtp inet n - n - - smtpd + -o <a href="postconf.5.html#content_filter">content_filter</a>=filter-service:filter-destination + -o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a> +</pre> + +</ul> + +<p> After this, you can follow the same procedure as outlined in +the "advanced" or "simple" content filtering examples above, except +that you must not specify "<a href="postconf.5.html#content_filter">content_filter</a>" or "<a href="postconf.5.html#receive_override_options">receive_override_options</a>" +in the <a href="postconf.5.html">main.cf</a> file. </p> + +<h2><a name="domain_dependent">Different filters for different +domains</a></h2> + +<p> If you are an MX service provider and want to apply different +content filters for different domains, you can configure ONE Postfix +instance with multiple SMTP server IP addresses in <a href="master.5.html">master.cf</a>. Each +address provides a different content filter service. </p> + +<blockquote> +<pre> +/etc/postfix.<a href="master.5.html">master.cf</a>: + # ================================================================= + # service type private unpriv chroot wakeup maxproc command + # (yes) (yes) (yes) (never) (100) + # ================================================================= + # SMTP service for domains that are filtered with service1:dest1 + 1.2.3.4:smtp inet n - n - - smtpd + -o <a href="postconf.5.html#content_filter">content_filter</a>=service1:dest1 + -o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a> + + # SMTP service for domains that are filtered with service2:dest2 + 1.2.3.5:smtp inet n - n - - smtpd + -o <a href="postconf.5.html#content_filter">content_filter</a>=service2:dest2 + -o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a> +</pre> +</blockquote> + +<p> After this, you can follow the same procedure as outlined in +the "advanced" or "simple" content filtering examples above, except +that you must not specify "<a href="postconf.5.html#content_filter">content_filter</a>" or "<a href="postconf.5.html#receive_override_options">receive_override_options</a>" +in the <a href="postconf.5.html">main.cf</a> file. </p> + +<p> Set up MX records in the DNS that route each domain to the +proper SMTP server instance. </p> + +<h2><a name="dynamic_filter">FILTER actions in access or header/body +tables</a></h2> + +<p> The above filtering configurations are static. Mail that follows +a given path is either always filtered or it is never filtered. As +of Postfix 2.0 you can also turn on content filtering on the fly. +</p> + +<p> To turn on content filtering with an <a href="access.5.html">access(5)</a> table rule: </p> + +<blockquote> +<pre> +/etc/postfix/access: + <i>whatever</i> FILTER foo:bar +</pre> +</blockquote> + +<p> To turn on content filtering with a <a href="header_checks.5.html">header_checks(5)</a> or +<a href="header_checks.5.html">body_checks(5)</a> table pattern: </p> + +<blockquote> +<pre> +/etc/postfix/header_checks: + /<i>whatever</i>/ FILTER foo:bar +</pre> +</blockquote> + +<p> You can do this in smtpd access maps as well as the cleanup +server's header/body_checks. This feature must be used with great +care: you must disable all the UCE features in the after-filter +smtpd and cleanup daemons or else you will have a content filtering +loop. </p> + +<p> Limitations: </p> + +<ul> + +<li> <p> FILTER actions from smtpd access maps and header/body_checks +take precedence over filters specified with the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#content_filter">content_filter</a> +parameter. </p> + +<li> <p> If a message triggers more than one filter action, only +the last one takes effect. </p> + +<li> <p> The same content filter is applied to all the recipients +of a given message. </p> + +</ul> + +</body> + +</html> |