summaryrefslogtreecommitdiffstats
path: root/proto/SMTPD_POLICY_README.html
blob: b249c809908dfa4514d61481ec22b9af5eec63eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
<!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=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 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
<b>Postfix version 3.8 and later:</b>
compatibility_level=<i>major</i>.<i>minor</i>.<i>patch</i>
mail_version=3.8.0
[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>

   <li> <p> The "compatibility_level" attribute corresponds to the
   compatibility_level parameter value. It has the form
   <i>major</i>.<i>minor</i>.<i>patch</i> where <i>minor</i> and
   <i>patch</i> may be absent. </p>

   <li> <p> The "mail_version" attribute corresponds to the
   mail_version parameter value. It has the form
   <i>major</i>.<i>minor</i>.<i>patch</i> for stable releases, and
   <i>major</i>.<i>minor</i>-<i>yyyymmdd</i> for unstable releases.
   </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. On many systems, "local" is a synonym for "unix".</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 as 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 as 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
https://web.archive.org/web/20080526153208/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
allowlist 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-allowlist threshold. Specify 0 to disable, or the number of
# successful "come backs" after which a client is no longer subject
# to greylisting.
#
$auto_allowlist_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-allowlist.
    if ($auto_allowlist_threshold &gt; 0) {
        $count = read_database($attr{"client_address"});
        if ($count &gt; $auto_allowlist_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-allowlist.
        if ($auto_allowlist_threshold &gt; 0) {
            update_database($attr{"client_address"}, $count + 1);
        }
        return "dunno";
    } else {
        return "defer_if_permit Service temporarily unavailable";
    }
}
</pre>

</body>

</html>