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