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