need ebtables-save && ebtables-restore,  ebtables debian package don't include 
them.

ebtables-restore need to restore the full ruleset (atomicaly),
so we can't update only 1 chain

Signed-off-by: Alexandre Derumier <aderum...@odiso.com>
---
 src/PVE/Firewall.pm |  103 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/pve-firewall    |    7 +++-
 2 files changed, 105 insertions(+), 5 deletions(-)

diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm
index 761d107..8325b25 100644
--- a/src/PVE/Firewall.pm
+++ b/src/PVE/Firewall.pm
@@ -1395,6 +1395,12 @@ sub ipset_restore_cmdlist {
     run_command("/usr/sbin/ipset restore", input => $cmdlist);
 }
 
+sub ebtables_restore_cmdlist {
+    my ($cmdlist) = @_;
+
+    run_command("/sbin/ebtables-restore", input => $cmdlist);
+}
+
 sub iptables_get_chains {
     my ($iptablescmd) = @_;
 
@@ -1507,6 +1513,43 @@ sub ipset_get_chains {
     return $res;
 }
 
+sub ebtables_get_chains {
+
+    my $res = {};
+    my $chains = {};
+
+    my $parser = sub {
+       my $line = shift;
+       return if $line =~ m/^#/;
+       return if $line =~ m/^\s*$/;
+       if ($line =~ m/^(?:\S+)\s(PVEFW-\S+)\s(?:\S+).*/) {
+           my $chain = $1;
+           $line =~ s/\s+$//;
+           push @{$chains->{$chain}}, $line;
+       }elsif ($line =~ m/^(?:\S+)\s(tap\d+i\d+-(:?IN|OUT))\s(?:\S+).*/) {
+           my $chain = $1;
+           $line =~ s/\s+$//;
+           push @{$chains->{$chain}}, $line;
+       }elsif ($line =~ m/^(?:\S+)\s(veth\d+.\d+-(:?IN|OUT))\s(?:\S+).*/) {
+           my $chain = $1;
+           $line =~ s/\s+$//;
+           push @{$chains->{$chain}}, $line;
+
+       }else {
+           # simply ignore the rest
+           return;
+       }
+    };
+
+    run_command("/sbin/ebtables-save", outfunc => $parser);
+
+    # compute digest for each chain
+    foreach my $chain (keys %$chains) {
+       $res->{$chain} = iptables_chain_digest($chains->{$chain});
+    }
+    return $res;
+}
+
 sub ruleset_generate_cmdstr {
     my ($ruleset, $chain, $rule, $actions, $goto, $cluster_conf, $fw_conf) = 
@_;
 
@@ -3299,7 +3342,6 @@ sub get_ruleset_cmdlist {
        my $stat = $statushash->{$chain};
        die "internal error" if !$stat;
        next if $stat->{action} ne 'create';
-
        $cmdlist .= ":$chain - [0:0]\n";
     }
 
@@ -3348,6 +3390,42 @@ sub get_ruleset_cmdlist {
     return wantarray ? ($cmdlist, $changes) : $cmdlist;
 }
 
+sub get_ebtables_cmdlist {
+    my ($ruleset, $verbose) = @_;
+
+    my $changes = 0;
+    my $cmdlist = "*filter\n";
+
+    my ($active_chains, $hooks) = ebtables_get_chains();
+    my $statushash = get_ruleset_status($ruleset, $active_chains, 
\&iptables_chain_digest, $verbose);
+
+    # create chains first
+    foreach my $chain (sort keys %$ruleset) {
+       my $stat = $statushash->{$chain};
+       die "internal error" if !$stat;
+       $cmdlist .= ":$chain ACCEPT\n";
+    }
+
+    foreach my $h (qw(FORWARD)) {
+       my $chain = "PVEFW-$h";
+       if ($ruleset->{$chain}) {
+           $cmdlist .= "-A $h -j $chain\n";
+       }
+    }
+
+    foreach my $chain (sort keys %$ruleset) {
+       my $stat = $statushash->{$chain};
+       die "internal error" if !$stat;
+       $changes = 1 if ($stat->{action} ne 'exists');
+
+       foreach my $cmd (@{$ruleset->{$chain}}) {
+           $cmdlist .= "$cmd\n";
+       }
+    }
+
+    return wantarray ? ($cmdlist, $changes) : $cmdlist;
+}
+
 sub get_ipset_cmdlist {
     my ($ruleset, $verbose) = @_;
 
@@ -3408,7 +3486,7 @@ sub get_ipset_cmdlist {
 }
 
 sub apply_ruleset {
-    my ($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6, $verbose) = @_;
+    my ($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6, $ebtables_ruleset, 
$verbose) = @_;
 
     enable_bridge_firewall();
 
@@ -3417,6 +3495,7 @@ sub apply_ruleset {
 
     my ($cmdlist, $changes) = get_ruleset_cmdlist($ruleset, $verbose);
     my ($cmdlistv6, $changesv6) = get_ruleset_cmdlist($rulesetv6, $verbose, 
"ip6tables");
+    my ($ebtables_cmdlist, $ebtables_changes) = 
get_ebtables_cmdlist($ebtables_ruleset, $verbose);
 
     if ($verbose) {
        if ($ipset_changes) {
@@ -3434,6 +3513,11 @@ sub apply_ruleset {
            print "ip6tables changes:\n";
            print $cmdlistv6;
        }
+
+       if ($ebtables_changes) {
+           print "ebtables changes:\n";
+           print $ebtables_cmdlist;
+       }
     }
 
     ipset_restore_cmdlist($ipset_create_cmdlist);
@@ -3443,6 +3527,8 @@ sub apply_ruleset {
 
     ipset_restore_cmdlist($ipset_delete_cmdlist) if $ipset_delete_cmdlist;
 
+    ebtables_restore_cmdlist($ebtables_cmdlist);
+
     # test: re-read status and check if everything is up to date
     my $active_chains = iptables_get_chains();
     my $statushash = get_ruleset_status($ruleset, $active_chains, 
\&iptables_chain_digest, 0);
@@ -3467,6 +3553,17 @@ sub apply_ruleset {
        }
     }
 
+    my $active_ebtables_chains = ebtables_get_chains();
+    my $ebtables_statushash = get_ruleset_status($ebtables_ruleset, 
$active_ebtables_chains, \&iptables_chain_digest, 0);
+
+    foreach my $chain (sort keys %$ebtables_ruleset) {
+       my $stat = $ebtables_statushash->{$chain};
+       if ($stat->{action} ne 'exists') {
+           warn "ebtables : unable to update chain '$chain'\n";
+           $errors = 1;
+       }
+    }
+
     die "unable to apply firewall changes\n" if $errors;
 
     update_nf_conntrack_max($hostfw_conf);
@@ -3568,7 +3665,7 @@ sub update {
 
        my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = 
compile($cluster_conf, $hostfw_conf);
 
-       apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6);
+       apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6, 
$ebtables_ruleset);
     };
 
     run_locked($code);
diff --git a/src/pve-firewall b/src/pve-firewall
index 8e4c68d..b239c8f 100755
--- a/src/pve-firewall
+++ b/src/pve-firewall
@@ -350,8 +350,9 @@ __PACKAGE__->register_method ({
                my (undef, undef, $ipset_changes) = 
PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
                my ($test, $ruleset_changes) = 
PVE::Firewall::get_ruleset_cmdlist($ruleset, $verbose);
                my (undef, $ruleset_changesv6) = 
PVE::Firewall::get_ruleset_cmdlist($rulesetv6, $verbose, "ip6tables");
+               my (undef, $ebtables_changes) = 
PVE::Firewall::get_ebtables_cmdlist($ebtables_ruleset, $verbose);
 
-               $res->{changes} = ($ipset_changes || $ruleset_changes || 
$ruleset_changesv6) ? 1 : 0;
+               $res->{changes} = ($ipset_changes || $ruleset_changes || 
$ruleset_changesv6 || $ebtables_changes) ? 1 : 0;
            }
 
            return $res;
@@ -386,8 +387,10 @@ __PACKAGE__->register_method ({
            my (undef, undef, $ipset_changes) = 
PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
            my (undef, $ruleset_changes) = 
PVE::Firewall::get_ruleset_cmdlist($ruleset, $verbose);
            my (undef, $ruleset_changesv6) = 
PVE::Firewall::get_ruleset_cmdlist($rulesetv6, $verbose, "ip6tables");
+            my (undef, $ebtables_changes) = 
PVE::Firewall::get_ebtables_cmdlist($ebtables_ruleset, $verbose);
 
-           if ($ipset_changes || $ruleset_changes || $ruleset_changesv6) {
+
+           if ($ipset_changes || $ruleset_changes || $ruleset_changesv6 || 
$ebtables_changes) {
                print "detected changes\n";
            } else {
                print "no changes\n";
-- 
1.7.10.4

_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to