]> git.proxmox.com Git - pmg-api.git/blame - PMG/RuleCache.pm
PMG/API2/Cluster.pm: also start/stop pmgmirror on create/join
[pmg-api.git] / PMG / RuleCache.pm
CommitLineData
c881fe35
DM
1package PMG::RuleCache;
2
3use strict;
4use warnings;
5use DBI;
c881fe35
DM
6
7use PVE::SafeSyslog;
8
9use PMG::Utils;
10use PMG::RuleDB;
11use Digest::SHA;
12
13my $ocache_size = 1023;
14
15sub new {
16 my ($type, $ruledb) = @_;
17
18 my $self;
19
20 $self->{ruledb} = $ruledb;
21 $self->{ocache} = ();
22
23 bless $self, $type;
24
25 my $rules = ();
26
27 my $dbh = $ruledb->{dbh};
28
29 my $sha1 = Digest::SHA->new;
30
31 eval {
32 $dbh->begin_work;
33
34 # read a consistent snapshot
35 $dbh->do("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
36
37 my $sth = $dbh->prepare(
38 "SELECT ID, Name, Priority, Active, Direction FROM Rule " .
39 "where Active > 0 " .
40 "ORDER BY Priority DESC");
41
42 $sth->execute();
43
44 while (my $ref = $sth->fetchrow_hashref()) {
45 my $ruleid = $ref->{id};
46 my $rule = PMG::RuleDB::Rule->new(
47 $ref->{name}, $ref->{priority}, $ref->{active},
48 $ref->{direction});
49
50 $rule->{id} = $ruleid;
51 push @$rules, $rule;
52
53 $sha1->add(join (',', values (%$ref)) . "|");
54
55 my ($from, $to, $when, $what, $action);
56
57 my $sth1 = $dbh->prepare(
58 "SELECT Objectgroup_ID, Grouptype FROM RuleGroup " .
59 "where RuleGroup.Rule_ID = '$ruleid' " .
60 "ORDER BY Grouptype, Objectgroup_ID");
61
62 $sth1->execute();
63 while (my $ref1 = $sth1->fetchrow_hashref()) {
64 my $gtype = $ref1->{grouptype};
65 my $groupid = $ref1->{objectgroup_id};
66
67 # emtyp groups differ from non-existent groups!
68
69 if ($gtype == 0) { #from
70 $from = [] if !defined ($from);
71 } elsif ($gtype == 1) { # to
72 $to = [] if !defined ($to);
73 } elsif ($gtype == 2) { # when
74 $when = [] if !defined ($when);
75 } elsif ($gtype == 3) { # what
76 $what = [] if !defined ($what);
77 } elsif ($gtype == 4) { # action
78 $action = [] if !defined ($action);
79 }
80
81 my $sth2 = $dbh->prepare(
82 "SELECT ID FROM Object where Objectgroup_ID = '$groupid' " .
83 "ORDER BY ID");
84 $sth2->execute();
85 while (my $ref2 = $sth2->fetchrow_hashref()) {
86 my $objid = $ref2->{'id'};
87 my $obj = $self->_get_object($objid);
88
89 $sha1->add (join (',', $objid, $gtype, $groupid) . "|");
90 $sha1->add ($obj->{digest}, "|");
91
92 if ($gtype == 0) { #from
93 push @$from, $obj;
94 } elsif ($gtype == 1) { # to
95 push @$to, $obj;
96 } elsif ($gtype == 2) { # when
97 push @$when, $obj;
98 } elsif ($gtype == 3) { # what
99 push @$what, $obj;
100 if ($obj->otype == PMG::RuleDB::ArchiveFilter->otype) {
101 if ($rule->{direction} == 0) {
102 $self->{archivefilter_in} = 1;
103 } elsif ($rule->{direction} == 1) {
104 $self->{archivefilter_out} = 1;
105 } else {
106 $self->{archivefilter_in} = 1;
107 $self->{archivefilter_out} = 1;
108 }
109 }
110 } elsif ($gtype == 4) { # action
111 push @$action, $obj;
112 $self->{"$ruleid:final"} = 1 if $obj->final();
113 }
114 }
115 $sth2->finish();
116 }
117
118 $sth1->finish();
119
120 $self->{"$ruleid:from"} = $from;
121 $self->{"$ruleid:to"} = $to;
122 $self->{"$ruleid:when"} = $when;
123 $self->{"$ruleid:what"} = $what;
124 $self->{"$ruleid:action"} = $action;
125 }
126
127 # Cache Greylist Exclusion
128 $sth = $dbh->prepare(
129 "SELECT object.id FROM object, objectgroup " .
130 "WHERE class = 'greylist' AND " .
131 "objectgroup.id = object.objectgroup_id " .
132 "ORDER BY object.id");
133
134 $sth->execute();
135 my $grey_excl_sender = ();
136 my $grey_excl_receiver = ();
137 while (my $ref2 = $sth->fetchrow_hashref()) {
138 my $obj = $self->_get_object ($ref2->{'id'});
139
140 if ($obj->receivertest()) {
141 push @$grey_excl_receiver, $obj;
142 } else {
143 push @$grey_excl_sender, $obj;
144 }
145 $sha1->add (join (',', values (%$ref2)) . "|");
146 $sha1->add ($obj->{digest}, "|");
147 }
148
149 $self->{"greylist:sender"} = $grey_excl_sender;
150 $self->{"greylist:receiver"} = $grey_excl_receiver;
151
152 $sth->finish();
153 };
154 my $err = $@;
155
156 $dbh->rollback; # end transaction
157
158 syslog ('err', PMG::Utils::msgquote("unable to load rulecache : $err")) if $err;
159
160 $self->{rules} = $rules;
161
162 $self->{digest} = $sha1->hexdigest;
163
164 return $self;
165}
166
167sub final {
168 my ($self, $ruleid) = @_;
169
9ef3f143 170 defined($ruleid) || die "undefined rule id: ERROR";
c881fe35
DM
171
172 return $self->{"$ruleid:final"};
173}
174
175sub rules {
176 my ($self) = @_;
177
178 $self->{rules};
179}
180
181sub _get_object {
182 my ($self, $objid) = @_;
183
184 my $cid = $objid % $ocache_size;
185
186 my $obj = $self->{ocache}[$cid];
187
188 if (!defined ($obj) || $obj->{id} != $objid) {
189 $obj = $self->{ruledb}->load_object($objid);
190 $self->{ocache}[$cid] = $obj;
191 }
192
9ef3f143 193 $obj || die "unable to get object $objid: ERROR";
c881fe35
DM
194
195 return $obj;
196}
197
198sub get_actions {
199 my ($self, $ruleid) = @_;
200
9ef3f143 201 defined($ruleid) || die "undefined rule id: ERROR";
c881fe35
DM
202
203 return $self->{"$ruleid:action"};
204}
205
206sub greylist_match {
207 my ($self, $addr, $ip) = @_;
208
209 my $grey = $self->{"greylist:sender"};
210
211 foreach my $obj (@$grey) {
212 if ($obj->who_match ($addr, $ip)) {
213 return 1;
214 }
215 }
216
217 return 0;
218}
219
220sub greylist_match_receiver {
221 my ($self, $addr) = @_;
222
223 my $grey = $self->{"greylist:receiver"};
224
225 foreach my $obj (@$grey) {
226 if ($obj->who_match($addr)) {
227 return 1;
228 }
229 }
230
231 return 0;
232}
233
234sub from_match {
235 my ($self, $ruleid, $addr, $ip, $ldap) = @_;
236
237 my $from = $self->{"$ruleid:from"};
238
239 return 1 if !defined ($from);
240
241 foreach my $obj (@$from) {
242 return 1 if $obj->who_match($addr, $ip, $ldap);
243 }
244
245 return 0;
246}
247
248sub to_match {
249 my ($self, $ruleid, $addr, $ldap) = @_;
250
251 my $to = $self->{"$ruleid:to"};
252
253 return 1 if !defined ($to);
254
255 foreach my $obj (@$to) {
256 return 1 if $obj->who_match($addr, undef, $ldap);
257 }
258
259 return 0;
260}
261
262sub when_match {
263 my ($self, $ruleid, $time) = @_;
264
265 my $when = $self->{"$ruleid:when"};
266
267 return 1 if !defined ($when);
268
269 foreach my $obj (@$when) {
270 return 1 if $obj->when_match($time);
271 }
272
273 return 0;
274}
275
276sub what_match {
277 my ($self, $ruleid, $queue, $element, $msginfo, $dbh) = @_;
278
279 my $what = $self->{"$ruleid:what"};
280
281 my $res;
282
283 # $res->{marks} is used by mark specific actions like remove-attachments
284 # $res->{$target}->{marks} is only used in apply_rules() to exclude some
285 # targets (spam blacklist and whitelist)
286
287 if (!defined ($what)) {
288 # match all targets
289 foreach my $target (@{$msginfo->{targets}}) {
290 $res->{$target}->{marks} = [];
291 }
292
293 $res->{marks} = [];
294 return $res;
295 }
296
297 my $marks;
298
299 foreach my $obj (@$what) {
300 if (!$obj->can('what_match_targets')) {
301 if (my $match = $obj->what_match($queue, $element, $msginfo, $dbh)) {
302 push @$marks, @$match;
303 }
304 }
305 }
306
307 foreach my $target (@{$msginfo->{targets}}) {
308 $res->{$target}->{marks} = $marks;
309 $res->{marks} = $marks;
310 }
311
312 foreach my $obj (@$what) {
313 if ($obj->can ("what_match_targets")) {
314 my $target_info;
315 if ($target_info = $obj->what_match_targets($queue, $element, $msginfo, $dbh)) {
316 foreach my $k (keys %$target_info) {
317 my $cmarks = $target_info->{$k}->{marks}; # make a copy
318 $res->{$k} = $target_info->{$k};
319 push @{$res->{$k}->{marks}}, @$cmarks if $cmarks;
320 }
321 }
322 }
323 }
324
325 return $res;
326}
327
3281;