]> git.proxmox.com Git - pve-firewall.git/blame - src/PVE/API2/Firewall/Rules.pm
improve rule verification
[pve-firewall.git] / src / PVE / API2 / Firewall / Rules.pm
CommitLineData
86791289
DM
1package PVE::API2::Firewall::RulesBase;
2
3use strict;
4use warnings;
5use PVE::JSONSchema qw(get_standard_option);
0d22acb3 6use PVE::Exception qw(raise raise_param_exc);
86791289
DM
7
8use PVE::Firewall;
9
10use base qw(PVE::RESTHandler);
11
12my $api_properties = {
86791289
DM
13 pos => {
14 description => "Rule position.",
15 type => 'integer',
16 minimum => 0,
17 },
18};
19
20sub load_config {
21 my ($class, $param) = @_;
22
23 die "implement this in subclass";
24
a523e057 25 #return ($cluster_conf, $fw_conf, $rules);
86791289
DM
26}
27
28sub save_rules {
29 my ($class, $param, $fw_conf, $rules) = @_;
30
31 die "implement this in subclass";
32}
33
63c91681 34my $additional_param_hash = {};
86791289 35
b6b8e6ad
DM
36sub rule_env {
37 my ($class, $param) = @_;
38
39 die "implement this in subclass";
7ca36671
DM
40}
41
63c91681 42sub additional_parameters {
86791289
DM
43 my ($class, $new_value) = @_;
44
63c91681
DM
45 if (defined($new_value)) {
46 $additional_param_hash->{$class} = $new_value;
47 }
86791289 48
63c91681
DM
49 # return a copy
50 my $copy = {};
51 my $org = $additional_param_hash->{$class} || {};
52 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
53 return $copy;
86791289
DM
54}
55
56sub register_get_rules {
57 my ($class) = @_;
58
63c91681 59 my $properties = $class->additional_parameters();
86791289
DM
60
61 $class->register_method({
62 name => 'get_rules',
63 path => '',
64 method => 'GET',
65 description => "List rules.",
66 parameters => {
67 additionalProperties => 0,
68 properties => $properties,
69 },
70 returns => {
71 type => 'array',
72 items => {
73 type => "object",
74 properties => {
75 pos => {
76 type => 'integer',
77 }
78 },
79 },
80 links => [ { rel => 'child', href => "{pos}" } ],
81 },
82 code => sub {
83 my ($param) = @_;
84
a523e057 85 my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
86791289 86
5d38d64f 87 my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules);
86791289
DM
88
89 my $ind = 0;
5d38d64f
DM
90 foreach my $rule (@$list) {
91 $rule->{pos} = $ind++;
86791289
DM
92 }
93
5d38d64f 94 return $list;
86791289
DM
95 }});
96}
97
98sub register_get_rule {
99 my ($class) = @_;
100
63c91681 101 my $properties = $class->additional_parameters();
86791289
DM
102
103 $properties->{pos} = $api_properties->{pos};
104
86791289
DM
105 $class->register_method({
106 name => 'get_rule',
107 path => '{pos}',
108 method => 'GET',
109 description => "Get single rule data.",
110 parameters => {
111 additionalProperties => 0,
112 properties => $properties,
113 },
114 returns => {
115 type => "object",
116 properties => {
117 pos => {
118 type => 'integer',
119 }
120 },
121 },
122 code => sub {
123 my ($param) = @_;
124
a523e057 125 my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
86791289 126
5d38d64f 127 my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules);
86791289 128
5d38d64f 129 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$list);
86791289 130
5d38d64f
DM
131 my $rule = $list->[$param->{pos}];
132 $rule->{pos} = $param->{pos};
133
134 return $rule;
86791289
DM
135 }});
136}
137
138sub register_create_rule {
139 my ($class) = @_;
140
63c91681 141 my $properties = $class->additional_parameters();
86791289
DM
142
143 my $create_rule_properties = PVE::Firewall::add_rule_properties($properties);
3655b01f
DM
144 $create_rule_properties->{action}->{optional} = 0;
145 $create_rule_properties->{type}->{optional} = 0;
146
86791289
DM
147 $class->register_method({
148 name => 'create_rule',
149 path => '',
150 method => 'POST',
151 description => "Create new rule.",
152 protected => 1,
153 parameters => {
154 additionalProperties => 0,
155 properties => $create_rule_properties,
156 },
157 returns => { type => "null" },
158 code => sub {
159 my ($param) = @_;
160
a523e057 161 my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
86791289 162
3655b01f 163 my $rule = {};
86791289
DM
164
165 PVE::Firewall::copy_rule_data($rule, $param);
a523e057 166 PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
86791289 167
3655b01f
DM
168 $rule->{enable} = 0 if !defined($param->{enable});
169
86791289
DM
170 unshift @$rules, $rule;
171
172 $class->save_rules($param, $fw_conf, $rules);
173
174 return undef;
175 }});
176}
177
178sub register_update_rule {
179 my ($class) = @_;
180
63c91681 181 my $properties = $class->additional_parameters();
86791289
DM
182
183 $properties->{pos} = $api_properties->{pos};
184
86791289
DM
185 $properties->{moveto} = {
186 description => "Move rule to new position <moveto>. Other arguments are ignored.",
187 type => 'integer',
188 minimum => 0,
189 optional => 1,
190 };
191
5b7974df
DM
192 $properties->{delete} = {
193 type => 'string', format => 'pve-configid-list',
194 description => "A list of settings you want to delete.",
195 optional => 1,
196 };
197
86791289
DM
198 my $update_rule_properties = PVE::Firewall::add_rule_properties($properties);
199
200 $class->register_method({
201 name => 'update_rule',
202 path => '{pos}',
203 method => 'PUT',
204 description => "Modify rule data.",
205 protected => 1,
206 parameters => {
207 additionalProperties => 0,
208 properties => $update_rule_properties,
209 },
210 returns => { type => "null" },
211 code => sub {
212 my ($param) = @_;
213
a523e057 214 my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
86791289 215
5d38d64f
DM
216 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
217 PVE::Tools::assert_if_modified($digest, $param->{digest});
ddf1e07d 218
86791289
DM
219 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
220
221 my $rule = $rules->[$param->{pos}];
222
223 my $moveto = $param->{moveto};
224 if (defined($moveto) && $moveto != $param->{pos}) {
225 my $newrules = [];
226 for (my $i = 0; $i < scalar(@$rules); $i++) {
227 next if $i == $param->{pos};
228 if ($i == $moveto) {
229 push @$newrules, $rule;
230 }
231 push @$newrules, $rules->[$i];
232 }
233 push @$newrules, $rule if $moveto >= scalar(@$rules);
234 $rules = $newrules;
235 } else {
236 PVE::Firewall::copy_rule_data($rule, $param);
5b7974df
DM
237
238 PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
7ca36671 239
a523e057 240 PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
86791289
DM
241 }
242
243 $class->save_rules($param, $fw_conf, $rules);
244
245 return undef;
246 }});
247}
248
249sub register_delete_rule {
250 my ($class) = @_;
251
63c91681 252 my $properties = $class->additional_parameters();
86791289
DM
253
254 $properties->{pos} = $api_properties->{pos};
ddf1e07d
DM
255
256 $properties->{digest} = get_standard_option('pve-config-digest');
86791289 257
86791289
DM
258 $class->register_method({
259 name => 'delete_rule',
260 path => '{pos}',
261 method => 'DELETE',
262 description => "Delete rule.",
263 protected => 1,
264 parameters => {
265 additionalProperties => 0,
266 properties => $properties,
267 },
268 returns => { type => "null" },
269 code => sub {
270 my ($param) = @_;
271
a523e057 272 my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
86791289 273
5d38d64f
DM
274 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
275 PVE::Tools::assert_if_modified($digest, $param->{digest});
86791289
DM
276
277 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
278
279 splice(@$rules, $param->{pos}, 1);
280
281 $class->save_rules($param, $fw_conf, $rules);
282
283 return undef;
284 }});
285}
286
287sub register_handlers {
288 my ($class) = @_;
289
290 $class->register_get_rules();
291 $class->register_get_rule();
292 $class->register_create_rule();
293 $class->register_update_rule();
294 $class->register_delete_rule();
295}
296
297package PVE::API2::Firewall::GroupRules;
298
299use strict;
300use warnings;
387d0ffc 301use PVE::JSONSchema qw(get_standard_option);
86791289
DM
302
303use base qw(PVE::API2::Firewall::RulesBase);
304
387d0ffc 305__PACKAGE__->additional_parameters({ group => get_standard_option('pve-security-group-name') });
86791289 306
b6b8e6ad
DM
307sub rule_env {
308 my ($class, $param) = @_;
309
310 return 'group';
7ca36671
DM
311}
312
86791289
DM
313sub load_config {
314 my ($class, $param) = @_;
315
316 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
317 my $rules = $fw_conf->{groups}->{$param->{group}};
318 die "no such security group '$param->{group}'\n" if !defined($rules);
319
a523e057 320 return (undef, $fw_conf, $rules);
86791289
DM
321}
322
323sub save_rules {
324 my ($class, $param, $fw_conf, $rules) = @_;
325
326 $fw_conf->{groups}->{$param->{group}} = $rules;
327 PVE::Firewall::save_clusterfw_conf($fw_conf);
328}
329
63c91681 330__PACKAGE__->register_handlers();
86791289
DM
331
332package PVE::API2::Firewall::ClusterRules;
333
334use strict;
335use warnings;
336
337use base qw(PVE::API2::Firewall::RulesBase);
338
b6b8e6ad
DM
339sub rule_env {
340 my ($class, $param) = @_;
341
342 return 'cluster';
343}
344
86791289
DM
345sub load_config {
346 my ($class, $param) = @_;
347
348 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
349 my $rules = $fw_conf->{rules};
350
a523e057 351 return (undef, $fw_conf, $rules);
86791289
DM
352}
353
354sub save_rules {
355 my ($class, $param, $fw_conf, $rules) = @_;
356
357 $fw_conf->{rules} = $rules;
358 PVE::Firewall::save_clusterfw_conf($fw_conf);
359}
360
63c91681
DM
361__PACKAGE__->register_handlers();
362
363package PVE::API2::Firewall::HostRules;
364
365use strict;
366use warnings;
367use PVE::JSONSchema qw(get_standard_option);
368
369use base qw(PVE::API2::Firewall::RulesBase);
370
371__PACKAGE__->additional_parameters({ node => get_standard_option('pve-node')});
372
b6b8e6ad
DM
373sub rule_env {
374 my ($class, $param) = @_;
375
376 return 'host';
377}
378
63c91681
DM
379sub load_config {
380 my ($class, $param) = @_;
381
a523e057
DM
382 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
383 my $fw_conf = PVE::Firewall::load_hostfw_conf($cluster_conf);
63c91681
DM
384 my $rules = $fw_conf->{rules};
385
a523e057 386 return ($cluster_conf, $fw_conf, $rules);
63c91681
DM
387}
388
389sub save_rules {
390 my ($class, $param, $fw_conf, $rules) = @_;
391
392 $fw_conf->{rules} = $rules;
393 PVE::Firewall::save_hostfw_conf($fw_conf);
394}
395
396__PACKAGE__->register_handlers();
86791289 397
464f933e
DM
398package PVE::API2::Firewall::VMRules;
399
400use strict;
401use warnings;
402use PVE::JSONSchema qw(get_standard_option);
403
404use base qw(PVE::API2::Firewall::RulesBase);
405
406__PACKAGE__->additional_parameters({
407 node => get_standard_option('pve-node'),
408 vmid => get_standard_option('pve-vmid'),
409});
410
b6b8e6ad
DM
411sub rule_env {
412 my ($class, $param) = @_;
413
414 return 'vm';
415}
416
417sub load_config {
418 my ($class, $param) = @_;
419
a523e057
DM
420 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
421 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
b6b8e6ad
DM
422 my $rules = $fw_conf->{rules};
423
a523e057 424 return ($cluster_conf, $fw_conf, $rules);
b6b8e6ad
DM
425}
426
427sub save_rules {
428 my ($class, $param, $fw_conf, $rules) = @_;
429
430 $fw_conf->{rules} = $rules;
431 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
432}
433
434__PACKAGE__->register_handlers();
435
436package PVE::API2::Firewall::CTRules;
437
438use strict;
439use warnings;
440use PVE::JSONSchema qw(get_standard_option);
441
442use base qw(PVE::API2::Firewall::RulesBase);
443
444__PACKAGE__->additional_parameters({
445 node => get_standard_option('pve-node'),
446 vmid => get_standard_option('pve-vmid'),
447});
448
449sub rule_env {
450 my ($class, $param) = @_;
451
452 return 'ct';
453}
454
464f933e
DM
455sub load_config {
456 my ($class, $param) = @_;
457
a523e057
DM
458 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
459 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
464f933e
DM
460 my $rules = $fw_conf->{rules};
461
a523e057 462 return ($cluster_conf, $fw_conf, $rules);
464f933e
DM
463}
464
465sub save_rules {
466 my ($class, $param, $fw_conf, $rules) = @_;
467
468 $fw_conf->{rules} = $rules;
469 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
470}
471
472__PACKAGE__->register_handlers();
473
86791289 4741;