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