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