haraka / Haraka

A fast, highly extensible, and event driven SMTP server
https://haraka.github.io
MIT License
5.02k stars 662 forks source link

[Feedback needed] Execution control of plugins #3304

Closed gminogiannis closed 5 months ago

gminogiannis commented 5 months ago

I'm using Haraka v2.8.24 as an MTA for incoming SMTP connections to WildDuck v1.23.5 (yes, I know I have old versions). The default /opt/haraka/config/plugins contains the following:

spf
dkim_verify

rspamd
tls

# WildDuck plugin handles recipient checking and queueing
wildduck

The wildduck plugin is located under the folder /opt/haraka/plugins/wildduck

Now, I would like to implement a plugin that takes control before the wildduck plugin. Below is the content of my custom plugin (which just aims to skip WildDuck for a specific recipient pattern):

exports.hook_rcpt = function (next, connection, params) {
    const rcpt = params[0];
    const address = rcpt.address();

    const dropPattern = /^foo.*@mailsac\.com$/i;

    if (dropPattern.test(address)) {
       connection.loginfo(this, "Dropping message to: " + address);
       return;
    }

    return next();
};

The file /opt/haraka/config/plugins is adjusted so that the last lines are the following:

pre-wildduck-hook
# WildDuck plugin handles recipient checking and queueing
wildduck

According to the logs, it takes exactly 30 seconds to pass control from the plugin pre-wildduck-hook to the core.
See the logs of Haraka:

Apr 04 21:43:51: [INFO] [98FEDD2A-2362-4924-9C0F-D72CC1469030.1] [pre-wildduck-hook] Dropping message to: foo1@mailsac.com
Apr 04 21:44:21: [INFO] [98FEDD2A-2362-4924-9C0F-D72CC1469030.1] [core]  hook=rcpt plugin=pre-wildduck-hook function=hook_rcpt params=<foo1@mailsac.com> retval=DENYSOFT msg="plugin timeout"

Any ideas why ? Thank you!

msimerson commented 5 months ago

Any ideas why?

Yes, remove the line with the bare return; Hooks must always call next when they're completed. If not, they get timed out after 30 seconds.

Improved:

exports.hook_rcpt = function (next, connection, params) {
    const rcpt = params[0];
    const address = rcpt.address();

    const dropPattern = /^foo.*@mailsac\.com$/i;

    if (dropPattern.test(address)) {
       connection.loginfo(this, `Dropping message to: ${address}`);
    }

    next();
}
gminogiannis commented 5 months ago

Thank you @msimerson for the prompt response. Nevertheless, the purpose of the custom plugin is to silently drop a message if the recipient conforms to the pattern foo*@mailsac.com

Your suggestion appends a log entry that a message is to be dropped, but it isn't (it's "promoted" to the next chain of commands and reaches the wildduck plugin). As mentioned in the original comment, the purpose of the plugin is to conditionally skip WildDuck.

Can you help ?

msimerson commented 5 months ago

You asked why it paused for 30 seconds. I answered your question.

To change what Haraka does when you call next, look into next return codes

gminogiannis commented 5 months ago

Thank you for pointing me to the proper section of the documentation.

For anyone encountering this thread, the solution was to use next(OK) in case the recipient's address matched the pattern. Quoting from the documentation:

After a plugin calls next(OK), no further plugins on that hook will run.