This new option allow filtering of destination macs for ingress traffic. This is a protection from bad/hosting networks (like hetzner) flooding traffic with non-hosted mac.
To be fast, one rule, this use the "--among-dst mac,mac,mac,mac," syntax. broadcast mac ff:ff:ff:ff:ff:ff is always allowed currently, ebtables-restore segfault if too many are defined https://www.spinics.net/lists/netfilter/msg55995.html So, I'm using "--among-dst-file", loading macs from an external file. Note that "ebtables-save" still show the syntax with "--among-dst mac,mac,mac," (with a comma at the end), so I compile the full mac list with --among-dst to compare, and if update is needed, I'm writing the dst file in /var/lib/pve-firewall/chain-macfilter, and replace among-dst syntax by among-dst-file Changelog v2: - as we use one rule for performance, add all vms/ct macaddress when vm firewall is enabled. (even if vm macfilter option is disabled). Signed-off-by: Alexandre Derumier <[email protected]> --- src/PVE/Firewall.pm | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index edc5336..8277ee0 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -1221,6 +1221,11 @@ our $cluster_option_properties = { default => 1, optional => 1, }, + ebtables_dst_macfilter => { + description => "Filtering VM/CT destination mac for ingress traffic.", + type => 'boolean', + optional => 1, + }, policy_in => { description => "Input policy.", type => 'string', @@ -2867,7 +2872,7 @@ sub parse_clusterfw_option { if (($value > 1) && ((time() - $value) > 60)) { $value = 0 } - } elsif ($line =~ m/^(ebtables):\s*(0|1)\s*$/i) { + } elsif ($line =~ m/^(ebtables|ebtables_dst_macfilter):\s*(0|1)\s*$/i) { $opt = lc($1); $value = int($2); } elsif ($line =~ m/^(policy_(in|out)):\s*(ACCEPT|DROP|REJECT)\s*$/i) { @@ -3948,11 +3953,19 @@ sub compile_ebtables_filter { ruleset_create_chain($ruleset, "PVEFW-FORWARD"); ruleset_create_chain($ruleset, "PVEFW-FWBR-OUT"); + + if ($cluster_conf->{options}->{ebtables_dst_macfilter}) { + #filtering destination mac for ipv4/ipv6 + ruleset_create_chain($ruleset, "PVEFW-FWBR-IN"); + ruleset_addrule($ruleset, 'PVEFW-FORWARD', '-i fwln+', '-j PVEFW-FWBR-IN'); + } + #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'); + my $maclist = []; # generate firewall rules for QEMU VMs foreach my $vmid (sort keys %{$vmdata->{qemu}}) { eval { @@ -3975,7 +3988,7 @@ sub compile_ebtables_filter { push(@$arpfilter, $ip); } } - generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter); + generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter, $maclist); } }; warn $@ if $@; # just to be sure - should not happen @@ -4012,17 +4025,23 @@ sub compile_ebtables_filter { push @$arpfilter, $ip; } } - generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter); + generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter, $maclist); } }; warn $@ if $@; # just to be sure - should not happen } + if ($cluster_conf->{options}->{'ebtables_dst_macfilter'} && @$maclist > 0) { + push @$maclist, 'ff:ff:ff:ff:ff:ff'; #allow broadcast mac + my $maclist_str = join ',',sort(@$maclist); + ruleset_addrule($ruleset, 'PVEFW-FWBR-IN', "--among-dst ! $maclist_str,", '-j DROP'); + } + return $ruleset; } sub generate_tap_layer2filter { - my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter) = @_; + my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid, $arpfilter, $maclist) = @_; my $options = $vmfw_conf->{options}; my $tapchain = $iface."-OUT"; @@ -4037,6 +4056,10 @@ sub generate_tap_layer2filter { ruleset_addrule($ruleset, $tapchain, "-s ! $macaddr", '-j DROP'); } + if (defined($macaddr)) { + push @$maclist, $macaddr; + } + if (@$arpfilter){ my $arpchain = $tapchain."-ARP"; ruleset_addrule($ruleset, $tapchain, "-p ARP", "-j $arpchain"); @@ -4225,6 +4248,15 @@ sub get_ebtables_cmdlist { next if ! $pve_include; $pve_include = 0; } + + if ($cmd =~ m/^-A (\S+) --among-dst ! (\S+) -j DROP/) { + my $chain = $1; + my $maclist_raw = $2."\n"; + my $filename = "$pve_fw_status_dir/ebtables_macfilter-$chain"; + PVE::Tools::file_set_contents($filename, $maclist_raw); + $cmd = "-A $1 --among-dst-file ! $filename -j DROP"; + } + $cmdlist .= "$cmd\n"; } } -- 2.30.2 _______________________________________________ pve-devel mailing list [email protected] https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
