]> git.proxmox.com Git - pve-firewall.git/blame - src/PVE/API2/Firewall/IPSet.pm
define standard option for security group names
[pve-firewall.git] / src / PVE / API2 / Firewall / IPSet.pm
CommitLineData
009ee3ac
DM
1package PVE::API2::Firewall::IPSetBase;
2
3use strict;
4use warnings;
4a11bba5 5use PVE::Exception qw(raise raise_param_exc);
009ee3ac
DM
6use PVE::JSONSchema qw(get_standard_option);
7
8use PVE::Firewall;
9
10use base qw(PVE::RESTHandler);
11
12my $api_properties = {
13 cidr => {
14 description => "Network/IP specification in CIDR format.",
15 type => 'string', format => 'IPv4orCIDR',
16 },
e74a87f5 17 name => get_standard_option('ipset-name'),
009ee3ac
DM
18 comment => {
19 type => 'string',
20 optional => 1,
21 },
22 nomatch => {
23 type => 'boolean',
24 optional => 1,
25 },
26};
27
28sub load_config {
29 my ($class, $param) = @_;
30
31 die "implement this in subclass";
32
33 #return ($fw_conf, $rules);
34}
35
36sub save_rules {
37 my ($class, $param, $fw_conf, $rules) = @_;
38
39 die "implement this in subclass";
40}
41
42my $additional_param_hash = {};
43
44sub additional_parameters {
45 my ($class, $new_value) = @_;
46
47 if (defined($new_value)) {
48 $additional_param_hash->{$class} = $new_value;
49 }
50
51 # return a copy
52 my $copy = {};
53 my $org = $additional_param_hash->{$class} || {};
54 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
55 return $copy;
56}
57
58sub register_get_ipset {
59 my ($class) = @_;
60
61 my $properties = $class->additional_parameters();
62
63 $properties->{name} = $api_properties->{name};
64
65 $class->register_method({
66 name => 'get_ipset',
67 path => '',
68 method => 'GET',
69 description => "List IPSet content",
70 parameters => {
71 additionalProperties => 0,
72 properties => $properties,
73 },
74 returns => {
75 type => 'array',
76 items => {
77 type => "object",
78 properties => {
79 cidr => {
80 type => 'string',
81 },
82 comment => {
83 type => 'string',
84 optional => 1,
85 },
86 nomatch => {
87 type => 'boolean',
88 optional => 1,
89 },
90 },
91 },
92 links => [ { rel => 'child', href => "{cidr}" } ],
93 },
94 code => sub {
95 my ($param) = @_;
96
97 my ($fw_conf, $ipset) = $class->load_config($param);
98
99 return $ipset;
100 }});
101}
102
a33c74f6 103sub register_create_ip {
009ee3ac
DM
104 my ($class) = @_;
105
106 my $properties = $class->additional_parameters();
107
108 $properties->{name} = $api_properties->{name};
109 $properties->{cidr} = $api_properties->{cidr};
110 $properties->{nomatch} = $api_properties->{nomatch};
111 $properties->{comment} = $api_properties->{comment};
112
113 $class->register_method({
a33c74f6 114 name => 'create_ip',
009ee3ac
DM
115 path => '',
116 method => 'POST',
117 description => "Add IP or Network to IPSet.",
118 protected => 1,
119 parameters => {
120 additionalProperties => 0,
121 properties => $properties,
122 },
123 returns => { type => "null" },
124 code => sub {
125 my ($param) = @_;
126
127 my ($fw_conf, $ipset) = $class->load_config($param);
128
4a11bba5
DM
129 my $cidr = $param->{cidr};
130
131 foreach my $entry (@$ipset) {
132 raise_param_exc({ cidr => "address '$cidr' already exists" })
133 if $entry->{cidr} eq $cidr;
134 }
135
136 my $data = { cidr => $cidr };
009ee3ac
DM
137 $data->{nomatch} = 1 if $param->{nomatch};
138 $data->{comment} = $param->{comment} if $param->{comment};
139
009ee3ac
DM
140 unshift @$ipset, $data;
141
142 $class->save_ipset($param, $fw_conf, $ipset);
143
144 return undef;
145 }});
146}
147
a33c74f6
DM
148sub register_read_ip {
149 my ($class) = @_;
150
151 my $properties = $class->additional_parameters();
152
153 $properties->{name} = $api_properties->{name};
154 $properties->{cidr} = $api_properties->{cidr};
155
156 $class->register_method({
157 name => 'read_ip',
158 path => '{cidr}',
159 method => 'GET',
160 description => "Read IP or Network settings from IPSet.",
161 protected => 1,
162 parameters => {
163 additionalProperties => 0,
164 properties => $properties,
165 },
166 returns => { type => "object" },
167 code => sub {
168 my ($param) = @_;
169
170 my ($fw_conf, $ipset) = $class->load_config($param);
171
172 foreach my $entry (@$ipset) {
173 return $entry if $entry->{cidr} eq $param->{cidr};
174 }
175
176 raise_param_exc({ cidr => "no such IP/Network" });
177 }});
178}
179
180sub register_update_ip {
181 my ($class) = @_;
182
183 my $properties = $class->additional_parameters();
184
185 $properties->{name} = $api_properties->{name};
186 $properties->{cidr} = $api_properties->{cidr};
187 $properties->{nomatch} = $api_properties->{nomatch};
188 $properties->{comment} = $api_properties->{comment};
189
190 $class->register_method({
191 name => 'update_ip',
192 path => '{cidr}',
193 method => 'PUT',
194 description => "Update IP or Network settings",
195 protected => 1,
196 parameters => {
197 additionalProperties => 0,
198 properties => $properties,
199 },
200 returns => { type => "null" },
201 code => sub {
202 my ($param) = @_;
203
204 my ($fw_conf, $ipset) = $class->load_config($param);
205
206 foreach my $entry (@$ipset) {
207 if($entry->{cidr} eq $param->{cidr}) {
208 $entry->{nomatch} = $param->{nomatch};
209 $entry->{comment} = $param->{comment};
210 $class->save_ipset($param, $fw_conf, $ipset);
211 return;
212 }
213 }
214
215 raise_param_exc({ cidr => "no such IP/Network" });
216 }});
217}
218
219sub register_delete_ip {
009ee3ac
DM
220 my ($class) = @_;
221
222 my $properties = $class->additional_parameters();
223
224 $properties->{name} = $api_properties->{name};
225 $properties->{cidr} = $api_properties->{cidr};
226
227 $class->register_method({
228 name => 'remove_ip',
229 path => '{cidr}',
230 method => 'DELETE',
231 description => "Remove IP or Network from IPSet.",
232 protected => 1,
233 parameters => {
234 additionalProperties => 0,
235 properties => $properties,
236 },
237 returns => { type => "null" },
238 code => sub {
239 my ($param) = @_;
240
241 my ($fw_conf, $ipset) = $class->load_config($param);
242
4a11bba5
DM
243 my $new = [];
244
245 foreach my $entry (@$ipset) {
246 push @$new, $entry if $entry->{cidr} ne $param->{cidr};
247 }
009ee3ac 248
4a11bba5
DM
249 $class->save_ipset($param, $fw_conf, $new);
250
009ee3ac
DM
251 return undef;
252 }});
253}
254
255sub register_handlers {
256 my ($class) = @_;
257
258 $class->register_get_ipset();
a33c74f6
DM
259 $class->register_create_ip();
260 $class->register_read_ip();
261 $class->register_update_ip();
262 $class->register_delete_ip();
009ee3ac
DM
263}
264
265package PVE::API2::Firewall::ClusterIPset;
266
267use strict;
268use warnings;
269
270use base qw(PVE::API2::Firewall::IPSetBase);
271
272sub load_config {
273 my ($class, $param) = @_;
274
275 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
276 my $ipset = $fw_conf->{ipset}->{$param->{name}};
277 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
278
279 return ($fw_conf, $ipset);
280}
281
282sub save_ipset {
283 my ($class, $param, $fw_conf, $ipset) = @_;
284
285 $fw_conf->{ipset}->{$param->{name}} = $ipset;
286 PVE::Firewall::save_clusterfw_conf($fw_conf);
287}
288
289__PACKAGE__->register_handlers();
290
c85c87f9
DM
291package PVE::API2::Firewall::BaseIPSetList;
292
293use strict;
294use warnings;
e74a87f5 295use PVE::JSONSchema qw(get_standard_option);
c85c87f9 296use PVE::Exception qw(raise_param_exc);
e74a87f5 297use PVE::Firewall;
c85c87f9
DM
298
299use base qw(PVE::RESTHandler);
300
301sub register_index {
302 my ($class) = @_;
303
304 $class->register_method({
305 name => 'ipset_index',
306 path => '',
307 method => 'GET',
308 description => "List IPSets",
309 parameters => {
310 additionalProperties => 0,
311 },
312 returns => {
313 type => 'array',
314 items => {
315 type => "object",
316 properties => {
e74a87f5 317 name => get_standard_option('ipset-name'),
c85c87f9
DM
318 },
319 },
320 links => [ { rel => 'child', href => "{name}" } ],
321 },
322 code => sub {
323 my ($param) = @_;
324
325 my $fw_conf = $class->load_config();
326
327 my $res = [];
328 foreach my $name (keys %{$fw_conf->{ipset}}) {
329 push @$res, { name => $name, count => scalar(@{$fw_conf->{ipset}->{$name}}) };
330 }
331
332 return $res;
333 }});
334}
335
336sub register_create {
337 my ($class) = @_;
338
339 $class->register_method({
340 name => 'create_ipset',
341 path => '',
342 method => 'POST',
343 description => "Create new IPSet",
344 protected => 1,
345 parameters => {
346 additionalProperties => 0,
347 properties => {
e74a87f5
DM
348 name => get_standard_option('ipset-name'),
349 rename => get_standard_option('ipset-name', {
bc374ca7 350 description => "Rename an existing IPSet.",
bc374ca7 351 optional => 1,
e74a87f5 352 }),
c85c87f9
DM
353 }
354 },
355 returns => { type => 'null' },
356 code => sub {
357 my ($param) = @_;
358
359 my $fw_conf = $class->load_config();
360
361 foreach my $name (keys %{$fw_conf->{ipset}}) {
362 raise_param_exc({ name => "IPSet '$name' already exists" })
363 if $name eq $param->{name};
364 }
365
bc374ca7
DM
366 if ($param->{rename}) {
367 raise_param_exc({ name => "IPSet '$param->{rename}' does not exists" })
368 if !$fw_conf->{ipset}->{$param->{rename}};
369 my $data = delete $fw_conf->{ipset}->{$param->{rename}};
370 $fw_conf->{ipset}->{$param->{name}} = $data;
371 } else {
372 $fw_conf->{ipset}->{$param->{name}} = [];
373 }
374
c85c87f9
DM
375 $class->save_config($fw_conf);
376
377 return undef;
378 }});
379}
380
381sub register_delete {
382 my ($class) = @_;
383
384 $class->register_method({
385 name => 'delete_ipset',
386 path => '{name}',
387 method => 'DELETE',
388 description => "Delete IPSet",
389 protected => 1,
390 parameters => {
391 additionalProperties => 0,
392 properties => {
e74a87f5 393 name => get_standard_option('ipset-name'),
c85c87f9
DM
394 }
395 },
396 returns => { type => 'null' },
397 code => sub {
398 my ($param) = @_;
399
400 my $fw_conf = $class->load_config();
401
402 return undef if !$fw_conf->{ipset}->{$param->{name}};
403
76aad6c5 404 die "IPSet '$param->{name}' is not empty\n"
c85c87f9
DM
405 if scalar(@{$fw_conf->{ipset}->{$param->{name}}});
406
407 delete $fw_conf->{ipset}->{$param->{name}};
408
409 $class->save_config($fw_conf);
410
411 return undef;
412 }});
413}
414
415sub register_handlers {
416 my ($class) = @_;
417
418 $class->register_index();
419 $class->register_create();
420 $class->register_delete();
421}
422
423package PVE::API2::Firewall::ClusterIPSetList;
424
425use strict;
426use warnings;
427use PVE::Firewall;
428
429use base qw(PVE::API2::Firewall::BaseIPSetList);
430
431sub load_config {
432 my ($class) = @_;
433
434 return PVE::Firewall::load_clusterfw_conf();
435}
436
437sub save_config {
438 my ($class, $fw_conf) = @_;
439
440 PVE::Firewall::save_clusterfw_conf($fw_conf);
441}
442
443__PACKAGE__->register_handlers();
444
445__PACKAGE__->register_method ({
446 subclass => "PVE::API2::Firewall::ClusterIPset",
447 path => '{name}',
448 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
449 fragmentDelimiter => '',
450});
451
009ee3ac 4521;