From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id E4E469373D for ; Fri, 7 Apr 2023 15:43:09 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 7EFDA1A791 for ; Fri, 7 Apr 2023 15:43:09 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Fri, 7 Apr 2023 15:43:07 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 4E96646453 for ; Fri, 7 Apr 2023 15:43:07 +0200 (CEST) From: Leo Nunner To: pmg-devel@lists.proxmox.com Date: Fri, 7 Apr 2023 15:42:54 +0200 Message-Id: <20230407134258.199691-9-l.nunner@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230407134258.199691-1-l.nunner@proxmox.com> References: <20230407134258.199691-1-l.nunner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.123 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pmg-devel] [PATCH pmg-api 8/8] feature: match groups: implement matching logic X-BeenThere: pmg-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Mail Gateway development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Apr 2023 13:43:09 -0000 Implements the logic behind match groups; A match group holds several objects inside it, and only evalutes to true if ALL the contained objects evaluate to true. Match groups are connected via logical 'or' to all other objects inside the rule: - Rule - Match Group - Object 1 - Object 2 - Object 3 This rule will match if either (Object 1 && Object 2), or if Object 3 evaluate to true. Signed-off-by: Leo Nunner --- RFC: This might be a bit weird for What objects: currently, it checks if there are matches for each of the objects inside the match groups; if one exists, *all* marks get pushed to the list. I'm not sure if this is exactly what we want, but I can't really think of a better way here. src/PMG/RuleCache.pm | 50 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/PMG/RuleCache.pm b/src/PMG/RuleCache.pm index 9a531ef..eceffaf 100644 --- a/src/PMG/RuleCache.pm +++ b/src/PMG/RuleCache.pm @@ -253,11 +253,19 @@ sub from_match { $ip = $1; } + # don't return true if there are no elements marked with and! + my $and = grep { $_->{and} } @$from; foreach my $obj (@$from) { - return 1 if ($obj->who_match($addr, $ip, $ldap) xor $obj->{negate}); + my $match = ($obj->who_match($addr, $ip, $ldap) xor $obj->{negate}); + + if ($obj->{and}) { + $and &&= $match; + } else { + return 1 if $match; + } } - return 0; + return $and; } sub to_match { @@ -267,11 +275,18 @@ sub to_match { return 1 if !defined ($to); + my $and = grep { $_->{and} } @$to; foreach my $obj (@$to) { - return 1 if ($obj->who_match($addr, undef, $ldap) xor $obj->{negate}); + my $match = ($obj->who_match($addr, undef, $ldap) xor $obj->{negate}); + + if ($obj->{and}) { + $and &&= $match; + } else { + return 1 if $match; + } } - return 0; + return $and; } sub when_match { @@ -281,11 +296,18 @@ sub when_match { return 1 if !defined ($when); + my $and = grep { $_->{and} } @$when; foreach my $obj (@$when) { - return 1 if ($obj->when_match($time) xor $obj->{negate}); + my $match = ($obj->when_match($time) xor $obj->{negate}); + + if ($obj->{and}) { + $and &&= $match; + } else { + return 1 if $match; + } } - return 0; + return $and; } sub what_match { @@ -311,14 +333,28 @@ sub what_match { my $marks; + # First, we loop through all objects which are not 'Spam Filter' + my $group_valid = 1; + my @group_matches = (); foreach my $obj (@$what) { if (!$obj->can('what_match_targets')) { if (my $match = $obj->what_match($queue, $element, $msginfo, $dbh)) { - push @$marks, @$match; + if ($obj->{and}) { + push @group_matches, $match; + } else { + push @$marks, @$match; + } + } elsif ($obj->{and}) { + $group_valid = 0; } } } + # If the 'Match All' group matches, push everything into the list + if ($group_valid) { + push(@$marks, @group_matches); + } + foreach my $target (@{$msginfo->{targets}}) { $res->{$target}->{marks} = $marks; $res->{marks} = $marks; -- 2.30.2