On Fri, Nov 06, 2015 at 11:41:55AM +1100, Robert Mueller wrote: > Recently a user came under attack from someone using a distributed set > of compromised websites. Fortunately it was fairly easy to find a header > in the majority of emails to block on, so I added a pcre REJECT rule in > our header_checks.
The header_checks(5) feature is implemented in the cleanup(8) service, which receives the message content from smtpd(8) and returns a single go/no-go reply at the end of the message. This protocol does not support "early" replies, the cleanup service either commits the message into the "incoming" queue and returns "OK", or deletes it returns an error. The signal to attempt a commit comes from smtpd(8) when all of its checks are satisfied. Therefore the results of end of data restrictions are unavodably processed before the results of header and body checks. > The problem is that even though the REJECT in header_checks works to > have the email rejected, the check_policy_service still runs in the > smtpd_end_of_data_restrictions phase, which increases the receipt count > for that user, even though we didn't actually accept the email. There's nothing that can be done about that. Because end-of-data restrictions can reject messages, they run before the message is successfully enqueued, and thus before smtpd(8) finds out whether cleanup accepted the message or not. > Is there no way to tell in the smtpd_end_of_data_restrictions > check_policy_service request if the message is going to be REJECTed by > header_checks anyway? Sadly that's not possible. > Or are the > header_checks run after the smtpd_end_of_data_restrictions? The checks run in a separate process which atomically reports either failure or that the message is queued. Note that Postfix can't always predict whether enqueueing will succeed without actually doing it. The operating system might run out of some resource or other between the test and the action. Introducing a new synchronization point between smtpd(8) and cleanup(8) would complicate the protocol and might add delays. One might imagine cleanup sending a negative reply as soon as it is available, and smtpd(8) peeking at the cleanup(8) socket before calling end-of-data checks, which can short-circuit end-of-data checks for mail rejected by header/body checks and content processing in milters. However no such code exists at this time. > Is there any > way to have them run before? Can we add a "current_action" parameter to > the policy protocol so a policy daemon knows if the message is going to > be REJECTed or not? In the mean time you can replace the end-of-data checks and header checks with a milter that does both the header checks and the requisite end-of-message processing. -- Viktor.