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