fix iptables-restore - correctly add newline after COMMIT
[pve-firewall.git] / PVE / Firewall.pm
CommitLineData
b6360c3f
DM
1package PVE::Firewall;
2
3use warnings;
4use strict;
5use Data::Dumper;
f789653a 6use PVE::Tools;
b6360c3f 7use PVE::QemuServer;
5e1267a5
DM
8use File::Path;
9use IO::File;
ecbea048 10use Net::IP;
06320eb0 11use PVE::Tools qw(run_command lock_file);
ecbea048 12
5e1267a5 13use Data::Dumper;
b6360c3f 14
06320eb0
DM
15my $pve_fw_lock_filename = "/var/lock/pvefw.lck";
16
9aab3127 17my $macros;
3a616aa0
AD
18my @ruleset = ();
19
a332200b
DM
20# todo: implement some kind of MACROS, like shorewall /usr/share/shorewall/macro.*
21sub get_firewall_macros {
9aab3127
DM
22
23 return $macros if $macros;
24
a332200b
DM
25 #foreach my $path (</usr/share/shorewall/macro.*>) {
26 # if ($path =~ m|/macro\.(\S+)$|) {
27 # $macros->{$1} = 1;
28 # }
29 #}
30
31 $macros = {}; # fixme: implemet me
32
9aab3127
DM
33 return $macros;
34}
35
fcba0beb
DM
36my $etc_services;
37
38sub get_etc_services {
39
40 return $etc_services if $etc_services;
41
42 my $filename = "/etc/services";
43
44 my $fh = IO::File->new($filename, O_RDONLY);
45 if (!$fh) {
46 warn "unable to read '$filename' - $!\n";
47 return {};
48 }
49
50 my $services = {};
51
52 while (my $line = <$fh>) {
53 chomp ($line);
54 next if $line =~m/^#/;
55 next if ($line =~m/^\s*$/);
56
57 if ($line =~ m!^(\S+)\s+(\S+)/(tcp|udp).*$!) {
58 $services->{byid}->{$2}->{name} = $1;
59 $services->{byid}->{$2}->{$3} = 1;
60 $services->{byname}->{$1} = $services->{byid}->{$2};
61 }
62 }
63
64 close($fh);
65
66 $etc_services = $services;
67
3a616aa0 68
fcba0beb
DM
69 return $etc_services;
70}
71
72my $etc_protocols;
73
74sub get_etc_protocols {
75 return $etc_protocols if $etc_protocols;
76
77 my $filename = "/etc/protocols";
78
79 my $fh = IO::File->new($filename, O_RDONLY);
80 if (!$fh) {
81 warn "unable to read '$filename' - $!\n";
82 return {};
83 }
84
85 my $protocols = {};
86
87 while (my $line = <$fh>) {
88 chomp ($line);
89 next if $line =~m/^#/;
90 next if ($line =~m/^\s*$/);
91
92 if ($line =~ m!^(\S+)\s+(\d+)\s+.*$!) {
93 $protocols->{byid}->{$2}->{name} = $1;
94 $protocols->{byname}->{$1} = $protocols->{byid}->{$2};
95 }
96 }
97
98 close($fh);
99
100 $etc_protocols = $protocols;
101
102 return $etc_protocols;
103}
104
ecbea048
DM
105sub parse_address_list {
106 my ($str) = @_;
107
d6de1dc2 108 my $nbaor = 0;
ecbea048
DM
109 foreach my $aor (split(/,/, $str)) {
110 if (!Net::IP->new($aor)) {
111 my $err = Net::IP::Error();
112 die "invalid IP address: $err\n";
d6de1dc2
AD
113 }else{
114 $nbaor++;
ecbea048
DM
115 }
116 }
d6de1dc2 117 return $nbaor;
ecbea048 118}
dddd9413 119
fcba0beb
DM
120sub parse_port_name_number_or_range {
121 my ($str) = @_;
122
123 my $services = PVE::Firewall::get_etc_services();
4cdbb3b7 124 my $nbports = 0;
fcba0beb 125 foreach my $item (split(/,/, $str)) {
4cdbb3b7 126 my $portlist = "";
fcba0beb 127 foreach my $pon (split(':', $item, 2)) {
4cdbb3b7
AD
128 if ($pon =~ m/^\d+$/){
129 die "invalid port '$pon'\n" if $pon < 0 && $pon > 65536;
130 }else{
131 die "invalid port $services->{byname}->{$pon}\n" if !$services->{byname}->{$pon};
132 }
133 $nbports++;
fcba0beb
DM
134 }
135 }
136
4cdbb3b7 137 return ($nbports);
fcba0beb
DM
138}
139
8cebfa6f 140my $rule_format = "%-15s %-30s %-30s %-15s %-15s %-15s\n";
dddd9413 141
3a616aa0
AD
142sub iptables {
143 my ($cmd) = @_;
144
145 run_command("/sbin/iptables $cmd", outfunc => sub {}, errfunc => sub {});
146}
147
148sub iptables_restore {
149
150 unshift (@ruleset, '*filter');
151 push (@ruleset, 'COMMIT');
152
64568ce0 153 my $cmdlist = join("\n", @ruleset) . "\n";
3a616aa0 154
64568ce0
DM
155 my $verbose = 1; # fixme: how/when do we set this
156
157 #run_command("echo '$cmdlist' | /sbin/iptables-restore -n");
158 eval { run_command("/sbin/iptables-restore -n ", input => $cmdlist); };
159 if (my $err = $@) {
160 print STDERR $cmdlist if $verbose;
161 die $err;
162 }
3a616aa0
AD
163}
164
165sub iptables_addrule {
166 my ($rule) = @_;
167
168 push (@ruleset, $rule);
169}
170
171sub iptables_chain_exist {
172 my ($chain) = @_;
173
174 eval{
175 iptables("-n --list $chain");
176 };
177 return undef if $@;
178
179 return 1;
180}
181
182sub iptables_rule_exist {
183 my ($rule) = @_;
184
185 eval{
186 iptables("-C $rule");
187 };
188 return undef if $@;
189
190 return 1;
191}
192
193sub iptables_generate_rule {
194 my ($chain, $rule) = @_;
195
196 my $cmd = "-A $chain";
197
d6de1dc2 198 $cmd .= " -m iprange --src-range" if $rule->{nbsource} && $rule->{nbsource} > 1;
3a616aa0 199 $cmd .= " -s $rule->{source}" if $rule->{source};
d6de1dc2 200 $cmd .= " -m iprange --dst-range" if $rule->{nbdest} && $rule->{nbdest} > 1;
3a616aa0
AD
201 $cmd .= " -d $rule->{dest}" if $rule->{destination};
202 $cmd .= " -p $rule->{proto}" if $rule->{proto};
4cdbb3b7 203 $cmd .= " --match multiport" if $rule->{nbdport} && $rule->{nbdport} > 1;
3a616aa0 204 $cmd .= " --dport $rule->{dport}" if $rule->{dport};
4cdbb3b7 205 $cmd .= " --match multiport" if $rule->{nbsport} && $rule->{nbsport} > 1;
3a616aa0
AD
206 $cmd .= " --sport $rule->{sport}" if $rule->{sport};
207 $cmd .= " -j $rule->{action}" if $rule->{action};
208
209 iptables_addrule($cmd);
210
211}
212
213sub generate_bridge_rules {
214 my ($bridge) = @_;
215
216 if(!iptables_chain_exist("BRIDGEFW-OUT")){
217 iptables_addrule(":BRIDGEFW-OUT - [0:0]");
218 }
219
220 if(!iptables_chain_exist("BRIDGEFW-IN")){
221 iptables_addrule(":BRIDGEFW-IN - [0:0]");
222 }
223
224 if(!iptables_chain_exist("proxmoxfw-FORWARD")){
225 iptables_addrule(":proxmoxfw-FORWARD - [0:0]");
226 iptables_addrule("-I FORWARD -j proxmoxfw-FORWARD");
227 iptables_addrule("-A proxmoxfw-FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT");
228 iptables_addrule("-A proxmoxfw-FORWARD -m physdev --physdev-is-in --physdev-is-bridged -j BRIDGEFW-OUT");
229 iptables_addrule("-A proxmoxfw-FORWARD -m physdev --physdev-is-out --physdev-is-bridged -j BRIDGEFW-IN");
230
231 }
232
233 generate_proxmoxfwinput();
234
235 if(!iptables_chain_exist("$bridge-IN")){
236 iptables_addrule(":$bridge-IN - [0:0]");
237 iptables_addrule("-A proxmoxfw-FORWARD -i $bridge -j DROP"); #disable interbridge routing
238 iptables_addrule("-A BRIDGEFW-IN -j $bridge-IN");
239 iptables_addrule("-A $bridge-IN -j ACCEPT");
240
241 }
242
243 if(!iptables_chain_exist("$bridge-OUT")){
244 iptables_addrule(":$bridge-OUT - [0:0]");
245 iptables_addrule("-A proxmoxfw-FORWARD -o $bridge -j DROP"); # disable interbridge routing
246 iptables_addrule("-A BRIDGEFW-OUT -j $bridge-OUT");
247
248 }
249
250}
251
252
253sub generate_tap_rules_direction {
254 my ($iface, $netid, $rules, $bridge, $direction) = @_;
255
256 my $tapchain = "$iface-$direction";
257
258 iptables_addrule(":$tapchain - [0:0]");
259
260 iptables_addrule("-A $tapchain -m state --state INVALID -j DROP");
261 iptables_addrule("-A $tapchain -m state --state RELATED,ESTABLISHED -j ACCEPT");
262
263 if (scalar(@$rules)) {
264 foreach my $rule (@$rules) {
265 next if $rule->{iface} && $rule->{iface} ne $netid;
266 if($rule->{action} =~ m/^(GROUP-(\S+))$/){
267 $rule->{action} .= "-$direction";
268 #generate empty group rule if don't exist
269 if(!iptables_chain_exist($rule->{action})){
270 generate_group_rules($2);
271 }
272 }
273 #we go to vmbr-IN if accept in out rules
274 $rule->{action} = "$bridge-IN" if $rule->{action} eq 'ACCEPT' && $direction eq 'OUT';
275 iptables_generate_rule($tapchain, $rule);
276 }
277 }
278
279 iptables_addrule("-A $tapchain -j LOG --log-prefix \"$tapchain-dropped: \" --log-level 4");
280 iptables_addrule("-A $tapchain -j DROP");
281
282 #plug the tap chain to bridge chain
283 my $physdevdirection = $direction eq 'IN' ? "out":"in";
284 my $rule = "$bridge-$direction -m physdev --physdev-$physdevdirection $iface --physdev-is-bridged -j $tapchain";
285
286 if(!iptables_rule_exist($rule)){
287 iptables_addrule("-I $rule");
288 }
289
290 if($direction eq 'OUT'){
291 #add tap->host rules
292 my $rule = "proxmoxfw-INPUT -m physdev --physdev-$physdevdirection $iface -j $tapchain";
293
294 if(!iptables_rule_exist($rule)){
295 iptables_addrule("-A $rule");
296 }
297 }
298}
299
300sub generate_tap_rules {
301 my ($net, $netid, $vmid) = @_;
302
303 my $filename = "/etc/pve/firewall/$vmid.fw";
304 my $fh = IO::File->new($filename, O_RDONLY);
305 return if !$fh;
306
307 #generate bridge rules
308 my $bridge = $net->{bridge};
309 my $tag = $net->{tag};
310 $bridge .= "v$tag" if $tag;
311
312 #generate tap chain
313 my $rules = parse_fw_rules($filename, $fh);
314
315 my $inrules = $rules->{in};
316 my $outrules = $rules->{out};
317
318 my $iface = "tap".$vmid."i".$1 if $netid =~ m/net(\d+)/;
319
320 generate_bridge_rules($bridge);
321 generate_tap_rules_direction($iface, $netid, $inrules, $bridge, 'IN');
322 generate_tap_rules_direction($iface, $netid, $outrules, $bridge, 'OUT');
323 iptables_restore();
324}
325
326sub flush_tap_rules {
327 my ($net, $netid, $vmid) = @_;
328
329 my $bridge = $net->{bridge};
330 my $iface = "tap".$vmid."i".$1 if $netid =~ m/net(\d+)/;
331
332 flush_tap_rules_direction($iface, $bridge, 'IN');
333 flush_tap_rules_direction($iface, $bridge, 'OUT');
334 iptables_restore();
335}
336
337sub flush_tap_rules_direction {
338 my ($iface, $bridge, $direction) = @_;
339
340 my $tapchain = "$iface-$direction";
341
342 if(iptables_chain_exist($tapchain)){
343 iptables_addrule("-F $tapchain");
344
345 my $physdevdirection = $direction eq 'IN' ? "out":"in";
346 my $rule = "$bridge-$direction -m physdev --physdev-$physdevdirection $iface --physdev-is-bridged -j $tapchain";
347 if(iptables_rule_exist($rule)){
348 iptables_addrule("-D $rule");
349 }
350
351 if($direction eq 'OUT'){
352 my $rule = "proxmoxfw-INPUT -m physdev --physdev-$physdevdirection $iface -j $tapchain";
462a6553 353 if(iptables_rule_exist($rule)){
3a616aa0
AD
354 iptables_addrule("-D $rule");
355 }
356 }
357
358 iptables_addrule("-X $tapchain");
359 }
360}
361
0bd5f137
AD
362sub enablehostfw {
363
364 generate_proxmoxfwinput();
365 generate_proxmoxfwoutput();
366
367 my $filename = "/etc/pve/local/host.fw";
368 my $fh = IO::File->new($filename, O_RDONLY);
369 return if !$fh;
370
371 my $rules = parse_fw_rules($filename, $fh);
372 my $inrules = $rules->{in};
373 my $outrules = $rules->{out};
374
375 #host inbound firewall
376 iptables_addrule(":host-IN - [0:0]");
377 iptables_addrule("-A host-IN -m state --state INVALID -j DROP");
378 iptables_addrule("-A host-IN -m state --state RELATED,ESTABLISHED -j ACCEPT");
379 iptables_addrule("-A host-IN -i lo -j ACCEPT");
380 iptables_addrule("-A host-IN -m addrtype --dst-type MULTICAST -j ACCEPT");
381 iptables_addrule("-A host-IN -p udp -m state --state NEW -m multiport --dports 5404,5405 -j ACCEPT");
382 iptables_addrule("-A host-IN -p udp -m udp --dport 9000 -j ACCEPT"); #corosync
383
384 if (scalar(@$inrules)) {
385 foreach my $rule (@$inrules) {
386 #we use RETURN because we need to check also tap rules
387 $rule->{action} = 'RETURN' if $rule->{action} eq 'ACCEPT';
388 iptables_generate_rule('host-IN', $rule);
389 }
390 }
391
392 iptables_addrule("-A host-IN -j LOG --log-prefix \"kvmhost-IN dropped: \" --log-level 4");
393 iptables_addrule("-A host-IN -j DROP");
394
395 #host outbound firewall
396 iptables_addrule(":host-OUT - [0:0]");
397 iptables_addrule("-A host-OUT -m state --state INVALID -j DROP");
398 iptables_addrule("-A host-OUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
399 iptables_addrule("-A host-OUT -o lo -j ACCEPT");
400 iptables_addrule("-A host-OUT -m addrtype --dst-type MULTICAST -j ACCEPT");
401 iptables_addrule("-A host-OUT -p udp -m state --state NEW -m multiport --dports 5404,5405 -j ACCEPT");
402 iptables_addrule("-A host-OUT -p udp -m udp --dport 9000 -j ACCEPT"); #corosync
403
404 if (scalar(@$outrules)) {
405 foreach my $rule (@$outrules) {
406 #we use RETURN because we need to check also tap rules
407 $rule->{action} = 'RETURN' if $rule->{action} eq 'ACCEPT';
408 iptables_generate_rule('host-OUT', $rule);
409 }
410 }
411
412 iptables_addrule("-A host-OUT -j LOG --log-prefix \"kvmhost-OUT dropped: \" --log-level 4");
413 iptables_addrule("-A host-OUT -j DROP");
414
415
416 my $rule = "proxmoxfw-INPUT -j host-IN";
417 if(!iptables_rule_exist($rule)){
418 iptables_addrule("-I $rule");
419 }
420
421 $rule = "proxmoxfw-OUTPUT -j host-OUT";
422 if(!iptables_rule_exist($rule)){
423 iptables_addrule("-I $rule");
424 }
425
426 iptables_restore();
427
428
429}
430
431sub disablehostfw {
432
433 my $chain = "host-IN";
434
435 my $rule = "proxmoxfw-INPUT -j $chain";
436 if(iptables_rule_exist($rule)){
437 iptables_addrule("-D $rule");
438 }
439
440 if(iptables_chain_exist($chain)){
441 iptables_addrule("-F $chain");
442 iptables_addrule("-X $chain");
443 }
444
445 $chain = "host-OUT";
446
447 $rule = "proxmoxfw-OUTPUT -j $chain";
448 if(iptables_rule_exist($rule)){
449 iptables_addrule("-D $rule");
450 }
451
452 if(iptables_chain_exist($chain)){
453 iptables_addrule("-F $chain");
454 iptables_addrule("-X $chain");
455 }
456
457 iptables_restore();
458}
459
460sub generate_proxmoxfwinput {
461
462 if(!iptables_chain_exist("proxmoxfw-INPUT")){
463 iptables_addrule(":proxmoxfw-INPUT - [0:0]");
464 iptables_addrule("-I INPUT -j proxmoxfw-INPUT");
465 iptables_addrule("-A INPUT -j ACCEPT");
466 }
467}
468
469sub generate_proxmoxfwoutput {
470
471 if(!iptables_chain_exist("proxmoxfw-OUTPUT")){
472 iptables_addrule(":proxmoxfw-OUTPUT - [0:0]");
473 iptables_addrule("-I OUTPUT -j proxmoxfw-OUTPUT");
474 iptables_addrule("-A OUTPUT -j ACCEPT");
475 }
476
477}
478
9d31b418
AD
479sub enable_group_rules {
480 my ($group) = @_;
481
482 generate_group_rules($group);
483 iptables_restore();
484}
485
486sub generate_group_rules {
487 my ($group) = @_;
488
489 my $filename = "/etc/pve/firewall/groups.fw";
490 my $fh = IO::File->new($filename, O_RDONLY);
491 return if !$fh;
492
493 my $rules = parse_fw_rules($filename, $fh, $group);
494 my $inrules = $rules->{in};
495 my $outrules = $rules->{out};
496
497 my $chain = "GROUP-".$group."-IN";
498
499 iptables_addrule(":$chain - [0:0]");
500
501 if (scalar(@$inrules)) {
502 foreach my $rule (@$inrules) {
503 iptables_generate_rule($chain, $rule);
504 }
505 }
506
507 $chain = "GROUP-".$group."-OUT";
508
509 iptables_addrule(":$chain - [0:0]");
510
511 if(!iptables_chain_exist("BRIDGEFW-OUT")){
512 iptables_addrule(":BRIDGEFW-OUT - [0:0]");
513 }
514
515 if(!iptables_chain_exist("BRIDGEFW-IN")){
516 iptables_addrule(":BRIDGEFW-IN - [0:0]");
517 }
518
519 if (scalar(@$outrules)) {
520 foreach my $rule (@$outrules) {
521 #we go the BRIDGEFW-IN because we need to check also other tap rules
522 #(and group rules can be set on any bridge, so we can't go to VMBRXX-IN)
523 $rule->{action} = 'BRIDGEFW-IN' if $rule->{action} eq 'ACCEPT';
524 iptables_generate_rule($chain, $rule);
525 }
526 }
527
528}
529
530sub disable_group_rules {
531 my ($group) = @_;
532
533 my $chain = "GROUP-".$group."-IN";
534
535 if(iptables_chain_exist($chain)){
536 iptables_addrule("-F $chain");
537 iptables_addrule("-X $chain");
538 }
539
540 $chain = "GROUP-".$group."-OUT";
541
542 if(iptables_chain_exist($chain)){
543 iptables_addrule("-F $chain");
544 iptables_addrule("-X $chain");
545 }
546
547 #iptables_restore will die if security group is linked in a tap chain
548 #maybe can we improve that, parsing each vm config, or parsing iptables -S
549 #to see if the security group is linked or not
550 iptables_restore();
551}
552
5e1267a5 553sub parse_fw_rules {
9d31b418 554 my ($filename, $fh, $group) = @_;
5e1267a5
DM
555
556 my $section;
9d31b418
AD
557 my $securitygroup;
558 my $securitygroupexist;
5e1267a5
DM
559
560 my $res = { in => [], out => [] };
561
a332200b 562 my $macros = get_firewall_macros();
fcba0beb
DM
563 my $protocols = get_etc_protocols();
564
5e1267a5
DM
565 while (defined(my $line = <$fh>)) {
566 next if $line =~ m/^#/;
567 next if $line =~ m/^\s*$/;
568
9d31b418 569 if ($line =~ m/^\[(in|out)(:(\S+))?\]\s*$/i) {
5e1267a5 570 $section = lc($1);
9d31b418
AD
571 $securitygroup = lc($3) if $3;
572 $securitygroupexist = 1 if $securitygroup && $securitygroup eq $group;
5e1267a5
DM
573 next;
574 }
575 next if !$section;
9d31b418 576 next if $group && $securitygroup ne $group;
5e1267a5
DM
577
578 my ($action, $iface, $source, $dest, $proto, $dport, $sport) =
579 split(/\s+/, $line);
580
581 if (!$action) {
582 warn "skip incomplete line\n";
583 next;
584 }
585
586 my $service;
3a616aa0 587 if ($action =~ m/^(ACCEPT|DROP|REJECT|GROUP-(\S+))$/) {
5e1267a5
DM
588 # OK
589 } elsif ($action =~ m/^(\S+)\((ACCEPT|DROP|REJECT)\)$/) {
590 ($service, $action) = ($1, $2);
591 if (!$macros->{$service}) {
592 warn "unknown service '$service'\n";
593 next;
594 }
595 } else {
596 warn "unknown action '$action'\n";
597 next;
598 }
599
600 $iface = undef if $iface && $iface eq '-';
601 if ($iface && $iface !~ m/^(net0|net1|net2|net3|net4|net5)$/) {
602 warn "unknown interface '$iface'\n";
603 next;
604 }
605
606 $proto = undef if $proto && $proto eq '-';
fcba0beb
DM
607 if ($proto && !(defined($protocols->{byname}->{$proto}) ||
608 defined($protocols->{byid}->{$proto}))) {
5e1267a5
DM
609 warn "unknown protokol '$proto'\n";
610 next;
611 }
612
613 $source = undef if $source && $source eq '-';
5e1267a5 614 $dest = undef if $dest && $dest eq '-';
5e1267a5
DM
615
616 $dport = undef if $dport && $dport eq '-';
617 $sport = undef if $sport && $sport eq '-';
4cdbb3b7
AD
618 my $nbdport = undef;
619 my $nbsport = undef;
d6de1dc2
AD
620 my $nbsource = undef;
621 my $nbdest = undef;
5e1267a5 622
ecbea048 623 eval {
d6de1dc2
AD
624 $nbsource = parse_address_list($source) if $source;
625 $nbdest = parse_address_list($dest) if $dest;
4cdbb3b7
AD
626 $nbdport = parse_port_name_number_or_range($dport) if $dport;
627 $nbsport = parse_port_name_number_or_range($sport) if $sport;
ecbea048
DM
628 };
629 if (my $err = $@) {
630 warn $err;
631 next;
632
633 }
634
635
5e1267a5
DM
636 my $rule = {
637 action => $action,
638 service => $service,
639 iface => $iface,
640 source => $source,
641 dest => $dest,
d6de1dc2
AD
642 nbsource => $nbsource,
643 nbdest => $nbdest,
5e1267a5
DM
644 proto => $proto,
645 dport => $dport,
646 sport => $sport,
4cdbb3b7
AD
647 nbdport => $nbdport,
648 nbsport => $nbsport,
649
5e1267a5
DM
650 };
651
652 push @{$res->{$section}}, $rule;
653 }
654
9d31b418 655 die "security group $group don't exist" if $group && !$securitygroupexist;
5e1267a5
DM
656 return $res;
657}
658
06320eb0
DM
659sub run_locked {
660 my ($code, @param) = @_;
661
662 my $timeout = 10;
663
664 my $res = lock_file($pve_fw_lock_filename, $timeout, $code, @param);
665
666 die $@ if $@;
667
668 return $res;
669}
670
5e1267a5
DM
671sub read_local_vm_config {
672
673 my $openvz = {};
674
675 my $qemu = {};
676
677 my $list = PVE::QemuServer::config_list();
678
679 foreach my $vmid (keys %$list) {
b9b06789 680 #next if !($vmid eq '100' || $vmid eq '102');
5e1267a5
DM
681 my $cfspath = PVE::QemuServer::cfs_config_path($vmid);
682 if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) {
683 $qemu->{$vmid} = $conf;
684 }
685 }
686
687 my $vmdata = { openvz => $openvz, qemu => $qemu };
688
689 return $vmdata;
690};
691
692sub read_vm_firewall_rules {
693 my ($vmdata) = @_;
694 my $rules = {};
695 foreach my $vmid (keys %{$vmdata->{qemu}}, keys %{$vmdata->{openvz}}) {
696 my $filename = "/etc/pve/firewall/$vmid.fw";
697 my $fh = IO::File->new($filename, O_RDONLY);
698 next if !$fh;
699
700 $rules->{$vmid} = parse_fw_rules($filename, $fh);
701 }
702
703 return $rules;
704}
705
706sub compile {
5e1267a5
DM
707 my $vmdata = read_local_vm_config();
708 my $rules = read_vm_firewall_rules($vmdata);
709
710 # print Dumper($vmdata);
711
a332200b 712 die "implement me";
b6360c3f
DM
713}
714
5e1267a5
DM
715sub compile_and_start {
716 my ($restart) = @_;
886aba9c 717
5e1267a5 718 compile();
b6360c3f 719
a332200b 720 die "implement me";
b6360c3f
DM
721}
722
b6360c3f 7231;