summaryrefslogtreecommitdiffstats
path: root/proto/SMTPD_POLICY_README.html
diff options
context:
space:
mode:
Diffstat (limited to 'proto/SMTPD_POLICY_README.html')
-rw-r--r--proto/SMTPD_POLICY_README.html811
1 files changed, 811 insertions, 0 deletions
diff --git a/proto/SMTPD_POLICY_README.html b/proto/SMTPD_POLICY_README.html
new file mode 100644
index 0000000..e2554b2
--- /dev/null
+++ b/proto/SMTPD_POLICY_README.html
@@ -0,0 +1,811 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix SMTP Access Policy Delegation </title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix SMTP Access Policy Delegation </h1>
+
+<hr>
+
+<h2>Purpose of Postfix SMTP access policy delegation</h2>
+
+<p> The Postfix SMTP server has a number of built-in mechanisms to
+block or accept mail at specific SMTP protocol stages. In addition,
+the Postfix SMTP server can delegate decisions to an external policy
+server (Postfix 2.1 and later). </p>
+
+<p> With this policy delegation mechanism, a simple <a href="#greylist">
+greylist </a> policy can be implemented with only a dozen lines of
+Perl, as is shown at the end of this document. A complete example
+can be found in the Postfix source code, in the directory
+examples/smtpd-policy. </p>
+
+<p> Another example of policy delegation is the SPF policy server
+at https://web.archive.org/web/20190221142057/http://www.openspf.org/Software. </p>
+
+<p> Policy delegation is now the preferred method for adding policies
+to Postfix. It's much easier to develop a new feature in few lines
+of Perl, Python, Ruby, or TCL, than trying to do the same in C code.
+The difference in
+performance will be unnoticeable except in the most demanding
+environments. On active systems a policy daemon process is used
+multiple times, for up to $max_use incoming SMTP connections. </p>
+
+<p> This document covers the following topics: </p>
+
+<ul>
+
+<li><a href="#protocol">Policy protocol description</a>
+
+<li><a href="#client_config">Simple policy client/server configuration</a>
+
+<li><a href="#advanced">Advanced policy client configuration</a>
+
+<li><a href="#greylist">Example: greylist policy server</a>
+
+<li><a href="#frequent">Greylisting mail from frequently forged domains</a>
+
+<li><a href="#all_mail">Greylisting all your mail</a>
+
+<li><a href="#maintenance">Routine greylist maintenance</a>
+
+<li><a href="#greylist_code">Example Perl greylist server</a>
+
+</ul>
+
+<h2><a name="protocol">Protocol description</a></h2>
+
+<p> The Postfix policy delegation protocol is really simple. The client
+sends a request and the server sends a response. Unless there was an
+error, the server must not close the connection, so that the same
+connection can be used multiple times. </p>
+
+<p> The client request is a sequence of name=value attributes separated
+by newline, and is terminated by an empty line. The server reply is one
+name=value attribute and it, too, is terminated by an empty line. </p>
+
+<p> Here is an example of all the attributes that the Postfix SMTP
+server sends in a delegated SMTPD access policy request: </p>
+
+<blockquote>
+<pre>
+<b>Postfix version 2.1 and later:</b>
+request=smtpd_access_policy
+protocol_state=RCPT
+protocol_name=SMTP
+helo_name=some.domain.tld
+queue_id=8045F2AB23
+sender=foo@bar.tld
+recipient=bar@foo.tld
+recipient_count=0
+client_address=1.2.3.4
+client_name=another.domain.tld
+reverse_client_name=another.domain.tld
+instance=123.456.7
+<b>Postfix version 2.2 and later:</b>
+sasl_method=plain
+sasl_username=you
+sasl_sender=
+size=12345
+ccert_subject=solaris9.porcupine.org
+ccert_issuer=Wietse+20Venema
+ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04
+<b>Postfix version 2.3 and later:</b>
+encryption_protocol=TLSv1/SSLv3
+encryption_cipher=DHE-RSA-AES256-SHA
+encryption_keysize=256
+etrn_domain=
+<b>Postfix version 2.5 and later:</b>
+stress=
+<b>Postfix version 2.9 and later:</b>
+ccert_pubkey_fingerprint=68:B3:29:DA:98:93:E3:40:99:C7:D8:AD:5C:B9:C9:40
+<b>Postfix version 3.0 and later:</b>
+client_port=1234
+<b>Postfix version 3.1 and later:</b>
+policy_context=submission
+<b>Postfix version 3.2 and later:</b>
+server_address=10.3.2.1
+server_port=54321
+[empty line]
+</pre>
+</blockquote>
+
+<p> Notes: </p>
+
+<ul>
+
+ <li> <p> The "request" attribute is required. In this example
+ the request type is "smtpd_access_policy". </p>
+
+ <li> <p> The order of the attributes does not matter. The policy
+ server should ignore any attributes that it does not care about.
+ </p>
+
+ <li> <p> When the same attribute name is sent more than once,
+ the server may keep the first value or the last attribute value.
+ </p>
+
+ <li> <p> When an attribute value is unavailable, the client
+ either does not send the attribute, sends the attribute with
+ an empty value ("name="), or sends a zero value ("name=0") in
+ the case of a numerical attribute. </p>
+
+ <li> <p> The "recipient" attribute is available in the "RCPT
+ TO" stage. It is also available in the "DATA" and "END-OF-MESSAGE"
+ stages if Postfix accepted only one recipient for the current
+ message.
+ The DATA protocol state also applies to email that is received
+ with BDAT commands (Postfix 3.4 and later). </p>
+
+ <li> <p> The "recipient_count" attribute (Postfix 2.3 and later)
+ is non-zero only in the "DATA" and "END-OF-MESSAGE" stages. It
+ specifies the number of recipients that Postfix accepted for
+ the current message.
+ The DATA protocol state also applies to email that is received
+ with BDAT commands (Postfix 3.4 and later). </p>
+
+ <li> <p> The remote client or local server IP address is an
+ IPv4 dotted quad in the form 1.2.3.4 or it is an IPv6 address
+ in the form 1:2:3::4:5:6. </p>
+
+ <li> <p> The remote client or local server port is a decimal
+ number in the range 0-65535. </p>
+
+ <li> <p> For a discussion of the differences between reverse
+ and verified client_name information, see the
+ reject_unknown_client_hostname discussion in the postconf(5)
+ document. </p>
+
+ <li> <p> An attribute name must not contain "=", null or newline,
+ and an attribute value must not contain null or newline. </p>
+
+ <li> <p> The "instance" attribute value can be used to correlate
+ different requests regarding the same message delivery. These
+ requests are sent over the same policy connection (unless the
+ policy daemon terminates the connection). Once Postfix sends
+ a query with a different instance attribute over that same
+ policy connection, the previous message delivery is either
+ completed or aborted. </p>
+
+ <li> <p> The "size" attribute value specifies the message size
+ that the client specified in the MAIL FROM command (zero if
+ none was specified). With Postfix 2.2 and later, it specifies
+ the actual message size after the client sends the END-OF-MESSAGE.
+ </p>
+
+ <li> <p> The "sasl_*" attributes (Postfix 2.2 and later) specify
+ information about how the client was authenticated via SASL.
+ These attributes are empty in case of no SASL authentication.
+ </p>
+
+ <li> <p> The "ccert_*" attributes (Postfix 2.2 and later) specify
+ information about how the client was authenticated via TLS.
+ These attributes are empty in case of no certificate authentication.
+ As of Postfix 2.2.11 these attribute values are encoded as
+ xtext: some characters are represented by +XX, where XX is the
+ two-digit hexadecimal representation of the character value. With
+ Postfix 2.6 and later, the decoded string is an UTF-8 string
+ without non-printable ASCII characters. </p>
+
+ <li> <p> The "encryption_*" attributes (Postfix 2.3 and later)
+ specify information about how the connection is encrypted. With
+ plaintext connections the protocol and cipher attributes are
+ empty and the keysize is zero. </p>
+
+ <li> <p> The "etrn_domain" attribute is defined only in the
+ context of the ETRN command, and specifies the ETRN command
+ parameter. </p>
+
+ <li> <p> The "stress" attribute is either empty or "yes". See
+ the STRESS_README document for further information. </p>
+
+ <li> <p> The "policy_context" attribute provides a way to pass
+ information that is not available via other attributes (Postfix
+ version 3.1 and later). </p>
+
+</ul>
+
+<p> The following is specific to SMTPD delegated policy requests:
+</p>
+
+<ul>
+
+ <li> <p> Protocol names are ESMTP or SMTP. </p>
+
+ <li> <p> Protocol states are CONNECT, EHLO, HELO, MAIL, RCPT,
+ DATA, END-OF-MESSAGE, VRFY or ETRN; these are the SMTP protocol
+ states where
+ the Postfix SMTP server makes an OK/REJECT/HOLD/etc. decision.
+ The DATA protocol state also applies to email that is received
+ with BDAT commands (Postfix 3.4 and later).
+ </p>
+
+</ul>
+
+<p> The policy server replies with any action that is allowed in a
+Postfix SMTPD access(5) table. Example: </p>
+
+<blockquote>
+<pre>
+action=defer_if_permit Service temporarily unavailable
+[empty line]
+</pre>
+</blockquote>
+
+<p> This causes the Postfix SMTP server to reject the request with
+a 450 temporary error code and with text "Service temporarily
+unavailable", if the Postfix SMTP server finds no reason to reject
+the request permanently. </p>
+
+<p> In case of trouble the policy server must not send a reply.
+Instead the server must log a warning and disconnect. Postfix will
+retry the request at some later time. </p>
+
+<h2><a name="client_config">Simple policy client/server configuration</a></h2>
+
+<p> The Postfix delegated policy client can connect to a TCP socket
+or to a UNIX-domain socket. Examples: </p>
+
+<blockquote>
+<pre>
+inet:127.0.0.1:9998
+unix:/some/where/policy
+unix:private/policy
+</pre>
+</blockquote>
+
+<p> The first example specifies that the policy server listens on
+a TCP socket at 127.0.0.1 port 9998. The second example specifies
+an absolute pathname of a UNIX-domain socket. The third example
+specifies a pathname relative to the Postfix queue directory; use
+this for policy servers that are spawned by the Postfix master
+daemon. </p>
+
+<p> To create a policy service that listens on a UNIX-domain socket
+called "policy", and that runs under control of the Postfix spawn(8)
+daemon, you would use something like this: </p>
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/master.cf:
+ 2 policy unix - n n - 0 spawn
+ 3 user=nobody argv=/some/where/policy-server
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 smtpd_recipient_restrictions =
+ 7 ...
+ 8 reject_unauth_destination
+ 9 check_policy_service unix:private/policy
+10 ...
+11 policy_time_limit = 3600
+12 # smtpd_policy_service_request_limit = 1
+</pre>
+</blockquote>
+
+<p> NOTES: </p>
+
+<ul>
+
+<li> <p> Lines 2-3: this creates the service called "policy" that
+listens on a UNIX-domain socket. The service is implemented by the
+Postfix spawn(8) daemon, which executes the policy server program
+that is specified with the <b>argv</b> attribute, using the privileges
+specified with the <b>user</b> attribute. </p>
+
+<li> <p> Line 2: specify a "0" process limit instead of the default
+"-", to avoid "connection refused" and other problems when you
+increase the smtpd process limit. </p>
+
+<li> <p> Line 8: reject_unauth_destination is not needed here if
+the mail relay policy is specified with smtpd_relay_restrictions
+(available with Postfix 2.10 and later). </p>
+
+<li> <p> Lines 8, 9: always specify "check_policy_service" AFTER
+"reject_unauth_destination" or else your system could become an
+open relay. </p>
+
+<li> <p> Line 11: this increases the time that a policy server
+process may run to 3600 seconds. The default time limit of 1000
+seconds is too short; the policy daemon needs to run long as the
+SMTP server process that talks to it.
+See the spawn(8) manpage for more information about the
+<i>transport</i>_time_limit parameter. </p>
+
+<blockquote> <p> Note: the "policy_time_limit" parameter will not
+show up in "postconf" command output before Postfix version 2.9.
+This limitation applies to many parameters whose name is a combination
+of a master.cf service name (in the above example, "policy") and a
+built-in suffix (in the above example: "_time_limit"). </p>
+</blockquote>
+
+<li> <p> Line 12: specify smtpd_policy_service_request_limit to
+avoid error-recovery delays with policy servers that cannot
+maintain a persistent connection. </p>
+
+<li> <p> With Solaris &lt; 9, or Postfix &lt; 2.10 on any Solaris
+version, use TCP sockets instead of UNIX-domain sockets: </p>
+
+</ul>
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/master.cf:
+ 2 127.0.0.1:9998 inet n n n - 0 spawn
+ 3 user=nobody argv=/some/where/policy-server
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 smtpd_recipient_restrictions =
+ 7 ...
+ 8 reject_unauth_destination
+ 9 check_policy_service inet:127.0.0.1:9998
+10 ...
+11 127.0.0.1:9998_time_limit = 3600
+12 # smtpd_policy_service_request_limit = 1
+</pre>
+</blockquote>
+
+<p> Configuration parameters that control the client side of the
+policy delegation protocol: </p>
+
+<ul>
+
+<li> <p> smtpd_policy_service_default_action (default: 451 4.3.5
+Server configuration problem): The default action when an SMTPD
+policy service request fails. Available with Postfix 3.0 and
+later. </p>
+
+<li> <p> smtpd_policy_service_max_idle (default: 300s): The amount
+of time before the Postfix SMTP server closes an unused policy
+client connection. </p>
+
+<li> <p> smtpd_policy_service_max_ttl (default: 1000s): The amount
+of time before the Postfix SMTP server closes an active policy
+client connection. </p>
+
+<li> <p> smtpd_policy_service_request_limit (default: 0): The maximal
+number of requests per policy connection, or zero (no limit).
+Available with Postfix 3.0 and later. </p>
+
+<li> <p> smtpd_policy_service_timeout (default: 100s): The time
+limit to connect to, send to or receive from a policy server. </p>
+
+<li> <p> smtpd_policy_service_try_limit (default: 2): The maximal
+number of attempts to send an SMTPD policy service request before
+giving up. Available with Postfix 3.0 and later. </p>
+
+<li> <p> smtpd_policy_service_retry_delay (default: 1s): The delay
+between attempts to resend a failed SMTPD policy service request.
+Available with Postfix 3.0 and later. </p>
+
+<li> <p> smtpd_policy_service_policy_context (default: empty):
+Optional information that is passed in the "policy_context" attribute
+of an SMTPD policy service request (originally, to share the same
+SMTPD service endpoint among multiple check_policy_service clients).
+Available with Postfix 3.1 and later. </p>
+
+</ul>
+
+<p> Configuration parameters that control the server side of the
+policy delegation protocol: </p>
+
+<ul>
+
+<li> <p> <i>transport</i>_time_limit ($command_time_limit): The
+maximal amount of time the policy daemon is allowed to run before
+it is terminated. The <i>transport</i> is the service name of the
+master.cf entry for the policy daemon service. In the above
+examples, the service name is "policy" or "127.0.0.1:9998". </p>
+
+</ul>
+
+<h2><a name="advanced">Advanced policy client configuration</a></h2>
+
+<p> The previous section lists a number of Postfix main.cf parameters
+that control time limits and other settings for all policy clients.
+This is sufficient for simple configurations. With more complex
+configurations it becomes desirable to have different settings per
+policy client. This is supported with Postfix 3.0 and later. </p>
+
+<p> The following example shows a "non-critical" policy service
+with a short timeout, and with "DUNNO" as default action when the
+service is unvailable. The "DUNNO" action causes Postfix to ignore
+the result. </p>
+
+<blockquote>
+<pre>
+1 /etc/postfix/main.cf:
+2 mua_recipient_restrictions =
+3 ...
+4 reject_unauth_destination
+5 check_policy_service { inet:host:port,
+6 timeout=10s, default_action=DUNNO
+7 policy_context=submission }
+8 ...
+</pre>
+</blockquote>
+
+<p> Instead of a server endpoint, we now have a list enclosed in {}. </p>
+
+<ul>
+
+<li> <p> Line 5: The first item in the list is the server endpoint.
+This supports the exact same "inet" and "unix" syntax as described
+earlier. </p>
+
+<li> <p> Line 6-7: The remainder of the list contains per-client
+settings. These settings override global main.cf parameters,
+and have the same name as those parameters, without the
+"smtpd_policy_service_" prefix. </p>
+
+</ul>
+
+<p> Inside the list, syntax is similar to what we already know from
+main.cf: items separated by space or comma. There is one difference:
+<b>you must enclose a setting in parentheses, as in "{ name = value
+}", if you want to have space or comma within a value or around
+"="</b>. This comes in handy when different policy servers require
+different default actions with different SMTP status codes or text:
+</p>
+
+<blockquote>
+<pre>
+1 /etc/postfix/main.cf:
+2 smtpd_recipient_restrictions =
+3 ...
+4 reject_unauth_destination
+5 check_policy_service {
+6 inet:host:port1,
+7 { default_action = 451 4.3.5 See http://www.example.com/support1 }
+8 }
+9 ...
+</pre>
+</blockquote>
+
+<h2><a name="greylist">Example: greylist policy server</a></h2>
+
+<p> Greylisting is a defense against junk email that is described at
+http://www.greylisting.org/. The idea was discussed on the
+postfix-users mailing list <a
+href="http://archives.neohapsis.com/archives/postfix/2002-03/0846.html">
+one year before it was popularized</a>. </p>
+
+<p> The file examples/smtpd-policy/greylist.pl in the Postfix source
+tree implements a simplified greylist policy server. This server
+stores a time stamp for every (client, sender, recipient) triple.
+By default, mail is not accepted until a time stamp is more than
+60 seconds old. This stops junk mail with randomly selected sender
+addresses, and mail that is sent through randomly selected open
+proxies. It also stops junk mail from spammers that change their
+IP address frequently. </p>
+
+<p> Copy examples/smtpd-policy/greylist.pl to /usr/libexec/postfix
+or whatever location is appropriate for your system. </p>
+
+<p> In the greylist.pl Perl script you need to specify the
+location of the greylist database file, and how long mail will
+be delayed before it is accepted. The default settings are:
+</p>
+
+<blockquote>
+<pre>
+$database_name="/var/mta/greylist.db";
+$greylist_delay=60;
+</pre>
+</blockquote>
+
+<p> The /var/mta directory (or whatever you choose) should be
+writable by "nobody", or by whatever username you configure below
+in master.cf for the policy service. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+# mkdir /var/mta
+# chown nobody /var/mta
+</pre>
+</blockquote>
+
+<p> Note: DO NOT create the greylist database in a world-writable
+directory such as /tmp or /var/tmp, and DO NOT create the greylist
+database in a file system that may run out of space. Postfix can
+survive "out of space" conditions with the mail queue and with the
+mailbox store, but it cannot survive a corrupted greylist database.
+If the file becomes corrupted you may not be able to receive mail
+at all until you delete the file by hand. </p>
+
+<p> The greylist.pl Perl script can be run under control by
+the Postfix master daemon. For example, to run the script as user
+"nobody", using a UNIX-domain socket that is accessible by Postfix
+processes only: </p>
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/master.cf:
+ 2 greylist unix - n n - 0 spawn
+ 3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 greylist_time_limit = 3600
+ 7 smtpd_recipient_restrictions =
+ 8 ...
+ 9 reject_unauth_destination
+10 check_policy_service unix:private/greylist
+11 ...
+12 # smtpd_policy_service_request_limit = 1
+</pre>
+</blockquote>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> Lines 2-3: this creates the service called "greylist" that
+listens on a UNIX-domain socket. The service is implemented by the
+Postfix spawn(8) daemon, which executes the greylist.pl script that
+is specified with the <b>argv</b> attribute, using the privileges
+specified with the <b>user</b> attribute. </p>
+
+<li> <p> Line 2: specify a "0" process limit instead of the default
+"-", to avoid "connection refused" and other problems when you
+increase the smtpd process limit. </p>
+
+<li> <p> Line 3: Specify "greylist.pl -v" for verbose logging of
+each request and reply. </p>
+
+<li> <p> Line 6: this increases the time that a greylist server
+process may run to 3600 seconds. The default time limit of 1000
+seconds is too short; the greylist daemon needs to run long as the
+SMTP server process that talks to it.
+See the spawn(8) manpage for more information about the
+<i>transport</i>_time_limit parameter. </p>
+
+<li> <p> Line 9: reject_unauth_destination is not needed here if
+the mail relay policy is specified with smtpd_relay_restrictions
+(available with Postfix 2.10 and later). </p>
+
+<blockquote> <p> Note: the "greylist_time_limit" parameter will not
+show up in "postconf" command output before Postfix version 2.9.
+This limitation applies to many parameters whose name is a combination
+of a master.cf service name (in the above example, "greylist") and
+a built-in suffix (in the above example: "_time_limit"). </p>
+</blockquote>
+
+<li> <p> Line 12: specify smtpd_policy_service_request_limit to
+avoid error-recovery delays with policy servers that cannot
+maintain a persistent connection. </p>
+
+</ul>
+
+<p> With Solaris &lt; 9, or Postfix &lt; 2.10 on any Solaris
+version, use inet: style sockets instead of unix:
+style, as detailed in the "<a href="#client_config">Policy
+client/server configuration</a>" section above. </p>
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/master.cf:
+ 2 127.0.0.1:9998 inet n n n - 0 spawn
+ 3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
+ 4
+ 5 /etc/postfix/main.cf:
+ 6 127.0.0.1:9998_time_limit = 3600
+ 7 smtpd_recipient_restrictions =
+ 8 ...
+ 9 reject_unauth_destination
+10 check_policy_service inet:127.0.0.1:9998
+11 ...
+12 # smtpd_policy_service_request_limit = 1
+</pre>
+</blockquote>
+
+<h2><a name="frequent">Greylisting mail from frequently forged domains</a></h2>
+
+<p> It is relatively safe to turn on greylisting for specific
+domains that often appear in forged email. At some point
+in cyberspace/time a list of frequently
+forged MAIL FROM domains could be found at
+http://www.monkeys.com/anti-spam/filtering/sender-domain-validate.in.
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/main.cf:
+ 2 smtpd_recipient_restrictions =
+ 3 reject_unlisted_recipient
+ 4 ...
+ 5 reject_unauth_destination
+ 6 check_sender_access hash:/etc/postfix/sender_access
+ 7 ...
+ 8 smtpd_restriction_classes = greylist
+ 9 greylist = check_policy_service unix:private/greylist
+10
+11 /etc/postfix/sender_access:
+12 aol.com greylist
+13 hotmail.com greylist
+14 bigfoot.com greylist
+15 ... <i>etcetera</i> ...
+</pre>
+</blockquote>
+
+<p> NOTES: </p>
+
+<ul>
+
+<li> <p> Line 9: On Solaris &lt; 9, or Postfix &lt; 2.10 on any
+Solaris version, use inet: style sockets
+instead of unix: style, as detailed in the "<a href="#greylist">Example:
+greylist policy server</a>" section above. </p>
+
+<li> <p> Line 5: reject_unauth_destination is not needed here if
+the mail relay policy is specified with smtpd_relay_restrictions
+(available with Postfix 2.10 and later). </p>
+
+<li> <p> Line 6: Be sure to specify "check_sender_access" AFTER
+"reject_unauth_destination" or else your system could become an
+open mail relay. </p>
+
+<li> <p> Line 3: With Postfix 2.0 snapshot releases,
+"reject_unlisted_recipient" is called "check_recipient_maps".
+Postfix 2.1 understands both forms. </p>
+
+<li> <p> Line 3: The greylist database gets polluted quickly with
+bogus addresses. It helps if you protect greylist lookups with
+other restrictions that reject unknown senders and/or recipients.
+</p>
+
+</ul>
+
+<h2><a name="all_mail">Greylisting all your mail</a></h2>
+
+<p> If you turn on greylisting for all mail you may want to make
+exceptions for mailing lists that use one-time sender addresses,
+because each message will be delayed due to greylisting, and the
+one-time sender addresses can pollute your greylist database
+relatively quickly. Instead of making exceptions, you can automatically
+whitelist clients that survive greylisting repeatedly; this avoids
+most of the delays and most of the database pollution problem. </p>
+
+<blockquote>
+<pre>
+ 1 /etc/postfix/main.cf:
+ 2 smtpd_recipient_restrictions =
+ 3 reject_unlisted_recipient
+ 4 ...
+ 5 reject_unauth_destination
+ 6 check_sender_access hash:/etc/postfix/sender_access
+ 7 check_policy_service unix:private/policy
+ 8 ...
+ 9
+10 /etc/postfix/sender_access:
+11 securityfocus.com OK
+12 ...
+</pre>
+</blockquote>
+
+<p> NOTES: </p>
+
+<ul>
+
+<li> <p> Line 7: On Solaris &lt; 9, or Postfix &lt; 2.10 on any
+Solaris version, use inet: style sockets
+instead of unix: style, as detailed in the "<a href="#greylist">Example:
+greylist policy server</a>" section above. </p>
+
+<li> <p> Line 5: reject_unauth_destination is not needed here if
+the mail relay policy is specified with smtpd_relay_restrictions
+(available with Postfix 2.10 and later). </p>
+
+<li> <p> Lines 6-7: Be sure to specify check_sender_access and
+check_policy_service AFTER reject_unauth_destination or else your
+system could become an open mail relay. </p>
+
+<li> <p> Line 3: The greylist database gets polluted quickly with
+bogus addresses. It helps if you precede greylist lookups with
+restrictions that reject unknown senders and/or recipients. </p>
+
+</ul>
+
+<h2><a name="maintenance">Routine greylist maintenance</a></h2>
+
+<p> The greylist database grows over time, because the greylist server
+never removes database entries. If left unattended, the greylist
+database will eventually run your file system out of space. </p>
+
+<p> When the status file size exceeds some threshold you can simply
+rename or remove the file without adverse effects; Postfix
+automatically creates a new file. In the worst case, new mail will
+be delayed by an hour or so. To lessen the impact, rename or remove
+the file in the middle of the night at the beginning of a weekend.
+</p>
+
+<h2><a name="greylist_code">Example Perl greylist server</a></h2>
+
+<p> This is the Perl subroutine that implements the example greylist
+policy. It is part of a general purpose sample policy server that
+is distributed with the Postfix source as
+examples/smtpd-policy/greylist.pl. </p>
+
+<pre>
+#
+# greylist status database and greylist time interval. DO NOT create the
+# greylist status database in a world-writable directory such as /tmp
+# or /var/tmp. DO NOT create the greylist database in a file system
+# that can run out of space.
+#
+$database_name="/var/mta/greylist.db";
+$greylist_delay=60;
+
+#
+# Auto-whitelist threshold. Specify 0 to disable, or the number of
+# successful "come backs" after which a client is no longer subject
+# to greylisting.
+#
+$auto_whitelist_threshold = 10;
+
+#
+# Demo SMTPD access policy routine. The result is an action just like
+# it would be specified on the right-hand side of a Postfix access
+# table. Request attributes are available via the %attr hash.
+#
+sub smtpd_access_policy {
+ my($key, $time_stamp, $now);
+
+ # Open the database on the fly.
+ open_database() unless $database_obj;
+
+ # Search the auto-whitelist.
+ if ($auto_whitelist_threshold &gt; 0) {
+ $count = read_database($attr{"client_address"});
+ if ($count &gt; $auto_whitelist_threshold) {
+ return "dunno";
+ }
+ }
+
+ # Lookup the time stamp for this client/sender/recipient.
+ $key =
+ lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
+ $time_stamp = read_database($key);
+ $now = time();
+
+ # If new request, add this client/sender/recipient to the database.
+ if ($time_stamp == 0) {
+ $time_stamp = $now;
+ update_database($key, $time_stamp);
+ }
+
+ # The result can be any action that is allowed in a Postfix access(5) map.
+ #
+ # To label the mail, return ``PREPEND headername: headertext''
+ #
+ # In case of success, return ``DUNNO'' instead of ``OK'', so that the
+ # check_policy_service restriction can be followed by other restrictions.
+ #
+ # In case of failure, return ``DEFER_IF_PERMIT optional text...'',
+ # so that mail can still be blocked by other access restrictions.
+ #
+ syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
+ if ($now - $time_stamp &gt; $greylist_delay) {
+ # Update the auto-whitelist.
+ if ($auto_whitelist_threshold &gt; 0) {
+ update_database($attr{"client_address"}, $count + 1);
+ }
+ return "dunno";
+ } else {
+ return "defer_if_permit Service temporarily unavailable";
+ }
+}
+</pre>
+
+</body>
+
+</html>