diff options
Diffstat (limited to 'proto/SMTPD_POLICY_README.html')
-rw-r--r-- | proto/SMTPD_POLICY_README.html | 811 |
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 < 9, or Postfix < 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 < 9, or Postfix < 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 < 9, or Postfix < 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 < 9, or Postfix < 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 > 0) { + $count = read_database($attr{"client_address"}); + if ($count > $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 > $greylist_delay) { + # Update the auto-whitelist. + if ($auto_whitelist_threshold > 0) { + update_database($attr{"client_address"}, $count + 1); + } + return "dunno"; + } else { + return "defer_if_permit Service temporarily unavailable"; + } +} +</pre> + +</body> + +</html> |