-A FORWARD -j PVEFW-FORWARD
   -A PVEFW-FORWARD -p IPv4 -j ACCEPT  #filter mac in iptables for ipv4, so we 
can speedup rules with conntrack established
   -A PVEFW-FORWARD -p IPv6 -j ACCEPT
   -A PVEFW-FORWARD -o fwln+ -j PVEFW-FWBR-OUT
        -A PVEFW-FWBR-OUT -i tap110i0 -j tap110i0-OUT
                -A tap110i0-OUT -s ! 36:97:15:91:19:3c -j DROP
                -A tap110i0-OUT -p ARP -j ACCEPT
                -A tap110i0-OUT -j DROP
                -A tap110i0-OUT -j ACCEPT
        -A PVEFW-FWBR-OUT -i veth130.1 -j veth130.1-OUT
                -A veth130.1-OUT -s ! 36:95:a9:ae:f5:ec -j DROP
                -A veth130.1-OUT -j ACCEPT

Signed-off-by: Alexandre Derumier <aderum...@odiso.com>
---
 debian/example/100.fw |    3 ++
 src/PVE/Firewall.pm   |   99 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/pve-firewall      |    4 +-
 3 files changed, 102 insertions(+), 4 deletions(-)

diff --git a/debian/example/100.fw b/debian/example/100.fw
index 7a8da48..0388dde 100644
--- a/debian/example/100.fw
+++ b/debian/example/100.fw
@@ -9,6 +9,9 @@ enable: 1
 # disable/enable MAC address filter
 macfilter: 0
 
+# allow only layer2 specific protocols
+layer2filter_protocols: ARP,802_1Q,IPX,NetBEUI,PPP
+
 # default policy
 policy_in: DROP
 policy_out: REJECT
diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm
index 06a02ee..47c6965 100644
--- a/src/PVE/Firewall.pm
+++ b/src/PVE/Firewall.pm
@@ -2244,6 +2244,9 @@ sub parse_vmfw_option {
     } elsif ($line =~ m/^(policy_(in|out)):\s*(ACCEPT|DROP|REJECT)\s*$/i) {
        $opt = lc($1);
        $value = uc($3);
+    } elsif ($line =~ 
m/^(layer2filter_protocols):\s*(((ARP|802_1Q|IPX|NetBEUI|PPP)[,]?)+)\s*$/i) {
+       $opt = lc($1);
+       $value = $2;
     } elsif ($line =~ m/^(ips_queues):\s*((\d+)(:(\d+))?)\s*$/i) {
        $opt = lc($1);
        $value = $2;
@@ -2999,8 +3002,9 @@ sub compile {
 
     my ($ruleset, $ipset_ruleset) = compile_iptables_filter($cluster_conf, 
$hostfw_conf, $vmfw_configs, $vmdata, 4, $verbose);
     my ($rulesetv6) = compile_iptables_filter($cluster_conf, $hostfw_conf, 
$vmfw_configs, $vmdata, 6, $verbose);
+    my ($ebtables_ruleset) = compile_ebtables_filter($cluster_conf, 
$hostfw_conf, $vmfw_configs, $vmdata, $verbose);
 
-    return ($ruleset, $ipset_ruleset, $rulesetv6);
+    return ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset);
 }
 
 sub compile_iptables_filter {
@@ -3149,6 +3153,97 @@ sub compile_iptables_filter {
     return ($ruleset, $ipset_ruleset);
 }
 
+sub compile_ebtables_filter {
+    my ($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, $verbose) = @_;
+
+    return ({}, {}) if !$cluster_conf->{options}->{enable};
+
+    my $ruleset = {};
+
+    ruleset_create_chain($ruleset, "PVEFW-FORWARD");
+
+
+    ruleset_create_chain($ruleset, "PVEFW-FWBR-OUT");
+    #for ipv4 and ipv6, check macaddress in iptables, so we use conntrack 
'ESTABLISHED', to speedup rules
+    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-p IPv4 -j ACCEPT");
+    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-p IPv6 -j ACCEPT");
+    ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o fwln+ -j PVEFW-FWBR-OUT");
+
+    # generate firewall rules for QEMU VMs
+    foreach my $vmid (keys %{$vmdata->{qemu}}) {
+       eval {
+           my $conf = $vmdata->{qemu}->{$vmid};
+           my $vmfw_conf = $vmfw_configs->{$vmid};
+           return if !$vmfw_conf;
+
+           foreach my $netid (keys %$conf) {
+               next if $netid !~ m/^net(\d+)$/;
+               my $net = PVE::QemuServer::parse_net($conf->{$netid});
+               next if !$net->{firewall};
+               my $iface = "tap${vmid}i$1";
+               my $macaddr = $net->{macaddr};
+
+               generate_tap_layer2filter($ruleset, $iface, $macaddr, 
$vmfw_conf, $vmid);
+
+           }
+       };
+       warn $@ if $@; # just to be sure - should not happen
+    }
+
+    # generate firewall rules for OpenVZ containers
+    foreach my $vmid (keys %{$vmdata->{openvz}}) {
+       eval {
+           my $conf = $vmdata->{openvz}->{$vmid};
+
+           my $vmfw_conf = $vmfw_configs->{$vmid};
+           return if !$vmfw_conf;
+
+           if ($conf->{netif} && $conf->{netif}->{value}) {
+               my $netif = PVE::OpenVZ::parse_netif($conf->{netif}->{value});
+               foreach my $netid (keys %$netif) {
+                   my $d = $netif->{$netid};
+                   my $bridge = $d->{bridge};
+                   next if !$bridge || $bridge !~ m/^vmbr\d+(v(\d+))?f$/; # 
firewall enabled ?
+                   my $macaddr = $d->{mac};
+                   my $iface = $d->{host_ifname};
+
+                   generate_tap_layer2filter($ruleset, $iface, $macaddr, 
$vmfw_conf, $vmid);
+               }
+           }
+       };
+       warn $@ if $@; # just to be sure - should not happen
+    }
+
+    return $ruleset;
+}
+
+sub generate_tap_layer2filter {
+    my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid) = @_;
+    my $options = $vmfw_conf->{options};
+
+    my $tapchain = $iface."-OUT";
+
+    # ebtables remove zeros from mac pairs
+    $macaddr =~ s/0([0-9a-f])/$1/ig;
+    $macaddr = lc($macaddr);
+
+    ruleset_create_chain($ruleset, $tapchain);
+
+    if (defined($macaddr) && !(defined($options->{macfilter}) && 
$options->{macfilter} == 0)) {
+           ruleset_addrule($ruleset, $tapchain, "-s ! $macaddr -j DROP");
+    }
+
+    if (defined($options->{layer2filter_protocols})){
+       foreach my $proto (split(/,/, $options->{layer2filter_protocols})) {
+           ruleset_addrule($ruleset, $tapchain, "-p $proto -j ACCEPT");
+       }
+       ruleset_addrule($ruleset, $tapchain, "-j DROP");
+    }
+
+    ruleset_addrule($ruleset, $tapchain, "-j ACCEPT");
+    ruleset_addrule($ruleset, "PVEFW-FWBR-OUT","-i $iface -j $tapchain");
+}
+
 sub get_ruleset_status {
     my ($ruleset, $active_chains, $digest_fn, $verbose) = @_;
 
@@ -3498,7 +3593,7 @@ sub update {
 
        my $hostfw_conf = load_hostfw_conf();
 
-       my ($ruleset, $ipset_ruleset, $rulesetv6) = compile($cluster_conf, 
$hostfw_conf);
+       my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = 
compile($cluster_conf, $hostfw_conf);
 
        apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6);
     };
diff --git a/src/pve-firewall b/src/pve-firewall
index 6e5eb16..8e4c68d 100755
--- a/src/pve-firewall
+++ b/src/pve-firewall
@@ -344,7 +344,7 @@ __PACKAGE__->register_method ({
 
            if ($status eq 'running') {
                
-               my ($ruleset, $ipset_ruleset, $rulesetv6) = 
PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
+               my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = 
PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
 
                $verbose = 0; # do not show iptables details
                my (undef, undef, $ipset_changes) = 
PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
@@ -381,7 +381,7 @@ __PACKAGE__->register_method ({
            my $verbose = 1;
 
            my $cluster_conf = PVE::Firewall::load_clusterfw_conf(undef, 
$verbose); 
-           my ($ruleset, $ipset_ruleset, $rulesetv6) = 
PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
+           my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = 
PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
 
            my (undef, undef, $ipset_changes) = 
PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
            my (undef, $ruleset_changes) = 
PVE::Firewall::get_ruleset_cmdlist($ruleset, $verbose);
-- 
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