5

I would like to accept all clients that pass RBL and SPF checks (and possibly some checks, but these are minimum requirements for me), and greylist those who don't. When a client passes the SPF check (SPF record exists, no fail, no soft-fail), we can be pretty sure that it's not a botnet zombie, but an MTA that will retry delivery, so there's little point in greylisting such clients.

So far I have been using Whitelister, which can implement this rule, but it hasn't been maintained for the last 10 years or so, and is not available in modern distributions, so I'm looking for alternatives. As far as I understand, Postfix can only reject clients that are in RBLs, but cannot use RBLs as parts of more complex conditions, so I can't see any way to use reject_rbl_client here. Is there a policy daemon that can do such checks?

My recipient restrictions in main.cf are as follows. I don't know what I can put in place of ???:

smtpd_recipient_restrictions =
        check_sender_access regexp:/etc/postfix/sender_access_regexp,
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_unknown_sender_domain,
        reject_unauth_destination,
        ???,
        check_policy_service unix:postgrey/postgrey.sock
michau
  • 51
  • 6
  • 2
    Why are you considering doing this? It doesn't make sense. RBL and SPF checks are only valid at the time they are made. These records can change at any time, causing you to whitelist unwanted spam, or worse. – Michael Hampton Aug 22 '19 at 01:37
  • @MichaelHampton My wording was a bit sloppy. I don't want to whitelist such clients permanently, I just want to accept them at a given time, so that they don't need to go through greylisting this time. I've updated my question; I hope it's clearer now. – michau Aug 22 '19 at 03:45
  • @anx In my setup there is no hard fail at all, by design. Greylisting is the only way I reject emails. I've been doing this for the last 12 years, so I know that it works well enough in my case; the amount of spam that gets through greylisting is so small that I don't want to risk rejecting legitimate emails. – michau Aug 25 '19 at 14:09

2 Answers2

3

I don't know what I can put in place of ???

A: check_policy_service


Long answer:

The postfix source implements reject_rbl_client in smtpd/smtpd_check.c
I expect it should work to add another function there which implements a copy of the reject_rbl_addr function with inverse logic - not replying with DUNNO but OK for a successful check.

--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
     rbl = find_dnsxl_addr(state, rbl_domain, addr);
     if (!SMTPD_DNSXL_STAT_OK(rbl)) {
-       return (SMTPD_CHECK_DUNNO);
+       return (SMTPD_CHECK_OK);
     } else {

Which you could then use in postfix' config instead of reject_rbl_client.

But this means additional, continual, maintenance to keep updated; patching your source as new releases occur. So I don't expect anyone to go that route.

In lieu of that, you will want to use an external policy check, as the whitelister program did for you. That means you can use check_policy_service here, you just need the right tool/program to interface with. (Btw, it's good to think of upgrading from that, since there was a reason for it being dropped. It fails checks on any IPv6 address.)

Checking for alternatives to that, there are (that I know of, in the debian repos)

all of them Python implementations - so while they may not do what you want out of the box (I haven't checked), they should be fairly easily adaptable.

Further ones are

  • postfix-policyd-spf-perl,
  • mtpolicyd (Perl),
  • a more complex and modular "PolicyD" (Perl)

and probably a ton more. You might even write your own, based on the many SPF libraries available.

The documentation about check_policy_service is a bit light, only the sample code blurb explains what values check_policy_service expects:

The result can be any action that is allowed in a Postfix access(5) map.

So access is the next stop, which (maybe) explains that changing DUNNO for OK will turn a "maybe-pass, run further checks first" (> greylist) logic into "mail passed, stop rule processing here".

So now you know how to turn any policy server into a whitelisting system, even if it doesn't do so out of the box.


Addendum: How to set up the policy server, from the policyd-spf README (though I expect you are aware of that, based on whitelister on postgrey).

Installing
----------

 1. Add the following to /etc/postfix/master.cf:

        policyd-spf  unix  -       n       n       -       0       spawn
            user=policyd-spf argv=/usr/bin/policyd-spf

 2. Configure the Postfix policy service in /etc/postfix/main.cf:

        smtpd_recipient_restrictions =
            ...
            reject_unauth_destination
            check_policy_service unix:private/policyd-spf
            ...

        policyd-spf_time_limit = 3600

    NOTE:  Specify check_policy_service AFTER reject_unauth_destination or
    else your system can become an open relay.

 3. Reload Postfix.
nyov
  • 291
  • 2
  • 8
  • Thanks for your answer! I've taken a look at the policy daemons you listed, and it looks like there most of them either don't support RBL or SPF. However, there are two that seem to have support for all I need: bley and mtpolicyd. I don't know what I'm going to use yet, but you definitely deserve the bounty. – michau Sep 02 '19 at 06:38
  • @michau, Ah yes I was kind of focused on SPF, I'm so used to the `reject_rbl*` and `reject_rhsbl*` parameters for the RBL stuff. Thanks for the bounty. – nyov Sep 02 '19 at 07:28
0

Theory: If you add an SPF policy check before the greylist check and it returns permit for SPF pass results, restriction evaluation should stop there.

In main.cf:

smtpd_recipient_restrictions =
    check_sender_access regexp:/etc/postfix/sender_access_regexp,
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unknown_sender_domain,
    reject_unauth_destination,
    check_policy_service unix:private/policy-spf,
    check_policy_service unix:postgrey/postgrey.sock

in /etc/postfix-policyd-spf-python/policyd-spf.conf:

Mail_From_pass_restriction = permit

If the theory is sound, it should be a matter of installing the already mentioned postfix-policyd-spf-python and the given reconfiguration. Testing it right now...