* [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable
@ 2024-01-12 19:21 Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-docs v2 1/1] doc-generator: add new option filter-timeout Stoiko Ivanov
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
v1->v2:
* addressed Thomas' feedback - Thanks very much
* changed the setting from filter_timeout to filter-timeout (thus
template toolkit needs to access it as 'pmg.mail.item('filter-timeout')
* fixed a few glitches in the commit messages
original cover-letter for v1:
This series improves mail-handling in case pmg-smtp-filter takes too long in
processing a mail.
Currently the timeout is based on postfix defaults which differ between
after-queue filtering (600s) and before-queue filtering (120s) (patch 1/4
unifies the timeout, and is meant as a stop-gap measure).
In both cases - once the timeout is reached the behavior is inconvenient
(to put it mildly):
* postfix detects the timeout and reports a temporary 4xx code to the
sender, while pmg-smtp-filter sends the mail further after processing
anyways
This results in such mails getting delivered multiple times to the
recipient (and you need the administrator of the server sending to PMG to
remove it from their queue, for the deliveries to stop).
Tested by adding a `sleep 200;` in PMG::Utils::analyze_virus_clam.
The docs patch is necessary for patch 3/5 (new config-options need to be
known in the doc-generator)
pmg-api:
Stoiko Ivanov (4):
templates: postfix: set same timeouts for before and after-queue
pmg-smtp-filter: cleanup use of gettimeofday
config: postfix: make smtp-filter-timeout configurable
pmg-smtp-filter: die if processing took longer than the timeout
src/PMG/Config.pm | 9 +++++++++
src/bin/pmg-smtp-filter | 21 ++++++++++++---------
src/templates/main.cf.in | 5 ++++-
3 files changed, 25 insertions(+), 10 deletions(-)
pmg-docs:
Stoiko Ivanov (1):
doc-generator: add new option filter-timeout
gen-pmg.conf.5-opts.pl | 1 +
1 file changed, 1 insertion(+)
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] [PATCH pmg-docs v2 1/1] doc-generator: add new option filter-timeout
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
@ 2024-01-12 19:21 ` Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 1/4] templates: postfix: set same timeouts for before and after-queue Stoiko Ivanov
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
gen-pmg.conf.5-opts.pl | 1 +
1 file changed, 1 insertion(+)
diff --git a/gen-pmg.conf.5-opts.pl b/gen-pmg.conf.5-opts.pl
index 1aff46a..72ee379 100755
--- a/gen-pmg.conf.5-opts.pl
+++ b/gen-pmg.conf.5-opts.pl
@@ -43,6 +43,7 @@ my $key_groups = {
before_queue_filtering => 1,
ndr_on_block => 1,
smtputf8 => 1,
+ 'filter-timeout' => 1,
}],
'mail-tls' => [
'mail' , {
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] [PATCH pmg-api v2 1/4] templates: postfix: set same timeouts for before and after-queue
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-docs v2 1/1] doc-generator: add new option filter-timeout Stoiko Ivanov
@ 2024-01-12 19:21 ` Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 2/4] pmg-smtp-filter: cleanup use of gettimeofday Stoiko Ivanov
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
When a mail takes longer to get processed (observed with some scanned
pages as pdf - where clamav+avast took 2.2 minutes for scanning) the
behavior of the filtering is different between before-queue and
after-queue filtering:
In the before-queue case the timeout is `$smtpd_proxy_timout` (120s)
[0], so the mail does not get processed in time and the listening
smtpd responds with `451 4.3.0 Error: queue file write error`. However
pmg-smtp-filter sends the mail to the smtpd on 10025 once it's done.
the original sender resends the mail due to the 451 error - which
results in the mail getting delivered multiple times (until it gets
removed from the queue on the original sender)
In the after-queue case the timeout is `$lmtp_data_done_timeout`
(pmg-smtp-filter acts as lmtp server) (600s) - so the mail gets
send successfully only once. In case the processing time reaches
600s the behavior is equivalent - but for lmtp postfix logs:
```
...timed out while sending end of data -- message may be sent more
than once
```
The value needs to be set as literal - referring to the builtin
default as `$lmtp_data_done_timeout` does not work.
While the underlying issue of mails getting sent multiple times in
case the timeout is reached is not fixed by this - having the same
timeout in both cases is a good idea and 600s increases the chances
of clamav+avast+custom_check_script+spamassassin to get their job done.
tested by adding a `sleep 200` in PMG::Utils::analyze_virus_clam.
(before the eval block running with the 5 minute timeout)
[0] https://www.postfix.org/SMTPD_PROXY_README.html#parameters
Reported-by: Martin Maurer <martin@proxmox.com>
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
src/templates/main.cf.in | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/templates/main.cf.in b/src/templates/main.cf.in
index 3b56355..51cdd8b 100644
--- a/src/templates/main.cf.in
+++ b/src/templates/main.cf.in
@@ -49,7 +49,9 @@ relay_transport = [% pmg.mail.relayprotocol %]:[% pmg.mail.relay %]:[% pmg.mail.
default_transport = smtp:[% pmg.mail.smarthost %]:[% pmg.mail.smarthostport %]
[% END %]
-[% IF ! pmg.mail.before_queue_filtering -%]
+[% IF pmg.mail.before_queue_filtering -%]
+smtpd_proxy_timeout = 600s
+[% ELSE %]
content_filter=scan:127.0.0.1:10024
[%- END %]
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] [PATCH pmg-api v2 2/4] pmg-smtp-filter: cleanup use of gettimeofday
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-docs v2 1/1] doc-generator: add new option filter-timeout Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 1/4] templates: postfix: set same timeouts for before and after-queue Stoiko Ivanov
@ 2024-01-12 19:21 ` Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 3/4] config: postfix: make smtp-filter-timeout configurable Stoiko Ivanov
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
in preparation for handling a processing timeout and passing the
startime to apply_rules, just unify the different syntax we use
throught the file.
no semantic change intended.
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
src/bin/pmg-smtp-filter | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/bin/pmg-smtp-filter b/src/bin/pmg-smtp-filter
index 7da3de8..ba4e58e 100755
--- a/src/bin/pmg-smtp-filter
+++ b/src/bin/pmg-smtp-filter
@@ -524,7 +524,7 @@ sub run_dequeue {
$self->log (2, "starting database maintenance");
- my ($csec, $usec) = gettimeofday ();
+ my $starttime = [ gettimeofday() ];
my $cinfo = PVE::INotify::read_file("cluster.conf");
@@ -540,8 +540,7 @@ sub run_dequeue {
if ($err) {
$self->log (0, $err);
} else {
- my ($csec_end, $usec_end) = gettimeofday ();
- my $ptime = int (($csec_end - $csec) * 1000 + ($usec_end - $usec) / 1000);
+ my $ptime = int(tv_interval($starttime) * 1000);
$self->log (2, "end database maintenance ($ptime ms)");
}
@@ -560,7 +559,7 @@ sub unpack_entity {
if (PMG::Unpack::is_archive ($magic)) {
$self->log (3, "$queue->{logid}: found archive '$filename' ($magic)");
- my $start = [gettimeofday];
+ my $start = [ gettimeofday() ];
$unpack->{mime} = {};
@@ -591,7 +590,7 @@ sub unpack_entity {
sub handle_smtp {
my ($self, $smtp) = @_;
- my ($csec, $usec) = gettimeofday ();
+ my $starttime = [ gettimeofday() ];
my $queue;
my $msginfo = {};
@@ -714,7 +713,7 @@ sub handle_smtp {
my $decdir = $queue->{dumpdir} . "/__decoded_archives";
mkdir $decdir;
- my $start = [gettimeofday];
+ my $start = [ gettimeofday() ];
my $unpack;
eval {
@@ -769,9 +768,7 @@ sub handle_smtp {
die $err if $err;
- my ($csec_end, $usec_end) = gettimeofday ();
- my $time_total =
- int (($csec_end-$csec)*1000 + ($usec_end - $usec)/1000);
+ my $time_total = int(tv_interval($starttime) * 1000);
# PHASE 5 - log statistics
# on error: log error messages
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] [PATCH pmg-api v2 3/4] config: postfix: make smtp-filter-timeout configurable
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
` (2 preceding siblings ...)
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 2/4] pmg-smtp-filter: cleanup use of gettimeofday Stoiko Ivanov
@ 2024-01-12 19:21 ` Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-smtp-filter: die if processing took longer than the timeout Stoiko Ivanov
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
accessing the value in the config-template needs to use the
item virtual method (`pmg.mail.item('filter-timeout')` instead of the
. operator, due to using kebab-case for 'filter-timeout' see [0].
the minimal value is set to 2 as we add 1 second for the rules
processing in the next patch, and postfix has 1 as minimum.
[0] http://template-toolkit.org/docs/manual/VMethods.html#section_item
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
src/PMG/Config.pm | 9 +++++++++
src/templates/main.cf.in | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/PMG/Config.pm b/src/PMG/Config.pm
index 7339e0d..43baec5 100644
--- a/src/PMG/Config.pm
+++ b/src/PMG/Config.pm
@@ -699,6 +699,14 @@ sub properties {
type => 'boolean',
default => 1
},
+ 'filter-timeout' => {
+ description => "Timeout for the processing of one mail (in seconds) (postfix option"
+ ." `smtpd_proxy_timeout` and `lmtp_data_done_timeout`)",
+ type => 'integer',
+ default => 600,
+ minimum => 2,
+ maximum => 86400
+ },
};
}
@@ -740,6 +748,7 @@ sub options {
before_queue_filtering => { optional => 1 },
ndr_on_block => { optional => 1 },
smtputf8 => { optional => 1 },
+ 'filter-timeout' => { optional => 1 },
};
}
diff --git a/src/templates/main.cf.in b/src/templates/main.cf.in
index 51cdd8b..434d5cd 100644
--- a/src/templates/main.cf.in
+++ b/src/templates/main.cf.in
@@ -50,9 +50,10 @@ default_transport = smtp:[% pmg.mail.smarthost %]:[% pmg.mail.smarthostport %]
[% END %]
[% IF pmg.mail.before_queue_filtering -%]
-smtpd_proxy_timeout = 600s
+smtpd_proxy_timeout = [% pmg.mail.item('filter-timeout') %]s
[% ELSE %]
content_filter=scan:127.0.0.1:10024
+lmtp_data_done_timeout = [% pmg.mail.item('filter-timeout') %]s
[%- END %]
mail_name = Proxmox
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] [PATCH pmg-api v2 4/4] pmg-smtp-filter: die if processing took longer than the timeout
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
` (3 preceding siblings ...)
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 3/4] config: postfix: make smtp-filter-timeout configurable Stoiko Ivanov
@ 2024-01-12 19:21 ` Stoiko Ivanov
2024-02-21 14:35 ` [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Dominik Csapak
2024-02-22 15:23 ` [pmg-devel] applied-series: " Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Stoiko Ivanov @ 2024-01-12 19:21 UTC (permalink / raw)
To: pmg-devel
In case a mail took longer to get processed than the configured
timeout - 1 second - `die` before running any action.
The `die` results in a temporary failure to be reported to the sending
server by PMG::SMTP.pm ("451 4.4.0 detected undelivered mail").
The reason for the 1s extra slack is to have some time to actually
run the action - and also justified that in both cases (postfix
detecting the timeout, and pmg-smtp-filter `die`ing the sender gets
a temporary failure reported back).
Tested with a small filter_timeout setting (30), and a larger sleep in
added in analyze_virus.
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
src/bin/pmg-smtp-filter | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/bin/pmg-smtp-filter b/src/bin/pmg-smtp-filter
index ba4e58e..79d951c 100755
--- a/src/bin/pmg-smtp-filter
+++ b/src/bin/pmg-smtp-filter
@@ -316,6 +316,11 @@ sub apply_rules {
my $mod_group = PMG::ModGroup->new($entity, $msginfo->{targets});
+ my $processing_time = int(tv_interval($msginfo->{starttime}));
+ my $filter_timeout = $self->{pmg_cfg}->get('mail', 'filter-timeout');
+ die "processing took ${processing_time}s, longer than the timeout (${filter_timeout}s)\n"
+ if $processing_time > $filter_timeout;
+
foreach my $rule (@$rules) {
my $targets = $rule_targets{$rule->{id}};
next if !$targets;
@@ -637,6 +642,7 @@ sub handle_smtp {
$msginfo->{fqdn} = $msginfo->{hostname};
$msginfo->{fqdn} .= ".$msginfo->{domain}" if $msginfo->{domain};
$msginfo->{lcid} = $lcid;
+ $msginfo->{starttime} = $starttime;
# $msginfo->{targets} is case sensitive,
# but pmail is always lower case!
--
2.39.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
` (4 preceding siblings ...)
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-smtp-filter: die if processing took longer than the timeout Stoiko Ivanov
@ 2024-02-21 14:35 ` Dominik Csapak
2024-02-22 15:23 ` [pmg-devel] applied-series: " Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2024-02-21 14:35 UTC (permalink / raw)
To: Stoiko Ivanov, pmg-devel
Looked and tested this, and it does what it says on the tin.
My original concern still exists but that would require a much more
intrusive fix (that we can still do in the future):
when the sending/remaining processing of the mail (aka the actions)
take longer than what time we still have remaining, we have
the same behavior as the original problem.
a short example:
filter-timeout: x seconds
processing up to the check: y seconds (but smaller than x)
if now the actions take more than 'x - y' seconds, the first
postfix instance runs into it's timeout, but the pmg-smtp-filter
is already processing the action (e.g. sending/quarantining)
To completely fix that, we'd have to (before the timeout check):
find out what actions would be taken,
return the postfix that status as if it was done
(e.g. accept/reject) (if that's even possible?)
and then do the actual action.
if that fails, we'd have to take an appropriate action,
e.g. send an ndr.
Aside from that, consider this series
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pmg-devel] applied-series: [PATCH pmg-api/pmg-docs v2] make filter timeout configurable
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
` (5 preceding siblings ...)
2024-02-21 14:35 ` [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Dominik Csapak
@ 2024-02-22 15:23 ` Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Thomas Lamprecht @ 2024-02-22 15:23 UTC (permalink / raw)
To: Stoiko Ivanov, pmg-devel
Am 12/01/2024 um 20:21 schrieb Stoiko Ivanov:
> v1->v2:
> * addressed Thomas' feedback - Thanks very much
> * changed the setting from filter_timeout to filter-timeout (thus
> template toolkit needs to access it as 'pmg.mail.item('filter-timeout')
> * fixed a few glitches in the commit messages
>
> original cover-letter for v1:
> This series improves mail-handling in case pmg-smtp-filter takes too long in
> processing a mail.
> Currently the timeout is based on postfix defaults which differ between
> after-queue filtering (600s) and before-queue filtering (120s) (patch 1/4
> unifies the timeout, and is meant as a stop-gap measure).
>
> In both cases - once the timeout is reached the behavior is inconvenient
> (to put it mildly):
> * postfix detects the timeout and reports a temporary 4xx code to the
> sender, while pmg-smtp-filter sends the mail further after processing
> anyways
> This results in such mails getting delivered multiple times to the
> recipient (and you need the administrator of the server sending to PMG to
> remove it from their queue, for the deliveries to stop).
>
> Tested by adding a `sleep 200;` in PMG::Utils::analyze_virus_clam.
>
> The docs patch is necessary for patch 3/5 (new config-options need to be
> known in the doc-generator)
>
> pmg-api:
> Stoiko Ivanov (4):
> templates: postfix: set same timeouts for before and after-queue
> pmg-smtp-filter: cleanup use of gettimeofday
> config: postfix: make smtp-filter-timeout configurable
> pmg-smtp-filter: die if processing took longer than the timeout
>
> src/PMG/Config.pm | 9 +++++++++
> src/bin/pmg-smtp-filter | 21 ++++++++++++---------
> src/templates/main.cf.in | 5 ++++-
> 3 files changed, 25 insertions(+), 10 deletions(-)
>
> pmg-docs:
> Stoiko Ivanov (1):
> doc-generator: add new option filter-timeout
>
> gen-pmg.conf.5-opts.pl | 1 +
> 1 file changed, 1 insertion(+)
>
applied, with Dominik's R-b & T-b, thanks!
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-02-22 15:23 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-12 19:21 [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-docs v2 1/1] doc-generator: add new option filter-timeout Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 1/4] templates: postfix: set same timeouts for before and after-queue Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 2/4] pmg-smtp-filter: cleanup use of gettimeofday Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 3/4] config: postfix: make smtp-filter-timeout configurable Stoiko Ivanov
2024-01-12 19:21 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-smtp-filter: die if processing took longer than the timeout Stoiko Ivanov
2024-02-21 14:35 ` [pmg-devel] [PATCH pmg-api/pmg-docs v2] make filter timeout configurable Dominik Csapak
2024-02-22 15:23 ` [pmg-devel] applied-series: " Thomas Lamprecht
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox