+ my $res = {};
+
+ my $fh = IO::File->new ($filename, "r");
+ return $res if !$fh;
+
+ my $int_to_quad = sub {
+ return join '.' => map { ($_[0] >> 8*(3-$_)) % 256 } (3, 2, 1, 0);
+ };
+
+ while (defined(my $line = <$fh>)) {
+ next if $line =~/^Iface\s+Destination/; # skip head
+ my ($iface, $dest, $gateway, $metric, $mask, $mtu) = (split(/\s+/, $line))[0,1,2,6,7,8];
+ push @{$res->{$iface}}, {
+ dest => &$int_to_quad(hex($dest)),
+ gateway => &$int_to_quad(hex($gateway)),
+ mask => &$int_to_quad(hex($mask)),
+ metric => $metric,
+ mtu => $mtu,
+ };
+ }
+
+ return $res;
+}
+
+sub load_clusterfw_conf {
+
+ my $cluster_conf = {};
+ if (my $fh = IO::File->new($clusterfw_conf_filename, O_RDONLY)) {
+ $cluster_conf = parse_cluster_fw_rules($clusterfw_conf_filename, $fh);
+ }
+
+ return $cluster_conf;
+}
+
+my $rules_to_conf = sub {
+ my ($rules, $need_iface) = @_;
+
+ my $raw = '';
+
+ foreach my $rule (@$rules) {
+ if ($rule->{type} eq 'in' || $rule->{type} eq 'out') {
+ $raw .= '|' if defined($rule->{enable}) && !$rule->{enable};
+ $raw .= uc($rule->{type});
+ $raw .= " " . $rule->{action};
+ $raw .= " " . ($rule->{iface} || '-') if $need_iface;
+ $raw .= " " . ($rule->{source} || '-');
+ $raw .= " " . ($rule->{dest} || '-');
+ $raw .= " " . ($rule->{proto} || '-');
+ $raw .= " " . ($rule->{dport} || '-');
+ $raw .= " " . ($rule->{sport} || '-');
+ $raw .= " # " . encode('utf8', $rule->{comment})
+ if $rule->{comment} && $rule->{comment} !~ m/^\s*$/;
+ $raw .= "\n";
+ } else {
+ die "implement me '$rule->{type}'";
+ }
+ }
+
+ return $raw;
+};
+
+sub save_clusterfw_conf {
+ my ($cluster_conf) = @_;
+
+ my $raw = '';
+
+ my $options = $cluster_conf->{options};
+ if (scalar(keys %$options)) {
+ $raw .= "[OPTIONS]\n\n";
+ foreach my $opt (keys %$options) {
+ $raw .= "$opt: $options->{$opt}\n";
+ }
+ $raw .= "\n";
+ }
+
+ # fixme: save ipset
+
+ my $rules = $cluster_conf->{rules};
+ if (scalar(@$rules)) {
+ $raw .= "[RULES]\n\n";
+ $raw .= &$rules_to_conf($rules, 1);
+ $raw .= "\n";
+ }
+
+ foreach my $group (sort keys %{$cluster_conf->{groups}}) {
+ my $rules = $cluster_conf->{groups}->{$group};
+ $raw .= "[group $group]\n\n";
+ $raw .= &$rules_to_conf($rules, 0);
+ $raw .= "\n";
+ }
+
+ PVE::Tools::file_set_contents($clusterfw_conf_filename, $raw);
+}
+
+sub load_hostfw_conf {
+
+ my $hostfw_conf = {};
+ my $filename = "/etc/pve/local/host.fw";