From 74601077c1456791bd0a19f07fa4f852a5c91b8a Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 2 Mar 2016 12:59:14 +0100 Subject: [PATCH] added the 'ipfilter' option This effectively acts like adding an emtpy 'ipfilter-netX' ipset for every firewall-enabled interface. --- src/PVE/API2/Firewall/VM.pm | 9 ++++++++ src/PVE/Firewall.pm | 42 ++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/PVE/API2/Firewall/VM.pm b/src/PVE/API2/Firewall/VM.pm index aad973b..192737a 100644 --- a/src/PVE/API2/Firewall/VM.pm +++ b/src/PVE/API2/Firewall/VM.pm @@ -38,6 +38,15 @@ my $option_properties = { type => 'boolean', optional => 1, }, + ipfilter => { + description => "Enable default IP filters. " . + "This is equivalent to adding an empty ipfilter-net ipset " . + "for every interface. Such ipsets implicitly contain sane default " . + "restrictions such as restricting IPv6 link local addresses to " . + "the one derived from the interface's MAC address.", + type => 'boolean', + optional => 1, + }, policy_in => { description => "Input policy.", type => 'string', diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 1479d3b..73ae6f7 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -2073,7 +2073,7 @@ sub generate_tap_rules_direction { my $ipfilter_name = compute_ipfilter_ipset_name($netid); my $ipfilter_ipset = compute_ipset_chain_name($vmid, $ipfilter_name, $ipversion) - if $vmfw_conf->{ipset}->{$ipfilter_name}; + if $options->{ipfilter} || $vmfw_conf->{ipset}->{$ipfilter_name}; # create chain with mac and ip filter ruleset_create_vm_chain($ruleset, $tapchain, $ipversion, $options, $macaddr, $ipfilter_ipset, $direction); @@ -2360,7 +2360,7 @@ sub parse_vmfw_option { my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog"; - if ($line =~ m/^(enable|dhcp|ndp|radv|macfilter|ips):\s*(0|1)\s*$/i) { + if ($line =~ m/^(enable|dhcp|ndp|radv|macfilter|ipfilter|ips):\s*(0|1)\s*$/i) { $opt = lc($1); $value = int($2); } elsif ($line =~ m/^(log_level_in|log_level_out):\s*(($loglevels)\s*)?$/i) { @@ -2972,11 +2972,11 @@ sub generate_std_chains { } sub generate_ipset_chains { - my ($ipset_ruleset, $clusterfw_conf, $fw_conf, $device_ips) = @_; #fixme + my ($ipset_ruleset, $clusterfw_conf, $fw_conf, $device_ips, $ipsets) = @_; - foreach my $ipset (keys %{$fw_conf->{ipset}}) { + foreach my $ipset (keys %{$ipsets}) { - my $options = $fw_conf->{ipset}->{$ipset}; + my $options = $ipsets->{$ipset}; if ($device_ips && $ipset =~ /^ipfilter-(net\d+)$/) { if (my $ips = $device_ips->{$1}) { @@ -3314,12 +3314,24 @@ sub compile_ipsets { my $vmfw_conf = $vmfw_configs->{$vmid}; return if !$vmfw_conf; + # When the 'ipfilter' option is enabled every device for which there + # is no 'ipfilter-netX' ipset defiend gets an implicit empty default + # ipset. + # The reason is that ipfilter ipsets are always filled with standard + # IPv6 link-local filters. + my $ipsets = $vmfw_conf->{ipset}; + my $implicit_sets = {}; + my $device_ips = {}; foreach my $netid (keys %$conf) { next if $netid !~ m/^net(\d+)$/; my $net = PVE::QemuServer::parse_net($conf->{$netid}); next if !$net->{firewall}; + if ($vmfw_conf->{options}->{ipfilter} && !$ipsets->{"ipfilter-$netid"}) { + $implicit_sets->{"ipfilter-$netid"} = []; + } + my $macaddr = $net->{macaddr}; my $linklocal = mac_to_linklocal($macaddr); $device_ips->{$netid} = [ @@ -3328,7 +3340,8 @@ sub compile_ipsets { ]; } - generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips); + generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips, $ipsets); + generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips, $implicit_sets); }; warn $@ if $@; # just to be sure - should not happen } @@ -3340,12 +3353,24 @@ sub compile_ipsets { my $vmfw_conf = $vmfw_configs->{$vmid}; return if !$vmfw_conf; + # When the 'ipfilter' option is enabled every device for which there + # is no 'ipfilter-netX' ipset defiend gets an implicit empty default + # ipset. + # The reason is that ipfilter ipsets are always filled with standard + # IPv6 link-local filters. + my $ipsets = $vmfw_conf->{ipset}; + my $implicit_sets = {}; + my $device_ips = {}; foreach my $netid (keys %$conf) { next if $netid !~ m/^net(\d+)$/; my $net = PVE::LXC::parse_lxc_network($conf->{$netid}); next if !$net->{firewall}; + if ($vmfw_conf->{options}->{ipfilter} && !$ipsets->{"ipfilter-$netid"}) { + $implicit_sets->{"ipfilter-$netid"} = []; + } + my $macaddr = $net->{hwaddr}; my $linklocal = mac_to_linklocal($macaddr); $device_ips->{$netid} = [ @@ -3354,12 +3379,13 @@ sub compile_ipsets { ]; } - generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips); + generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips, $ipsets); + generate_ipset_chains($ipset_ruleset, $cluster_conf, $vmfw_conf, $device_ips, $implicit_sets); }; warn $@ if $@; # just to be sure - should not happen } - generate_ipset_chains($ipset_ruleset, undef, $cluster_conf, undef); + generate_ipset_chains($ipset_ruleset, undef, $cluster_conf, undef, $cluster_conf->{ipset}); return $ipset_ruleset; } -- 2.39.2