5b9b6dd7a6c670b80fd343b7022b076d9105b63d
[pve-firewall.git] / src / PVE / API2 / Firewall / VM.pm
1 package PVE::API2::Firewall::VMBase;
2
3 use strict;
4 use warnings;
5
6 use PVE::Exception qw(raise_param_exc);
7 use PVE::JSONSchema qw(get_standard_option);
8 use PVE::Cluster;
9 use PVE::Firewall;
10 use PVE::API2::Firewall::Rules;
11 use PVE::API2::Firewall::Aliases;
12
13
14 use base qw(PVE::RESTHandler);
15
16 my $option_properties = $PVE::Firewall::vm_option_properties;
17
18 my $add_option_properties = sub {
19     my ($properties) = @_;
20
21     foreach my $k (keys %$option_properties) {
22         $properties->{$k} = $option_properties->{$k};
23     }
24
25     return $properties;
26 };
27
28 sub register_handlers {
29     my ($class, $rule_env) = @_;
30
31     $class->register_method({
32         name => 'index',
33         path => '',
34         method => 'GET',
35         permissions => { user => 'all' },
36         description => "Directory index.",
37         parameters => {
38             additionalProperties => 0,
39             properties => {
40                 node => get_standard_option('pve-node'),
41                 vmid => get_standard_option('pve-vmid'),
42             },
43         },
44         returns => {
45             type => 'array',
46             items => {
47                 type => "object",
48                 properties => {},
49             },
50             links => [ { rel => 'child', href => "{name}" } ],
51         },
52         code => sub {
53             my ($param) = @_;
54
55             my $result = [
56                 { name => 'rules' },
57                 { name => 'aliases' },
58                 { name => 'ipset' },
59                 { name => 'refs' },
60                 { name => 'options' },
61                 ];
62
63             return $result;
64         }});
65
66
67     $class->register_method({
68         name => 'get_options',
69         path => 'options',
70         method => 'GET',
71         description => "Get VM firewall options.",
72         proxyto => 'node',
73         permissions => {
74             check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
75         },
76         parameters => {
77             additionalProperties => 0,
78             properties => {
79                 node => get_standard_option('pve-node'),
80                 vmid => get_standard_option('pve-vmid'),
81             },
82         },
83         returns => {
84             type => "object",
85             #additionalProperties => 1,
86             properties => $option_properties,
87         },
88         code => sub {
89             my ($param) = @_;
90
91             my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
92             my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
93
94             return PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options});
95         }});
96
97     $class->register_method({
98         name => 'set_options',
99         path => 'options',
100         method => 'PUT',
101         description => "Set Firewall options.",
102         protected => 1,
103         proxyto => 'node',
104         permissions => {
105             check => ['perm', '/vms/{vmid}', [ 'VM.Config.Network' ]],
106         },
107         parameters => {
108             additionalProperties => 0,
109             properties => &$add_option_properties({
110                 node => get_standard_option('pve-node'),
111                 vmid => get_standard_option('pve-vmid'),
112                 delete => {
113                     type => 'string', format => 'pve-configid-list',
114                     description => "A list of settings you want to delete.",
115                     optional => 1,
116                 },
117                 digest => get_standard_option('pve-config-digest'),
118             }),
119         },
120         returns => { type => "null" },
121         code => sub {
122             my ($param) = @_;
123
124
125             my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
126             my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
127
128             my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options});
129             PVE::Tools::assert_if_modified($digest, $param->{digest});
130
131             if ($param->{delete}) {
132                 foreach my $opt (PVE::Tools::split_list($param->{delete})) {
133                     raise_param_exc({ delete => "no such option '$opt'" })
134                         if !$option_properties->{$opt};
135                     delete $vmfw_conf->{options}->{$opt};
136                 }
137             }
138
139             if (defined($param->{enable})) {
140                 $param->{enable} = $param->{enable} ? 1 : 0;
141             }
142
143             foreach my $k (keys %$option_properties) {
144                 next if !defined($param->{$k});
145                 $vmfw_conf->{options}->{$k} = $param->{$k};
146             }
147
148             PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf);
149
150             return undef;
151         }});
152
153     $class->register_method({
154         name => 'log',
155         path => 'log',
156         method => 'GET',
157         description => "Read firewall log",
158         proxyto => 'node',
159         permissions => {
160             check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]],
161         },
162         protected => 1,
163         parameters => {
164             additionalProperties => 0,
165             properties => {
166                 node => get_standard_option('pve-node'),
167                 vmid => get_standard_option('pve-vmid'),
168                 start => {
169                     type => 'integer',
170                     minimum => 0,
171                     optional => 1,
172                 },
173                 limit => {
174                     type => 'integer',
175                     minimum => 0,
176                     optional => 1,
177                 },
178             },
179         },
180         returns => {
181             type => 'array',
182             items => {
183                 type => "object",
184                 properties => {
185                     n => {
186                         description=>  "Line number",
187                         type=> 'integer',
188                     },
189                     t => {
190                         description=>  "Line text",
191                         type => 'string',
192                     }
193                 }
194             }
195         },
196         code => sub {
197             my ($param) = @_;
198
199             my $rpcenv = PVE::RPCEnvironment::get();
200             my $user = $rpcenv->get_user();
201             my $vmid = $param->{vmid};
202
203             my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log",
204                                                            $param->{start}, $param->{limit},
205                                                            "^$vmid ");
206
207             $rpcenv->set_result_attrib('total', $count);
208
209             return $lines;
210         }});
211
212
213     $class->register_method({
214         name => 'refs',
215         path => 'refs',
216         method => 'GET',
217         description => "Lists possible IPSet/Alias reference which are allowed in source/dest properties.",
218         permissions => {
219             check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
220         },
221         parameters => {
222             additionalProperties => 0,
223             properties => {
224                 node => get_standard_option('pve-node'),
225                 vmid => get_standard_option('pve-vmid'),
226                 type => {
227                     description => "Only list references of specified type.",
228                     type => 'string',
229                     enum => ['alias', 'ipset'],
230                     optional => 1,
231                 },
232             },
233         },
234         returns => {
235             type => 'array',
236             items => {
237                 type => "object",
238                 properties => {
239                     type => {
240                         type => 'string',
241                         enum => ['alias', 'ipset'],
242                     },
243                     name => {
244                         type => 'string',
245                     },
246                     comment => {
247                         type => 'string',
248                         optional => 1,
249                     },
250                 },
251             },
252         },
253         code => sub {
254             my ($param) = @_;
255
256             my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
257             my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
258
259             my $ipsets = {};
260             my $aliases = {};
261
262             foreach my $conf (($cluster_conf, $fw_conf)) {
263                 next if !$conf;
264                 if (!$param->{type} || $param->{type} eq 'ipset') {
265                     foreach my $name (keys %{$conf->{ipset}}) {
266                         my $data = {
267                             type => 'ipset',
268                             name => $name,
269                             ref => "+$name",
270                         };
271                         if (my $comment = $conf->{ipset_comments}->{$name}) {
272                             $data->{comment} = $comment;
273                         }
274                         $ipsets->{$name} = $data;
275                     }
276                 }
277
278                 if (!$param->{type} || $param->{type} eq 'alias') {
279                     foreach my $name (keys %{$conf->{aliases}}) {
280                         my $e = $conf->{aliases}->{$name};
281                         my $data = {
282                             type => 'alias',
283                             name => $name,
284                             ref => $name,
285                         };
286                         $data->{comment} = $e->{comment} if $e->{comment};
287                         $aliases->{$name} = $data;
288                     }
289                 }
290             }
291
292             my $res = [];
293             foreach my $e (values %$ipsets) { push @$res, $e; };
294             foreach my $e (values %$aliases) { push @$res, $e; };
295
296             return $res;
297         }});
298 }
299
300 package PVE::API2::Firewall::VM;
301
302 use strict;
303 use warnings;
304
305 use base qw(PVE::API2::Firewall::VMBase);
306
307 __PACKAGE__->register_method ({
308     subclass => "PVE::API2::Firewall::VMRules",
309     path => 'rules',
310 });
311
312 __PACKAGE__->register_method ({
313     subclass => "PVE::API2::Firewall::VMAliases",
314     path => 'aliases',
315 });
316
317 __PACKAGE__->register_method ({
318     subclass => "PVE::API2::Firewall::VMIPSetList",
319     path => 'ipset',
320 });
321
322 __PACKAGE__->register_handlers('vm');
323
324 package PVE::API2::Firewall::CT;
325
326 use strict;
327 use warnings;
328
329 use base qw(PVE::API2::Firewall::VMBase);
330
331 __PACKAGE__->register_method ({
332     subclass => "PVE::API2::Firewall::CTRules",
333     path => 'rules',
334 });
335
336 __PACKAGE__->register_method ({
337     subclass => "PVE::API2::Firewall::CTAliases",
338     path => 'aliases',
339 });
340
341 __PACKAGE__->register_method ({
342     subclass => "PVE::API2::Firewall::CTIPSetList",
343     path => 'ipset',
344 });
345
346 __PACKAGE__->register_handlers('vm');
347
348 1;