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