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