1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
|
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Postfix Before-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 Before-Queue Content Filter </h1>
<hr>
<h2>WARNING </h2>
<p> The before-queue content filtering feature described in this
document limits the amount of mail that a site can handle. See the
"<a href="#pros_cons">Pros and Cons</a>" section below for details.
</p>
<h2>The Postfix before-queue content filter feature</h2>
<p> As of version 2.1, the Postfix SMTP server can forward all
incoming mail to a content filtering proxy server that inspects all
mail BEFORE it is stored in the Postfix mail queue. It is roughly
equivalent in capabilities to the approach described in MILTER_README,
except that the latter uses a dedicated protocol instead of SMTP.
<p> The before-queue content filter is meant to be used as follows: </p>
<blockquote>
<table>
<tr>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> Internet </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="smtpd.8.html">Postfix SMTP server</a>
</td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <b>Before</b> <b>queue</b> <b>filter</b> </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="smtpd.8.html">Postfix SMTP server</a>
</td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="cleanup.8.html">Postfix cleanup
server</a> </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> Postfix queue </td>
<td align="center" valign="middle" width="5%"> <tt> -< </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="smtp.8.html">smtp</a><br> <a
href="local.8.html">local</a><br> <a
href="virtual.8.html">virtual</a> </td>
</tr>
</table>
</blockquote>
<p> The before-queue content filter is not to be confused with the
approach described in the FILTER_README document, where mail is
filtered AFTER it is stored in the Postfix mail queue. </p>
<p> This document describes the following topics: </p>
<ul>
<li><a href="#principles">Principles of operation</a>
<li><a href="#pros_cons">Pros and cons of before-queue content filtering</a>
<li><a href="#config">Configuring the Postfix SMTP pass-through
proxy feature</a>
<li><a href="#parameters">Configuration parameters</a>
<li><a href="#protocol">How Postfix talks to the before-queue content
filter</a>
</ul>
<h2><a name="principles">Principles of operation</a></h2>
<p> As shown in the diagram above, the before-queue filter sits
between two Postfix SMTP server processes. </p>
<ul>
<li> <p> The before-filter Postfix SMTP server accepts connections from the
Internet and does the usual relay access control, SASL authentication,
TLS negotiation,
RBL lookups, rejecting non-existent sender or recipient addresses,
etc. </p>
<li> <p> The before-queue filter receives unfiltered mail content from
Postfix and does one of the following: </p>
<ol>
<li> <p> Re-inject the mail back into Postfix via SMTP, perhaps
after changing its content and/or destination. </p>
<li> <p> Discard or quarantine the mail. </p>
<li> <p> Reject the mail by sending a suitable SMTP status code
back to Postfix. Postfix passes the status back to the remote
SMTP client. This way, Postfix does not have to send a bounce
message. </p>
</ol>
<li> <p>The after-filter Postfix SMTP server receives mail from the
content filter. From then on Postfix processes the mail as usual. </p>
</ul>
<p> The before-queue content filter described here works just like
the after-queue content filter described in the FILTER_README
document. In many cases you can use the same software, within the
limitations as discussed in the "<a href="#pros_cons">Pros and
Cons</a>" section below. </p>
<h2><a name="pros_cons">Pros and cons of before-queue content
filtering</a></h2>
<ul>
<li> <p> Pro: Postfix can reject mail before the incoming SMTP mail
transfer completes, so that Postfix does not have to send rejected
mail back to the sender (which is usually forged anyway). Mail
that is not accepted remains the responsibility of the remote SMTP
client. </p>
<li> <p> Con: The smtpd(8) service before the smtpd_proxy_filter
cannot support features that involve header or body access, or that
involve queue file manipulation (i.e., anything that involves
processing by the cleanup(8) service). </p>
<ul>
<li> <p> No support for HOLD actions in Postfix smtpd access(5)
restrictions. </p>
<li> <p> No support for smtpd_milters features that involve message
header or body content. </p>
<li> <p> No support for receive_override_options.
</ul>
<p> Instead, specify those features with the smtpd(8) service behind
the smtpd_proxy_filter. In some cases, it may be possible to combine
a before-filter PREPEND action that emits a unique pattern (for
example containing the MTA domain name), with an after-filter
header_checks action that does what you want, and with an
smtp_header_checks IGNORE action that deletes the prepended header
from transit mail. </p>
<li> <p> Con: The remote SMTP client expects an SMTP reply within
a deadline. As the system load increases, fewer and fewer CPU
cycles remain available to answer within the deadline, and eventually
you either have to stop accepting mail or you have to stop filtering
mail. It is for this reason that the before-queue content filter
limits the amount of mail that a site can handle. </p>
<li> <p> Con: Content filtering software can use lots of memory
resources. You have to reduce the number of simultaneous content
filter processes so that a burst of mail will not drive your system
into the ground. </p>
<ul>
<li> <p> With Postfix versions 2.7 and later, SMTP clients will
experience an increase in the delay between the time the client
sends "end-of-message" and the time the Postfix SMTP server replies
(here, the number of before-filter SMTP server processes can be
larger than the number of filter processes). </p>
<li> <p> With Postfix versions before 2.7, SMTP clients will
experience an increase in the delay before they can receive service
(here, the number of before-filter SMTP server processes is always
equal to the number of filter processes). </p>
</ul>
</ul>
<h2><a name="config">Configuring the Postfix SMTP pass-through
proxy feature</a></h2>
<p> In the following example, the before-filter Postfix SMTP server
gives mail to a content filter that listens on localhost port 10025.
The after-filter Postfix SMTP server receives mail from the content
filter via localhost port 10026. From then on mail is processed as
usual. </p>
<p> The content filter itself is not described here. You can use
any filter that is SMTP enabled. For non-SMTP capable content
filtering software, Bennett Todd's SMTP proxy implements a nice
Perl-based framework. See:
https://web.archive.org/web/20151022025756/http://bent.latency.net/smtpprox/
or https://github.com/jnorell/smtpprox/ </p>
<blockquote>
<table border="0">
<tr>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> Internet </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="smtpd.8.html">Postfix SMTP server on
port 25</a> </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> filter on localhost port 10025 </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="smtpd.8.html">Postfix SMTP server on
localhost port 10026</a> </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> <a href="cleanup.8.html">Postfix cleanup
server</a> </td>
<td align="center" valign="middle" width="5%"> <tt> -> </tt> </td>
<td bgcolor="#f0f0ff" align="center" valign="middle"
width="10%"> Postfix incoming queue </td>
</tr>
</table>
</blockquote>
<p> This is configured by editing the master.cf file: </p>
<blockquote>
<pre>
/etc/postfix/master.cf:
# =============================================================
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =============================================================
#
# Before-filter SMTP server. Receive mail from the network and
# pass it to the content filter on localhost port 10025.
#
smtp inet n - n - 20 smtpd
-o smtpd_proxy_filter=127.0.0.1:10025
-o smtpd_client_connection_count_limit=10
# Postfix 2.7 and later performance feature.
# -o smtpd_proxy_options=speed_adjust
#
# After-filter SMTP server. Receive mail from the content filter
# on localhost port 10026.
#
127.0.0.1:10026 inet n - n - - smtpd
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
# Postfix 2.10 and later: specify empty smtpd_relay_restrictions.
-o smtpd_relay_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=
-o mynetworks=127.0.0.0/8
-o receive_override_options=no_unknown_recipient_checks
</pre>
</blockquote>
<p> Note: do not specify spaces around the "=" or "," characters. </p>
<p> The before-filter SMTP server entry is a modified version of the
default Postfix SMTP server entry that is normally configured at
the top of the master.cf file: </p>
<ul>
<li> <p> The number of SMTP sessions is reduced from the default
100 to only 20. This prevents a burst of mail from running your
system into the ground with too many content filter processes. </p>
<li> <p> The "-o smtpd_client_connection_count_limit=10" prevents
one SMTP client from using up all 20 SMTP server processes.
This limit is not necessary if you receive all mail from a
trusted relay host. </p>
<p> Note: this setting is available in Postfix version 2.2 and
later. Earlier Postfix versions will ignore it. </p>
<li> <p> The "-o smtpd_proxy_filter=127.0.0.1:10025" tells the
before-filter SMTP server that it should give incoming mail to
the content filter that listens on localhost TCP port 10025.
<li> <p> The "-o smtpd_proxy_options=speed_adjust" tells the
before-filter SMTP server that it should receive an entire email
message before it connects to a content filter. This reduces
the number of simultaneous filter processes. </p>
<p> NOTE 1: When this option is turned on, a content filter must
not <i>selectively</i> reject recipients of a multi-recipient
message. Rejecting all recipients is OK, as is accepting all
recipients. </p>
<p> NOTE 2: This feature increases the minimum amount of free
queue space by $message_size_limit. The extra space is needed
to save the message to a temporary file. </p>
<li> <p> Postfix ≥ 2.3 supports both TCP and UNIX-domain filters.
The above filter could be specified as "inet:127.0.0.1:10025".
To specify a UNIX-domain filter, specify "unix:<i>pathname</i>".
A relative pathname is interpreted relative to the Postfix queue
directory. </p>
</ul>
<p> The after-filter SMTP server is a new master.cf entry: </p>
<ul>
<li> <p> The "127.0.0.1:10026" makes the after-filter SMTP
server listen
on the localhost address only, without exposing it to the
network. NEVER expose the after-filter SMTP server to the
Internet :-) </p>
<li> <p> The "-o smtpd_authorized_xforward_hosts=127.0.0.0/8"
allows the after-filter SMTP server to receive remote SMTP
client information from the before-filter SMTP server, so that
the after-filter Postfix daemons log the remote SMTP client
information instead of logging localhost[127.0.0.1]. </p>
<li> <p> The other after-filter SMTP server settings avoid
duplication of work that is already done in the "before filter"
SMTP server. </p>
</ul>
<p> By default, the filter has 100 seconds to do its work. If it
takes longer then Postfix gives up and reports an error to the
remote SMTP client. You can increase this time limit (see the <a href="#parameters">"Configuration
parameters"</a> section below) but doing so is pointless because you
can't control when the remote SMTP client times out. </p>
<h2><a name="parameters">Configuration parameters</a></h2>
<p> Parameters that control proxying: </p>
<ul>
<li> <p> smtpd_proxy_filter (syntax: host:port): The host and TCP
port of the before-queue content filter. When no host or host:
is specified here, localhost is assumed. </p>
<li> <p> smtpd_proxy_timeout (default: 100s): Timeout for connecting
to the before-queue content filter and for sending and receiving
commands and data. All proxy errors are logged to the maillog
file. For privacy reasons, all the remote SMTP client sees is "451
Error: queue file write error". It would not be right to disclose
internal details to strangers. </p>
<li> <p> smtpd_proxy_ehlo (default: $myhostname): The hostname to
use when sending an EHLO command to the before-queue content filter.
</p>
</ul>
<h2><a name="protocol">How Postfix talks to the before-queue content
filter</a></h2>
<p> The before-filter Postfix SMTP server connects to the content
filter, delivers one message, and disconnects. While sending mail
into the content filter, Postfix speaks ESMTP but uses no command
pipelining. Postfix generates its own EHLO, XFORWARD (for logging
the remote client IP address instead of localhost[127.0.0.1]), DATA
and QUIT commands, and forwards unmodified copies of all the MAIL
FROM and RCPT TO commands that the before-filter Postfix SMTP server
didn't reject itself.
Postfix sends no other SMTP commands. </p>
<p> The content filter should accept the same MAIL FROM and RCPT
TO command syntax as the before-filter Postfix SMTP server, and
should forward the commands without modification to the after-filter
SMTP server. If the content filter or after-filter SMTP server
does not support all the ESMTP features that the before-filter
Postfix SMTP server supports, then the missing features must be
turned off in the before-filter Postfix SMTP server with the
smtpd_discard_ehlo_keywords parameter. </p>
<p> When the filter rejects content, it should send a negative SMTP
response back to the before-filter Postfix SMTP server, and it
should abort the connection with the after-filter Postfix SMTP
server without completing the SMTP conversation with the after-filter
Postfix SMTP server. </p>
</body>
</html>
|