diff options
Diffstat (limited to 'proto/POSTSCREEN_3_5_README.html')
-rw-r--r-- | proto/POSTSCREEN_3_5_README.html | 1199 |
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 <CR><LF>. Lines ending in a +"bare" <LF>, 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> = ${stress?<i>something</i>}${stress:<i>something</i>}" or +"<i>parametername</i> = ${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> |