summaryrefslogtreecommitdiffstats
path: root/proto/POSTSCREEN_3_5_README.html
diff options
context:
space:
mode:
Diffstat (limited to 'proto/POSTSCREEN_3_5_README.html')
-rw-r--r--proto/POSTSCREEN_3_5_README.html1199
1 files changed, 1199 insertions, 0 deletions
diff --git a/proto/POSTSCREEN_3_5_README.html b/proto/POSTSCREEN_3_5_README.html
new file mode 100644
index 0000000..36dc21e
--- /dev/null
+++ b/proto/POSTSCREEN_3_5_README.html
@@ -0,0 +1,1199 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<head>
+
+<title>Postfix Postscreen Howto (Postfix 2.8 - 3.5)</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix Postscreen Howto (Postfix 2.8 - 3.5)</h1>
+
+<hr>
+
+<h2> <a name="intro">Introduction</a> </h2>
+
+<p> This document describes features that are available in Postfix
+2.8 - 3.5. </p>
+
+<p> The Postfix postscreen(8) daemon provides additional protection
+against mail server overload. One postscreen(8) process handles
+multiple inbound SMTP connections, and decides which clients may
+talk to a Postfix SMTP server process. By keeping spambots away,
+postscreen(8) leaves more SMTP server processes available for
+legitimate clients, and delays the onset of <a
+href="STRESS_README.html">server overload</a> conditions. </p>
+
+<p> postscreen(8) should not be used on SMTP ports that receive
+mail from end-user clients (MUAs). In a typical deployment,
+postscreen(8) handles the MX service on TCP port 25, while MUA
+clients submit mail via the submission service on TCP port 587 which
+requires client authentication. Alternatively, a site could set up
+a dedicated, non-postscreen, "port 25" server that provides submission
+service and client authentication, but no MX service. </p>
+
+<p> postscreen(8) maintains a temporary allowlist for clients that
+pass its tests; by allowing allowlisted clients to skip tests,
+postscreen(8) minimizes its impact on legitimate email traffic.
+</p>
+
+<p> postscreen(8) is part of a multi-layer defense. <p>
+
+<ul>
+
+<li> <p> As the first layer, postscreen(8) blocks connections from
+zombies and other spambots that are responsible for about 90% of
+all spam. It is implemented as a single process to make this defense
+as inexpensive as possible. </p>
+
+<li> <p> The second layer implements more complex SMTP-level access
+checks with <a href="SMTPD_ACCESS_README.html">Postfix SMTP servers</a>,
+<a href="SMTPD_POLICY_README.html">policy daemons</a>, and
+<a href="MILTER_README.html">Milter applications</a>. </p>
+
+<li> <p> The third layer performs light-weight content inspection
+with the Postfix built-in header_checks and body_checks. This can
+block unacceptable attachments such as executable programs, and
+worms or viruses with easy-to-recognize signatures. </p>
+
+<li> <p> The fourth layer provides heavy-weight content inspection
+with external content filters. Typical examples are <a
+href="http://www.ijs.si/software/amavisd/">Amavisd-new</a>, <a
+href="http://spamassassin.apache.org/">SpamAssassin</a>, and <a
+href="MILTER_README.html">Milter applications</a>. </p>
+
+</ul>
+
+<p> Each layer reduces the spam volume. The general strategy is to
+use the less expensive defenses first, and to use the more expensive
+defenses only for the spam that remains. </p>
+
+<p> Topics in this document: </p>
+
+<ul>
+
+<li> <a href="#intro">Introduction</a>
+
+<li> <a href="#basic">The basic idea behind postscreen(8)</a>
+
+<li> <a href="#general"> General operation </a>
+
+<li> <a href="#quick">Quick tests before everything else</a>
+
+<li> <a href="#before_220"> Tests before the 220 SMTP server greeting </a>
+
+<li> <a href="#after_220">Tests after the 220 SMTP server greeting</a>
+
+<li> <a href="#other_error">Other errors</a>
+
+<li> <a href="#victory">When all tests succeed</a>
+
+<li> <a href="#config"> Configuring the postscreen(8) service</a>
+
+<li> <a href="#historical"> Historical notes and credits </a>
+
+</ul>
+
+<h2> <a name="basic">The basic idea behind postscreen(8)</a> </h2>
+
+<p> Most email is spam, and most spam is sent out by zombies (malware
+on compromised end-user computers). Wietse expects that the zombie
+problem will get worse before things improve, if ever. Without a
+tool like postscreen(8) that keeps the zombies away, Postfix would be
+spending most of its resources not receiving email. </p>
+
+<p> The main challenge for postscreen(8) is to make an is-a-zombie
+decision based on a single measurement. This is necessary because
+many zombies try to fly under the radar and avoid spamming the same
+site repeatedly. Once postscreen(8) decides that a client is
+not-a-zombie, it allowlists the client temporarily to avoid further
+delays for legitimate mail. </p>
+
+<p> Zombies have challenges too: they have only a limited amount
+of time to deliver spam before their IP address becomes denylisted.
+To speed up spam deliveries, zombies make compromises in their SMTP
+protocol implementation. For example, they speak before their turn,
+or they ignore responses from SMTP servers and continue sending
+mail even when the server tells them to go away. </p>
+
+<p> postscreen(8) uses a variety of measurements to recognize
+zombies. First, postscreen(8) determines if the remote SMTP client
+IP address is denylisted. Second, postscreen(8) looks for protocol
+compromises that are made to speed up delivery. These are good
+indicators for making is-a-zombie decisions based on single
+measurements. </p>
+
+<p> postscreen(8) does not inspect message content. Message content
+can vary from one delivery to the next, especially with clients
+that (also) send legitimate email. Content is not a good indicator
+for making is-a-zombie decisions based on single measurements,
+and that is the problem that postscreen(8) is focused on. </p>
+
+<h2> <a name="general"> General operation </a> </h2>
+
+<p> For each connection from an SMTP client, postscreen(8) performs
+a number of tests
+in the order as described below. Some tests introduce a delay of
+a few seconds. postscreen(8) maintains a temporary allowlist for
+clients that pass its tests; by allowing allowlisted clients to
+skip tests, postscreen(8) minimizes its impact on legitimate email
+traffic. </p>
+
+<p> By default, postscreen(8) hands off all connections to a Postfix
+SMTP server process after logging its findings. This mode is useful
+for non-destructive testing. </p>
+
+<p> In a typical production setting, postscreen(8) is configured
+to reject mail from clients that fail one or more tests, after
+logging the helo, sender and recipient information. </p>
+
+<p> Note: postscreen(8) is not an SMTP proxy; this is intentional.
+The purpose is to keep zombies away from Postfix, with minimal
+overhead for legitimate clients. </p>
+
+<h2> <a name="quick">Quick tests before everything else</a> </h2>
+
+<p> Before engaging in SMTP-level tests. postscreen(8) queries a
+number of local deny and allowlists. These tests speed up the
+handling of known clients. </p>
+
+<ul>
+
+<li> <a href="#perm_white_black"> Permanent allow/denylist test </a>
+
+<li> <a href="#temp_white"> Temporary allowlist test </a>
+
+<li> <a href="#white_veto"> MX Policy test </a>
+
+</ul>
+
+<h3> <a name="perm_white_black"> Permanent allow/denylist test </a> </h3>
+
+<p> The postscreen_access_list parameter (default: permit_mynetworks)
+specifies a permanent access list for SMTP client IP addresses. Typically
+one would specify something that allowlists local networks, followed
+by a CIDR table for selective allow- and denylisting. </p>
+
+<p> Example: </p>
+
+<pre>
+/etc/postfix/main.cf:
+ postscreen_access_list = permit_mynetworks,
+ cidr:/etc/postfix/postscreen_access.cidr
+
+/etc/postfix/postscreen_access.cidr:
+ # Rules are evaluated in the order as specified.
+ # Denylist 192.168.* except 192.168.0.1.
+ 192.168.0.1 permit
+ 192.168.0.0/16 reject
+</pre>
+
+<p> See the postscreen_access_list manpage documentation for more
+details. </p>
+
+<p> When the SMTP client address matches a "permit" action,
+postscreen(8) logs this with the client address and port number as:
+</p>
+
+<pre>
+ <b>WHITELISTED</b> <i>[address]:port</i>
+</pre>
+
+<p> The allowlist action is not configurable: immediately hand off the
+connection to a Postfix SMTP server process. </p>
+
+<p> When the SMTP client address matches a "reject" action,
+postscreen(8) logs this with the client address and port number as:
+</p>
+
+<pre>
+ <b>BLACKLISTED</b> <i>[address]:port</i>
+</pre>
+
+<p> The postscreen_blacklist_action parameter specifies the action
+that is taken next. See "<a href="#fail_before_220">When tests
+fail before the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="temp_white"> Temporary allowlist test </a> </h3>
+
+<p> The postscreen(8) daemon maintains a <i>temporary</i>
+allowlist for SMTP client IP addresses that have passed all
+the tests described below. The postscreen_cache_map parameter
+specifies the location of the temporary allowlist. The
+temporary allowlist is not used for SMTP client addresses
+that appear on the <i>permanent</i> access list. </p>
+
+<p> By default the temporary allowlist is not shared with other
+postscreen(8) daemons. See
+<a href="#temp_white_sharing"> Sharing
+the temporary allowlist </a> below for alternatives. </p>
+
+<p> When the SMTP client address appears on the temporary
+allowlist, postscreen(8) logs this with the client address and port
+number as: </p>
+
+<pre>
+ <b>PASS OLD</b> <i>[address]:port</i>
+</pre>
+
+<p> The action is not configurable: immediately hand off the
+connection to a Postfix SMTP server process. The client is
+excluded from further tests until its temporary allowlist
+entry expires, as controlled with the postscreen_*_ttl
+parameters. Expired entries are silently renewed if possible. </p>
+
+<h3> <a name="white_veto"> MX Policy test </a> </h3>
+
+<p> When the remote SMTP client is not on the static access list
+or temporary allowlist, postscreen(8) can implement a number of
+allowlist tests, before it grants the client a temporary allowlist
+status that allows it to talk to a Postfix SMTP server process. </p>
+
+<p> When postscreen(8) is configured to monitor all primary and
+backup MX addresses, it can refuse to allowlist clients that connect
+to a backup MX address only (an old spammer trick to take advantage
+of backup MX hosts with weaker anti-spam policies than primary MX
+hosts). </p>
+
+<blockquote> <p> NOTE: The following solution is for small sites.
+Larger sites would have to share the postscreen(8) cache between
+primary and backup MTAs, which would introduce a common point of
+failure. </p> </blockquote>
+
+<ul>
+
+<li> <p> First, configure the host to listen on both primary and
+backup MX addresses. Use the appropriate <tt>ifconfig</tt> or <tt>ip</tt>
+command for the local operating system, or update the appropriate
+configuration files and "refresh" the network protocol stack. </p>
+
+<p> <p> Second, configure Postfix to listen on the new IP address
+(this step is needed when you have specified inet_interfaces in
+main.cf). </p>
+
+<li> <p> Then, configure postscreen(8) to deny the temporary allowlist
+status on the backup MX address(es). An example for Wietse's
+server is: </p>
+
+<pre>
+/etc/postfix/main.cf:
+ postscreen_whitelist_interfaces = !168.100.189.8 static:all
+</pre>
+
+<p> Translation: allow clients to obtain the temporary allowlist
+status on all server IP addresses except 168.100.189.8, which is a
+backup MX address. </p>
+
+</ul>
+
+<p> When a non-allowlisted client connects the backup MX address,
+postscreen(8) logs this with the client address and port number as:
+</p>
+
+<pre>
+ <b>CONNECT from</b> <i>[address]:port</i> <b>to [168.100.189.8]:25</b>
+ <b>WHITELIST VETO</b> <i>[address]:port</i>
+</pre>
+
+<p> Translation: the client at <i>[address]:port</i> connected to
+the backup MX address 168.100.189.8 while it was not allowlisted.
+The client will not be granted the temporary allowlist status, even
+if passes all the allowlist tests described below. </p>
+
+<h2> <a name="before_220"> Tests before the 220 SMTP server greeting </a> </h2>
+
+<p> The postscreen_greet_wait parameter specifies a short time
+interval before the "220 <i>text</i>..." server greeting, where
+postscreen(8) can run a number of tests in parallel. </p>
+
+<p> When a good client passes these tests, and no "<a
+href="#after_220">deep protocol tests</a>"
+are configured, postscreen(8)
+adds the client to the temporary allowlist and hands off the "live"
+connection to a Postfix SMTP server process. The client can then
+continue as if postscreen(8) never even existed (except of course
+for the short postscreen_greet_wait delay). </p>
+
+<ul>
+
+<li> <a href="#pregreet"> Pregreet test </a>
+
+<li> <a href="#dnsbl"> DNS Allow/denylist test </a>
+
+<li> <a href="#fail_before_220">When tests fail before the 220 SMTP server greeting</a>
+
+</ul>
+
+<h3> <a name="pregreet"> Pregreet test </a> </h3>
+
+<p> The SMTP protocol is a classic example of a protocol where the
+server speaks before the client. postscreen(8) detects zombies
+that are in a hurry and that speak before their turn. This test is
+enabled by default. </p>
+
+<p> The postscreen_greet_banner parameter specifies the <i>text</i>
+portion of a "220-<i>text</i>..." teaser banner (default: $smtpd_banner).
+Note that this becomes the first part of a multi-line server greeting.
+The postscreen(8) daemon sends this before the postscreen_greet_wait
+timer is started. The purpose of the teaser banner is to confuse
+zombies so that they speak before their turn. It has no effect on
+SMTP clients that correctly implement the protocol. </p>
+
+<p> To avoid problems with poorly-implemented SMTP engines in network
+appliances or network testing tools, either exclude them from all
+tests with the postscreen_access_list feature or else specify
+an empty teaser banner: </p>
+
+<pre>
+/etc/postfix/main.cf:
+ # Exclude broken clients by allowlisting. Clients in mynetworks
+ # should always be allowlisted.
+ postscreen_access_list = permit_mynetworks,
+ cidr:/etc/postfix/postscreen_access.cidr
+
+/etc/postfix/postscreen_access.cidr:
+ 192.168.254.0/24 permit
+</pre>
+
+<pre>
+/etc/postfix/main.cf:
+ # Disable the teaser banner (try allowlisting first if you can).
+ postscreen_greet_banner =
+</pre>
+
+<p> When an SMTP client sends a command before the
+postscreen_greet_wait time has elapsed, postscreen(8) logs this as:
+</p>
+
+<pre>
+ <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>[address]:port text...</i>
+</pre>
+
+<p> Translation: the client at <i>[address]:port</i> sent <i>count</i>
+bytes before its turn to speak. This happened <i>time</i> seconds
+after the postscreen_greet_wait timer was started. The <i>text</i>
+is what the client sent (truncated to 100 bytes, and with non-printable
+characters replaced with C-style escapes such as \r for carriage-return
+and \n for newline). </p>
+
+<p> The postscreen_greet_action parameter specifies the action that
+is taken next. See "<a href="#fail_before_220">When tests fail
+before the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="dnsbl"> DNS Allow/denylist test </a> </h3>
+
+<p> The postscreen_dnsbl_sites parameter (default: empty) specifies
+a list of DNS blocklist servers with optional filters and weight
+factors (positive weights for denylisting, negative for allowlisting).
+These servers will be queried in parallel with the reverse client
+IP address. This test is disabled by default. </p>
+
+<blockquote>
+<p>
+CAUTION: when postscreen rejects mail, its SMTP reply contains the
+DNSBL domain name. Use the postscreen_dnsbl_reply_map feature to
+hide "password" information in DNSBL domain names.
+</p>
+</blockquote>
+
+<p> When the postscreen_greet_wait time has elapsed, and the combined
+DNSBL score is equal to or greater than the postscreen_dnsbl_threshold
+parameter value, postscreen(8) logs this as: </p>
+
+<pre>
+ <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>[address]:port</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> has a combined
+DNSBL score of <i>count</i>. </p>
+
+<p> The postscreen_dnsbl_action parameter specifies the action that
+is taken when the combined DNSBL score is equal to or greater than
+the threshold. See "<a href="#fail_before_220">When tests fail
+before the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="fail_before_220">When tests fail before the 220 SMTP server greeting</a> </h3>
+
+<p> When the client address matches the permanent denylist, or
+when the client fails the pregreet or DNSBL tests, the action is
+specified with postscreen_blacklist_action, postscreen_greet_action,
+or postscreen_dnsbl_action, respectively. </p>
+
+<dl>
+
+<dt> <b>ignore</b> (default) </dt>
+
+<dd> Ignore the failure of this test. Allow other tests to complete.
+Repeat this test the next time the client connects. This option
+is useful for testing and collecting statistics without blocking
+mail. </dd>
+
+<dt> <b>enforce</b> </dt>
+
+<dd> Allow other tests to complete. Reject attempts to deliver mail
+with a 550 SMTP reply, and log the helo/sender/recipient information.
+Repeat this test the next time the client connects. </dd>
+
+<dt> <b>drop</b> </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply. Repeat
+this test the next time the client connects. </dd>
+
+</dl>
+
+<h2> <a name="after_220">Tests after the 220 SMTP server greeting</a> </h2>
+
+<p> In this phase of the protocol, postscreen(8) implements a
+number of "deep protocol" tests. These tests use an SMTP protocol
+engine that is built into the postscreen(8) server. </p>
+
+<p> Important note: these protocol tests are disabled by default.
+They are more intrusive than the pregreet and DNSBL tests, and they
+have limitations as discussed next. </p>
+
+<ul>
+
+<li> <p> The main limitation of "after 220 greeting" tests is that
+a new client must disconnect after passing these tests (reason:
+postscreen is not a proxy). Then the client must reconnect from
+the same IP address before it can deliver mail. The following
+measures may help to avoid email delays: </p>
+
+<ul>
+
+<li> <p> Allow "good" clients to skip tests with the
+postscreen_dnsbl_whitelist_threshold feature (Postfix 2.11 and
+later). This is especially effective for sites such as Google that
+never retry immediately from the same IP address. </p>
+
+<li> <p> Small sites: Configure postscreen(8) to listen on multiple
+IP addresses, published in DNS as different IP addresses for the
+same MX hostname or for different MX hostnames. This avoids mail
+delivery delays with clients that reconnect immediately from the
+same IP address. </p>
+
+<li> <p> Large sites: Share the postscreen(8) cache between different
+Postfix MTAs with a large-enough memcache_table(5). Again, this
+avoids mail delivery delays with clients that reconnect immediately
+from the same IP address. </p>
+
+</ul>
+
+<li> <p> postscreen(8)'s built-in SMTP engine does not implement the
+AUTH, XCLIENT, and XFORWARD features. If you need to make these
+services available on port 25, then do not enable the tests after
+the 220 server greeting. </p>
+
+<li> <p> End-user clients should connect directly to the submission
+service, so that they never have to deal with postscreen(8)'s tests.
+</p>
+
+</ul>
+
+<p> The following "after 220 greeting" tests are available: </p>
+
+<ul>
+
+<li> <a href="#pipelining">Command pipelining test</a>
+
+<li> <a href="#non_smtp">Non-SMTP command test</a>
+
+<li> <a href="#barelf">Bare newline test</a>
+
+<li> <a href="#fail_after_220">When tests fail after the 220 SMTP server greeting</a>
+
+</ul>
+
+<h3> <a name="pipelining">Command pipelining test</a> </h3>
+
+<p> By default, SMTP is a half-duplex protocol: the sender and
+receiver send one command and one response at a time. Unlike the
+Postfix SMTP server, postscreen(8) does not announce support
+for ESMTP command pipelining. Therefore, clients are not allowed
+to send multiple commands. postscreen(8)'s
+<a href="#after_220">deep
+protocol test</a> for this is disabled by default. </p>
+
+<p> With "postscreen_pipelining_enable = yes", postscreen(8) detects
+zombies that send multiple commands, instead of sending one command
+and waiting for the server to reply. </p>
+
+<p> This test is opportunistically enabled when postscreen(8) has
+to use the built-in SMTP engine anyway. This is to make postscreen(8)
+logging more informative. </p>
+
+<p> When a client sends multiple commands, postscreen(8) logs this
+as: </p>
+
+<pre>
+ <b>COMMAND PIPELINING from</b> <i>[address]:port</i> <b>after</b> <i>command</i>: <i>text</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> sent
+multiple SMTP commands, instead of sending one command and then
+waiting for the server to reply. This happened after the client
+sent <i>command</i>. The <i>text</i> shows part of the input that
+was sent too early; it is not logged with Postfix 2.8. </p>
+
+<p> The postscreen_pipelining_action parameter specifies the action
+that is taken next. See "<a href="#fail_after_220">When tests fail
+after the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="non_smtp">Non-SMTP command test</a> </h3>
+
+<p> Some spambots send their mail through open proxies. A symptom
+of this is the usage of commands such as CONNECT and other non-SMTP
+commands. Just like the Postfix SMTP server's smtpd_forbidden_commands
+feature, postscreen(8) has an equivalent postscreen_forbidden_commands
+feature to block these clients. postscreen(8)'s
+<a href="#after_220">deep
+protocol test</a> for this is disabled by default. </p>
+
+<p> With "postscreen_non_smtp_command_enable = yes", postscreen(8)
+detects zombies that send commands specified with the
+postscreen_forbidden_commands parameter. This also detects commands
+with the syntax of a message header label. The latter is a symptom
+that the client is sending message content after ignoring all the
+responses from postscreen(8) that reject mail. </p>
+
+<p> This test is opportunistically enabled when postscreen(8) has
+to use the built-in SMTP engine anyway. This is to make postscreen(8)
+logging more informative. </p>
+
+<p> When a client sends non-SMTP commands, postscreen(8) logs this
+as: </p>
+
+<pre>
+ <b>NON-SMTP COMMAND from</b> <i>[address]:port</i> <b>after</b> <i>command: text</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a
+command that matches the postscreen_forbidden_commands
+parameter, or that has the syntax of a message header label (text
+followed by optional space and ":").
+The "<tt><b>after</b> <i>command</i></tt>" portion is logged with
+Postfix 2.10 and later. </p>
+
+<p> The postscreen_non_smtp_command_action parameter specifies
+the action that is taken next. See "<a href="#fail_after_220">When
+tests fail after the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="barelf">Bare newline test</a> </h3>
+
+<p> SMTP is a line-oriented protocol: lines have a limited length,
+and are terminated with &lt;CR&gt;&lt;LF&gt;. Lines ending in a
+"bare" &lt;LF&gt;, that is newline not preceded by carriage return,
+are not allowed in SMTP. postscreen(8)'s
+<a href="#after_220">deep
+protocol test</a> for this is disabled by default. </p>
+
+<p> With "postscreen_bare_newline_enable = yes", postscreen(8)
+detects clients that send lines ending in bare newline characters.
+</p>
+
+<p> This test is opportunistically enabled when postscreen(8) has
+to use the built-in SMTP engine anyway. This is to make postscreen(8)
+logging more informative. </p>
+
+<p> When a client sends bare newline characters, postscreen(8) logs
+this as:
+</p>
+
+<pre>
+ <b>BARE NEWLINE from</b> <i>[address]:port</i> <b>after</b> <i>command</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a bare
+newline character, that is newline not preceded by carriage
+return.
+The "<tt><b>after</b> <i>command</i></tt>" portion is logged with
+Postfix 2.10 and later. </p>
+
+<p> The postscreen_bare_newline_action parameter specifies the
+action that is taken next. See "<a href="#fail_after_220">When
+tests fail after the 220 SMTP server greeting</a>" below. </p>
+
+<h3> <a name="fail_after_220">When tests fail after the 220 SMTP server greeting</a> </h3>
+
+<p> When the client fails the pipelining, non-SMTP command or bare
+newline tests, the action is specified with postscreen_pipelining_action,
+postscreen_non_smtp_command_action or postscreen_bare_newline_action,
+respectively. </p>
+
+<dl>
+
+<dt> <b>ignore</b> (default for bare newline) </dt>
+
+<dd> Ignore the failure of this test. Allow other tests to complete.
+Do NOT repeat this test before the result from some other test
+expires.
+
+This option is useful for testing and collecting statistics without
+blocking mail permanently. </dd>
+
+<dt> <b>enforce</b> (default for pipelining) </dt>
+
+<dd> Allow other tests to complete. Reject attempts to deliver
+mail with a 550 SMTP reply, and log the helo/sender/recipient
+information. Repeat this test the next time the client connects.
+</dd>
+
+<dt> <b>drop</b> (default for non-SMTP commands) </dt>
+
+<dd> Drop the connection immediately with a 521 SMTP reply. Repeat
+this test the next time the client connects. This action is
+compatible with the Postfix SMTP server's smtpd_forbidden_commands
+feature. </dd>
+
+</dl>
+
+<h2> <a name="other_error">Other errors</a> </h2>
+
+<p> When an SMTP client hangs up unexpectedly, postscreen(8) logs
+this as: </p>
+
+<pre>
+ <b>HANGUP after</b> <i>time</i> <b>from</b> <i>[address]:port</i> <b>in</b> <i>test name</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> disconnected
+unexpectedly, <i>time</i> seconds after the start of the
+test named <i>test name</i>. </p>
+
+<p> There is no punishment for hanging up. A client that hangs up
+without sending the QUIT command can still pass all postscreen(8)
+tests. </p>
+
+<!--
+
+<p> While an unexpired penalty is in effect, an SMTP client is not
+allowed to pass any tests, and postscreen(8) logs each connection
+with the remaining amount of penalty time as: </p>
+
+<pre>
+ <b>PENALTY</b> <i>time</i> <b>for</b> <i>[address]:port</i>
+</pre>
+
+<p> During this time, all attempts by the client to deliver mail
+will be deferred with a 450 SMTP status. </p>
+
+-->
+
+<p> The following errors are reported by the built-in SMTP engine.
+This engine never accepts mail, therefore it has per-session limits
+on the number of commands and on the session length. </p>
+
+<pre>
+ <b>COMMAND TIME LIMIT</b> <b>from</b> <i>[address]:port</i> <b>after</b> <i>command</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
+per-command time limit as specified with the postscreen_command_time_limit
+parameter. The session is terminated immediately.
+The "<tt><b>after</b> <i>command</i></tt>" portion is logged with
+Postfix 2.10 and later. </p>
+
+<pre>
+ <b>COMMAND COUNT LIMIT from</b> <i>[address]:port</i> <b>after</b> <i>command</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
+per-session command count limit as specified with the
+postscreen_command_count_limit parameter. The session is terminated
+immediately.
+The "<tt><b>after</b> <i>command</i></tt>" portion is logged with
+Postfix 2.10 and later. </p>
+
+<pre>
+ <b>COMMAND LENGTH LIMIT from</b> <i>[address]:port</i> <b>after</b> <i>command</i>
+</pre>
+
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
+per-command length limit, as specified with the line_length_limit
+parameter. The session is terminated immediately.
+The "<tt><b>after</b> <i>command</i></tt>" portion is logged with
+Postfix 2.10 and later. </p>
+
+<p> When an SMTP client makes too many connections at the same time,
+postscreen(8) rejects the connection with a 421 status code and logs: </p>
+
+<pre>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: too many connections</b>
+</pre>
+
+<p> The postscreen_client_connection_count_limit parameter controls this limit. </p>
+
+<p> When an SMTP client connects after postscreen(8) has reached a
+connection count limit, postscreen(8) rejects the connection with
+a 421 status code and logs: </p>
+
+<pre>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: all screening ports busy</b>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: all server ports busy</b>
+</pre>
+
+<p> The postscreen_pre_queue_limit and postscreen_post_queue_limit
+parameters control these limits. </p>
+
+<h2> <a name="victory">When all tests succeed</a> </h2>
+
+<p> When a new SMTP client passes all tests (i.e. it is not allowlisted
+via some mechanism), postscreen(8) logs this as: </p>
+
+<pre>
+ <b>PASS NEW</b> <i>[address]:port</i>
+</pre>
+
+<p> Where <i>[address]:port</i> are the client IP address and port.
+Then, postscreen(8)
+creates a temporary allowlist entry that excludes the client IP
+address from further tests until the temporary allowlist entry
+expires, as controlled with the postscreen_*_ttl parameters. </p>
+
+<p> When no "<a href="#after_220">deep protocol tests</a>" are
+configured, postscreen(8) hands off the "live" connection to a Postfix
+SMTP server process. The client can then continue as if postscreen(8)
+never even existed (except for the short postscreen_greet_wait delay).
+</p>
+
+<p> When any "<a href="#after_220">deep protocol tests</a>" are
+configured, postscreen(8) cannot hand off the "live" connection to
+a Postfix SMTP server process in the middle of the session. Instead,
+postscreen(8) defers mail delivery attempts with a 4XX status, logs
+the helo/sender/recipient information, and waits for the client to
+disconnect. The next time the client connects it will be allowed
+to talk to a Postfix SMTP server process to deliver its mail.
+postscreen(8) mitigates the impact of this limitation by giving
+<a href="#after_220">deep protocol tests</a> a long expiration
+time. </p>
+
+<h2> <a name="config"> Configuring the postscreen(8) service</a>
+</h2>
+
+<p> postscreen(8) has been tested on FreeBSD [4-8], Linux 2.[4-6]
+and Solaris 9 systems. </p>
+
+<ul>
+
+<li> <a href="#enable"> Turning on postscreen(8) without blocking
+mail</a>
+
+<li> <a href="#starttls"> postscreen(8) TLS configuration </a>
+
+<li> <a href="#blocking"> Blocking mail with postscreen(8) </a>
+
+<li> <a href="#turnoff"> Turning off postscreen(8) </a>
+
+<li> <a href="#temp_white_sharing"> Sharing the temporary allowlist
+</a>
+
+</ul>
+
+<h3> <a name="enable"> Turning on postscreen(8) without blocking mail</a> </h3>
+
+<p> To enable the postscreen(8) service and log client information
+without blocking mail: </p>
+
+<ol>
+
+<li> <p> Make sure that local clients and systems with non-standard
+SMTP implementations are excluded from any postscreen(8) tests. The
+default is to exclude all clients in mynetworks. To exclude additional
+clients, for example, third-party performance monitoring tools (these
+tend to have broken SMTP implementations): </p>
+
+<pre>
+/etc/postfix/main.cf:
+ # Exclude broken clients by allowlisting. Clients in mynetworks
+ # should always be allowlisted.
+ postscreen_access_list = permit_mynetworks,
+ cidr:/etc/postfix/postscreen_access.cidr
+
+/etc/postfix/postscreen_access.cidr:
+ 192.168.254.0/24 permit
+</pre>
+
+<li> <p> Comment out the "<tt>smtp inet ... smtpd</tt>" service
+in master.cf, including any "<tt>-o parameter=value</tt>" entries
+that follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ #smtp inet n - n - - smtpd
+ # -o parameter=value ...
+</pre>
+
+<li> <p> Uncomment the new "<tt>smtpd pass ... smtpd</tt>" service
+in master.cf, and duplicate any "<tt>-o parameter=value</tt>" entries
+from the smtpd service that was commented out in the previous step.
+</p>
+
+<pre>
+/etc/postfix/master.cf:
+ smtpd pass - - n - - smtpd
+ -o parameter=value ...
+</pre>
+
+<li> <p> Uncomment the new "<tt>smtp inet ... postscreen</tt>"
+service in master.cf. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ smtp inet n - n - 1 postscreen
+</pre>
+
+<li> <p> Uncomment the new "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in master.cf. This service implements STARTTLS support for
+postscreen(8). </p>
+
+<pre>
+/etc/postfix/master.cf:
+ tlsproxy unix - - n - 0 tlsproxy
+</pre>
+
+<li> <p> Uncomment the new "<tt>dnsblog unix ... dnsblog</tt>"
+service in master.cf. This service does DNSBL lookups for postscreen(8)
+and logs results. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ dnsblog unix - - n - 0 dnsblog
+</pre>
+
+<li> <p> To enable DNSBL lookups, list some DNS blocklist sites in
+main.cf, separated by whitespace. Different sites can have different
+weights. For example:
+
+<pre>
+/etc/postfix/main.cf:
+ postscreen_dnsbl_threshold = 2
+ postscreen_dnsbl_sites = zen.spamhaus.org*2
+ bl.spamcop.net*1 b.barracudacentral.org*1
+</pre>
+
+<p> Note: if your DNSBL queries have a "secret" in the domain name,
+you must censor this information from the postscreen(8) SMTP replies.
+For example: </p>
+
+<pre>
+/etc/postfix/main.cf:
+ postscreen_dnsbl_reply_map = texthash:/etc/postfix/dnsbl_reply
+</pre>
+
+<pre>
+/etc/postfix/dnsbl_reply:
+ # Secret DNSBL name Name in postscreen(8) replies
+ secret.zen.dq.spamhaus.net zen.spamhaus.org
+</pre>
+
+<p> The texthash: format is similar to hash: except that there is
+no need to run postmap(1) before the file can be used, and that it
+does not detect changes after the file is read. It is new with
+Postfix version 2.8. </p>
+
+<li> <p> Read the new configuration with "<tt>postfix reload</tt>".
+</p>
+
+</ol>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> Some postscreen(8) configuration parameters implement
+stress-dependent behavior. This is supported only when the default
+value is stress-dependent (that is, "postconf -d <i>parametername</i>"
+output shows
+"<i>parametername</i>&nbsp;=&nbsp;${stress?<i>something</i>}${stress:<i>something</i>}" or
+"<i>parametername</i>&nbsp;=&nbsp;${stress?{<i>something</i>}:{<i>something</i>}}").
+Other parameters always evaluate as if the stress value is the empty
+string. </p>
+
+<li> <p> See "<a href="#before_220">Tests before the 220 SMTP server
+greeting</a>" for details about the logging from these
+postscreen(8) tests. </p>
+
+<li> <p> If you run Postfix 2.6 or earlier you must stop and start
+the master daemon ("<tt>postfix stop; postfix start</tt>"). This
+is needed because the Postfix "pass" master service type did not
+work reliably on all systems. </p>
+
+</ul>
+
+<h3> <a name="starttls"> postscreen(8) TLS configuration </a> </h3>
+
+<p> postscreen(8) TLS support is available for remote SMTP clients
+that aren't allowlisted, including clients that need to renew their
+temporary allowlist status. When a remote SMTP client requests TLS
+service, postscreen(8) invisibly hands off the connection to a
+tlsproxy(8) process. Then, tlsproxy(8) encrypts and decrypts the
+traffic between postscreen(8) and the remote SMTP client. One
+tlsproxy(8) process can handle multiple SMTP sessions. The number
+of tlsproxy(8) processes slowly increases with server load, but it
+should always be much smaller than the number of postscreen(8) TLS
+sessions. </p>
+
+<p> TLS support for postscreen(8) and tlsproxy(8) uses the same
+parameters as with smtpd(8). We recommend that you keep the relevant
+configuration parameters in main.cf. If you must specify "-o
+smtpd_mumble=value" parameter overrides in master.cf for a
+postscreen-protected smtpd(8) service, then you should specify those
+same parameter overrides for the postscreen(8) and tlsproxy(8)
+services. </p>
+
+<h3> <a name="blocking"> Blocking mail with postscreen(8) </a> </h3>
+
+<p> For compatibility with smtpd(8), postscreen(8) implements the
+soft_bounce safety feature. This causes Postfix to reject mail with
+a "try again" reply code. </p>
+
+<ul>
+
+<li> <p> To turn this on for all of Postfix, specify "<tt>soft_bounce
+= yes</tt>" in main.cf. </p>
+
+<li> <p> To turn this on for postscreen(8) only, append "<tt>-o
+soft_bounce=yes</tt>" (note: NO SPACES around '=') to the postscreen
+entry in master.cf. <p>
+
+</ul>
+
+<p> Execute "<tt>postfix reload</tt>" to make the change effective. </p>
+
+<p> After testing, do not forget to remove the soft_bounce feature,
+otherwise senders won't receive their non-delivery notification
+until many days later. </p>
+
+<p> To use the postscreen(8) service to block mail, edit main.cf and
+specify one or more of: </p>
+
+<ul>
+
+<li> <p> "<tt>postscreen_dnsbl_action = enforce</tt>", to reject
+clients that are on DNS blocklists, and to log the helo/sender/recipient
+information. With good DNSBLs this reduces the amount of load on
+Postfix SMTP servers dramatically. </p>
+
+<li> <p> "<tt>postscreen_greet_action = enforce</tt>", to reject
+clients that talk before their turn, and to log the helo/sender/recipient
+information. This stops over half of all known-to-be illegitimate
+connections to Wietse's mail server. It is backup protection for
+zombies that haven't yet been denylisted. </p>
+
+<li> <p> You can also enable "<a href="#after_220">deep protocol
+tests</a>", but these are more intrusive than the pregreet or DNSBL
+tests. </p>
+
+<p> When a good client passes the "<a href="#after_220">deep
+protocol tests</a>",
+postscreen(8) adds the client to the temporary
+allowlist but it cannot hand off the "live" connection to a Postfix
+SMTP server process in the middle of the session. Instead, postscreen(8)
+defers mail delivery attempts with a 4XX status, logs the
+helo/sender/recipient information, and waits for the client to
+disconnect. </p>
+
+<p> When the good client comes back in a later session, it is allowed
+to talk directly to a Postfix SMTP server. See "<a href="#after_220">Tests
+after the 220 SMTP server greeting</a>" above for limitations with
+AUTH and other features that clients may need. </p>
+
+<p> An unexpected benefit from "<a href="#after_220">deep protocol
+tests</a>" is that some "good" clients don't return after the 4XX
+reply; these clients were not so good after all. </p>
+
+<p> Unfortunately, some senders will retry requests from different
+IP addresses, and may never get allowlisted. For this reason,
+Wietse stopped using "<a href="#after_220">deep protocol tests</a>"
+on his own internet-facing mail server. </p>
+
+<li> <p> There is also support for permanent denylisting and
+allowlisting; see the description of the postscreen_access_list
+parameter for details. </p>
+
+</ul>
+
+<h3> <a name="turnoff"> Turning off postscreen(8) </a> </h3>
+
+<p> To turn off postscreen(8) and handle mail directly with Postfix
+SMTP server processes: </p>
+
+<ol>
+
+<li> <p> Comment out the "<tt>smtp inet ... postscreen</tt>" service
+in master.cf, including any "<tt>-o parameter=value</tt>" entries
+that follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ #smtp inet n - n - 1 postscreen
+ # -o parameter=value ...
+</pre>
+
+<li> <p> Comment out the "<tt>dnsblog unix ... dnsblog</tt>" service
+in master.cf. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ #dnsblog unix - - n - 0 dnsblog
+</pre>
+
+<li> <p> Comment out the "<tt>smtpd pass ... smtpd</tt>" service
+in master.cf, including any "<tt>-o parameter=value</tt>" entries
+that follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ #smtpd pass - - n - - smtpd
+ # -o parameter=value ...
+</pre>
+
+<li> <p> Comment out the "<tt>tlsproxy unix ... tlsproxy</tt>"
+service in master.cf, including any "<tt>-o parameter=value</tt>"
+entries that follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ #tlsproxy unix - - n - 0 tlsproxy
+ # -o parameter=value ...
+</pre>
+
+<li> <p> Uncomment the "<tt>smtp inet ... smtpd</tt>" service in
+master.cf, including any "<tt>-o parameter=value</tt>" entries that
+may follow. </p>
+
+<pre>
+/etc/postfix/master.cf:
+ smtp inet n - n - - smtpd
+ -o parameter=value ...
+</pre>
+
+<li> <p> Read the new configuration with "<tt>postfix reload</tt>".
+</p>
+
+</ol>
+
+<h3> <a name="temp_white_sharing"> Sharing the temporary allowlist </a> </h3>
+
+<p> By default, the temporary allowlist is not shared between
+multiple postscreen(8) daemons. To enable sharing, choose one
+of the following options: </p>
+
+<ul>
+
+<li> <p> A non-persistent memcache: temporary allowlist can be shared
+ between postscreen(8) daemons on the same host or different
+ hosts. Disable cache cleanup (postscreen_cache_cleanup_interval
+ = 0) in all postscreen(8) daemons because memcache: has no
+ first-next API (but see example 4 below for memcache: with
+ persistent backup). This requires Postfix 2.9 or later. </p>
+
+ <pre>
+ # Example 1: non-persistent memcache: allowlist.
+ /etc/postfix/main.cf:
+ postscreen_cache_map = memcache:/etc/postfix/postscreen_cache
+ postscreen_cache_cleanup_interval = 0
+
+ /etc/postfix/postscreen_cache:
+ memcache = inet:127.0.0.1:11211
+ key_format = postscreen:%s
+ </pre>
+
+<li> <p>
+ A persistent lmdb: temporary allowlist can be shared between
+ postscreen(8) daemons that run under the same master(8) daemon,
+ or under different master(8) daemons on the same host. Disable
+ cache cleanup (postscreen_cache_cleanup_interval = 0) in all
+ postscreen(8) daemons except one that is responsible for cache
+ cleanup. This requires Postfix 2.11 or later. </p>
+
+ <pre>
+ # Example 2: persistent lmdb: allowlist.
+ /etc/postfix/main.cf:
+ postscreen_cache_map = lmdb:$data_directory/postscreen_cache
+ # See note 1 below.
+ # postscreen_cache_cleanup_interval = 0
+ </pre>
+
+<li> <p> Other kinds of persistent temporary allowlist can be shared
+ only between postscreen(8) daemons that run under the same
+ master(8) daemon. In this case, temporary allowlist access must
+ be shared through the proxymap(8) daemon. This requires Postfix
+ 2.9 or later. </p>
+
+ <pre>
+ # Example 3: proxied btree: allowlist.
+ /etc/postfix/main.cf:
+ postscreen_cache_map =
+ proxy:btree:/var/lib/postfix/postscreen_cache
+ # See note 1 below.
+ # postscreen_cache_cleanup_interval = 0
+
+ # Example 4: proxied btree: allowlist with memcache: accelerator.
+ /etc/postfix/main.cf:
+ postscreen_cache_map = memcache:/etc/postfix/postscreen_cache
+ proxy_write_maps =
+ proxy:btree:/var/lib/postfix/postscreen_cache
+ ... other proxied tables ...
+ # See note 1 below.
+ # postscreen_cache_cleanup_interval = 0
+
+ /etc/postfix/postscreen_cache:
+ # Note: the $data_directory macro is not defined in this context.
+ memcache = inet:127.0.0.1:11211
+ backup = proxy:btree:/var/lib/postfix/postscreen_cache
+ key_format = postscreen:%s
+ </pre>
+
+ <p> Note 1: disable cache cleanup (postscreen_cache_cleanup_interval
+ = 0) in all postscreen(8) daemons except one that is responsible
+ for cache cleanup. </p>
+
+ <p> Note 2: postscreen(8) cache sharing via proxymap(8) requires Postfix
+ 2.9 or later; earlier proxymap(8) implementations don't support
+ cache cleanup. </p>
+
+</ul>
+
+<h2> <a name="historical"> Historical notes and credits </a> </h2>
+
+<p> Many ideas in postscreen(8) were explored in earlier work by
+Michael Tokarev, in OpenBSD spamd, and in MailChannels Traffic
+Control. </p>
+
+<p> Wietse threw together a crude prototype with pregreet and dnsbl
+support in June 2009, because he needed something new for a Mailserver
+conference presentation in July. Ralf Hildebrandt ran this code on
+several servers to collect real-world statistics. This version used
+the dnsblog(8) ad-hoc DNS client program. </p>
+
+<p> Wietse needed new material for a LISA conference presentation
+in November 2010, so he added support for DNSBL weights and filters
+in August, followed by a major code rewrite, deep protocol tests,
+helo/sender/recipient logging, and stress-adaptive behavior in
+September. Ralf Hildebrandt ran this code on several servers to
+collect real-world statistics. This version still used the embarrassing
+dnsblog(8) ad-hoc DNS client program. </p>
+
+<p> Wietse added STARTTLS support in December 2010. This makes
+postscreen(8) usable for sites that require TLS support. The
+implementation introduces the tlsproxy(8) event-driven TLS proxy
+that decrypts/encrypts the sessions for multiple SMTP clients. </p>
+
+<p> The tlsproxy(8) implementation led to the discovery of a "new"
+class of vulnerability (<a
+href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-0411"
+>CVE-2011-0411</a>) that affected multiple implementations of SMTP,
+POP, IMAP, NNTP, and FTP over TLS. </p>
+
+<p> postscreen(8) was officially released as part of the Postfix
+2.8 stable release in January 2011.</p>
+
+</body>
+
+</html>