]>
git.proxmox.com Git - pve-firewall.git/blob - src/PVE/API2/Firewall/IPSet.pm
1 package PVE
::API2
::Firewall
::IPSetBase
;
5 use PVE
::Exception
qw(raise raise_param_exc);
6 use PVE
::JSONSchema
qw(get_standard_option);
10 use base
qw(PVE::RESTHandler);
12 my $api_properties = {
14 description
=> "Network/IP specification in CIDR format.",
15 type
=> 'string', format
=> 'IPv4orCIDRorAlias',
17 name
=> get_standard_option
('ipset-name'),
29 my ($class, $param) = @_;
31 die "implement this in subclass";
33 #return ($cluster_conf, $fw_conf, $ipset);
37 my ($class, $param, $fw_conf) = @_;
39 die "implement this in subclass";
43 my ($class, $param, $fw_conf, $ipset) = @_;
45 if (!defined($ipset)) {
46 delete $fw_conf->{ipset
}->{$param->{name
}};
48 $fw_conf->{ipset
}->{$param->{name
}} = $ipset;
51 $class->save_config($param, $fw_conf);
54 my $additional_param_hash = {};
56 sub additional_parameters
{
57 my ($class, $new_value) = @_;
59 if (defined($new_value)) {
60 $additional_param_hash->{$class} = $new_value;
65 my $org = $additional_param_hash->{$class} || {};
66 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
70 sub register_get_ipset
{
73 my $properties = $class->additional_parameters();
75 $properties->{name
} = $api_properties->{name
};
77 $class->register_method({
81 description
=> "List IPSet content",
83 additionalProperties
=> 0,
84 properties
=> $properties,
102 digest
=> get_standard_option
('pve-config-digest', { optional
=> 0} ),
105 links
=> [ { rel
=> 'child', href
=> "{cidr}" } ],
110 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
112 return PVE
::Firewall
::copy_list_with_digest
($ipset);
116 sub register_delete_ipset
{
119 my $properties = $class->additional_parameters();
121 $properties->{name
} = get_standard_option
('ipset-name');
123 $class->register_method({
124 name
=> 'delete_ipset',
127 description
=> "Delete IPSet",
130 additionalProperties
=> 0,
131 properties
=> $properties,
133 returns
=> { type
=> 'null' },
137 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
139 die "IPSet '$param->{name}' is not empty\n"
142 $class->save_ipset($param, $fw_conf, undef);
148 my $verify_alias_exists = sub {
149 my ($cluster_conf, $fw_conf, $cidr) = @_;
151 if ($cidr !~ m/^\d/) {
152 my $alias = lc($cidr);
153 die "no such alias '$cidr'\n"
154 if !(($cluster_conf && $cluster_conf->{aliases
}->{$alias}) ||
155 ($fw_conf && $fw_conf->{aliases
}->{$alias}));
159 sub register_create_ip
{
162 my $properties = $class->additional_parameters();
164 $properties->{name
} = $api_properties->{name
};
165 $properties->{cidr
} = $api_properties->{cidr
};
166 $properties->{nomatch
} = $api_properties->{nomatch
};
167 $properties->{comment
} = $api_properties->{comment
};
169 $class->register_method({
173 description
=> "Add IP or Network to IPSet.",
176 additionalProperties
=> 0,
177 properties
=> $properties,
179 returns
=> { type
=> "null" },
183 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
185 my $cidr = $param->{cidr
};
187 foreach my $entry (@$ipset) {
188 raise_param_exc
({ cidr
=> "address '$cidr' already exists" })
189 if $entry->{cidr
} eq $cidr;
192 &$verify_alias_exists($cluster_conf, $fw_conf, $cidr);
194 my $data = { cidr
=> $cidr };
196 $data->{nomatch
} = 1 if $param->{nomatch
};
197 $data->{comment
} = $param->{comment
} if $param->{comment
};
199 unshift @$ipset, $data;
201 $class->save_ipset($param, $fw_conf, $ipset);
207 sub register_read_ip
{
210 my $properties = $class->additional_parameters();
212 $properties->{name
} = $api_properties->{name
};
213 $properties->{cidr
} = $api_properties->{cidr
};
215 $class->register_method({
219 description
=> "Read IP or Network settings from IPSet.",
222 additionalProperties
=> 0,
223 properties
=> $properties,
225 returns
=> { type
=> "object" },
229 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
231 my $list = PVE
::Firewall
::copy_list_with_digest
($ipset);
233 foreach my $entry (@$list) {
234 if ($entry->{cidr
} eq $param->{cidr
}) {
239 raise_param_exc
({ cidr
=> "no such IP/Network" });
243 sub register_update_ip
{
246 my $properties = $class->additional_parameters();
248 $properties->{name
} = $api_properties->{name
};
249 $properties->{cidr
} = $api_properties->{cidr
};
250 $properties->{nomatch
} = $api_properties->{nomatch
};
251 $properties->{comment
} = $api_properties->{comment
};
252 $properties->{digest
} = get_standard_option
('pve-config-digest');
254 $class->register_method({
258 description
=> "Update IP or Network settings",
261 additionalProperties
=> 0,
262 properties
=> $properties,
264 returns
=> { type
=> "null" },
268 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
270 my (undef, $digest) = PVE
::Firewall
::copy_list_with_digest
($ipset);
271 PVE
::Tools
::assert_if_modified
($digest, $param->{digest
});
273 foreach my $entry (@$ipset) {
274 if($entry->{cidr
} eq $param->{cidr
}) {
275 $entry->{nomatch
} = $param->{nomatch
};
276 $entry->{comment
} = $param->{comment
};
277 $class->save_ipset($param, $fw_conf, $ipset);
282 raise_param_exc
({ cidr
=> "no such IP/Network" });
286 sub register_delete_ip
{
289 my $properties = $class->additional_parameters();
291 $properties->{name
} = $api_properties->{name
};
292 $properties->{cidr
} = $api_properties->{cidr
};
293 $properties->{digest
} = get_standard_option
('pve-config-digest');
295 $class->register_method({
299 description
=> "Remove IP or Network from IPSet.",
302 additionalProperties
=> 0,
303 properties
=> $properties,
305 returns
=> { type
=> "null" },
309 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
311 my (undef, $digest) = PVE
::Firewall
::copy_list_with_digest
($ipset);
312 PVE
::Tools
::assert_if_modified
($digest, $param->{digest
});
316 foreach my $entry (@$ipset) {
317 push @$new, $entry if $entry->{cidr
} ne $param->{cidr
};
320 $class->save_ipset($param, $fw_conf, $new);
326 sub register_handlers
{
329 $class->register_delete_ipset();
330 $class->register_get_ipset();
331 $class->register_create_ip();
332 $class->register_read_ip();
333 $class->register_update_ip();
334 $class->register_delete_ip();
337 package PVE
::API2
::Firewall
::ClusterIPset
;
342 use base
qw(PVE::API2::Firewall::IPSetBase);
345 my ($class, $param) = @_;
347 my $fw_conf = PVE
::Firewall
::load_clusterfw_conf
();
348 my $ipset = $fw_conf->{ipset
}->{$param->{name
}};
349 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
351 return (undef, $fw_conf, $ipset);
355 my ($class, $param, $fw_conf) = @_;
357 PVE
::Firewall
::save_clusterfw_conf
($fw_conf);
360 __PACKAGE__-
>register_handlers();
362 package PVE
::API2
::Firewall
::VMIPset
;
366 use PVE
::JSONSchema
qw(get_standard_option);
368 use base
qw(PVE::API2::Firewall::IPSetBase);
370 __PACKAGE__-
>additional_parameters({
371 node
=> get_standard_option
('pve-node'),
372 vmid
=> get_standard_option
('pve-vmid'),
376 my ($class, $param) = @_;
378 my $cluster_conf = PVE
::Firewall
::load_clusterfw_conf
();
379 my $fw_conf = PVE
::Firewall
::load_vmfw_conf
($cluster_conf, 'vm', $param->{vmid
});
380 my $ipset = $fw_conf->{ipset
}->{$param->{name
}};
381 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
383 return ($cluster_conf, $fw_conf, $ipset);
387 my ($class, $param, $fw_conf) = @_;
389 PVE
::Firewall
::save_vmfw_conf
($param->{vmid
}, $fw_conf);
392 __PACKAGE__-
>register_handlers();
394 package PVE
::API2
::Firewall
::CTIPset
;
398 use PVE
::JSONSchema
qw(get_standard_option);
400 use base
qw(PVE::API2::Firewall::IPSetBase);
402 __PACKAGE__-
>additional_parameters({
403 node
=> get_standard_option
('pve-node'),
404 vmid
=> get_standard_option
('pve-vmid'),
408 my ($class, $param) = @_;
410 my $cluster_conf = PVE
::Firewall
::load_clusterfw_conf
();
411 my $fw_conf = PVE
::Firewall
::load_vmfw_conf
($cluster_conf, 'ct', $param->{vmid
});
412 my $ipset = $fw_conf->{ipset
}->{$param->{name
}};
413 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
415 return ($cluster_conf, $fw_conf, $ipset);
419 my ($class, $param, $fw_conf) = @_;
421 PVE
::Firewall
::save_vmfw_conf
($param->{vmid
}, $fw_conf);
424 __PACKAGE__-
>register_handlers();
426 package PVE
::API2
::Firewall
::BaseIPSetList
;
430 use PVE
::JSONSchema
qw(get_standard_option);
431 use PVE
::Exception
qw(raise_param_exc);
434 use base
qw(PVE::RESTHandler);
437 my ($class, $param) = @_;
439 die "implement this in subclass";
441 #return ($cluster_conf, $fw_conf);
445 my ($class, $param, $fw_conf) = @_;
447 die "implement this in subclass";
450 my $additional_param_hash_list = {};
452 sub additional_parameters
{
453 my ($class, $new_value) = @_;
455 if (defined($new_value)) {
456 $additional_param_hash_list->{$class} = $new_value;
461 my $org = $additional_param_hash_list->{$class} || {};
462 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
466 my $get_ipset_list = sub {
470 foreach my $name (keys %{$fw_conf->{ipset
}}) {
474 if (my $comment = $fw_conf->{ipset_comments
}->{$name}) {
475 $data->{comment
} = $comment;
480 my ($list, $digest) = PVE
::Firewall
::copy_list_with_digest
($res);
482 return wantarray ?
($list, $digest) : $list;
488 my $properties = $class->additional_parameters();
490 $class->register_method({
491 name
=> 'ipset_index',
494 description
=> "List IPSets",
496 additionalProperties
=> 0,
497 properties
=> $properties,
504 name
=> get_standard_option
('ipset-name'),
505 digest
=> get_standard_option
('pve-config-digest', { optional
=> 0} ),
512 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
517 my ($cluster_conf, $fw_conf) = $class->load_config($param);
519 return &$get_ipset_list($fw_conf);
523 sub register_create
{
526 my $properties = $class->additional_parameters();
528 $properties->{name
} = get_standard_option
('ipset-name');
530 $properties->{comment
} = { type
=> 'string', optional
=> 1 };
532 $properties->{digest
} = get_standard_option
('pve-config-digest');
534 $properties->{rename} = get_standard_option
('ipset-name', {
535 description
=> "Rename an existing IPSet. You can set 'rename' to the same value as 'name' to update the 'comment' of an existing IPSet.",
538 $class->register_method({
539 name
=> 'create_ipset',
542 description
=> "Create new IPSet",
545 additionalProperties
=> 0,
546 properties
=> $properties,
548 returns
=> { type
=> 'null' },
552 my ($cluster_conf, $fw_conf) = $class->load_config($param);
554 if ($param->{rename}) {
555 my (undef, $digest) = &$get_ipset_list($fw_conf);
556 PVE
::Tools
::assert_if_modified
($digest, $param->{digest
});
558 raise_param_exc
({ name
=> "IPSet '$param->{rename}' does not exists" })
559 if !$fw_conf->{ipset
}->{$param->{rename}};
561 my $data = delete $fw_conf->{ipset
}->{$param->{rename}};
562 $fw_conf->{ipset
}->{$param->{name
}} = $data;
563 if (my $comment = delete $fw_conf->{ipset_comments
}->{$param->{rename}}) {
564 $fw_conf->{ipset_comments
}->{$param->{name
}} = $comment;
566 $fw_conf->{ipset_comments
}->{$param->{name
}} = $param->{comment
} if defined($param->{comment
});
568 foreach my $name (keys %{$fw_conf->{ipset
}}) {
569 raise_param_exc
({ name
=> "IPSet '$name' already exists" })
570 if $name eq $param->{name
};
573 $fw_conf->{ipset
}->{$param->{name
}} = [];
574 $fw_conf->{ipset_comments
}->{$param->{name
}} = $param->{comment
} if defined($param->{comment
});
577 $class->save_config($param, $fw_conf);
583 sub register_handlers
{
586 $class->register_index();
587 $class->register_create();
590 package PVE
::API2
::Firewall
::ClusterIPSetList
;
596 use base
qw(PVE::API2::Firewall::BaseIPSetList);
599 my ($class, $param) = @_;
601 my $cluster_conf = PVE
::Firewall
::load_clusterfw_conf
();
602 return (undef, $cluster_conf);
606 my ($class, $param, $fw_conf) = @_;
608 PVE
::Firewall
::save_clusterfw_conf
($fw_conf);
611 __PACKAGE__-
>register_handlers();
613 __PACKAGE__-
>register_method ({
614 subclass
=> "PVE::API2::Firewall::ClusterIPset",
616 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
617 fragmentDelimiter
=> '',
620 package PVE
::API2
::Firewall
::VMIPSetList
;
624 use PVE
::JSONSchema
qw(get_standard_option);
627 use base
qw(PVE::API2::Firewall::BaseIPSetList);
629 __PACKAGE__-
>additional_parameters({
630 node
=> get_standard_option
('pve-node'),
631 vmid
=> get_standard_option
('pve-vmid'),
635 my ($class, $param) = @_;
637 my $cluster_conf = PVE
::Firewall
::load_clusterfw_conf
();
638 my $fw_conf = PVE
::Firewall
::load_vmfw_conf
($cluster_conf, 'vm', $param->{vmid
});
639 return ($cluster_conf, $fw_conf);
643 my ($class, $param, $fw_conf) = @_;
645 PVE
::Firewall
::save_vmfw_conf
($param->{vmid
}, $fw_conf);
648 __PACKAGE__-
>register_handlers();
650 __PACKAGE__-
>register_method ({
651 subclass
=> "PVE::API2::Firewall::VMIPset",
653 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
654 fragmentDelimiter
=> '',
657 package PVE
::API2
::Firewall
::CTIPSetList
;
661 use PVE
::JSONSchema
qw(get_standard_option);
664 use base
qw(PVE::API2::Firewall::BaseIPSetList);
666 __PACKAGE__-
>additional_parameters({
667 node
=> get_standard_option
('pve-node'),
668 vmid
=> get_standard_option
('pve-vmid'),
672 my ($class, $param) = @_;
674 my $cluster_conf = PVE
::Firewall
::load_clusterfw_conf
();
675 my $fw_conf = PVE
::Firewall
::load_vmfw_conf
($cluster_conf, 'ct', $param->{vmid
});
676 return ($cluster_conf, $fw_conf);
680 my ($class, $param, $fw_conf) = @_;
682 PVE
::Firewall
::save_vmfw_conf
($param->{vmid
}, $fw_conf);
685 __PACKAGE__-
>register_handlers();
687 __PACKAGE__-
>register_method ({
688 subclass
=> "PVE::API2::Firewall::CTIPset",
690 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
691 fragmentDelimiter
=> '',