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