2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-2.7-20091229

This commit is contained in:
Wietse Venema 2009-12-29 00:00:00 -05:00 committed by Viktor Dukhovni
parent 51826fc8f2
commit 2ccf57f4ac
37 changed files with 1692 additions and 408 deletions

1
postfix/.indent.pro vendored
View File

@ -57,6 +57,7 @@
-TDELIVER_REQUEST
-TDELTA_TIME
-TDICT
-TDICT_CACHE
-TDICT_CDBM
-TDICT_CDBQ
-TDICT_CIDR

View File

@ -15453,7 +15453,7 @@ Apologies for any names omitted.
20091023
Feature: specify "smtp_command_filter = pcre:/file/name"
Feature: specify "smtpd_command_filter = pcre:/file/name"
to replace remote SMTP client commands before they are
executed by the Postfix SMTP server. This a last-resort
tool to fix inter-operability problems. See examples in
@ -15563,3 +15563,42 @@ Apologies for any names omitted.
Cleanup: the postscreen daemon now applies the permanent
whitelist first. It is a safety feature that prevents mail
from being blocked. File: postscreeb/postscreen.c.
20091224
Bugfix (introduced 20041215): dict_dbm_sequence() did not
release the shared lock when the end of the sequence was
reached. File: util/dict_dbm.c.
20091227
Cleanup: postscreen and verify periodic cache cleanup
(default: 12 hours after the previous cache cleanup run).
This is based on a new dict_cache(3) module that implements
a generalized version of the tlsmgr(8) cache maintenance
code. Once the new dict_cache(3) code is burned in, the
tlsmgr(8) will be migrated to it. See the RELEASE_NOTES for
user interface details. Files: util/htable.[hc], util/dict_ht.c,
util/dict_cache.[hc], postscreen/postscreen.c, verify/verify.c.
Bugfix: the event handler starved I/O events when a timer
call-back routine scheduled a zero-delay timer request.
This bug was exposed when adding the new dict_cache(3)
module for cache expiration. File: util/events.c.
20091228
Cleanup: postscreen and verify periodic cache cleanup is
now optional (specify a null time interval between cache
cleanup runs).
20091229
Cleanup: the address_verify_poll_count default parameter
value is now stress-dependent, so that the Postfix SMTP
server will not wait (up to 6 seconds) for the address
verification result. File: global/mail_params.h.
Final slution for the I/O event starvation problem when a
timer call-back schedules a zero-delay timer request. File:
util/events.c.

View File

@ -36,23 +36,28 @@ This document describes the following topics:
PPrriinncciipplleess ooff ooppeerraattiioonn
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. The before-
queue filter receives unfiltered mail content from Postfix and does one of the
following:
As shown in the diagram above, the before-queue filter sits between two Postfix
SMTP server processes.
1. Re-inject the mail back into Postfix via SMTP, perhaps after changing its
content and/or destination.
* 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.
2. Discard or quarantine the mail.
* The before-queue filter receives unfiltered mail content from Postfix and
does one of the following:
3. 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.
1. Re-inject the mail back into Postfix via SMTP, perhaps after changing
its content and/or destination.
The after-filter Postfix SMTP server receives mail from the content filter.
From then on Postfix processes the mail as usual.
2. Discard or quarantine the mail.
3. 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.
* The after-filter Postfix SMTP server receives mail from the content filter.
From then on Postfix processes the mail as usual.
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

View File

@ -14,6 +14,33 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.5 or earlier, read RELEASE_NOTES-2.6
before proceeding.
Incompatibility with snapshot 20091229
======================================
The verify(8) service now uses a persistent cache by default
(address_verify_map = btree:$data_directory/verify_cache). To
disable, specify "address_verify_map =" in main.cf.
When periodic cache cleanup is enabled (the default), the postscreen(8)
and verify(8) servers now require that their cache databases support
the "delete" and "sequence" operations. To disable periodic cache
cleanup specify a zero xxx_cache_cleanup_interval.
Major changes with snapshot 20091229
====================================
Periodic cache cleanup for the postscreen(8) and verify(8) cache
databases. The time between cache cleanup runs is controlled with
the address_verify_cache_cleanup_interval (default: 12h) and
postscreen_cache_cleanup_interval (default: 12h) parameters. Cache
cleanup increases the database access latency, so this should not
be run more often than necessary.
In addition, the postscreen_cache_retention_time (default: 1d)
parameter specifies how long to keep an expired entry in the cache.
This prevents a client from being logged as "NEW" after its record
expired only a little while ago.
Incompatibility with snapshot 20091209
======================================
@ -112,11 +139,12 @@ without blocking mail:
1 - Comment out the "smtp inet ... smtpd" service in master.cf,
including any "-o parameter=value" entries that follow.
2 - Uncomment the new "smtpd pass ... smtpd" service in master.cf.
2 - Uncomment the new "smtpd pass ... smtpd" service in master.cf,
and duplicate any "-o parameter=value" entries from the smtpd
service that was commented out in step 1.
3 - Uncomment the the new "smtp inet ... postscreen" service in
master.cf, and duplicate any "-o parameter=value" entries from
the smtpd service that was commented out in step 1.
master.cf.
4 - Uncomment the new "dnsblog unix ... dnsblog" service in
master.cf. This service does DNSBL lookups for postscreen(8)

View File

@ -2,11 +2,25 @@ Wish list:
Remove this file from the stable release.
It would be nice if the generic dict_cache(3) cache manager
could postpone process suicide until cache cleanup is
completed (but that is not possible when postscreen forks
into the background to finish already-accepted connections).
When postscreen drops a connection, a 521 "greeting" should
be of the form "521 servername..." and not have an enhanced
status code. The "521 5.7.1" form can be used after EHLO.
Of course no spammer is going to complain about Postfix
SMTP compliance.
Find a place to document all the mail routing mechanisms
in one place so people can figure out how Postfix works.
owner-listname does not work for shell commands.
Investigate viability of Sendmail socket maps (the moral
equivalent of tcp_table(5)), and dns maps.
The BCC action is marked "not stable", perhaps because
people would also expect BCC actions in header/body_checks.
How much would it take to make the queue file editing code

View File

@ -108,11 +108,18 @@ filter</a>
<h2><a name="principles">Principles of operation</a></h2>
<p> The before-filter Postfix SMTP server accepts connections from the
<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. The before-queue filter receives unfiltered mail content from
etc. </p>
<li> <p> The before-queue filter receives unfiltered mail content from
Postfix and does one of the following: </p>
<ol>
@ -129,9 +136,11 @@ Postfix and does one of the following: </p>
</ol>
<p>The after-filter Postfix SMTP server receives mail from the
<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 <a href="FILTER_README.html">FILTER_README</a>
document. In many cases you can use the same software, within the

View File

@ -58,8 +58,10 @@ CLEANUP(8) CLEANUP(8)
<a href="http://tools.ietf.org/html/rfc822">RFC 822</a> (ARPA Internet Text Messages)
<a href="http://tools.ietf.org/html/rfc2045">RFC 2045</a> (MIME: Format of Internet Message Bodies)
<a href="http://tools.ietf.org/html/rfc2046">RFC 2046</a> (MIME: Media Types)
<a href="http://tools.ietf.org/html/rfc2822">RFC 2822</a> (Internet Message Format)
<a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a> (Enhanced Status Codes)
<a href="http://tools.ietf.org/html/rfc3464">RFC 3464</a> (Delivery status notifications)
<a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> (Internet Message Format)
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).

View File

@ -119,6 +119,23 @@ Do not change this unless you have a complete understanding of <a href="http://t
</p>
</DD>
<DT><b><a name="address_verify_cache_cleanup_interval">address_verify_cache_cleanup_interval</a>
(default: 12h)</b></DT><DD>
<p> The amount of time between <a href="verify.8.html">verify(8)</a> cache cleanup runs. Cache
cleanup increases the load on the cache database and should therefore
not be run frequently. This feature requires that the cache database
supports the "delete" and "sequence" operators. Specify a zero
interval to disable cache cleanup. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
</DD>
<DT><b><a name="address_verify_default_transport">address_verify_default_transport</a>
@ -249,7 +266,7 @@ This feature is available in Postfix 2.1 and later.
</DD>
<DT><b><a name="address_verify_poll_count">address_verify_poll_count</a>
(default: 3)</b></DT><DD>
(default: see "postconf -d" output)</b></DT><DD>
<p>
How many times to query the <a href="verify.8.html">verify(8)</a> service for the completion
@ -257,12 +274,16 @@ of an address verification request in progress.
</p>
<p>
The default poll count is 3.
With Postfix version 2.7 and later, the SMTP server polls the
<a href="verify.8.html">verify(8)</a> service up to three times under non-overload conditions,
and only once when under overload. With earlier Postfix versions,
the SMTP server always polls the <a href="verify.8.html">verify(8)</a> service up to three
times.
</p>
<p>
Specify 1 to implement a crude form of greylisting, that is, always
defer the first delivery request for a never seen before address.
defer the first delivery request for a new address.
</p>
<p>
@ -6561,6 +6582,23 @@ never uses the remote SMTP client hostname. </p>
<p> This feature is available in Postfix 2.7. </p>
</DD>
<DT><b><a name="postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a>
(default: 12h)</b></DT><DD>
<p> The amount of time between <a href="postscreen.8.html">postscreen(8)</a> cache cleanup runs.
Cache cleanup increases the load on the cache database and should
therefore not be run frequently. This feature requires that the
cache database supports the "delete" and "sequence" operators.
Specify a zero interval to disable cache cleanup. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
</DD>
<DT><b><a name="postscreen_cache_map">postscreen_cache_map</a>
@ -6571,6 +6609,22 @@ never uses the remote SMTP client hostname. </p>
<p> This feature is available in Postfix 2.7. </p>
</DD>
<DT><b><a name="postscreen_cache_retention_time">postscreen_cache_retention_time</a>
(default: 1d)</b></DT><DD>
<p> The amount of time that <a href="postscreen.8.html">postscreen(8)</a> will cache an expired
temporary whitelist entry before it is removed. This prevents clients
from being logged as "NEW" just because their cache entry expired
an hour ago. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
</DD>
<DT><b><a name="postscreen_cache_ttl">postscreen_cache_ttl</a>
@ -6579,9 +6633,9 @@ never uses the remote SMTP client hostname. </p>
<p> The amount of time that <a href="postscreen.8.html">postscreen(8)</a> will cache a decision for
a specific SMTP client IP address. During this time, the client IP
address is excluded from tests. If possible, expired decisions are
renewed silently. Specify a non-zero time value (an integral value
plus an optional one-letter suffix that specifies the time unit).
</p>
renewed automatically. Specify a non-zero time value (an integral
value plus an optional one-letter suffix that specifies the time
unit). </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
@ -6661,7 +6715,8 @@ IP address. </p>
<DT><b><a name="postscreen_greet_banner">postscreen_greet_banner</a>
(default: $<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b></DT><DD>
<p> The text in the optional "220-text..." server response that
<p> The <i>text</i> in the optional "220-<i>text</i>..." server
response that
<a href="postscreen.8.html">postscreen(8)</a> sends ahead of the real Postfix SMTP server's "220
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet). Specify an empty
@ -8905,7 +8960,7 @@ invalid responses. </p>
<ul>
<li> <p> In the case of a multi-line reply, the Postfix SMTP client
uses the last reply line's numerical SMTP reply code and enhanced
uses the final reply line's numerical SMTP reply code and enhanced
status code. </p>
<li> <p> The numerical SMTP reply code (XYZ) takes precedence over
@ -8924,16 +8979,16 @@ server, except that the trailing &lt;CR&gt;&lt;LF&gt; are removed. </p>
<pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_reply_filter">smtp_reply_filter</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/command_filter
<a href="postconf.5.html#smtp_reply_filter">smtp_reply_filter</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/reply_filter
</pre>
<pre>
/etc/postfix/reply_filter:
# Transform garbage into part of a multi-line reply. Note
# that the Postfix SMTP client uses only the last numerical
# SMTP reply code and enhanced status code from a multi-line
# reply, so it does not matter what we substitute here as
# long as it has the right syntax.
# Transform garbage into "250-filler..." so that it looks like
# one line from a multi-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix
# SMTP client will use the final line's numerical SMTP reply
# code and enhanced status code.
!/^([2-5][0-9][0-9]($|[- ]))/ 250-filler for garbage
</pre>
@ -11226,6 +11281,20 @@ except that initial whitespace and the trailing &lt;CR&gt;&lt;LF&gt;
are removed. The result value is executed by the Postfix SMTP
server. </p>
<p> Postfix already implements a number of workarounds for malformed
client commands. </p>
<ul>
<li> <p> Use "<a href="postconf.5.html#resolve_numeric_domain">resolve_numeric_domain</a> = yes" to accept "<i>user@ipaddress</i>"
Postfix already accepts the correct form "<i>user@[ipaddress]</i>".
</p>
<li> <p> Use "<a href="postconf.5.html#strict_rfc821_envelopes">strict_rfc821_envelopes</a> = no" to accept "<i>User Name
&lt;user@example.com&gt;</i>". </p>
</ul>
<p> Examples: </p>
<pre>
@ -11557,8 +11626,9 @@ it changes under overload to just 1 with Postfix 2.6 and later.
(default: no)</b></DT><DD>
<p>
Require that a remote SMTP client introduces itself at the beginning
of an SMTP session with the HELO or EHLO command.
Require that a remote SMTP client introduces itself with the HELO
or EHLO command before sending the MAIL command or other commands
that require EHLO negotiation.
</p>
<p>
@ -12800,12 +12870,12 @@ inside the chroot jail. </p>
<p> By default (see <a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>), client certificates are
not requested, and <a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> should remain empty. In contrast
to <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a>, DNs of certificate authorities installed
to <a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>, DNs of certificate authorities installed
in $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> are not included in the client certificate
request message. MUAs with multiple client certificates may use the
list of preferred certificate authorities to select the correct
client certificate. You may want to put your "preferred" CA or
CAs in $<a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a>, and install the remaining trusted CAs in
CAs in $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>, and install the remaining trusted CAs in
$<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a>. </p>
<p> Example: </p>

View File

@ -14,26 +14,34 @@ POSTSCREEN(8) POSTSCREEN(8)
<b>DESCRIPTION</b>
The Postfix <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server performs triage on multi-
ple inbound SMTP connections in parallel. The program can
run in two basic modes.
ple inbound SMTP connections in parallel. By running
time-consuming tests in parallel in <a href="postscreen.8.html"><b>postscreen</b>(8)</a>, zombies
and other bogus clients can be kept away from Postfix SMTP
server processes. Thus, more Postfix SMTP server processes
remain available for legitimate clients.
The purpose of <b>observation mode</b> is to collect statistics
without actually blocking mail. <a href="postscreen.8.html"><b>postscreen</b>(8)</a> runs a num-
ber of tests before it forwards a connection to a real
SMTP server process. These tests introduce a delay of a
few seconds; once a client passes the tests as "clean",
its IP address is temporarily whitelisted and subsequent
connections incur no delays until the temporary whitelist
entry expires.
This triage process involves a number of tests, documented
below. The tests introduce a delay of a few seconds; once
a client passes the tests, its IP address is temporarily
whitelisted, typically for 24 hours.
The purpose of <b>enforcement mode</b> is to block mail without
using up one Postfix SMTP server process for every connec-
tion. Here, <a href="postscreen.8.html"><b>postscreen</b>(8)</a> terminates connections from
SMTP clients that fail the above tests, and forwards only
the remaining connections to a real SMTP server process.
By running time-consuming spam tests in parallel in
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>, more Postfix SMTP server processes remain
available for legitimate clients.
The program can run in two basic modes.
<b>Observation mode</b>
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> reports the results of the tests, and
forwards all connections to a real Postfix SMTP
server process.
<b>Enforcement mode</b>
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> reports the results of the tests, but
forwards only connections to a real SMTP server
process from clients that passed the tests.
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> disconnects clients that fail the
tests, after sending a 521 status message (a future
version may pass the connection to a dummy SMTP
protocol engine that logs sender and recipient
information).
Note: <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is not an SMTP proxy; this is inten-
tional. The purpose is to prioritize legitimate clients
@ -44,144 +52,145 @@ POSTSCREEN(8) POSTSCREEN(8)
<b>1. PERMANENT WHITELIST TEST</b>
The <a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> parameter (default:
$<a href="postconf.5.html#mynetworks">mynetworks</a>) specifies a permanent whitelist for SMTP
client IP addresses. This feature is not used for
addresses that appear on the permanent blacklist.
client IP addresses.
When the SMTP client address matches the permanent
When the SMTP client address matches the permanent
whitelist, this is logged as:
<b>WHITELISTED</b> <i>address</i>
The action is not configurable: immediately forward the
The action is not configurable: immediately forward the
connection to a real SMTP server process.
<b>2. PERMANENT BLACKLIST TEST</b>
The <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter (default:
empty) specifies a permanent blacklist for SMTP client IP
The <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter (default:
empty) specifies a permanent blacklist for SMTP client IP
addresses. The address syntax is as with <a href="postconf.5.html#mynetworks">mynetworks</a>.
When the SMTP client address matches the permanent black-
When the SMTP client address matches the permanent black-
list, this is logged as:
<b>BLACKLISTED</b> <i>address</i>
The <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter specifies the
The <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter specifies the
action that is taken next:
<b>continue</b> (default, observation mode)
Continue with the SMTP GREETING PHASE TESTS below.
Continue with the SMTP GREETING PHASE TESTS below.
<b>drop</b> (enforcement mode)
Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
<b>3. TEMPORARY WHITELIST TEST</b>
The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> daemon maintains a <i>temporary</i> whitelist
for SMTP client IP addresses that have passed all the
tests described below. The <a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> parameter
specifies the location of the temporary whitelist. The
temporary whitelist is not used for SMTP client addresses
The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> daemon maintains a <i>temporary</i> whitelist
for SMTP client IP addresses that have passed all the
tests described below. The <a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> parameter
specifies the location of the temporary whitelist. The
temporary whitelist is not used for SMTP client addresses
that appear on the <i>permanent</i> blacklist or whitelist.
When the SMTP client address appears on the temporary
When the SMTP client address appears on the temporary
whitelist, this is logged as:
<b>PASS OLD</b> <i>address</i>
The action is not configurable: immediately forward the
connection to a real SMTP server process. The client is
excluded from further tests until its temporary whitelist
The action is not configurable: immediately forward the
connection to a real SMTP server process. The client is
excluded from further tests until its temporary whitelist
entry expires, as controlled with the <a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a>
parameter. Expired entries are silently renewed if possi-
ble.
<b>4. SMTP GREETING PHASE TESTS</b>
The <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter specifies a time
The <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter specifies a time
interval during which <a href="postscreen.8.html"><b>postscreen</b>(8)</a> runs a number of tests
as described below. These tests run before the client may
see the real SMTP server's "220 text..." server greeting.
in parallel. These tests are described below, and are run
before the client may see the real SMTP server's "220
text..." server greeting.
When the SMTP client passes all the tests, this is logged
as:
When the SMTP client passes all greeting-phase tests, this
is logged as:
<b>PASS NEW</b> <i>address</i>
The action is to forward the connection to a real SMTP
server process and to create a temporary whitelist entry
that excludes the client IP address from further tests
The action is to forward the connection to a real SMTP
server process and to create a temporary whitelist entry
that excludes the client IP address from further tests
until the temporary whitelist entry expires, as controlled
with the <a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> parameter.
In a future implementation, the connection may first be
passed to a dummy SMTP protocol engine that implements
more protocol tests including greylisting, before the
In a future implementation, the connection may first be
passed to a dummy SMTP protocol engine that implements
more protocol tests including greylisting, before the
client is allowed to talk to a real SMTP server process.
<b>4A. PREGREET TEST</b>
The <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> parameter specifies the text
for a "220-text..." teaser banner (default: $<a href="postconf.5.html#smtpd_banner">smtpd_ban</a>-
<a href="postconf.5.html#smtpd_banner">ner</a>). The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> daemon sends this before the
<a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> timer is started. The purpose of
the teaser banner is to confuse SPAM clients so that they
speak before their turn. It has no effect on SMTP clients
that correctly implement the protocol.
The <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> parameter specifies the <i>text</i>
portion of a "220-<i>text</i>..." teaser banner (default:
$<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>). The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> daemon sends this
before the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> timer is started. The
purpose of the teaser banner is to confuse SPAM clients so
that they speak before their turn. It has no effect on
SMTP clients that correctly implement the protocol.
To avoid problems with broken SMTP engines in network
appliances, either exclude them from all tests with the
<a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> feature or else specify an
empty <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> value to disable the
To avoid problems with broken SMTP engines in network
appliances, either exclude them from all tests with the
<a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> feature or else specify an
empty <a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> value to disable the
"220-text..." teaser banner.
When an SMTP client sends a command before the
When an SMTP client sends a command before the
<a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, this is logged as:
<b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>address text...</i>
Translation: the client at <i>address</i> sent <i>count</i> bytes before
its turn to speak, and this happened <i>time</i> seconds after
the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> timer was started. The <i>text</i> is
what the client sent (truncated to 100 bytes, and with
its turn to speak, and this happened <i>time</i> seconds after
the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> timer was started. The <i>text</i> is
what the client sent (truncated to 100 bytes, and with
non-printable characters replaced with "?").
The <a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> parameter specifies the action
that is taken next:
<b>continue</b> (default, observation mode)
Wait until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
Wait until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
elapsed, then report DNSBL lookup results if appli-
cable. Either perform DNSBL-related actions or for-
ward the connection to a real SMTP server process.
ward the connection to a real SMTP server process.
<b>drop</b> (enforcement mode)
Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
<b>4B. HANGUP TEST</b>
When the SMTP client hangs up without sending any data
When the SMTP client hangs up without sending any data
before the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, this is
logged as:
<b>HANGUP after</b> <i>time</i> <b>from</b> <i>address</i>
The <a href="postconf.5.html#postscreen_hangup_action">postscreen_hangup_action</a> specifies the action that is
The <a href="postconf.5.html#postscreen_hangup_action">postscreen_hangup_action</a> specifies the action that is
taken next:
<b>continue</b> (default, observation mode)
Wait until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
Wait until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
elapsed, then report DNSBL lookup results if appli-
cable. Do not forward the broken connection to a
cable. Do not forward the broken connection to a
real SMTP server process.
<b>drop</b> (enforcement mode)
Drop the connection immediately.
<b>4C. DNS BLOCKLIST TEST</b>
The <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter (default: empty)
specifies a list of DNS blocklist servers.
The <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter (default: empty)
specifies a list of DNS blocklist servers. These lookups
are made in parallel.
When the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, and the
SMTP client address is listed with at least one of these
@ -237,14 +246,6 @@ POSTSCREEN(8) POSTSCREEN(8)
see the <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter for
possible actions.
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b>
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
decisions.
<b><a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache a
decision for a specific SMTP client IP address.
<b><a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> (continue)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client is listed at the DNS blocklist domains spec-
@ -259,7 +260,7 @@ POSTSCREEN(8) POSTSCREEN(8)
ified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> ($<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b>
The text in the optional "220-text..." server
The <i>text</i> in the optional "220-<i>text</i>..." server
response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
Postfix SMTP server's "220 text..." response, in an
attempt to confuse bad SMTP clients so that they
@ -294,22 +295,40 @@ POSTSCREEN(8) POSTSCREEN(8)
The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> forwards
allowed connections to.
<b>CACHE CONTROLS</b>
<b><a href="postconf.5.html#postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a> (12h)</b>
The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
cleanup runs.
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b>
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
decisions.
<b><a href="postconf.5.html#postscreen_cache_retention_time">postscreen_cache_retention_time</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache an
expired temporary whitelist entry before it is
removed.
<b><a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache a
decision for a specific SMTP client IP address.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
The maximal number of digits after the decimal
The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative com-
The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@ -317,24 +336,24 @@ POSTSCREEN(8) POSTSCREEN(8)
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The process ID of a Postfix command or daemon
The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
The process name of a Postfix command or daemon
The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
@ -343,7 +362,7 @@ POSTSCREEN(8) POSTSCREEN(8)
syslogd(8), system logging
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>

View File

@ -906,123 +906,124 @@ SMTPD(8) SMTPD(8)
<b><a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> (no)</b>
Require that a remote SMTP client introduces itself
at the beginning of an SMTP session with the HELO
or EHLO command.
with the HELO or EHLO command before sending the
MAIL command or other commands that require EHLO
negotiation.
<b><a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a> (empty)</b>
Optional restrictions that the Postfix SMTP server
Optional restrictions that the Postfix SMTP server
applies in the context of the SMTP HELO command.
<b><a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a> (empty)</b>
Optional restrictions that the Postfix SMTP server
Optional restrictions that the Postfix SMTP server
applies in the context of the MAIL FROM command.
<b><a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,</b>
<b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>)</b>
The access restrictions that the Postfix SMTP
server applies in the context of the RCPT TO com-
server applies in the context of the RCPT TO com-
mand.
<b><a href="postconf.5.html#smtpd_etrn_restrictions">smtpd_etrn_restrictions</a> (empty)</b>
Optional SMTP server access restrictions in the
Optional SMTP server access restrictions in the
context of a client ETRN request.
<b><a href="postconf.5.html#allow_untrusted_routing">allow_untrusted_routing</a> (no)</b>
Forward mail with sender-specified routing
(user[@%!]remote[@%!]site) from untrusted clients
Forward mail with sender-specified routing
(user[@%!]remote[@%!]site) from untrusted clients
to destinations matching $<a href="postconf.5.html#relay_domains">relay_domains</a>.
<b><a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> (empty)</b>
User-defined aliases for groups of access restric-
User-defined aliases for groups of access restric-
tions.
<b><a href="postconf.5.html#smtpd_null_access_lookup_key">smtpd_null_access_lookup_key</a> (</b>&lt;&gt;<b>)</b>
The lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a> tables
The lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a> tables
instead of the null sender address.
<b><a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> (empty)</b>
Restrict the use of the <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> SMTP
access feature to only domains whose primary MX
access feature to only domains whose primary MX
hosts match the listed networks.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#smtpd_data_restrictions">smtpd_data_restrictions</a> (empty)</b>
Optional access restrictions that the Postfix SMTP
Optional access restrictions that the Postfix SMTP
server applies in the context of the SMTP DATA com-
mand.
<b><a href="postconf.5.html#smtpd_expansion_filter">smtpd_expansion_filter</a> (see 'postconf -d' output)</b>
What characters are allowed in $name expansions of
What characters are allowed in $name expansions of
RBL reply templates.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> (no)</b>
Request that the Postfix SMTP server rejects mail
from unknown sender addresses, even when no
explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
Request that the Postfix SMTP server rejects mail
from unknown sender addresses, even when no
explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
is specified.
<b><a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> (yes)</b>
Request that the Postfix SMTP server rejects mail
Request that the Postfix SMTP server rejects mail
for unknown recipient addresses, even when no
explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
tion is specified.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a> (empty)</b>
Optional access restrictions that the Postfix SMTP
server applies in the context of the SMTP END-OF-
Optional access restrictions that the Postfix SMTP
server applies in the context of the SMTP END-OF-
DATA command.
<b>SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS</b>
Postfix version 2.1 introduces sender and recipient
address verification. This feature is implemented by
sending probe email messages that are not actually deliv-
ered. This feature is requested via the reject_unveri-
fied_sender and <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a> access
restrictions. The status of verification probes is main-
Postfix version 2.1 introduces sender and recipient
address verification. This feature is implemented by
sending probe email messages that are not actually deliv-
ered. This feature is requested via the reject_unveri-
fied_sender and <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a> access
restrictions. The status of verification probes is main-
tained by the <a href="verify.8.html"><b>verify</b>(8)</a> server. See the file <a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VER</a>-
<a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a> for information about how to configure
<a href="ADDRESS_VERIFICATION_README.html">IFICATION_README</a> for information about how to configure
and operate the Postfix sender/recipient address verifica-
tion service.
<b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (3)</b>
How many times to query the <a href="verify.8.html"><b>verify</b>(8)</a> service for
the completion of an address verification request
<b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (see 'postconf -d' output)</b>
How many times to query the <a href="verify.8.html"><b>verify</b>(8)</a> service for
the completion of an address verification request
in progress.
<b><a href="postconf.5.html#address_verify_poll_delay">address_verify_poll_delay</a> (3s)</b>
The delay between queries for the completion of an
The delay between queries for the completion of an
address verification request in progress.
<b><a href="postconf.5.html#address_verify_sender">address_verify_sender</a> ($<a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a>)</b>
The sender address to use in address verification
The sender address to use in address verification
probes; prior to Postfix 2.5 the default was "post-
master".
<b><a href="postconf.5.html#unverified_sender_reject_code">unverified_sender_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a recipient address is rejected by the
The numerical Postfix SMTP server response code
when a recipient address is rejected by the
<a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a> restriction.
<b><a href="postconf.5.html#unverified_recipient_reject_code">unverified_recipient_reject_code</a> (450)</b>
The numerical Postfix SMTP server response when a
The numerical Postfix SMTP server response when a
recipient address is rejected by the reject_unveri-
fied_recipient restriction.
Available in Postfix version 2.6 and later:
<b><a href="postconf.5.html#unverified_sender_defer_code">unverified_sender_defer_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a sender address probe fails due to a tempo-
The numerical Postfix SMTP server response code
when a sender address probe fails due to a tempo-
rary error condition.
<b><a href="postconf.5.html#unverified_recipient_defer_code">unverified_recipient_defer_code</a> (450)</b>
The numerical Postfix SMTP server response when a
recipient address probe fails due to a temporary
The numerical Postfix SMTP server response when a
recipient address probe fails due to a temporary
error condition.
<b><a href="postconf.5.html#unverified_sender_reject_reason">unverified_sender_reject_reason</a> (empty)</b>
@ -1036,7 +1037,7 @@ SMTPD(8) SMTPD(8)
<b><a href="postconf.5.html#unverified_sender_tempfail_action">unverified_sender_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
<b><a href="postconf.5.html#reject_tempfail_action">fail_action</a>)</b>
The Postfix SMTP server's action when <a href="postconf.5.html#reject_unverified_sender">reject_unver</a>-
<a href="postconf.5.html#reject_unverified_sender">ified_sender</a> fails due to a temporary error condi-
<a href="postconf.5.html#reject_unverified_sender">ified_sender</a> fails due to a temporary error condi-
tion.
<b><a href="postconf.5.html#unverified_recipient_tempfail_action">unverified_recipient_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
@ -1046,7 +1047,7 @@ SMTPD(8) SMTPD(8)
dition.
<b>ACCESS CONTROL RESPONSES</b>
The following parameters control numerical SMTP reply
The following parameters control numerical SMTP reply
codes and/or text responses.
<b><a href="postconf.5.html#access_map_reject_code">access_map_reject_code</a> (554)</b>
@ -1054,18 +1055,18 @@ SMTPD(8) SMTPD(8)
an <a href="access.5.html"><b>access</b>(5)</a> map "reject" action.
<b><a href="postconf.5.html#defer_code">defer_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a remote SMTP client request is rejected by
The numerical Postfix SMTP server response code
when a remote SMTP client request is rejected by
the "defer" restriction.
<b><a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> (501)</b>
The numerical Postfix SMTP server response code
when the client HELO or EHLO command parameter is
rejected by the <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
The numerical Postfix SMTP server response code
when the client HELO or EHLO command parameter is
rejected by the <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a>
restriction.
<b><a href="postconf.5.html#maps_rbl_reject_code">maps_rbl_reject_code</a> (554)</b>
The numerical Postfix SMTP server response code
The numerical Postfix SMTP server response code
when a remote SMTP client request is blocked by the
<a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>, <a href="postconf.5.html#reject_rhsbl_client">reject_rhsbl_client</a>,
<a href="postconf.5.html#reject_rhsbl_sender">reject_rhsbl_sender</a> or <a href="postconf.5.html#reject_rhsbl_recipient">reject_rhsbl_recipient</a>
@ -1073,53 +1074,53 @@ SMTPD(8) SMTPD(8)
<b><a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> (504)</b>
The numerical Postfix SMTP server reply code when a
client request is rejected by the
client request is rejected by the
<a href="postconf.5.html#reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a>,
<a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a>
restriction.
<b><a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a request is rejected by the <b>reject_plain-</b>
The numerical Postfix SMTP server response code
when a request is rejected by the <b>reject_plain-</b>
<b>text_session</b> restriction.
<b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
The numerical Postfix SMTP server response code
when a remote SMTP client request is rejected by
The numerical Postfix SMTP server response code
when a remote SMTP client request is rejected by
the "reject" restriction.
<b><a href="postconf.5.html#relay_domains_reject_code">relay_domains_reject_code</a> (554)</b>
The numerical Postfix SMTP server response code
when a client request is rejected by the
The numerical Postfix SMTP server response code
when a client request is rejected by the
<a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> recipient restriction.
<b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a sender or recipient address is rejected by
The numerical Postfix SMTP server response code
when a sender or recipient address is rejected by
the <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> or
<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction.
<b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a client without valid address &lt;=&gt; name map-
The numerical Postfix SMTP server response code
when a client without valid address &lt;=&gt; name map-
ping is rejected by the reject_unknown_client_host-
name restriction.
<b><a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when the hostname specified with the HELO or EHLO
command is rejected by the
The numerical Postfix SMTP server response code
when the hostname specified with the HELO or EHLO
command is rejected by the
<a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> restriction.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#default_rbl_reply">default_rbl_reply</a> (see 'postconf -d' output)</b>
The default SMTP server response template for a
request that is rejected by an RBL-based restric-
The default SMTP server response template for a
request that is rejected by an RBL-based restric-
tion.
<b><a href="postconf.5.html#multi_recipient_bounce_reject_code">multi_recipient_bounce_reject_code</a> (550)</b>
The numerical Postfix SMTP server response code
The numerical Postfix SMTP server response code
when a remote SMTP client request is blocked by the
<a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipient_bounce</a> restriction.
@ -1130,38 +1131,38 @@ SMTPD(8) SMTPD(8)
<b><a href="postconf.5.html#access_map_defer_code">access_map_defer_code</a> (450)</b>
The numerical Postfix SMTP server response code for
an <a href="access.5.html"><b>access</b>(5)</a> map "defer" action, including
an <a href="access.5.html"><b>access</b>(5)</a> map "defer" action, including
"<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>" or "<a href="postconf.5.html#defer_if_reject">defer_if_reject</a>".
<b><a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a> (<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>)</b>
The Postfix SMTP server's action when a reject-type
restriction fails due to a temporary error condi-
restriction fails due to a temporary error condi-
tion.
<b><a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_temp</a>-</b>
<b><a href="postconf.5.html#reject_tempfail_action">fail_action</a>)</b>
The Postfix SMTP server's action when
The Postfix SMTP server's action when
<a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> fails due to an tempo-
rary error condition.
<b><a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
The Postfix SMTP server's action when
The Postfix SMTP server's action when
<a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> or
<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> fail due to a tem-
<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> fail due to a tem-
porary error condition.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative com-
The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a> (double-bounce)</b>
@ -1182,37 +1183,37 @@ SMTPD(8) SMTPD(8)
and most Postfix daemon processes.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
The maximal number of incoming connections that a
Postfix daemon process will service before termi-
The maximal number of incoming connections that a
Postfix daemon process will service before termi-
nating voluntarily.
<b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
The internet hostname of this mail system.
<b><a href="postconf.5.html#mynetworks">mynetworks</a> (see 'postconf -d' output)</b>
The list of "trusted" SMTP clients that have more
The list of "trusted" SMTP clients that have more
privileges than "strangers".
<b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
The domain name that locally-posted mail appears to
come from, and that locally posted mail is deliv-
come from, and that locally posted mail is deliv-
ered to.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The process ID of a Postfix command or daemon
The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
The process name of a Postfix command or daemon
The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
The location of the Postfix top-level queue direc-
The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
@ -1220,28 +1221,28 @@ SMTPD(8) SMTPD(8)
sions (user+foo).
<b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
The text that follows the 220 status code in the
The text that follows the 220 status code in the
SMTP greeting banner.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT, GET, POST)</b>
List of commands that causes the Postfix SMTP
server to immediately terminate the session with a
List of commands that causes the Postfix SMTP
server to immediately terminate the session with a
221 code.
Available in Postfix version 2.5 and later:
<b><a href="postconf.5.html#smtpd_client_port_logging">smtpd_client_port_logging</a> (no)</b>
Enable logging of the remote SMTP client port in
Enable logging of the remote SMTP client port in
addition to the hostname and IP address.
<b>SEE ALSO</b>
@ -1271,7 +1272,7 @@ SMTPD(8) SMTPD(8)
<a href="XFORWARD_README.html">XFORWARD_README</a>, Postfix XFORWARD extension
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>

View File

@ -115,17 +115,23 @@ VERIFY(8) VERIFY(8)
The time after which a failed address verification
probe needs to be refreshed.
Available with Postfix 2.7 and later:
<b><a href="postconf.5.html#address_verify_cache_cleanup_interval">address_verify_cache_cleanup_interval</a> (12h)</b>
The amount of time between <a href="verify.8.html"><b>verify</b>(8)</a> cache cleanup
runs.
<b>PROBE MESSAGE ROUTING CONTROLS</b>
By default, probe messages are delivered via the same
route as regular messages. The following parameters can
By default, probe messages are delivered via the same
route as regular messages. The following parameters can
be used to override specific message routing mechanisms.
<b><a href="postconf.5.html#address_verify_relayhost">address_verify_relayhost</a> ($<a href="postconf.5.html#relayhost">relayhost</a>)</b>
Overrides the <a href="postconf.5.html#relayhost">relayhost</a> parameter setting for
Overrides the <a href="postconf.5.html#relayhost">relayhost</a> parameter setting for
address verification probes.
<b><a href="postconf.5.html#address_verify_transport_maps">address_verify_transport_maps</a> ($<a href="postconf.5.html#transport_maps">transport_maps</a>)</b>
Overrides the <a href="postconf.5.html#transport_maps">transport_maps</a> parameter setting for
Overrides the <a href="postconf.5.html#transport_maps">transport_maps</a> parameter setting for
address verification probes.
<b><a href="postconf.5.html#address_verify_local_transport">address_verify_local_transport</a> ($<a href="postconf.5.html#local_transport">local_transport</a>)</b>
@ -133,7 +139,7 @@ VERIFY(8) VERIFY(8)
address verification probes.
<b><a href="postconf.5.html#address_verify_virtual_transport">address_verify_virtual_transport</a> ($<a href="postconf.5.html#virtual_transport">virtual_transport</a>)</b>
Overrides the <a href="postconf.5.html#virtual_transport">virtual_transport</a> parameter setting
Overrides the <a href="postconf.5.html#virtual_transport">virtual_transport</a> parameter setting
for address verification probes.
<b><a href="postconf.5.html#address_verify_relay_transport">address_verify_relay_transport</a> ($<a href="postconf.5.html#relay_transport">relay_transport</a>)</b>
@ -141,17 +147,32 @@ VERIFY(8) VERIFY(8)
address verification probes.
<b><a href="postconf.5.html#address_verify_default_transport">address_verify_default_transport</a> ($<a href="postconf.5.html#default_transport">default_transport</a>)</b>
Overrides the <a href="postconf.5.html#default_transport">default_transport</a> parameter setting
Overrides the <a href="postconf.5.html#default_transport">default_transport</a> parameter setting
for address verification probes.
Available in Postfix 2.3 and later:
<b><a href="postconf.5.html#address_verify_sender_dependent_relayhost_maps">address_verify_sender_dependent_relayhost_maps</a></b>
<b>($<a href="postconf.5.html#sender_dependent_relayhost_maps">sender_dependent_relayhost_maps</a>)</b>
Overrides the <a href="postconf.5.html#sender_dependent_relayhost_maps">sender_dependent_relayhost_maps</a>
parameter setting for address verification probes.
Available in Postfix 2.7 and later:
<b><a href="postconf.5.html#address_verify_sender_dependent_default_transport_maps">address_verify_sender_dependent_default_transport_maps</a></b>
<b>($<a href="postconf.5.html#sender_dependent_default_transport_maps">sender_dependent_default_transport_maps</a>)</b>
Overrides the <a href="postconf.5.html#sender_dependent_default_transport_maps">sender_dependent_default_trans</a>-
<a href="postconf.5.html#sender_dependent_default_transport_maps">port_maps</a> parameter setting for address verifica-
tion probes.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@ -159,23 +180,23 @@ VERIFY(8) VERIFY(8)
over an internal communication channel.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The process ID of a Postfix command or daemon
The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
The process name of a Postfix command or daemon
The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
The location of the Postfix top-level queue direc-
The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
@ -188,7 +209,7 @@ VERIFY(8) VERIFY(8)
<a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VERIFICATION_README</a>, address verification howto
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>

View File

@ -77,6 +77,17 @@ The numerical Postfix SMTP server response code for
an \fBaccess\fR(5) map "reject" action.
.PP
Do not change this unless you have a complete understanding of RFC 2821.
.SH address_verify_cache_cleanup_interval (default: 12h)
The amount of time between \fBverify\fR(8) cache cleanup runs. Cache
cleanup increases the load on the cache database and should therefore
not be run frequently. This feature requires that the cache database
supports the "delete" and "sequence" operators. Specify a zero
interval to disable cache cleanup.
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks).
.PP
This feature is available in Postfix 2.7.
.SH address_verify_default_transport (default: $default_transport)
Overrides the default_transport parameter setting for address
verification probes.
@ -138,14 +149,18 @@ be refreshed.
Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
.PP
This feature is available in Postfix 2.1 and later.
.SH address_verify_poll_count (default: 3)
.SH address_verify_poll_count (default: see "postconf -d" output)
How many times to query the \fBverify\fR(8) service for the completion
of an address verification request in progress.
.PP
The default poll count is 3.
With Postfix version 2.7 and later, the SMTP server polls the
\fBverify\fR(8) service up to three times under non-overload conditions,
and only once when under overload. With earlier Postfix versions,
the SMTP server always polls the \fBverify\fR(8) service up to three
times.
.PP
Specify 1 to implement a crude form of greylisting, that is, always
defer the first delivery request for a never seen before address.
defer the first delivery request for a new address.
.PP
Example:
.PP
@ -3673,16 +3688,38 @@ The blacklist has higher precedence than whitelists. This feature
never uses the remote SMTP client hostname.
.PP
This feature is available in Postfix 2.7.
.SH postscreen_cache_cleanup_interval (default: 12h)
The amount of time between \fBpostscreen\fR(8) cache cleanup runs.
Cache cleanup increases the load on the cache database and should
therefore not be run frequently. This feature requires that the
cache database supports the "delete" and "sequence" operators.
Specify a zero interval to disable cache cleanup.
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks).
.PP
This feature is available in Postfix 2.7.
.SH postscreen_cache_map (default: btree:$data_directory/ps_whitelist)
Persistent storage for the \fBpostscreen\fR(8) server decisions.
.PP
This feature is available in Postfix 2.7.
.SH postscreen_cache_retention_time (default: 1d)
The amount of time that \fBpostscreen\fR(8) will cache an expired
temporary whitelist entry before it is removed. This prevents clients
from being logged as "NEW" just because their cache entry expired
an hour ago.
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks).
.PP
This feature is available in Postfix 2.7.
.SH postscreen_cache_ttl (default: 1d)
The amount of time that \fBpostscreen\fR(8) will cache a decision for
a specific SMTP client IP address. During this time, the client IP
address is excluded from tests. If possible, expired decisions are
renewed silently. Specify a non-zero time value (an integral value
plus an optional one-letter suffix that specifies the time unit).
renewed automatically. Specify a non-zero time value (an integral
value plus an optional one-letter suffix that specifies the time
unit).
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks).
@ -3722,7 +3759,8 @@ IP address.
.PP
This feature is available in Postfix 2.7.
.SH postscreen_greet_banner (default: $smtpd_banner)
The text in the optional "220-text..." server response that
The \fItext\fR in the optional "220-\fItext\fR..." server
response that
\fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet). Specify an empty
@ -5028,7 +5066,7 @@ invalid responses.
Notes:
.IP \(bu
In the case of a multi-line reply, the Postfix SMTP client
uses the last reply line's numerical SMTP reply code and enhanced
uses the final reply line's numerical SMTP reply code and enhanced
status code.
.IP \(bu
The numerical SMTP reply code (XYZ) takes precedence over
@ -5047,7 +5085,7 @@ Examples:
.na
.ft C
/etc/postfix/main.cf:
smtp_reply_filter = pcre:/etc/postfix/command_filter
smtp_reply_filter = pcre:/etc/postfix/reply_filter
.fi
.ad
.ft R
@ -5056,11 +5094,11 @@ Examples:
.na
.ft C
/etc/postfix/reply_filter:
# Transform garbage into part of a multi-line reply. Note
# that the Postfix SMTP client uses only the last numerical
# SMTP reply code and enhanced status code from a multi-line
# reply, so it does not matter what we substitute here as
# long as it has the right syntax.
# Transform garbage into "250-filler..." so that it looks like
# one line from a multi-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix
# SMTP client will use the final line's numerical SMTP reply
# code and enhanced status code.
!/^([2-5][0-9][0-9]($|[- ]))/ 250-filler for garbage
.fi
.ad
@ -6890,6 +6928,15 @@ except that initial whitespace and the trailing <CR><LF>
are removed. The result value is executed by the Postfix SMTP
server.
.PP
Postfix already implements a number of workarounds for malformed
client commands.
.IP \(bu
Use "resolve_numeric_domain = yes" to accept "\fIuser@ipaddress\fR"
Postfix already accepts the correct form "\fIuser@[ipaddress]\fR".
.IP \(bu
Use "strict_rfc821_envelopes = no" to accept "\fIUser Name
<user@example.com>\fR".
.PP
Examples:
.PP
.nf
@ -7104,8 +7151,9 @@ make without delivering mail. The Postfix SMTP server disconnects
when the limit is exceeded. Normally the default limit is 20, but
it changes under overload to just 1 with Postfix 2.6 and later.
.SH smtpd_helo_required (default: no)
Require that a remote SMTP client introduces itself at the beginning
of an SMTP session with the HELO or EHLO command.
Require that a remote SMTP client introduces itself with the HELO
or EHLO command before sending the MAIL command or other commands
that require EHLO negotiation.
.PP
Example:
.PP
@ -7927,12 +7975,12 @@ inside the chroot jail.
.PP
By default (see smtpd_tls_ask_ccert), client certificates are
not requested, and smtpd_tls_CApath should remain empty. In contrast
to smtp_tls_CAfile, DNs of certificate authorities installed
to smtpd_tls_CAfile, DNs of certificate authorities installed
in $smtpd_tls_CApath are not included in the client certificate
request message. MUAs with multiple client certificates may use the
list of preferred certificate authorities to select the correct
client certificate. You may want to put your "preferred" CA or
CAs in $smtp_tls_CAfile, and install the remaining trusted CAs in
CAs in $smtpd_tls_CAfile, and install the remaining trusted CAs in
$smtpd_tls_CApath.
.PP
Example:

View File

@ -54,8 +54,10 @@ in case of trouble.
RFC 822 (ARPA Internet Text Messages)
RFC 2045 (MIME: Format of Internet Message Bodies)
RFC 2046 (MIME: Media Types)
RFC 2822 (Internet Message Format)
RFC 3463 (Enhanced Status Codes)
RFC 3464 (Delivery status notifications)
RFC 5322 (Internet Message Format)
.SH DIAGNOSTICS
.ad
.fi

View File

@ -13,26 +13,31 @@ Postfix SMTP triage server
.ad
.fi
The Postfix \fBpostscreen\fR(8) server performs triage on
multiple inbound SMTP connections in parallel. The program
can run in two basic modes.
multiple inbound SMTP connections in parallel. By running
time-consuming tests in parallel in \fBpostscreen\fR(8),
zombies and other bogus clients can be kept away from Postfix
SMTP server processes. Thus, more Postfix SMTP server
processes remain available for legitimate clients.
The purpose of \fBobservation mode\fR is to collect statistics
without actually blocking mail. \fBpostscreen\fR(8) runs a
number of tests before it forwards a connection to a real
SMTP server process. These tests introduce a delay of a
few seconds; once a client passes the tests as "clean", its
IP address is temporarily whitelisted and subsequent
connections incur no delays until the temporary whitelist
entry expires.
This triage process involves a number of tests, documented
below. The tests introduce a delay of a few seconds; once
a client passes the tests, its IP address is temporarily
whitelisted, typically for 24 hours.
The purpose of \fBenforcement mode\fR is to block mail
without using up one Postfix SMTP server process for every
connection. Here, \fBpostscreen\fR(8) terminates connections
from SMTP clients that fail the above tests, and forwards
only the remaining connections to a real SMTP server process.
By running time-consuming spam tests in parallel in
\fBpostscreen\fR(8), more Postfix SMTP server processes
remain available for legitimate clients.
The program can run in two basic modes.
.IP "\fBObservation mode\fR"
\fBpostscreen\fR(8) reports the results of the tests, and
forwards all connections to a real Postfix SMTP server
process.
.IP "\fBEnforcement mode\fR"
\fBpostscreen\fR(8) reports the results of the tests, but
forwards only connections to a real SMTP server process
from clients that passed the tests.
.sp
\fBpostscreen\fR(8) disconnects clients that fail the tests,
after sending a 521 status message (a future version may
pass the connection to a dummy SMTP protocol engine that
logs sender and recipient information).
.PP
Note: \fBpostscreen\fR(8) is not an SMTP proxy; this is
intentional. The purpose is to prioritize legitimate clients
@ -44,8 +49,7 @@ with as little overhead as possible.
.fi
The postscreen_whitelist_networks parameter (default:
$mynetworks) specifies a permanent whitelist for SMTP client
IP addresses. This feature is not used for addresses that
appear on the permanent blacklist.
IP addresses.
When the SMTP client address matches the permanent whitelist,
this is logged as:
@ -105,12 +109,13 @@ parameter. Expired entries are silently renewed if possible.
.ad
.fi
The postscreen_greet_wait parameter specifies a time interval
during which \fBpostscreen\fR(8) runs a number of tests as
described below. These tests run before the client may
see the real SMTP server's "220 text..." server greeting.
during which \fBpostscreen\fR(8) runs a number of tests in
parallel. These tests are described below, and are run
before the client may see the real SMTP server's "220
text..." server greeting.
When the SMTP client passes all the tests, this is logged
as:
When the SMTP client passes all greeting-phase tests, this
is logged as:
.sp
.nf
\fBPASS NEW \fIaddress\fR
@ -129,8 +134,9 @@ to talk to a real SMTP server process.
.SH 4A. PREGREET TEST
.ad
.fi
The postscreen_greet_banner parameter specifies the text
for a "220-text..." teaser banner (default: $smtpd_banner).
The postscreen_greet_banner parameter specifies the \fItext\fR
portion of a "220-\fItext\fR..." teaser banner (default:
$smtpd_banner).
The \fBpostscreen\fR(8) daemon sends this before the
postscreen_greet_wait timer is started. The purpose of the
teaser banner is to confuse SPAM clients so that they speak
@ -191,7 +197,8 @@ Drop the connection immediately.
.ad
.fi
The postscreen_dnsbl_sites parameter (default: empty)
specifies a list of DNS blocklist servers.
specifies a list of DNS blocklist servers. These lookups
are made in parallel.
When the postscreen_greet_wait time has elapsed, and the
SMTP client address is listed with at least one of these
@ -256,11 +263,6 @@ parameter.
.IP "\fBpostscreen_blacklist_networks (empty)\fR"
Network addresses that are permanently blacklisted; see the
postscreen_blacklist_action parameter for possible actions.
.IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
Persistent storage for the \fBpostscreen\fR(8) server decisions.
.IP "\fBpostscreen_cache_ttl (1d)\fR"
The amount of time that \fBpostscreen\fR(8) will cache a decision for
a specific SMTP client IP address.
.IP "\fBpostscreen_dnsbl_action (continue)\fR"
The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
at the DNS blocklist domains specified with the postscreen_dnsbl_sites
@ -272,7 +274,8 @@ The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
before its turn within the time specified with the postscreen_greet_wait
parameter.
.IP "\fBpostscreen_greet_banner ($smtpd_banner)\fR"
The text in the optional "220-text..." server response that
The \fItext\fR in the optional "220-\fItext\fR..." server
response that
\fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet).
@ -297,6 +300,21 @@ will not be subjected to \fBpostscreen\fR(8) checks.
.IP "\fBsmtpd_service (smtpd)\fR"
The internal service that \fBpostscreen\fR(8) forwards allowed
connections to.
.SH "CACHE CONTROLS"
.na
.nf
.ad
.fi
.IP "\fBpostscreen_cache_cleanup_interval (12h)\fR"
The amount of time between \fBpostscreen\fR(8) cache cleanup runs.
.IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
Persistent storage for the \fBpostscreen\fR(8) server decisions.
.IP "\fBpostscreen_cache_retention_time (1d)\fR"
The amount of time that \fBpostscreen\fR(8) will cache an expired
temporary whitelist entry before it is removed.
.IP "\fBpostscreen_cache_ttl (1d)\fR"
The amount of time that \fBpostscreen\fR(8) will cache a decision for
a specific SMTP client IP address.
.SH "MISCELLANEOUS CONTROLS"
.na
.nf

View File

@ -729,8 +729,9 @@ instead of requiring an explicit ".domain.tld" pattern.
Optional SMTP server access restrictions in the context of a client
SMTP connection request.
.IP "\fBsmtpd_helo_required (no)\fR"
Require that a remote SMTP client introduces itself at the beginning
of an SMTP session with the HELO or EHLO command.
Require that a remote SMTP client introduces itself with the HELO
or EHLO command before sending the MAIL command or other commands
that require EHLO negotiation.
.IP "\fBsmtpd_helo_restrictions (empty)\fR"
Optional restrictions that the Postfix SMTP server applies in the
context of the SMTP HELO command.
@ -791,7 +792,7 @@ verification probes is maintained by the \fBverify\fR(8) server.
See the file ADDRESS_VERIFICATION_README for information
about how to configure and operate the Postfix sender/recipient
address verification service.
.IP "\fBaddress_verify_poll_count (3)\fR"
.IP "\fBaddress_verify_poll_count (see 'postconf -d' output)\fR"
How many times to query the \fBverify\fR(8) service for the completion
of an address verification request in progress.
.IP "\fBaddress_verify_poll_delay (3s)\fR"

View File

@ -113,6 +113,10 @@ verification cache.
.IP "\fBaddress_verify_negative_refresh_time (3h)\fR"
The time after which a failed address verification probe needs to
be refreshed.
.PP
Available with Postfix 2.7 and later:
.IP "\fBaddress_verify_cache_cleanup_interval (12h)\fR"
The amount of time between \fBverify\fR(8) cache cleanup runs.
.SH "PROBE MESSAGE ROUTING CONTROLS"
.na
.nf
@ -139,6 +143,16 @@ verification probes.
.IP "\fBaddress_verify_default_transport ($default_transport)\fR"
Overrides the default_transport parameter setting for address
verification probes.
.PP
Available in Postfix 2.3 and later:
.IP "\fBaddress_verify_sender_dependent_relayhost_maps ($sender_dependent_relayhost_maps)\fR"
Overrides the sender_dependent_relayhost_maps parameter setting for address
verification probes.
.PP
Available in Postfix 2.7 and later:
.IP "\fBaddress_verify_sender_dependent_default_transport_maps ($sender_dependent_default_transport_maps)\fR"
Overrides the sender_dependent_default_transport_maps parameter
setting for address verification probes.
.SH "MISCELLANEOUS CONTROLS"
.na
.nf

View File

@ -76,6 +76,7 @@ while (<>) {
s;\baddress_verify_negative_cache\b;<a href="postconf.5.html#address_verify_negative_cache">$&</a>;g;
s;\baddress_verify_negative_expire_time\b;<a href="postconf.5.html#address_verify_negative_expire_time">$&</a>;g;
s;\baddress_verify_negative_refresh_time\b;<a href="postconf.5.html#address_verify_negative_refresh_time">$&</a>;g;
s;\baddress_verify_cache_cleanup_interval\b;<a href="postconf.5.html#address_verify_cache_cleanup_interval">$&</a>;g;
s;\baddress_verify_poll_count\b;<a href="postconf.5.html#address_verify_poll_count">$&</a>;g;
s;\baddress_verify_poll_delay\b;<a href="postconf.5.html#address_verify_poll_delay">$&</a>;g;
s;\baddress_verify_positive_expire_time\b;<a href="postconf.5.html#address_verify_positive_expire_time">$&</a>;g;
@ -899,6 +900,8 @@ while (<>) {
# postscreen
s;\bpostscreen_cache_map\b;<a href="postconf.5.html#postscreen_cache_map">$&</a>;g;
s;\bpostscreen_cache_ttl\b;<a href="postconf.5.html#postscreen_cache_ttl">$&</a>;g;
s;\bpostscreen_cache_cleanup_interval\b;<a href="postconf.5.html#postscreen_cache_cleanup_interval">$&</a>;g;
s;\bpostscreen_cache_retention_time\b;<a href="postconf.5.html#postscreen_cache_retention_time">$&</a>;g;
s;\bsmtpd_service\b;<a href="postconf.5.html#smtpd_service">$&</a>;g;
s;\bpostscreen_post_queue_limit\b;<a href="postconf.5.html#postscreen_post_queue_limit">$&</a>;g;
s;\bpostscreen_pre_queue_limit\b;<a href="postconf.5.html#postscreen_pre_queue_limit">$&</a>;g;

View File

@ -108,11 +108,18 @@ filter</a>
<h2><a name="principles">Principles of operation</a></h2>
<p> The before-filter Postfix SMTP server accepts connections from the
<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. The before-queue filter receives unfiltered mail content from
etc. </p>
<li> <p> The before-queue filter receives unfiltered mail content from
Postfix and does one of the following: </p>
<ol>
@ -129,9 +136,11 @@ Postfix and does one of the following: </p>
</ol>
<p>The after-filter Postfix SMTP server receives mail from the
<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

View File

@ -199,7 +199,7 @@ verification probes.
This feature is available in Postfix 2.1 and later.
</p>
%PARAM address_verify_map
%PARAM address_verify_map
<p>
Optional lookup table for persistent address verification status
@ -280,7 +280,20 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
This feature is available in Postfix 2.1 and later.
</p>
%PARAM address_verify_poll_count 3
%PARAM address_verify_cache_cleanup_interval 12h
<p> The amount of time between verify(8) cache cleanup runs. Cache
cleanup increases the load on the cache database and should therefore
not be run frequently. This feature requires that the cache database
supports the "delete" and "sequence" operators. Specify a zero
interval to disable cache cleanup. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
%PARAM address_verify_poll_count see "postconf -d" output
<p>
How many times to query the verify(8) service for the completion
@ -288,12 +301,16 @@ of an address verification request in progress.
</p>
<p>
The default poll count is 3.
With Postfix version 2.7 and later, the SMTP server polls the
verify(8) service up to three times under non-overload conditions,
and only once when under overload. With earlier Postfix versions,
the SMTP server always polls the verify(8) service up to three
times.
</p>
<p>
Specify 1 to implement a crude form of greylisting, that is, always
defer the first delivery request for a never seen before address.
defer the first delivery request for a new address.
</p>
<p>
@ -5215,8 +5232,9 @@ This feature is available in Postfix 2.2 and later.
%PARAM smtpd_helo_required no
<p>
Require that a remote SMTP client introduces itself at the beginning
of an SMTP session with the HELO or EHLO command.
Require that a remote SMTP client introduces itself with the HELO
or EHLO command before sending the MAIL command or other commands
that require EHLO negotiation.
</p>
<p>
@ -8631,12 +8649,12 @@ inside the chroot jail. </p>
<p> By default (see smtpd_tls_ask_ccert), client certificates are
not requested, and smtpd_tls_CApath should remain empty. In contrast
to smtp_tls_CAfile, DNs of certificate authorities installed
to smtpd_tls_CAfile, DNs of certificate authorities installed
in $smtpd_tls_CApath are not included in the client certificate
request message. MUAs with multiple client certificates may use the
list of preferred certificate authorities to select the correct
client certificate. You may want to put your "preferred" CA or
CAs in $smtp_tls_CAfile, and install the remaining trusted CAs in
CAs in $smtpd_tls_CAfile, and install the remaining trusted CAs in
$smtpd_tls_CApath. </p>
<p> Example: </p>
@ -12436,9 +12454,34 @@ receive a 421 reponse. </p>
<p> The amount of time that postscreen(8) will cache a decision for
a specific SMTP client IP address. During this time, the client IP
address is excluded from tests. If possible, expired decisions are
renewed silently. Specify a non-zero time value (an integral value
plus an optional one-letter suffix that specifies the time unit).
</p>
renewed automatically. Specify a non-zero time value (an integral
value plus an optional one-letter suffix that specifies the time
unit). </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
%PARAM postscreen_cache_retention_time 1d
<p> The amount of time that postscreen(8) will cache an expired
temporary whitelist entry before it is removed. This prevents clients
from being logged as "NEW" just because their cache entry expired
an hour ago. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
<p> This feature is available in Postfix 2.7. </p>
%PARAM postscreen_cache_cleanup_interval 12h
<p> The amount of time between postscreen(8) cache cleanup runs.
Cache cleanup increases the load on the cache database and should
therefore not be run frequently. This feature requires that the
cache database supports the "delete" and "sequence" operators.
Specify a zero interval to disable cache cleanup. </p>
<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks). </p>
@ -12560,7 +12603,8 @@ never uses the remote SMTP client hostname. </p>
%PARAM postscreen_greet_banner $smtpd_banner
<p> The text in the optional "220-text..." server response that
<p> The <i>text</i> in the optional "220-<i>text</i>..." server
response that
postscreen(8) sends ahead of the real Postfix SMTP server's "220
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet). Specify an empty
@ -12608,6 +12652,20 @@ except that initial whitespace and the trailing &lt;CR&gt;&lt;LF&gt;
are removed. The result value is executed by the Postfix SMTP
server. </p>
<p> Postfix already implements a number of workarounds for malformed
client commands. </p>
<ul>
<li> <p> Use "resolve_numeric_domain = yes" to accept "<i>user@ipaddress</i>"
Postfix already accepts the correct form "<i>user@[ipaddress]</i>".
</p>
<li> <p> Use "strict_rfc821_envelopes = no" to accept "<i>User Name
&lt;user@example.com&gt;</i>". </p>
</ul>
<p> Examples: </p>
<pre>
@ -12647,7 +12705,7 @@ invalid responses. </p>
<ul>
<li> <p> In the case of a multi-line reply, the Postfix SMTP client
uses the last reply line's numerical SMTP reply code and enhanced
uses the final reply line's numerical SMTP reply code and enhanced
status code. </p>
<li> <p> The numerical SMTP reply code (XYZ) takes precedence over
@ -12666,16 +12724,16 @@ server, except that the trailing &lt;CR&gt;&lt;LF&gt; are removed. </p>
<pre>
/etc/postfix/main.cf:
smtp_reply_filter = pcre:/etc/postfix/command_filter
smtp_reply_filter = pcre:/etc/postfix/reply_filter
</pre>
<pre>
/etc/postfix/reply_filter:
# Transform garbage into part of a multi-line reply. Note
# that the Postfix SMTP client uses only the last numerical
# SMTP reply code and enhanced status code from a multi-line
# reply, so it does not matter what we substitute here as
# long as it has the right syntax.
# Transform garbage into "250-filler..." so that it looks like
# one line from a multi-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix
# SMTP client will use the final line's numerical SMTP reply
# code and enhanced status code.
!/^([2-5][0-9][0-9]($|[- ]))/ 250-filler for garbage
</pre>

View File

@ -46,8 +46,10 @@
/* RFC 822 (ARPA Internet Text Messages)
/* RFC 2045 (MIME: Format of Internet Message Bodies)
/* RFC 2046 (MIME: Media Types)
/* RFC 2822 (Internet Message Format)
/* RFC 3463 (Enhanced Status Codes)
/* RFC 3464 (Delivery status notifications)
/* RFC 5322 (Internet Message Format)
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* BUGS

View File

@ -2552,7 +2552,7 @@ extern int var_scache_stat_time;
extern char *var_verify_service;
#define VAR_VERIFY_MAP "address_verify_map"
#define DEF_VERIFY_MAP ""
#define DEF_VERIFY_MAP "btree:$data_directory/verify_cache"
extern char *var_verify_map;
#define VAR_VERIFY_POS_EXP "address_verify_positive_expire_time"
@ -2575,12 +2575,16 @@ extern int var_verify_neg_try;
#define DEF_VERIFY_NEG_CACHE 1
extern bool var_verify_neg_cache;
#define VAR_VERIFY_SCAN_CACHE "address_verify_cache_cleanup_interval"
#define DEF_VERIFY_SCAN_CACHE "12h"
extern int var_verify_scan_cache;
#define VAR_VERIFY_SENDER "address_verify_sender"
#define DEF_VERIFY_SENDER "$" VAR_DOUBLE_BOUNCE
extern char *var_verify_sender;
#define VAR_VERIFY_POLL_COUNT "address_verify_poll_count"
#define DEF_VERIFY_POLL_COUNT 3
#define DEF_VERIFY_POLL_COUNT "${stress?1}${stress:3}"
extern int var_verify_poll_count;
#define VAR_VERIFY_POLL_DELAY "address_verify_poll_delay"
@ -3186,6 +3190,14 @@ extern int var_ps_pre_queue_limit;
#define DEF_PS_CACHE_TTL "1d"
extern int var_ps_cache_ttl;
#define VAR_PS_CACHE_RET "postscreen_cache_retention_time"
#define DEF_PS_CACHE_RET "1d"
extern int var_ps_cache_ret;
#define VAR_PS_CACHE_SCAN "postscreen_cache_cleanup_interval"
#define DEF_PS_CACHE_SCAN "12h"
extern int var_ps_cache_scan;
#define VAR_PS_GREET_WAIT "postscreen_greet_wait"
#define DEF_PS_GREET_WAIT "4s"
extern int var_ps_greet_wait;

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20091209"
#define MAIL_RELEASE_DATE "20091229"
#define MAIL_VERSION_NUMBER "2.7"
#ifdef SNAPSHOT

View File

@ -61,7 +61,9 @@ postscreen.o: ../../include/addr_match_list.h
postscreen.o: ../../include/argv.h
postscreen.o: ../../include/attr.h
postscreen.o: ../../include/connect.h
postscreen.o: ../../include/data_redirect.h
postscreen.o: ../../include/dict.h
postscreen.o: ../../include/dict_cache.h
postscreen.o: ../../include/events.h
postscreen.o: ../../include/format_tv.h
postscreen.o: ../../include/htable.h

View File

@ -7,26 +7,31 @@
/* \fBpostscreen\fR [generic Postfix daemon options]
/* DESCRIPTION
/* The Postfix \fBpostscreen\fR(8) server performs triage on
/* multiple inbound SMTP connections in parallel. The program
/* can run in two basic modes.
/* multiple inbound SMTP connections in parallel. By running
/* time-consuming tests in parallel in \fBpostscreen\fR(8),
/* zombies and other bogus clients can be kept away from Postfix
/* SMTP server processes. Thus, more Postfix SMTP server
/* processes remain available for legitimate clients.
/*
/* The purpose of \fBobservation mode\fR is to collect statistics
/* without actually blocking mail. \fBpostscreen\fR(8) runs a
/* number of tests before it forwards a connection to a real
/* SMTP server process. These tests introduce a delay of a
/* few seconds; once a client passes the tests as "clean", its
/* IP address is temporarily whitelisted and subsequent
/* connections incur no delays until the temporary whitelist
/* entry expires.
/* This triage process involves a number of tests, documented
/* below. The tests introduce a delay of a few seconds; once
/* a client passes the tests, its IP address is temporarily
/* whitelisted, typically for 24 hours.
/*
/* The purpose of \fBenforcement mode\fR is to block mail
/* without using up one Postfix SMTP server process for every
/* connection. Here, \fBpostscreen\fR(8) terminates connections
/* from SMTP clients that fail the above tests, and forwards
/* only the remaining connections to a real SMTP server process.
/* By running time-consuming spam tests in parallel in
/* \fBpostscreen\fR(8), more Postfix SMTP server processes
/* remain available for legitimate clients.
/* The program can run in two basic modes.
/* .IP "\fBObservation mode\fR"
/* \fBpostscreen\fR(8) reports the results of the tests, and
/* forwards all connections to a real Postfix SMTP server
/* process.
/* .IP "\fBEnforcement mode\fR"
/* \fBpostscreen\fR(8) reports the results of the tests, but
/* forwards only connections to a real SMTP server process
/* from clients that passed the tests.
/* .sp
/* \fBpostscreen\fR(8) disconnects clients that fail the tests,
/* after sending a 521 status message (a future version may
/* pass the connection to a dummy SMTP protocol engine that
/* logs sender and recipient information).
/* .PP
/* Note: \fBpostscreen\fR(8) is not an SMTP proxy; this is
/* intentional. The purpose is to prioritize legitimate clients
@ -38,8 +43,7 @@
/* .fi
/* The postscreen_whitelist_networks parameter (default:
/* $mynetworks) specifies a permanent whitelist for SMTP client
/* IP addresses. This feature is not used for addresses that
/* appear on the permanent blacklist.
/* IP addresses.
/*
/* When the SMTP client address matches the permanent whitelist,
/* this is logged as:
@ -99,12 +103,13 @@
/* .ad
/* .fi
/* The postscreen_greet_wait parameter specifies a time interval
/* during which \fBpostscreen\fR(8) runs a number of tests as
/* described below. These tests run before the client may
/* see the real SMTP server's "220 text..." server greeting.
/* during which \fBpostscreen\fR(8) runs a number of tests in
/* parallel. These tests are described below, and are run
/* before the client may see the real SMTP server's "220
/* text..." server greeting.
/*
/* When the SMTP client passes all the tests, this is logged
/* as:
/* When the SMTP client passes all greeting-phase tests, this
/* is logged as:
/* .sp
/* .nf
/* \fBPASS NEW \fIaddress\fR
@ -123,8 +128,9 @@
/* .SH 4A. PREGREET TEST
/* .ad
/* .fi
/* The postscreen_greet_banner parameter specifies the text
/* for a "220-text..." teaser banner (default: $smtpd_banner).
/* The postscreen_greet_banner parameter specifies the \fItext\fR
/* portion of a "220-\fItext\fR..." teaser banner (default:
/* $smtpd_banner).
/* The \fBpostscreen\fR(8) daemon sends this before the
/* postscreen_greet_wait timer is started. The purpose of the
/* teaser banner is to confuse SPAM clients so that they speak
@ -185,7 +191,8 @@
/* .ad
/* .fi
/* The postscreen_dnsbl_sites parameter (default: empty)
/* specifies a list of DNS blocklist servers.
/* specifies a list of DNS blocklist servers. These lookups
/* are made in parallel.
/*
/* When the postscreen_greet_wait time has elapsed, and the
/* SMTP client address is listed with at least one of these
@ -240,11 +247,6 @@
/* .IP "\fBpostscreen_blacklist_networks (empty)\fR"
/* Network addresses that are permanently blacklisted; see the
/* postscreen_blacklist_action parameter for possible actions.
/* .IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
/* Persistent storage for the \fBpostscreen\fR(8) server decisions.
/* .IP "\fBpostscreen_cache_ttl (1d)\fR"
/* The amount of time that \fBpostscreen\fR(8) will cache a decision for
/* a specific SMTP client IP address.
/* .IP "\fBpostscreen_dnsbl_action (continue)\fR"
/* The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
/* at the DNS blocklist domains specified with the postscreen_dnsbl_sites
@ -256,7 +258,8 @@
/* before its turn within the time specified with the postscreen_greet_wait
/* parameter.
/* .IP "\fBpostscreen_greet_banner ($smtpd_banner)\fR"
/* The text in the optional "220-text..." server response that
/* The \fItext\fR in the optional "220-\fItext\fR..." server
/* response that
/* \fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220
/* text..." response, in an attempt to confuse bad SMTP clients so
/* that they speak before their turn (pre-greet).
@ -281,6 +284,19 @@
/* .IP "\fBsmtpd_service (smtpd)\fR"
/* The internal service that \fBpostscreen\fR(8) forwards allowed
/* connections to.
/* CACHE CONTROLS
/* .ad
/* .fi
/* .IP "\fBpostscreen_cache_cleanup_interval (12h)\fR"
/* The amount of time between \fBpostscreen\fR(8) cache cleanup runs.
/* .IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
/* Persistent storage for the \fBpostscreen\fR(8) server decisions.
/* .IP "\fBpostscreen_cache_retention_time (1d)\fR"
/* The amount of time that \fBpostscreen\fR(8) will cache an expired
/* temporary whitelist entry before it is removed.
/* .IP "\fBpostscreen_cache_ttl (1d)\fR"
/* The amount of time that \fBpostscreen\fR(8) will cache a decision for
/* a specific SMTP client IP address.
/* MISCELLANEOUS CONTROLS
/* .ad
/* .fi
@ -347,7 +363,7 @@
#include <events.h>
#include <mymalloc.h>
#include <myaddrinfo.h>
#include <dict.h>
#include <dict_cache.h>
#include <sane_accept.h>
#include <stringops.h>
#include <set_eugid.h>
@ -363,6 +379,7 @@
#include <mail_version.h>
#include <mail_proto.h>
#include <addr_match_list.h>
#include <data_redirect.h>
/* Master server protocols. */
@ -378,6 +395,8 @@ int var_ps_post_queue_limit;
int var_ps_pre_queue_limit;
int var_proc_limit;
int var_ps_cache_ttl;
int var_ps_cache_ret;
int var_ps_cache_scan;
int var_ps_greet_wait;
char *var_ps_dnsbl_sites;
char *var_ps_dnsbl_action;
@ -425,7 +444,7 @@ typedef struct {
static int check_queue_length; /* connections being checked */
static int post_queue_length; /* being sent to real SMTPD */
static DICT *cache_map; /* cache table handle */
static DICT_CACHE *cache_map; /* cache table handle */
static VSTRING *temp; /* scratchpad */
static char *smtp_service_name; /* path to real SMTPD */
static char *teaser_greeting; /* spamware teaser banner */
@ -520,26 +539,26 @@ static int ps_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
/* ps_dict_get - time-critical table lookup */
static const char *ps_dict_get(DICT *dict, const char *key)
static const char *ps_dict_get(DICT_CACHE *cache, const char *key)
{
const char *myname = "ps_dict_get";
const char *result;
PS_GET_TIME_BEFORE_LOOKUP;
result = dict_get(dict, key);
PS_CHECK_TIME_AFTER_LOOKUP(dict->name, "lookup");
result = dict_cache_lookup(cache, key);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup");
return (result);
}
/* ps_dict_put - table dictionary update */
static void ps_dict_put(DICT *dict, const char *key, const char *value)
static void ps_dict_put(DICT_CACHE *cache, const char *key, const char *value)
{
const char *myname = "ps_dict_put";
PS_GET_TIME_BEFORE_LOOKUP;
dict_put(dict, key, value);
PS_CHECK_TIME_AFTER_LOOKUP(dict->name, "update");
dict_cache_update(cache, key, value);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update");
}
/*
@ -965,6 +984,23 @@ static void smtp_read_event(int event, char *context)
}
}
/* postscreen_dump - dump some statistics before exit */
static void postscreen_dump(void)
{
/*
* Dump preliminary cache cleanup statistics when the process commits
* suicide while a cache cleanup run is in progress. We can't currently
* distinguish between "postfix reload" (we should restart) or "maximal
* idle time reached" (we could finish the cache cleanup first).
*/
if (cache_map) {
dict_cache_close(cache_map);
cache_map = 0;
}
}
/* postscreen_drain - delayed exit after "postfix reload" */
static void postscreen_drain(char *unused_service, char **unused_argv)
@ -989,7 +1025,7 @@ static void postscreen_drain(char *unused_service, char **unused_argv)
* version is an improvement over its predecessor.
*/
if (cache_map != 0) {
dict_close(cache_map);
dict_cache_close(cache_map);
cache_map = 0;
}
for (count = 0; /* see below */ ; count++) {
@ -1181,10 +1217,31 @@ static void postscreen_service(VSTREAM *smtp_client_stream,
postscreen_dnsbl_query(smtp_client_addr.buf);
}
/* postscreen_cache_validator - validate one cache entry */
static int postscreen_cache_validator(const char *client_addr,
const char *stamp_str,
char *unused_context)
{
time_t stamp_time;
/*
* This function is called by the cache cleanup pseudo thread.
*
* XX Eliminate code duplication and abstract the parser into a separate
* routine.
*
* Don't report a client as "NEW" just because their cache entry expired.
*/
stamp_time = strtoul(stamp_str, 0, 10);
return (event_time() < stamp_time + var_ps_cache_ttl + var_ps_cache_ret);
}
/* pre_jail_init - pre-jail initialization */
static void pre_jail_init(char *unused_name, char **unused_argv)
{
VSTRING *redirect;
/*
* Open read-only maps as before dropping privilege, for consistency with
@ -1192,7 +1249,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
*/
if (*var_ps_wlist_nets)
wlist_nets =
addr_match_list_init(MATCH_FLAG_NONE, var_ps_wlist_nets);
addr_match_list_init(MATCH_FLAG_NONE, var_ps_wlist_nets);
if (*var_ps_blist_nets)
blist_nets =
@ -1213,22 +1270,26 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
* to jail, temporarily drop root privileges.
*/
SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid);
redirect = vstring_alloc(100);
/*
* Keep state in persistent external map. As a safety measure we sync the
* database on each update. This hurts on LINUX systems that sync all
* their dirty disk blocks whenever any application invokes fsync().
*
* Start the cache maintenance pseudo thread after dropping privileges.
*/
#define PS_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
if (*var_ps_cache_map)
cache_map = dict_open(var_ps_cache_map,
O_CREAT | O_RDWR,
PS_DICT_OPEN_FLAGS);
cache_map =
dict_cache_open(data_redirect_map(redirect, var_ps_cache_map),
O_CREAT | O_RDWR, PS_DICT_OPEN_FLAGS);
/*
* Clean up and restore privilege.
*/
vstring_free(redirect);
RESTORE_SAVED_EUGID();
}
@ -1241,6 +1302,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
"continue", PS_ACT_CONT,
0, -1,
};
int expire_flags;
/*
* This routine runs after the skeleton code has entered the chroot jail.
@ -1275,6 +1337,18 @@ static void post_jail_init(char *unused_name, char **unused_argv)
if ((hangup_action = name_code(actions, NAME_CODE_FLAG_NONE,
var_ps_hangup_action)) < 0)
msg_fatal("bad %s value: %s", VAR_PS_HUP_ACTION, var_ps_hangup_action);
/*
* Start the cache maintenance pseudo thread last. Early cleanup makes
* verbose logging more informative (we get positive confirmation that
* the cleanup thread runs).
*/
expire_flags = DICT_CACHE_FLAG_EXP_SUMMARY;
if (msg_verbose)
expire_flags |= DICT_CACHE_FLAG_EXP_VERBOSE;
if (cache_map != 0 && var_ps_cache_scan > 0)
dict_cache_expire(cache_map, expire_flags, var_ps_cache_scan,
postscreen_cache_validator, (char *) 0);
}
MAIL_VERSION_STAMP_DECLARE;
@ -1309,6 +1383,8 @@ int main(int argc, char **argv)
static const CONFIG_TIME_TABLE time_table[] = {
VAR_PS_CACHE_TTL, DEF_PS_CACHE_TTL, &var_ps_cache_ttl, 1, 0,
VAR_PS_GREET_WAIT, DEF_PS_GREET_WAIT, &var_ps_greet_wait, 1, 0,
VAR_PS_CACHE_RET, DEF_PS_CACHE_RET, &var_ps_cache_ret, 0, 0,
VAR_PS_CACHE_SCAN, DEF_PS_CACHE_SCAN, &var_ps_cache_scan, 0, 0,
0,
};
@ -1326,5 +1402,6 @@ int main(int argc, char **argv)
MAIL_SERVER_POST_INIT, post_jail_init,
MAIL_SERVER_SOLITARY,
MAIL_SERVER_SLOW_EXIT, postscreen_drain,
MAIL_SERVER_EXIT, postscreen_dump,
0);
}

View File

@ -681,8 +681,9 @@
/* Optional SMTP server access restrictions in the context of a client
/* SMTP connection request.
/* .IP "\fBsmtpd_helo_required (no)\fR"
/* Require that a remote SMTP client introduces itself at the beginning
/* of an SMTP session with the HELO or EHLO command.
/* Require that a remote SMTP client introduces itself with the HELO
/* or EHLO command before sending the MAIL command or other commands
/* that require EHLO negotiation.
/* .IP "\fBsmtpd_helo_restrictions (empty)\fR"
/* Optional restrictions that the Postfix SMTP server applies in the
/* context of the SMTP HELO command.
@ -741,7 +742,7 @@
/* See the file ADDRESS_VERIFICATION_README for information
/* about how to configure and operate the Postfix sender/recipient
/* address verification service.
/* .IP "\fBaddress_verify_poll_count (3)\fR"
/* .IP "\fBaddress_verify_poll_count (see 'postconf -d' output)\fR"
/* How many times to query the \fBverify\fR(8) service for the completion
/* of an address verification request in progress.
/* .IP "\fBaddress_verify_poll_delay (3s)\fR"
@ -4942,6 +4943,7 @@ int main(int argc, char **argv)
VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0,
VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0,
VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0,
0,
};
static const CONFIG_INT_TABLE int_table[] = {
@ -4970,7 +4972,6 @@ int main(int argc, char **argv)
VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code, 0, 0,
VAR_PLAINTEXT_CODE, DEF_PLAINTEXT_CODE, &var_plaintext_code, 0, 0,
VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0,
VAR_SMTPD_CRATE_LIMIT, DEF_SMTPD_CRATE_LIMIT, &var_smtpd_crate_limit, 0, 0,
VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
VAR_SMTPD_CMAIL_LIMIT, DEF_SMTPD_CMAIL_LIMIT, &var_smtpd_cmail_limit, 0, 0,

View File

@ -32,7 +32,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
allascii.c load_file.c killme_after.c vstream_tweak.c upass_connect.c \
upass_listen.c upass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c
unix_pass_fd_fix.c dict_cache.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@ -66,7 +66,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
allascii.o load_file.o killme_after.o vstream_tweak.o upass_connect.o \
upass_listen.o upass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o
unix_pass_fd_fix.o dict_cache.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@ -86,7 +86,7 @@ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
stringops.h sys_defs.h timed_connect.h timed_wait.h trigger.h \
username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \
vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \
edit_file.h
edit_file.h dict_cache.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c test_send_fd test_recv_fd
DEFS = -I. -D$(SYSTYPE)
@ -740,6 +740,17 @@ dict_alloc.o: sys_defs.h
dict_alloc.o: vbuf.h
dict_alloc.o: vstream.h
dict_alloc.o: vstring.h
dict_cache.o: argv.h
dict_cache.o: dict.h
dict_cache.o: dict_cache.c
dict_cache.o: dict_cache.h
dict_cache.o: events.h
dict_cache.o: msg.h
dict_cache.o: mymalloc.h
dict_cache.o: sys_defs.h
dict_cache.o: vbuf.h
dict_cache.o: vstream.h
dict_cache.o: vstring.h
dict_cdb.o: argv.h
dict_cdb.o: dict.h
dict_cdb.o: dict_cdb.c
@ -1505,7 +1516,6 @@ stream_trigger.o: mymalloc.h
stream_trigger.o: stream_trigger.c
stream_trigger.o: sys_defs.h
stream_trigger.o: trigger.h
sys_compat.o: iostuff.h
sys_compat.o: sys_compat.c
sys_compat.o: sys_defs.h
timed_connect.o: iostuff.h

View File

@ -107,15 +107,16 @@
/* modified, or if the result is to survive multiple dict_lookup() calls.
/*
/* dict_delete() removes the named member from the named dictionary.
/* The result is non-zero when the member does not exist.
/* The result value is zero when the member was found.
/*
/* dict_sequence() steps throuh the named dictionary and returns
/* dict_sequence() steps through the named dictionary and returns
/* keys and values in some implementation-defined order. The func
/* argument is DICT_SEQ_FUN_FIRST to set the cursor to the first
/* entry or DICT_SEQ_FUN_NEXT to select the next entry. The result
/* is owned by the underlying dictionary method. Make a copy if the
/* result is to be modified, or if the result is to survive multiple
/* dict_sequence() calls.
/* dict_sequence() calls. The result value is zero when a member
/* was found.
/*
/* dict_eval() expands macro references in the specified string.
/* The result is owned by the dictionary manager. Make a copy if the

View File

@ -0,0 +1,577 @@
/*++
/* NAME
/* dict_cache 3
/* SUMMARY
/* External cache manager
/* SYNOPSIS
/* #include <dict_cache.h>
/*
/* DICT_CACHE *dict_cache_open(dbname, open_flags, dict_flags)
/* const char *dbname;
/* int open_flags;
/* int dict_flags;
/*
/* void dict_cache_close(cache)
/* DICT_CACHE *cache;
/*
/* const char *dict_cache_lookup(cache, cache_key)
/* DICT_CACHE *cache;
/* const char *cache_key;
/*
/* int dict_cache_update(cache, cache_key, cache_val)
/* DICT_CACHE *cache;
/* const char *cache_key;
/* const char *cache_val;
/*
/* int dict_cache_delete(cache, cache_key)
/* DICT_CACHE *cache;
/* const char *cache_key;
/*
/* int dict_cache_sequence(cache, first_next, cache_key, cache_val)
/* DICT_CACHE *cache;
/* int first_next;
/* const char **cache_key;
/* const char **cache_val;
/*
/* void dict_cache_expire(cache, flags, interval, validator, context)
/* DICT_CACHE *cache;
/* int flags;
/* int interval;
/* int (*validator)(const char *cache_key, const char *cache_val,
/* char *context);
/* char *context;
/* AUXILIARY FUNCTIONS
/* const char *dict_cache_name(cache)
/* DICT_CACHE *cache;
/*
/* DICT_CACHE *dict_cache_import(table)
/* DICT *table;
/* DESCRIPTION
/* This module maintains external cache files with support
/* for expiration. The underlying table must implement the
/* "lookup", "update", "delete" and "sequence" operations.
/*
/* Although this API is similar to the one documented in
/* dict_open(3), there are subtle differences in the interaction
/* between the iterators that access all cache elements, and
/* other operations that access individual cache elements.
/*
/* In particular, when a "sequence" or "expire" operation is
/* in progress the cache intercepts requests to delete the
/* "current" entry, as this would cause some databases to
/* mis-behave. Instead, the cache implements a "delete behind"
/* strategy, and deletes such an entry after the "sequence"
/* or "expire" operation moves on to the next cache element.
/* The "delete behind" strategy also affects the cache lookup
/* and update operations as detailed below.
/*
/* dict_cache_open() opens the specified cache and returns a
/* handle that must be used for subsequent access. This function
/* does not return in case of error.
/*
/* dict_cache_close() closes the specified cache and releases
/* memory that was allocated by dict_cache_open(), and terminates
/* any thread that was started with dict_cache_expire().
/*
/* dict_cache_lookup() looks up the specified cache entry.
/* The result value is a null pointer when the cache entry was
/* not found, or when the entry is scheduled for "delete
/* behind".
/*
/* dict_cache_update() updates the specified cache entry. If
/* the entry is scheduled for "delete behind", the delete
/* operation is canceled (meaning that the cache must be opened
/* with DICT_FLAG_DUP_REPLACE). This function does not return
/* in case of error.
/*
/* dict_cache_delete() removes the specified cache entry. If
/* this is the "current" entry of a "sequence" operation, the
/* entry is scheduled for "delete behind". The result value
/* is zero when the entry was found.
/*
/* dict_cache_sequence() iterates over the specified cache and
/* returns each entry in an implementation-defined order. The
/* result value is zero when a cache entry was found. Programs
/* must not use both dict_cache_sequence() and dict_cache_expire().
/*
/* dict_cache_expire() schedules a thread that expires cache
/* entries periodically. Specify a null validator argument to
/* cancel the thread. It is an error to schedule a cache
/* cleanup thread when one already exists. Programs must not
/* use both dict_cache_sequence() and dict_cache_expire().
/*
/* dict_cache_name() returns the name of the specified cache.
/*
/* dict_cache_import() encapsulates a pre-opened database
/* handle and adds the above features.
/*
/* Arguments:
/* .IP "dbname, open_flags, dict_flags"
/* These are passed unchanged to dict_open().
/* .IP cache
/* Cache handle created with dict_cache_open()or dict_cache_import().
/* .IP cache_key
/* Cache lookup key.
/* .IP cache_val
/* Information that is stored under a cache lookup key.
/* .IP first_next
/* One of DICT_SEQ_FUN_FIRST (first cache element) or
/* DICT_SEQ_FUN_NEXT (next cache element).
/* .sp
/* Note: there is no "stop" request. To ensure that the "delete
/* behind" strategy does not interfere with database access,
/* allow dict_cache_sequence() to run to completion.
/* .IP flags
/* Bit-wise OR of zero or more of the following:
/* .RS
/* .IP DICT_CACHE_FLAG_EXP_VERBOSE
/* Log each cache entry's status during a cache cleanup run.
/* .IP DICT_CACHE_FLAG_EXP_SUMMARY
/* Log the number of cache entries retained and dropped after
/* a cache cleaning run.
/* .RE
/* .IP interval
/* The non-zero time between scans for expired cache entries.
/* The interval timer starts after a scan completes.
/* .IP validator
/* Application call-back routine that returns non-zero when a
/* cache entry should be kept. The validator must not modify
/* or close the cache.
/* .IP context
/* Application-specific context.
/* .IP table
/* A bare dictonary handle.
/* DIAGNOSTICS
/* These routines terminate with a fatal run-time error
/* for unrecoverable database errors. This allows the
/* program to restart and reset the database to an
/* empty initial state.
/* BUGS
/* There should be a way to suspend automatic program suicide
/* until a cache cleanup run is completed. Some entries may
/* never be removed when the process max_idle time is less
/* than the time needed to make a full pass over the cache.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* HISTORY
/* .ad
/* .fi
/* A predecessor of this code was written first for the Postfix
/* tlsmgr(8) daemon.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
#include <stdlib.h>
/* Utility library. */
#include <msg.h>
#include <dict.h>
#include <mymalloc.h>
#include <events.h>
#include <dict_cache.h>
/* Application-specific. */
/*
* XXX Deleting entries while enumerating a map can he tricky. Some map
* types have a concept of cursor and support a "delete the current element"
* operation. Some map types without cursors don't behave well when the
* current first/next entry is deleted (example: with Berkeley DB < 2, the
* "next" operation produces garbage). To avoid trouble, we delete an entry
* after advancing the current first/next position beyond it; we use the
* same strategy with application requests to delete the current entry.
*/
/*
* Opaque data structure. Use dict_cache_name() to access the name of the
* underlying database.
*/
struct DICT_CACHE {
int flags; /* see below */
DICT *db; /* database handle */
/* Iterator support. */
char *saved_curr_key; /* "current" cache lookup key */
char *saved_curr_val; /* "current" cache lookup result */
/* Cleanup support. */
int exp_flags; /* logging */
int exp_interval; /* time between cleanup runs */
DICT_CACHE_VALIDATOR_FN exp_validator; /* expiration call-back */
char *exp_context; /* call-back context */
int retained; /* entries retained in cleanup run */
int dropped; /* entries removed in cleanup run */
};
#define DC_FLAG_DEL_SAVED_CURRENT_KEY (1<<0) /* delete-behind is scheduled */
/*
* Macros to make obscure code more readable.
*/
#define DC_SCHEDULE_FOR_DELETE_BEHIND(cp) \
((cp)->flags |= DC_FLAG_DEL_SAVED_CURRENT_KEY)
#define DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key) \
((cp)->saved_curr_key && strcmp((cp)->saved_curr_key, (cache_key)) == 0)
#define DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp) \
(/* NOT: (cp)->saved_curr_key && */ \
((cp)->flags & DC_FLAG_DEL_SAVED_CURRENT_KEY) != 0)
#define DC_CANCEL_DELETE_BEHIND(cp) \
((cp)->flags &= ~DC_FLAG_DEL_SAVED_CURRENT_KEY)
/*
* Special key to store the time of last cache cleanup run completion.
*/
#define DC_LAST_CACHE_CLEANUP_COMPLETED "_LAST_CACHE_CLEANUP_COMPLETED_"
/* dict_cache_lookup - load entry from cache */
const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key)
{
/*
* Search for the cache entry. Don't return an entry that was scheduled
* for deletion.
*/
if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)
&& DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) {
return (0);
} else {
return (dict_get(cp->db, cache_key));
}
}
/* dict_cache_update - save entry to cache */
void dict_cache_update(DICT_CACHE *cp, const char *cache_key,
const char *cache_val)
{
/*
* Store the cache entry and cancel a scheduled delete-behind operation.
*/
if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)
&& DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key))
DC_CANCEL_DELETE_BEHIND(cp);
dict_put(cp->db, cache_key, cache_val);
}
/* dict_cache_delete - delete entry from cache */
int dict_cache_delete(DICT_CACHE *cp, const char *cache_key)
{
int zero_means_found;
/*
* Delete the entry, unless we would delete the current first/next entry.
* Instead, schedule the "current" entry for delete-behind to avoid
* mis-behavior by some databases.
*/
if (DC_MATCH_SAVED_CURRENT_KEY(cp, cache_key)) {
DC_SCHEDULE_FOR_DELETE_BEHIND(cp);
zero_means_found = 0;
} else {
zero_means_found = dict_del(cp->db, cache_key);
}
return (zero_means_found);
}
/* dict_cache_sequence - look up the first/next cache entry */
int dict_cache_sequence(DICT_CACHE *cp, int first_next,
const char **cache_key,
const char **cache_val)
{
int zero_means_found;
const char *raw_cache_key;
const char *raw_cache_val;
char *previous_curr_key;
char *previous_curr_val;
/*
* Find the first or next database entry. Hide the record with the cache
* cleanup completion time stamp.
*/
zero_means_found =
dict_seq(cp->db, first_next, &raw_cache_key, &raw_cache_val);
if (zero_means_found == 0
&& strcmp(raw_cache_key, DC_LAST_CACHE_CLEANUP_COMPLETED) == 0)
zero_means_found =
dict_seq(cp->db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val);
/*
* Save the current cache_key and cache_val before they are clobbered by
* our own delete operation below. This also prevents surprises when the
* application accesses the database after this function returns.
*
* We also use the saved cache_key to protect the current entry against
* application delete requests.
*/
previous_curr_key = cp->saved_curr_key;
previous_curr_val = cp->saved_curr_val;
if (zero_means_found == 0) {
cp->saved_curr_key = mystrdup(raw_cache_key);
cp->saved_curr_val = mystrdup(raw_cache_val);
} else {
cp->saved_curr_key = 0;
cp->saved_curr_val = 0;
}
/*
* Delete behind.
*/
if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) {
DC_CANCEL_DELETE_BEHIND(cp);
if (dict_del(cp->db, previous_curr_key) != 0)
msg_warn("database %s: could not delete entry for %s",
cp->db->name, previous_curr_key);
}
/*
* Clean up previous iteration key and value.
*/
if (previous_curr_key)
myfree(previous_curr_key);
if (previous_curr_val)
myfree(previous_curr_val);
/*
* Return the result.
*/
*cache_key = (cp)->saved_curr_key;
*cache_val = (cp)->saved_curr_val;
return (zero_means_found);
}
/* dict_cache_delete_behind_reset - reset "delete behind" state */
static void dict_cache_delete_behind_reset(DICT_CACHE *cp)
{
#define FREE_AND_WIPE(s) do { if (s) { myfree(s); (s) = 0; } } while (0)
DC_CANCEL_DELETE_BEHIND(cp);
FREE_AND_WIPE(cp->saved_curr_key);
FREE_AND_WIPE(cp->saved_curr_val);
}
/* dict_cache_clean_stat_log_reset - log and reset cache cleanup statistics */
static void dict_cache_clean_stat_log_reset(DICT_CACHE *cp,
const char *full_partial)
{
if (cp->flags & DICT_CACHE_FLAG_EXP_SUMMARY)
msg_info("cache %s %s cleanup: retained=%d dropped=%d entries",
cp->db->name, full_partial, cp->retained, cp->dropped);
cp->retained = cp->dropped = 0;
}
/* dict_cache_expire_event - examine one cache entry */
static void dict_cache_expire_event(int unused_event, char *cache_context)
{
DICT_CACHE *cp = (DICT_CACHE *) cache_context;
const char *cache_key;
const char *cache_val;
int next_interval;
VSTRING *stamp_buf;
int first_next;
/*
* We interleave cache cleanup with other processing, so that the
* application's service remains available, with perhaps increased
* latency.
*/
/*
* Start a new cache cleanup run.
*/
if (cp->saved_curr_key == 0) {
cp->retained = cp->dropped = 0;
first_next = DICT_SEQ_FUN_FIRST;
if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE)
msg_info("start %s cache cleanup", cp->db->name);
}
/*
* Continue a cache cleanup run in progress.
*/
else {
first_next = DICT_SEQ_FUN_NEXT;
}
/*
* Examine one cache entry.
*/
if (dict_cache_sequence(cp, first_next, &cache_key, &cache_val) == 0) {
if (cp->exp_validator(cache_key, cache_val, cp->exp_context) == 0) {
DC_SCHEDULE_FOR_DELETE_BEHIND(cp);
cp->dropped++;
if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE)
msg_info("drop %s cache entry for %s", cp->db->name, cache_key);
} else {
cp->retained++;
if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE)
msg_info("keep %s cache entry for %s", cp->db->name, cache_key);
}
next_interval = 0;
}
/*
* Cache cleanup completed. Report vital statistics.
*/
else {
if (cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE)
msg_info("done %s cache cleanup scan", cp->db->name);
dict_cache_clean_stat_log_reset(cp, "full");
stamp_buf = vstring_alloc(100);
vstring_sprintf(stamp_buf, "%ld", (long) event_time());
dict_put(cp->db, DC_LAST_CACHE_CLEANUP_COMPLETED,
vstring_str(stamp_buf));
vstring_free(stamp_buf);
next_interval = cp->exp_interval;
}
event_request_timer(dict_cache_expire_event, cache_context, next_interval);
}
/* dict_cache_expire - schedule or stop the cache cleanup thread */
void dict_cache_expire(DICT_CACHE *cp, int flags, int interval,
DICT_CACHE_VALIDATOR_FN validator,
char *context)
{
const char *myname = "dict_cache_expire";
const char *last_done;
time_t next_interval;
/*
* Schedule the cache cleanup thread.
*/
if (validator != 0) {
/*
* Sanity checks.
*/
if (cp->exp_validator != 0)
msg_panic("%s: %s cache cleanup is already scheduled",
myname, cp->db->name);
if (interval <= 0)
msg_panic("%s: bad %s cache cleanup interval %d",
myname, cp->db->name, interval);
cp->exp_flags = flags;
cp->exp_interval = interval;
cp->exp_validator = validator;
cp->exp_context = context;
/*
* The next start time depends on the last completion time.
*/
#define NEXT_START(last, delta) ((delta) + (unsigned long) atol(last))
#define NOW (time((time_t *) 0)) /* NOT: event_time() */
if ((last_done = dict_get(cp->db, DC_LAST_CACHE_CLEANUP_COMPLETED)) == 0
|| (next_interval = (NEXT_START(last_done, interval) - NOW)) < 0)
next_interval = 0;
if (next_interval > interval)
next_interval = interval;
if ((cp->exp_flags & DICT_CACHE_FLAG_EXP_VERBOSE) && next_interval > 0)
msg_info("%s cache cleanup will start after %ds",
cp->db->name, (int) next_interval);
event_request_timer(dict_cache_expire_event, (char *) cp,
(int) next_interval);
}
/*
* Cancel the cache cleanup thread.
*/
else if (cp->exp_validator) {
if (cp->retained || cp->dropped)
dict_cache_clean_stat_log_reset(cp, "partial");
dict_cache_delete_behind_reset(cp);
cp->exp_interval = 0;
cp->exp_validator = 0;
cp->exp_context = 0;
event_cancel_timer(dict_cache_expire_event, (char *) cp);
}
}
/* dict_cache_open - open cache file */
DICT_CACHE *dict_cache_open(const char *dbname, int open_flags, int dict_flags)
{
DICT *dict;
/*
* Open the database as requested. Don't attempt to second-guess the
* application.
*/
dict = dict_open(dbname, open_flags, dict_flags);
return (dict_cache_import(dict));
}
/* dict_cache_import - encapsulate pre-opened database */
DICT_CACHE *dict_cache_import(DICT *dict)
{
DICT_CACHE *cp;
/*
* Create the DICT_CACHE object.
*/
cp = (DICT_CACHE *) mymalloc(sizeof(*cp));
cp->flags = 0;
cp->db = dict;
cp->saved_curr_key = 0;
cp->saved_curr_val = 0;
cp->exp_interval = 0;
cp->exp_validator = 0;
cp->exp_context = 0;
cp->retained = 0;
cp->dropped = 0;
return (cp);
}
/* dict_cache_close - close cache file */
void dict_cache_close(DICT_CACHE *cp)
{
/*
* Destroy the DICT_CACHE object.
*/
if (cp->exp_validator)
dict_cache_expire(cp, 0, 0, (DICT_CACHE_VALIDATOR_FN) 0, (char *) 0);
dict_close(cp->db);
if (cp->saved_curr_key)
myfree(cp->saved_curr_key);
if (cp->saved_curr_val)
myfree(cp->saved_curr_val);
myfree((char *) cp);
}
/* dict_cache_name - get the cache name */
const char *dict_cache_name(DICT_CACHE *cp)
{
/*
* This is used for verbose logging or warning messages, so the cost of
* call is only made where needed (well sort off - code that does not
* execute still presents overhead for the processor pipeline, processor
* cache, etc).
*/
return (cp->db->name);
}

View File

@ -0,0 +1,49 @@
#ifndef _DICT_CACHE_H_INCLUDED_
#define _DICT_CACHE_H_INCLUDED_
/*++
/* NAME
/* dict_cache 3h
/* SUMMARY
/* External cache manager
/* SYNOPSIS
/* #include <dict_cache.h>
/* DESCRIPTION
/* .nf
/*
* Utility library.
*/
#include <dict.h>
/*
* External interface.
*/
typedef struct DICT_CACHE DICT_CACHE;
typedef int (*DICT_CACHE_VALIDATOR_FN) (const char *, const char *, char *);
extern DICT_CACHE *dict_cache_open(const char *, int, int);
extern void dict_cache_close(DICT_CACHE *);
extern const char *dict_cache_lookup(DICT_CACHE *, const char *);
extern void dict_cache_update(DICT_CACHE *, const char *, const char *);
extern int dict_cache_delete(DICT_CACHE *, const char *);
extern int dict_cache_sequence(DICT_CACHE *, int, const char **, const char **);
extern void dict_cache_expire(DICT_CACHE *, int, int, DICT_CACHE_VALIDATOR_FN, char *);
extern const char *dict_cache_name(DICT_CACHE *);
extern DICT_CACHE *dict_cache_import(DICT *);
#define DICT_CACHE_FLAG_EXP_VERBOSE (1<<0)
#define DICT_CACHE_FLAG_EXP_SUMMARY (1<<1)
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
#endif

View File

@ -310,6 +310,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
DICT_DBM *dict_dbm = (DICT_DBM *) dict;
datum dbm_key;
datum dbm_value;
int status;
/*
* Acquire a shared lock.
@ -350,6 +351,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
* Copy the value so that it is guaranteed null terminated.
*/
*value = SCOPY(dict_dbm->val_buf, dbm_value.dptr, dbm_value.dsize);
status = 0;
} else {
/*
@ -358,7 +360,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
*/
if (dbm_error(dict_dbm->dbm))
msg_fatal("error seeking %s: %m", dict_dbm->dict.name);
return (1); /* no error: eof/not found
status = 1; /* no error: eof/not found
* (should not happen!) */
}
} else {
@ -368,7 +370,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
*/
if (dbm_error(dict_dbm->dbm))
msg_fatal("error seeking %s: %m", dict_dbm->dict.name);
return (1); /* no error: eof/not found */
status = 1; /* no error: eof/not found */
}
/*
@ -378,7 +380,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
return (0);
return (status);
}
/* dict_dbm_close - disassociate from data base */

View File

@ -75,6 +75,29 @@ static void dict_ht_update(DICT *dict, const char *name, const char *value)
ht->value = mystrdup(value);
}
/* dict_ht_sequence - first/next iterator */
static int dict_ht_sequence(DICT *dict, int how, const char **name,
const char **value)
{
DICT_HT *dict_ht = (DICT_HT *) dict;
HTABLE_INFO *ht;
ht = htable_sequence(dict_ht->table,
how == DICT_SEQ_FUN_FIRST ? HTABLE_SEQ_FIRST :
how == DICT_SEQ_FUN_NEXT ? HTABLE_SEQ_NEXT :
HTABLE_SEQ_STOP);
if (ht != 0) {
*name = ht->key;
*value = ht->value;
return (0);
} else {
*name = 0;
*value = 0;
return (1);
}
}
/* dict_ht_close - disassociate from hash table */
static void dict_ht_close(DICT *dict)
@ -95,6 +118,7 @@ DICT *dict_ht_open(const char *name, HTABLE *table, void (*remove) (char *))
dict_ht = (DICT_HT *) dict_alloc(DICT_TYPE_HT, name, sizeof(*dict_ht));
dict_ht->dict.lookup = dict_ht_lookup;
dict_ht->dict.update = dict_ht_update;
dict_ht->dict.sequence = dict_ht_sequence;
dict_ht->dict.close = dict_ht_close;
dict_ht->table = table;
dict_ht->remove = remove;

View File

@ -144,13 +144,13 @@
/* dict_put() stores the specified key and value into the named
/* dictionary.
/*
/* dict_del() removes a dictionary entry, and returns non-zero
/* dict_del() removes a dictionary entry, and returns zero
/* in case of success.
/*
/* dict_seq() iterates over all members in the named dictionary.
/* func is define DICT_SEQ_FUN_FIRST (select first member) or
/* DICT_SEQ_FUN_NEXT (select next member). A null result means
/* there is more.
/* DICT_SEQ_FUN_NEXT (select next member). A zero result means
/* that an entry was found.
/*
/* dict_close() closes the specified dictionary and cleans up the
/* associated data structures.

View File

@ -496,6 +496,11 @@ typedef struct epoll_event EVENT_BUFFER;
/*
* Timer events. Timer requests are kept sorted, in a circular list. We use
* the RING abstraction, so we get to use a couple ugly macros.
*
* When a call-back function adds a timer request, we label the request with
* the event_loop() call instance that invoked the call-back. We use this to
* prevent zero-delay timer requests from running in a tight loop and
* starving I/O events.
*/
typedef struct EVENT_TIMER EVENT_TIMER;
@ -503,10 +508,12 @@ struct EVENT_TIMER {
time_t when; /* when event is wanted */
EVENT_NOTIFY_TIME callback; /* callback function */
char *context; /* callback context */
long loop_instance; /* event_loop() call instance */
RING ring; /* linkage */
};
static RING event_timer_head; /* timer queue head */
static long event_loop_instance; /* event_loop() call instance */
#define RING_TO_TIMER(r) \
((EVENT_TIMER *) ((char *) (r) - offsetof(EVENT_TIMER, ring)))
@ -921,18 +928,24 @@ time_t event_request_timer(EVENT_NOTIFY_TIME callback, char *context, int delay
timer->when = event_present + delay;
timer->callback = callback;
timer->context = context;
timer->loop_instance = event_loop_instance;
if (msg_verbose > 2)
msg_info("%s: set 0x%lx 0x%lx %d", myname,
(long) callback, (long) context, delay);
}
/*
* Insert the request at the right place. Timer requests are kept sorted
* to reduce lookup overhead in the event loop.
* Timer requests are kept sorted to reduce lookup overhead in the event
* loop.
*
* XXX Append the new request after existing requests for the same time
* slot. The event_loop() routine depends on this to avoid starving I/O
* events when a call-back function schedules a zero-delay timer request.
*/
FOREACH_QUEUE_ENTRY(ring, &event_timer_head)
FOREACH_QUEUE_ENTRY(ring, &event_timer_head) {
if (timer->when < RING_TO_TIMER(ring)->when)
break;
break;
}
ring_prepend(ring, &timer->ring);
return (timer->when);
@ -1079,17 +1092,35 @@ void event_loop(int delay)
msg_panic("event_loop: recursive call");
/*
* Deliver timer events. Requests are sorted: we can stop when we reach
* the future or the list end. Allow the application to update the timer
* queue while it is being called back. To this end, we repeatedly pop
* the first request off the timer queue before delivering the event to
* the application.
* Deliver timer events. Allow the application to add/delete timer queue
* requests while it is being called back. Requests are sorted: we keep
* running over the timer request queue from the start, and stop when we
* reach the future or the list end. We also stop when we reach a timer
* request that was added by a call-back that was invoked from this
* event_loop() call instance, for reasons that are explained below.
*
* To avoid dangling pointer problems 1) we must remove a request from the
* timer queue before delivering its event to the application and 2) we
* must look up the next timer request *after* calling the application.
* The latter complicates the handling of zero-delay timer requests that
* are added by event_loop() call-back functions.
*
* XXX When a timer event call-back function adds a new timer request,
* event_request_timer() labels the request with the event_loop() call
* instance that invoked the timer event call-back. We use this instance
* label here to prevent zero-delay timer requests from running in a
* tight loop and starving I/O events. To make this solution work,
* event_request_timer() appends a new request after existing requests
* for the same time slot.
*/
event_present = time((time_t *) 0);
event_loop_instance += 1;
while ((timer = FIRST_TIMER(&event_timer_head)) != 0) {
if (timer->when > event_present)
break;
if (timer->loop_instance == event_loop_instance)
break;
ring_detach(&timer->ring); /* first this */
if (msg_verbose > 2)
msg_info("%s: timer 0x%lx 0x%lx", myname,
@ -1192,10 +1223,10 @@ static void echo(int unused_event, char *unused_context)
printf("Result: %s", buf);
}
int main(int argc, char **argv)
/* request - request a bunch of timer events */
static void request(int unused_event, char *unused_context)
{
if (argv[1])
msg_verbose = atoi(argv[1]);
event_request_timer(timer_event, "3 first", 3);
event_request_timer(timer_event, "3 second", 3);
event_request_timer(timer_event, "4 first", 4);
@ -1206,6 +1237,13 @@ int main(int argc, char **argv)
event_request_timer(timer_event, "1 second", 1);
event_request_timer(timer_event, "0 first", 0);
event_request_timer(timer_event, "0 second", 0);
}
int main(int argc, char **argv)
{
if (argv[1])
msg_verbose = atoi(argv[1]);
event_request_timer(request, (char *) 0, 0);
event_enable_read(fileno(stdin), echo, (char *) 0);
event_drain(10);
exit(0);

View File

@ -46,6 +46,10 @@
/*
/* HTABLE_INFO **htable_list(table)
/* HTABLE *table;
/*
/* HTABLE_INFO *htable_sequence(table, how)
/* HTABLE *table;
/* int how;
/* DESCRIPTION
/* This module maintains one or more hash tables. Each table entry
/* consists of a unique string-valued lookup key and a generic
@ -85,6 +89,12 @@
/* htable_list() returns a null-terminated list of pointers to
/* all elements in the named table. The list should be passed to
/* myfree().
/*
/* htable_sequence() returns the first or next element depending
/* on the value of the "how" argument. Specify HTABLE_SEQ_FIRST
/* to start a new sequence, HTABLE_SEQ_NEXT to continue, and
/* HTABLE_SEQ_STOP to terminate a sequence early. The caller
/* must not delete the current element.
/* RESTRICTIONS
/* A callback function should not modify the hash table that is
/* specified to its caller.
@ -172,6 +182,7 @@ HTABLE *htable_create(int size)
table = (HTABLE *) mymalloc(sizeof(HTABLE));
htable_size(table, size < 13 ? 13 : size);
table->seq_element = 0;
return (table);
}
@ -202,7 +213,7 @@ HTABLE_INFO *htable_enter(HTABLE *table, const char *key, char *value)
{
HTABLE_INFO *ht;
if (table->used >= table->size)
if (table->used >= table->size && table->seq_element == 0)
htable_grow(table);
ht = (HTABLE_INFO *) mymalloc(sizeof(HTABLE_INFO));
ht->key = mystrdup(key);
@ -332,6 +343,34 @@ HTABLE_INFO **htable_list(HTABLE *table)
return (list);
}
/* htable_sequence - dict_cache(3) compatibility iterator */
HTABLE_INFO *htable_sequence(HTABLE *table, int how)
{
if (table == 0)
return (0);
switch (how) {
case HTABLE_SEQ_FIRST: /* start new sequence */
table->seq_bucket = table->data;
table->seq_element = table->seq_bucket[0];
break;
case HTABLE_SEQ_NEXT: /* next element */
if (table->seq_element) {
table->seq_element = table->seq_element->next;
break;
}
/* FALLTHROUGH */
default: /* terminate sequence */
return (table->seq_element = 0);
}
while (table->seq_element == 0
&& ++(table->seq_bucket) < table->data + table->size)
table->seq_element = table->seq_bucket[0];
return (table->seq_element);
}
#ifdef TEST
#include <vstring_vstream.h>
#include <myrand.h>
@ -346,6 +385,7 @@ int main(int unused_argc, char **unused_argv)
HTABLE_INFO *info;
int i;
int r;
int op;
/*
* Load a large number of strings and delete them in a random order.
@ -353,6 +393,11 @@ int main(int unused_argc, char **unused_argv)
hash = htable_create(10);
while (vstring_get(buf, VSTREAM_IN) != VSTREAM_EOF)
htable_enter(hash, vstring_str(buf), CAST_INT_TO_CHAR_PTR(count++));
for (i = 0, op = HTABLE_SEQ_FIRST; htable_sequence(hash, op) != 0;
i++, op = HTABLE_SEQ_NEXT)
/* void */ ;
if (i != hash->used)
msg_panic("%d entries found, but %d entries exist", i, hash->used);
ht_info = htable_list(hash);
for (i = 0; i < hash->used; i++) {
r = myrand() % hash->used;

View File

@ -26,6 +26,8 @@ typedef struct HTABLE {
int size; /* length of entries array */
int used; /* number of entries in table */
HTABLE_INFO **data; /* entries array, auto-resized */
HTABLE_INFO **seq_bucket; /* current sequence bucket */
HTABLE_INFO *seq_element; /* current sequence element */
} HTABLE;
extern HTABLE *htable_create(int);
@ -36,6 +38,11 @@ extern void htable_delete(HTABLE *, const char *, void (*) (char *));
extern void htable_free(HTABLE *, void (*) (char *));
extern void htable_walk(HTABLE *, void (*) (HTABLE_INFO *, char *), char *);
extern HTABLE_INFO **htable_list(HTABLE *);
extern HTABLE_INFO *htable_sequence(HTABLE *, int);
#define HTABLE_SEQ_FIRST 0
#define HTABLE_SEQ_NEXT 1
#define HTABLE_SEQ_STOP (-1)
/* LICENSE
/* .ad

View File

@ -63,8 +63,10 @@ verify.o: ../../include/cleanup_user.h
verify.o: ../../include/data_redirect.h
verify.o: ../../include/deliver_request.h
verify.o: ../../include/dict.h
verify.o: ../../include/dict_cache.h
verify.o: ../../include/dict_ht.h
verify.o: ../../include/dsn.h
verify.o: ../../include/events.h
verify.o: ../../include/htable.h
verify.o: ../../include/int_filt.h
verify.o: ../../include/iostuff.h

View File

@ -97,6 +97,10 @@
/* .IP "\fBaddress_verify_negative_refresh_time (3h)\fR"
/* The time after which a failed address verification probe needs to
/* be refreshed.
/* .PP
/* Available with Postfix 2.7 and later:
/* .IP "\fBaddress_verify_cache_cleanup_interval (12h)\fR"
/* The amount of time between \fBverify\fR(8) cache cleanup runs.
/* PROBE MESSAGE ROUTING CONTROLS
/* .ad
/* .fi
@ -121,6 +125,16 @@
/* .IP "\fBaddress_verify_default_transport ($default_transport)\fR"
/* Overrides the default_transport parameter setting for address
/* verification probes.
/* .PP
/* Available in Postfix 2.3 and later:
/* .IP "\fBaddress_verify_sender_dependent_relayhost_maps ($sender_dependent_relayhost_maps)\fR"
/* Overrides the sender_dependent_relayhost_maps parameter setting for address
/* verification probes.
/* .PP
/* Available in Postfix 2.7 and later:
/* .IP "\fBaddress_verify_sender_dependent_default_transport_maps ($sender_dependent_default_transport_maps)\fR"
/* Overrides the sender_dependent_default_transport_maps parameter
/* setting for address verification probes.
/* MISCELLANEOUS CONTROLS
/* .ad
/* .fi
@ -187,10 +201,11 @@
#include <mymalloc.h>
#include <htable.h>
#include <dict_ht.h>
#include <dict.h>
#include <dict_cache.h>
#include <split_at.h>
#include <stringops.h>
#include <set_eugid.h>
#include <events.h>
/* Global library. */
@ -216,12 +231,13 @@ int var_verify_pos_exp;
int var_verify_pos_try;
int var_verify_neg_exp;
int var_verify_neg_try;
int var_verify_scan_cache;
char *var_verify_sender;
/*
* State.
*/
static DICT *verify_map;
static DICT_CACHE *verify_map;
/*
* Silly little macros.
@ -344,7 +360,7 @@ static void verify_update_service(VSTREAM *client_stream)
* some probes succeed the address will remain cached as OK.
*/
if (addr_status == DEL_RCPT_STAT_OK
|| (raw_data = dict_get(verify_map, STR(addr))) == 0
|| (raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0
|| STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) {
probed = 0;
updated = (long) time((time_t *) 0);
@ -352,7 +368,7 @@ static void verify_update_service(VSTREAM *client_stream)
if (msg_verbose)
msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
STR(addr), addr_status, probed, updated, STR(text));
dict_put(verify_map, STR(addr), STR(buf));
dict_cache_update(verify_map, STR(addr), STR(buf));
}
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, VRFY_STAT_OK,
@ -419,7 +435,7 @@ static void verify_query_service(VSTREAM *client_stream)
/* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
translit(STR(addr), ":", "_");
if ((raw_data = dict_get(verify_map, STR(addr))) == 0 /* not found */
if ((raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0 /* not found */
|| ((get_buf = vstring_alloc(10)),
vstring_strcpy(get_buf, raw_data), /* malformed */
verify_parse_entry(STR(get_buf), &addr_status, &probed,
@ -432,7 +448,7 @@ static void verify_query_service(VSTREAM *client_stream)
updated = 0;
text = "Address verification in progress";
if (raw_data != 0 && var_verify_neg_cache == 0)
dict_del(verify_map, STR(addr));
dict_cache_delete(verify_map, STR(addr));
}
if (msg_verbose)
msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
@ -482,7 +498,7 @@ static void verify_query_service(VSTREAM *client_stream)
if (msg_verbose)
msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
STR(addr), addr_status, now, updated, text);
dict_put(verify_map, STR(addr), STR(put_buf));
dict_cache_update(verify_map, STR(addr), STR(put_buf));
}
}
}
@ -493,6 +509,29 @@ static void verify_query_service(VSTREAM *client_stream)
vstring_free(put_buf);
}
/* verify_cache_validator - cache cleanup validator */
static int verify_cache_validator(const char *addr, const char *raw_data,
char *context)
{
VSTRING *get_buf = (VSTRING *) context;
int addr_status;
long probed;
long updated;
char *text;
long now = (long) event_time();
#define POS_OR_NEG_ENTRY_EXPIRED(stat, stamp) \
(POSITIVE_ENTRY_EXPIRED((stat), (stamp)) \
|| NEGATIVE_ENTRY_EXPIRED((stat), (stamp)))
vstring_strcpy(get_buf, raw_data);
return (verify_parse_entry(STR(get_buf), &addr_status, /* syntax OK */
&probed, &updated, &text) == 0
&& (now - probed < PROBE_TTL /* probe in progress */
|| !POS_OR_NEG_ENTRY_EXPIRED(addr_status, updated)));
}
/* verify_service - perform service for client */
static void verify_service(VSTREAM *client_stream, char *unused_service,
@ -530,6 +569,21 @@ static void verify_service(VSTREAM *client_stream, char *unused_service,
vstring_free(request);
}
/* verify_dump - dump some statistics */
static void verify_dump(void)
{
/*
* Dump preliminary cache cleanup statistics when the process commits
* suicide while a cache cleanup run is in progress. We can't currently
* distinguish between "postfix reload" (we should restart) or "maximal
* idle time reached" (we could finish the cache cleanup first).
*/
dict_cache_close(verify_map);
verify_map = 0;
}
/* post_jail_init - post-jail initialization */
static void post_jail_init(char *unused_name, char **unused_argv)
@ -544,6 +598,20 @@ static void post_jail_init(char *unused_name, char **unused_argv)
var_use_limit = 0;
var_idle_limit = 0;
}
/*
* Start the cache cleanup thread.
*/
if (var_verify_scan_cache > 0) {
int expire_flags;
expire_flags = DICT_CACHE_FLAG_EXP_SUMMARY;
if (msg_verbose)
expire_flags |= DICT_CACHE_FLAG_EXP_VERBOSE;
dict_cache_expire(verify_map, expire_flags, var_verify_scan_cache,
verify_cache_validator,
(char *) vstring_alloc(100));
}
}
/* pre_jail_init - pre-jail initialization */
@ -585,17 +653,20 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
/*
* Keep state in persistent (external) or volatile (internal) map.
*
* Start the cache cleanup thread after permanently dropping privileges.
*/
#define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
if (*var_verify_map) {
saved_mask = umask(022);
verify_map = dict_open(data_redirect_map(redirect, var_verify_map),
O_CREAT | O_RDWR,
VERIFY_DICT_OPEN_FLAGS);
verify_map =
dict_cache_open(data_redirect_map(redirect, var_verify_map),
O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS);
(void) umask(saved_mask);
} else {
verify_map = dict_ht_open("verify", htable_create(0), myfree);
verify_map =
dict_cache_import(dict_ht_open("verify", htable_create(0), myfree));
}
/*
@ -621,6 +692,7 @@ int main(int argc, char **argv)
VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0,
VAR_VERIFY_SCAN_CACHE, DEF_VERIFY_SCAN_CACHE, &var_verify_scan_cache, 0, 0,
0,
};
@ -635,5 +707,6 @@ int main(int argc, char **argv)
MAIL_SERVER_PRE_INIT, pre_jail_init,
MAIL_SERVER_POST_INIT, post_jail_init,
MAIL_SERVER_SOLITARY,
MAIL_SERVER_EXIT, verify_dump,
0);
}