use warnings;
use strict;
use Data::Dumper;
-use Digest::MD5;
+use Digest::SHA;
use PVE::Tools;
use PVE::QemuServer;
use File::Path;
return ($nbports);
}
+my $bridge_firewall_enabled = 0;
+
+sub enable_bridge_firewall {
+
+ return if $bridge_firewall_enabled; # only once
+
+ system("echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables");
+ system("echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables");
+
+ $bridge_firewall_enabled = 1;
+}
+
my $rule_format = "%-15s %-30s %-30s %-15s %-15s %-15s\n";
sub iptables {
my $chain = $1;
return if !&$is_pvefw_chain($chain);
$res->{$chain} = "unknown";
- } elsif ($line =~ m/^-A\s+(\S+)\s.*--log-prefix\s+\"PVESIG:(\S+)\"/) {
+ } elsif ($line =~ m/^-A\s+(\S+)\s.*--comment\s+\"PVESIG:(\S+)\"/) {
my ($chain, $sig) = ($1, $2);
return if !&$is_pvefw_chain($chain);
$res->{$chain} = $sig;
}
sub generate_tap_rules_direction {
- my ($ruleset, $iface, $netid, $rules, $bridge, $direction) = @_;
+ my ($ruleset, $iface, $netid, $macaddr, $rules, $bridge, $direction) = @_;
my $tapchain = "$iface-$direction";
ruleset_addrule($ruleset, $tapchain, "-m state --state INVALID -j DROP");
ruleset_addrule($ruleset, $tapchain, "-m state --state RELATED,ESTABLISHED -j ACCEPT");
+ if ($direction eq 'OUT' && defined($macaddr)) {
+ ruleset_addrule($ruleset, $tapchain, "-m mac ! --mac-source $macaddr -j DROP");
+ }
+
if ($rules) {
foreach my $rule (@$rules) {
next if $rule->{iface} && $rule->{iface} ne $netid;
ruleset_addrule($ruleset, $chain, "-j DROP");
# host outbound firewall
- my $chain = "PVEFW-HOST-OUT";
+ $chain = "PVEFW-HOST-OUT";
ruleset_create_chain($ruleset, $chain);
ruleset_addrule($ruleset, $chain, "-m state --state INVALID -j DROP");
generate_bridge_chains($ruleset, $bridge);
- generate_tap_rules_direction($ruleset, $iface, $netid, $rules->{$vmid}->{in}, $bridge, 'IN');
- generate_tap_rules_direction($ruleset, $iface, $netid, $rules->{$vmid}->{out}, $bridge, 'OUT');
+ my $macaddr = $net->{macaddr};
+ generate_tap_rules_direction($ruleset, $iface, $netid, $macaddr, $rules->{$vmid}->{in}, $bridge, 'IN');
+ generate_tap_rules_direction($ruleset, $iface, $netid, $macaddr, $rules->{$vmid}->{out}, $bridge, 'OUT');
}
}
return $ruleset;
my $statushash = {};
foreach my $chain (sort keys %$ruleset) {
- my $digest = Digest::MD5->new();
+ my $digest = Digest::SHA->new('sha1');
foreach my $cmd (@{$ruleset->{$chain}}) {
$digest->add("$cmd\n");
}
sub print_sig_rule {
my ($chain, $sig) = @_;
- # Note: This rule should never match! We just use this hack to store a SHA1 checksum
- # used to detect changes
- return "-A $chain -j LOG --log-prefix \"PVESIG:$sig\" -p tcp -s \"127.128.129.130\" --dport 1\n";
+ # We just use this to store a SHA1 checksum used to detect changes
+ return "-A $chain -m comment --comment \"PVESIG:$sig\"\n";
}
-sub compile_and_start {
- my ($verbose) = @_;
+sub apply_ruleset {
+ my ($ruleset, $verbose) = @_;
- my $ruleset = compile();
+ enable_bridge_firewall();
my $cmdlist = "*filter\n"; # we pass this to iptables-restore;