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