0bf8285f6db86b423dac612dacde921ccade8caa
[pve-firewall.git] / src / PVE / API2 / Firewall / Cluster.pm
1 package PVE::API2::Firewall::Cluster;
2
3 use strict;
4 use warnings;
5 use PVE::Exception qw(raise raise_param_exc raise_perm_exc);
6 use PVE::JSONSchema qw(get_standard_option);
7
8 use PVE::Firewall;
9 use PVE::API2::Firewall::Aliases;
10 use PVE::API2::Firewall::Rules;
11 use PVE::API2::Firewall::Groups;
12 use PVE::API2::Firewall::IPSet;
13
14 #fixme: locking?
15
16
17 use base qw(PVE::RESTHandler);
18
19 __PACKAGE__->register_method ({
20     subclass => "PVE::API2::Firewall::Groups",
21     path => 'groups',
22 });
23
24 __PACKAGE__->register_method ({
25     subclass => "PVE::API2::Firewall::ClusterRules",
26     path => 'rules',
27 });
28
29 __PACKAGE__->register_method ({
30     subclass => "PVE::API2::Firewall::ClusterIPSetList",
31     path => 'ipset',
32 });
33
34 __PACKAGE__->register_method ({
35     subclass => "PVE::API2::Firewall::ClusterAliases",
36     path => 'aliases',
37 });
38
39
40 __PACKAGE__->register_method({
41     name => 'index',
42     path => '',
43     method => 'GET',
44     permissions => { user => 'all' },
45     description => "Directory index.",
46     parameters => {
47         additionalProperties => 0,
48     },
49     returns => {
50         type => 'array',
51         items => {
52             type => "object",
53             properties => {},
54         },
55         links => [ { rel => 'child', href => "{name}" } ],
56     },
57     code => sub {
58         my ($param) = @_;
59
60         my $result = [
61             { name => 'aliases' },
62             { name => 'rules' },
63             { name => 'options' },
64             { name => 'groups' },
65             { name => 'ipset' },
66             { name => 'macros' },
67             { name => 'refs' },
68             ];
69
70         return $result;
71     }});
72
73 my $option_properties = $PVE::Firewall::cluster_option_properties;
74
75 my $add_option_properties = sub {
76     my ($properties) = @_;
77
78     foreach my $k (keys %$option_properties) {
79         $properties->{$k} = $option_properties->{$k};
80     }
81
82     return $properties;
83 };
84
85
86 __PACKAGE__->register_method({
87     name => 'get_options',
88     path => 'options',
89     method => 'GET',
90     description => "Get Firewall options.",
91     permissions => {
92         check => ['perm', '/', [ 'Sys.Audit' ]],
93     },
94     parameters => {
95         additionalProperties => 0,
96     },
97     returns => {
98         type => "object",
99         #additionalProperties => 1,
100         properties => $option_properties,
101     },
102     code => sub {
103         my ($param) = @_;
104
105         my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
106
107         return PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
108     }});
109
110
111 __PACKAGE__->register_method({
112     name => 'set_options',
113     path => 'options',
114     method => 'PUT',
115     description => "Set Firewall options.",
116     protected => 1,
117     permissions => {
118         check => ['perm', '/', [ 'Sys.Modify' ]],
119     },
120     parameters => {
121         additionalProperties => 0,
122         properties => &$add_option_properties({
123             delete => {
124                 type => 'string', format => 'pve-configid-list',
125                 description => "A list of settings you want to delete.",
126                 optional => 1,
127             },
128             digest => get_standard_option('pve-config-digest'),
129         }),
130     },
131     returns => { type => "null" },
132     code => sub {
133         my ($param) = @_;
134
135         my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
136
137         my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
138         PVE::Tools::assert_if_modified($digest, $param->{digest});
139
140         if ($param->{delete}) {
141             foreach my $opt (PVE::Tools::split_list($param->{delete})) {
142                 raise_param_exc({ delete => "no such option '$opt'" })
143                     if !$option_properties->{$opt};
144                 delete $cluster_conf->{options}->{$opt};
145             }
146         }
147
148         if (defined($param->{enable}) && ($param->{enable} > 1)) {
149             $param->{enable} = time();
150         }
151
152         foreach my $k (keys %$option_properties) {
153             next if !defined($param->{$k});
154             $cluster_conf->{options}->{$k} = $param->{$k};
155         }
156
157         PVE::Firewall::save_clusterfw_conf($cluster_conf);
158
159         # instant firewall update when using double (anti-lockout) API call
160         # -> not waiting for a firewall update at the first (timestamp enable) set
161         if (defined($param->{enable}) && ($param->{enable} > 1)) {
162             PVE::Firewall::update();
163         }
164
165         return undef;
166     }});
167
168 __PACKAGE__->register_method({
169     name => 'get_macros',
170     path => 'macros',
171     method => 'GET',
172     description => "List available macros",
173     permissions => { user => 'all' },
174     parameters => {
175         additionalProperties => 0,
176     },
177     returns => {
178         type => 'array',
179         items => {
180             type => "object",
181             properties => {
182                 macro => {
183                     description => "Macro name.",
184                     type => 'string',
185                 },
186                 descr => {
187                     description => "More verbose description (if available).",
188                     type => 'string',
189                 }
190             },
191         },
192     },
193     code => sub {
194         my ($param) = @_;
195
196         my $res = [];
197
198         my ($macros, $descr) = PVE::Firewall::get_macros();
199
200         foreach my $macro (keys %$macros) {
201             push @$res, { macro => $macro, descr => $descr->{$macro} || $macro };
202         }
203
204         return $res;
205     }});
206
207 __PACKAGE__->register_method({
208     name => 'refs',
209     path => 'refs',
210     method => 'GET',
211     description => "Lists possible IPSet/Alias reference which are allowed in source/dest properties.",
212     permissions => {
213         check => ['perm', '/', [ 'Sys.Audit' ]],
214     },
215     parameters => {
216         additionalProperties => 0,
217         properties => {
218             type => {
219                 description => "Only list references of specified type.",
220                 type => 'string',
221                 enum => ['alias', 'ipset'],
222                 optional => 1,
223             },
224         },
225     },
226     returns => {
227         type => 'array',
228         items => {
229             type => "object",
230             properties => {
231                 type => {
232                     type => 'string',
233                     enum => ['alias', 'ipset'],
234                 },
235                 name => {
236                     type => 'string',
237                 },
238                 ref => {
239                     type => 'string',
240                 },
241                 comment => {
242                     type => 'string',
243                     optional => 1,
244                 },
245             },
246         },
247     },
248     code => sub {
249         my ($param) = @_;
250
251         my $conf = PVE::Firewall::load_clusterfw_conf();
252
253         my $res = [];
254
255         if (!$param->{type} || $param->{type} eq 'ipset') {
256             foreach my $name (keys %{$conf->{ipset}}) {
257                 my $data = {
258                     type => 'ipset',
259                     name => $name,
260                     ref => "+$name",
261                 };
262                 if (my $comment = $conf->{ipset_comments}->{$name}) {
263                     $data->{comment} = $comment;
264                 }
265                 push @$res, $data;
266             }
267         }
268
269         if (!$param->{type} || $param->{type} eq 'alias') {
270             foreach my $name (keys %{$conf->{aliases}}) {
271                 my $e = $conf->{aliases}->{$name};
272                 my $data = {
273                     type => 'alias',
274                     name => $name,
275                     ref => $name,
276                 };
277                 $data->{comment} = $e->{comment} if $e->{comment};
278                 push @$res, $data;
279             }
280         }
281
282         return $res;
283     }});
284
285 1;