]> git.proxmox.com Git - pve-firewall.git/commitdiff
added the 'ipfilter' option
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 2 Mar 2016 11:59:14 +0000 (12:59 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 3 Mar 2016 08:41:49 +0000 (09:41 +0100)
This effectively acts like adding an emtpy 'ipfilter-netX'
ipset for every firewall-enabled interface.

src/PVE/API2/Firewall/VM.pm
src/PVE/Firewall.pm

index aad973bb33e2fe9bedeb886845d995be9725935f..192737a4c06c027a2f14b8bc7c4df537115eb36a 100644 (file)
@@ -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<id> 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',
index 1479d3b55873a6dccd646b54cb1b005d25119686..73ae6f7011c8f66bab4619c34d7b1fb752f9a191 100644 (file)
@@ -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;
 }