]> git.proxmox.com Git - pmg-api.git/commitdiff
add rule attributes and/invert (for each relevant type)
authorDominik Csapak <d.csapak@proxmox.com>
Wed, 21 Feb 2024 12:24:30 +0000 (13:24 +0100)
committerStoiko Ivanov <s.ivanov@proxmox.com>
Wed, 21 Feb 2024 18:30:13 +0000 (19:30 +0100)
like with the objectgroups, add an attributes table for groups, and an
'and'/'invert' attribute for each relevant object type
(what/when/from/to).

This is intended to modify the behaviour for the matching regarding
object groups, so that one has more choice in the logical matching.

Also adds the new table to cluster sync, backup and factory reset.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
src/PMG/API2/ObjectGroupHelpers.pm
src/PMG/API2/Rules.pm
src/PMG/Backup.pm
src/PMG/Cluster.pm
src/PMG/DBTools.pm
src/PMG/RuleDB.pm

index a08a6a366ce271972abf28bf1c6611789bc2e2b5..306015783f77d2c3e08ca9955694369f2d635abf 100644 (file)
@@ -31,6 +31,14 @@ sub format_rule {
        active => $rule->{active},
        direction => $rule->{direction},
     };
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+    for my $type ($types->@*) {
+       for my $attribute ($attributes->@*) {
+           my $opt = "${type}-${attribute}";
+           $data->{$opt} = $rule->{$opt} if defined($rule->{$opt});
+       }
+    }
 
     $cond_create_group->($data, 'from', $from);
     $cond_create_group->($data, 'to', $to);
index c48370fb4b603a732f37728933bfe9a9a56b90f9..1ebadc20ec432ca9b17a26a5a28daa96ed11dcf1 100644 (file)
@@ -149,6 +149,54 @@ my $rule_params = {
        type => 'boolean',
        optional => 1,
     },
+    'what-and' => {
+       description => "Flag to 'and' combine WHAT group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'what-invert' => {
+       description => "Flag to invert WHAT group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'when-and' => {
+       description => "Flag to 'and' combine WHEN group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'when-invert' => {
+       description => "Flag to invert WHEN group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'from-and' => {
+       description => "Flag to 'and' combine FROM group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'from-invert' => {
+       description => "Flag to invert FROM group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'to-and' => {
+       description => "Flag to 'and' combine TO group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
+    'to-invert' => {
+       description => "Flag to invert TO group matches.",
+       type => 'boolean',
+       default => 0,
+       optional => 1,
+    },
 };
 
 sub get_rule_params {
@@ -203,7 +251,10 @@ __PACKAGE__->register_method ({
 
        my $rule = $rdb->load_rule($id);
 
-       for my $key (qw(name active direction priority)) {
+       my $keys = ["name", "priority"];
+       push $keys->@*, keys get_rule_params()->%*;
+
+       for my $key ($keys->@*) {
            $rule->{$key} = $param->{$key} if defined($param->{$key});
        }
 
index 9fc91f88d9380f942dc5e8dfac86d42e4cf6adbf..5891afb7af8fa104e059b4a73c8581d67005e1c1 100644 (file)
@@ -95,6 +95,7 @@ sub dumpdb {
 
        dump_table($dbh, 'attribut', $ofh);
        dump_table($dbh, 'objectgroup_attributes', $ofh);
+       dump_table($dbh, 'rule_attributes', $ofh);
        dump_table($dbh, 'object', $ofh, 'object_id_seq', 'id');
        dump_table($dbh, 'objectgroup', $ofh, 'objectgroup_id_seq', 'id');
        dump_table($dbh, 'rule', $ofh, 'rule_id_seq', 'id');
index ac50cff36b10037866e51c8adceb90a1ccec039e..f46861873e583fff1800e5a51e5dee40a0a6e799 100644 (file)
@@ -533,6 +533,7 @@ sub sync_ruledb_from_master {
        $ldb->do("DELETE FROM Object");
        $ldb->do("DELETE FROM Attribut");
        $ldb->do("DELETE FROM Objectgroup_Attributes");
+       $ldb->do("DELETE FROM Rule_Attributes");
 
        eval {
            $rdb->begin_work;
@@ -545,6 +546,7 @@ sub sync_ruledb_from_master {
            PMG::DBTools::copy_table($ldb, $rdb, "ObjectGroup");
            PMG::DBTools::copy_table($ldb, $rdb, "Object", 'value');
            PMG::DBTools::copy_table($ldb, $rdb, "Attribut", 'value');
+           PMG::DBTools::copy_table($ldb, $rdb, "Rule_Attributes");
            PMG::DBTools::copy_table($ldb, $rdb, "Objectgroup_Attributes");
        };
 
index 3c8d18141d2e241509c2c1ee5425a6799b469d8d..3e814dc4e01336f0ef1bbe485b0c3b7555275ecb 100644 (file)
@@ -295,6 +295,18 @@ my $userprefs_ctablecmd =  <<__EOD;
 
 __EOD
 
+my $rule_attributes_cmd = <<__EOD;
+    CREATE TABLE Rule_Attributes (
+      Rule_ID INTEGER NOT NULL,
+      Name VARCHAR(20) NOT NULL,
+      Value BYTEA NULL,
+      PRIMARY KEY (Rule_ID, Name)
+    );
+
+    CREATE INDEX Rule_Attributes_Rule_ID_Index ON Rule_Attributes(Rule_ID);
+
+__EOD
+
 my $object_group_attributes_cmd = <<__EOD;
     CREATE TABLE Objectgroup_Attributes (
       Objectgroup_ID INTEGER NOT NULL,
@@ -452,6 +464,8 @@ sub create_ruledb {
 
         $virusinfo_stat_ctablecmd;
 
+        $rule_attributes_cmd;
+
         $object_group_attributes_cmd;
 EOD
     );
@@ -508,6 +522,7 @@ sub upgradedb {
        'CStatistic', $cstatistic_ctablecmd,
        'ClusterInfo', $clusterinfo_ctablecmd,
        'VirusInfo', $virusinfo_stat_ctablecmd,
+       'Rule_Attributes', $rule_attributes_cmd,
        'Objectgroup_Attributes', $object_group_attributes_cmd,
     };
 
@@ -620,6 +635,7 @@ sub init_ruledb {
        $dbh->do(
            "DELETE FROM Rule;"
            ." DELETE FROM RuleGroup;"
+           ." DELETE FROM Rule_Attributes;"
            ." DELETE FROM Objectgroup_Attributes;"
            ." DELETE FROM Attribut WHERE Object_ID NOT IN ($glids);"
            ." DELETE FROM Object WHERE ID NOT IN ($glids);"
index 0b112b47e319c08f7de79d910370aab0a328ca46..e5fe56eeea4df025984f313902b2763ce1da5f86 100644 (file)
@@ -668,6 +668,35 @@ sub delete_object {
     return 1;
 }
 
+sub update_rule_attributes {
+    my ($self, $rule) = @_;
+
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+
+    for my $type ($types->@*) {
+       for my $attribute ($attributes->@*) {
+           my $prop = "$type-$attribute";
+
+           # only save the values if they're set to 1
+           if ($rule->{$prop}) {
+               $self->{dbh}->do(
+                   "INSERT INTO Rule_Attributes (Rule_ID, Name, Value) " .
+                   "VALUES (?, ?, ?) ".
+                   "ON CONFLICT (Rule_ID, Name) DO UPDATE SET Value = ?", undef,
+                   $rule->{id}, $prop, $rule->{$prop}, $rule->{$prop},
+               );
+           } else {
+               $self->{dbh}->do(
+                   "DELETE FROM Rule_Attributes " .
+                   "WHERE Rule_ID = ? AND Name = ?", undef,
+                   $rule->{id}, $prop,
+               );
+           }
+       }
+    }
+}
+
 sub save_rule {
     my ($self, $rule) = @_;
 
@@ -682,28 +711,53 @@ sub save_rule {
 
     my $rulename = encode('UTF-8', $rule->{name});
     if (defined($rule->{id})) {
+       $self->{dbh}->begin_work;
+
+       eval {
+           $self->{dbh}->do(
+               "UPDATE Rule " .
+               "SET Name = ?, Priority = ?, Active = ?, Direction = ? " .
+               "WHERE ID = ?", undef,
+               $rulename, $rule->{priority}, $rule->{active},
+               $rule->{direction}, $rule->{id});
 
-       $self->{dbh}->do(
-           "UPDATE Rule " .
-           "SET Name = ?, Priority = ?, Active = ?, Direction = ? " .
-           "WHERE ID = ?", undef,
-           $rulename, $rule->{priority}, $rule->{active},
-           $rule->{direction}, $rule->{id});
+           $self->update_rule_attributes($rule);
 
-       return $rule->{id};
+           $self->{dbh}->commit;
+       };
 
+       if (my $err = $@) {
+           $self->{dbh}->rollback;
+           syslog('err', $err);
+           return undef;
+       }
     } else {
-       my $sth = $self->{dbh}->prepare(
-           "INSERT INTO Rule (Name, Priority, Active, Direction) " .
-           "VALUES (?, ?, ?, ?);");
+       $self->{dbh}->begin_work;
+
+       eval {
+           my $sth = $self->{dbh}->prepare(
+               "INSERT INTO Rule (Name, Priority, Active, Direction) " .
+               "VALUES (?, ?, ?, ?);");
+
+           $sth->execute($rulename, $rule->priority, $rule->active,
+               $rule->direction);
+
+
+           $rule->{id} = PMG::Utils::lastid($self->{dbh}, 'rule_id_seq');
 
-       $sth->execute($rulename, $rule->priority, $rule->active,
-                     $rule->direction);
+           $self->update_rule_attributes($rule);
 
-       return $rule->{id} = PMG::Utils::lastid($self->{dbh}, 'rule_id_seq');
+           $self->{dbh}->commit;
+       };
+
+       if (my $err = $@) {
+           $self->{dbh}->rollback;
+           syslog('err', $err);
+           return undef;
+       }
     }
 
-    return undef;
+    return $rule->{id};
 }
 
 sub delete_rule {
@@ -718,6 +772,8 @@ sub delete_rule {
                         "WHERE ID = ?", undef, $ruleid);
        $self->{dbh}->do("DELETE FROM RuleGroup " .
                         "WHERE Rule_ID = ?", undef, $ruleid);
+       $self->{dbh}->do("DELETE FROM Rule_Attributes " .
+                        "WHERE Rule_ID = ?", undef, $ruleid);
 
        $self->{dbh}->commit;
     };
@@ -829,24 +885,52 @@ sub rule_remove_group {
     return 1;
 }
 
+sub load_rule_attributes {
+    my ($self, $rule) = @_;
+
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+
+    my $attribute_sth = $self->{dbh}->prepare("SELECT * FROM Rule_Attributes WHERE Rule_ID = ?");
+    $attribute_sth->execute($rule->{id});
+
+    while (my $ref = $attribute_sth->fetchrow_hashref()) {
+       if ($ref->{name} =~ m/^((?:what|when|from|to)-(?:and|invert))$/) {
+           my $prop = $1;
+           $rule->{$prop} = $ref->{value};
+       }
+    }
+}
+
 sub load_rule {
     my ($self, $id) = @_;
 
     defined($id) || die "undefined id: ERROR";
 
-    my $sth = $self->{dbh}->prepare(
-       "SELECT * FROM Rule where id = ? ORDER BY Priority DESC");
+    $self->{dbh}->begin_work;
 
-    my $rules = ();
+    my $rule;
+
+    eval {
+       my $sth = $self->{dbh}->prepare(
+           "SELECT * FROM Rule where id = ? ORDER BY Priority DESC");
 
-    $sth->execute($id);
+       $sth->execute($id);
 
-    my $ref = $sth->fetchrow_hashref();
-    die "rule '$id' does not exist\n" if !defined($ref);
+       my $ref = $sth->fetchrow_hashref();
+       die "rule '$id' does not exist\n" if !defined($ref);
+
+       $rule = PMG::RuleDB::Rule->new($ref->{name}, $ref->{priority},
+                                         $ref->{active}, $ref->{direction});
+       $rule->{id} = $ref->{id};
+
+       $self->load_rule_attributes($rule);
+    };
+    my $err = $@;
+
+    $self->{dbh}->rollback; # finish transaction
 
-    my $rule = PMG::RuleDB::Rule->new($ref->{name}, $ref->{priority},
-                                     $ref->{active}, $ref->{direction});
-    $rule->{id} = $ref->{id};
+    die $err if $err;
 
     return $rule;
 }