prefix ipset chains with PVEFW-
[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
63c91681 35sub additional_parameters {
86791289
DM
36 my ($class, $new_value) = @_;
37
63c91681
DM
38 if (defined($new_value)) {
39 $additional_param_hash->{$class} = $new_value;
40 }
86791289 41
63c91681
DM
42 # return a copy
43 my $copy = {};
44 my $org = $additional_param_hash->{$class} || {};
45 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
46 return $copy;
86791289
DM
47}
48
49sub register_get_rules {
50 my ($class) = @_;
51
63c91681 52 my $properties = $class->additional_parameters();
86791289
DM
53
54 $class->register_method({
55 name => 'get_rules',
56 path => '',
57 method => 'GET',
58 description => "List rules.",
59 parameters => {
60 additionalProperties => 0,
61 properties => $properties,
62 },
63 returns => {
64 type => 'array',
65 items => {
66 type => "object",
67 properties => {
68 pos => {
69 type => 'integer',
70 }
71 },
72 },
73 links => [ { rel => 'child', href => "{pos}" } ],
74 },
75 code => sub {
76 my ($param) = @_;
77
78 my ($fw_conf, $rules) = $class->load_config($param);
79
80 my $digest = $fw_conf->{digest};
81
82 my $res = [];
83
84 my $ind = 0;
85 foreach my $rule (@$rules) {
86 push @$res, PVE::Firewall::cleanup_fw_rule($rule, $digest, $ind++);
87 }
88
89 return $res;
90 }});
91}
92
93sub register_get_rule {
94 my ($class) = @_;
95
63c91681 96 my $properties = $class->additional_parameters();
86791289
DM
97
98 $properties->{pos} = $api_properties->{pos};
99
86791289
DM
100 $class->register_method({
101 name => 'get_rule',
102 path => '{pos}',
103 method => 'GET',
104 description => "Get single rule data.",
105 parameters => {
106 additionalProperties => 0,
107 properties => $properties,
108 },
109 returns => {
110 type => "object",
111 properties => {
112 pos => {
113 type => 'integer',
114 }
115 },
116 },
117 code => sub {
118 my ($param) = @_;
119
120 my ($fw_conf, $rules) = $class->load_config($param);
121
122 my $digest = $fw_conf->{digest};
123 # fixme: check digest
124
125 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
126
127 my $rule = $rules->[$param->{pos}];
128
129 return PVE::Firewall::cleanup_fw_rule($rule, $digest, $param->{pos});
130 }});
131}
132
133sub register_create_rule {
134 my ($class) = @_;
135
63c91681 136 my $properties = $class->additional_parameters();
86791289
DM
137
138 my $create_rule_properties = PVE::Firewall::add_rule_properties($properties);
139
140 $class->register_method({
141 name => 'create_rule',
142 path => '',
143 method => 'POST',
144 description => "Create new rule.",
145 protected => 1,
146 parameters => {
147 additionalProperties => 0,
148 properties => $create_rule_properties,
149 },
150 returns => { type => "null" },
151 code => sub {
152 my ($param) = @_;
153
154 my ($fw_conf, $rules) = $class->load_config($param);
155
156 my $digest = $fw_conf->{digest};
157
158 my $rule = { type => 'out', action => 'ACCEPT', enable => 0};
159
160 PVE::Firewall::copy_rule_data($rule, $param);
161
162 unshift @$rules, $rule;
163
164 $class->save_rules($param, $fw_conf, $rules);
165
166 return undef;
167 }});
168}
169
170sub register_update_rule {
171 my ($class) = @_;
172
63c91681 173 my $properties = $class->additional_parameters();
86791289
DM
174
175 $properties->{pos} = $api_properties->{pos};
176
86791289
DM
177 $properties->{moveto} = {
178 description => "Move rule to new position <moveto>. Other arguments are ignored.",
179 type => 'integer',
180 minimum => 0,
181 optional => 1,
182 };
183
184 my $update_rule_properties = PVE::Firewall::add_rule_properties($properties);
185
186 $class->register_method({
187 name => 'update_rule',
188 path => '{pos}',
189 method => 'PUT',
190 description => "Modify rule data.",
191 protected => 1,
192 parameters => {
193 additionalProperties => 0,
194 properties => $update_rule_properties,
195 },
196 returns => { type => "null" },
197 code => sub {
198 my ($param) = @_;
199
200 my ($fw_conf, $rules) = $class->load_config($param);
201
202 my $digest = $fw_conf->{digest};
203 # fixme: check digest
204
205 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
206
207 my $rule = $rules->[$param->{pos}];
208
209 my $moveto = $param->{moveto};
210 if (defined($moveto) && $moveto != $param->{pos}) {
211 my $newrules = [];
212 for (my $i = 0; $i < scalar(@$rules); $i++) {
213 next if $i == $param->{pos};
214 if ($i == $moveto) {
215 push @$newrules, $rule;
216 }
217 push @$newrules, $rules->[$i];
218 }
219 push @$newrules, $rule if $moveto >= scalar(@$rules);
220 $rules = $newrules;
221 } else {
222 PVE::Firewall::copy_rule_data($rule, $param);
223 }
224
225 $class->save_rules($param, $fw_conf, $rules);
226
227 return undef;
228 }});
229}
230
231sub register_delete_rule {
232 my ($class) = @_;
233
63c91681 234 my $properties = $class->additional_parameters();
86791289
DM
235
236 $properties->{pos} = $api_properties->{pos};
237
86791289
DM
238 $class->register_method({
239 name => 'delete_rule',
240 path => '{pos}',
241 method => 'DELETE',
242 description => "Delete rule.",
243 protected => 1,
244 parameters => {
245 additionalProperties => 0,
246 properties => $properties,
247 },
248 returns => { type => "null" },
249 code => sub {
250 my ($param) = @_;
251
252 my ($fw_conf, $rules) = $class->load_config($param);
253
254 my $digest = $fw_conf->{digest};
255 # fixme: check digest
256
257 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
258
259 splice(@$rules, $param->{pos}, 1);
260
261 $class->save_rules($param, $fw_conf, $rules);
262
263 return undef;
264 }});
265}
266
267sub register_handlers {
268 my ($class) = @_;
269
270 $class->register_get_rules();
271 $class->register_get_rule();
272 $class->register_create_rule();
273 $class->register_update_rule();
274 $class->register_delete_rule();
275}
276
277package PVE::API2::Firewall::GroupRules;
278
279use strict;
280use warnings;
281
282use base qw(PVE::API2::Firewall::RulesBase);
283
63c91681
DM
284__PACKAGE__->additional_parameters({ group => {
285 description => "Security group name.",
286 type => 'string',
287 maxLength => 20, # fixme: what length?
288}});
86791289
DM
289
290sub load_config {
291 my ($class, $param) = @_;
292
293 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
294 my $rules = $fw_conf->{groups}->{$param->{group}};
295 die "no such security group '$param->{group}'\n" if !defined($rules);
296
297 return ($fw_conf, $rules);
298}
299
300sub save_rules {
301 my ($class, $param, $fw_conf, $rules) = @_;
302
303 $fw_conf->{groups}->{$param->{group}} = $rules;
304 PVE::Firewall::save_clusterfw_conf($fw_conf);
305}
306
63c91681 307__PACKAGE__->register_handlers();
86791289
DM
308
309package PVE::API2::Firewall::ClusterRules;
310
311use strict;
312use warnings;
313
314use base qw(PVE::API2::Firewall::RulesBase);
315
316sub load_config {
317 my ($class, $param) = @_;
318
319 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
320 my $rules = $fw_conf->{rules};
321
322 return ($fw_conf, $rules);
323}
324
325sub save_rules {
326 my ($class, $param, $fw_conf, $rules) = @_;
327
328 $fw_conf->{rules} = $rules;
329 PVE::Firewall::save_clusterfw_conf($fw_conf);
330}
331
63c91681
DM
332__PACKAGE__->register_handlers();
333
334package PVE::API2::Firewall::HostRules;
335
336use strict;
337use warnings;
338use PVE::JSONSchema qw(get_standard_option);
339
340use base qw(PVE::API2::Firewall::RulesBase);
341
342__PACKAGE__->additional_parameters({ node => get_standard_option('pve-node')});
343
344sub load_config {
345 my ($class, $param) = @_;
346
347 my $fw_conf = PVE::Firewall::load_hostfw_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_hostfw_conf($fw_conf);
358}
359
360__PACKAGE__->register_handlers();
86791289 361
464f933e
DM
362package PVE::API2::Firewall::VMRules;
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({
371 node => get_standard_option('pve-node'),
372 vmid => get_standard_option('pve-vmid'),
373});
374
375sub load_config {
376 my ($class, $param) = @_;
377
378 my $fw_conf = PVE::Firewall::load_vmfw_conf($param->{vmid});
379 my $rules = $fw_conf->{rules};
380
381 return ($fw_conf, $rules);
382}
383
384sub save_rules {
385 my ($class, $param, $fw_conf, $rules) = @_;
386
387 $fw_conf->{rules} = $rules;
388 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
389}
390
391__PACKAGE__->register_handlers();
392
86791289 3931;