]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
fix 901: encode unicode characters in sha digest
[pve-firewall.git] / src / PVE / Firewall.pm
index 8976bad5f3a5d3234d399193be4f55b46a5c256c..22d823f90fed82511d3589a8a5eb7498f6abf786 100644 (file)
@@ -138,10 +138,14 @@ my $pve_ipv6fw_macros = {
     ],
     'NeighborDiscovery' => [
        "IPv6 neighbor solicitation, neighbor and router advertisement",
+       { action => 'PARAM', proto => 'icmpv6', dport => 'router-solicitation' },
        { action => 'PARAM', proto => 'icmpv6', dport => 'router-advertisement' },
        { action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-solicitation' },
        { action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-advertisement' },
     ],
+    'DHCPv6' => [
+       { action => 'PARAM', proto => 'udp', dport => '546:547', sport => '546:547' },
+    ],
     'Trcrt' => [
        { action => 'PARAM', proto => 'udp', dport => '33434:33524' },
        { action => 'PARAM', proto => 'icmpv6', dport => 'echo-request' },
@@ -1089,7 +1093,10 @@ sub copy_list_with_digest {
            next if !defined($v);
            $data->{$k} = $v;
            # Note: digest ignores refs ($rule->{errors})
-           $sha->add($k, ':', $v, "\n") if !ref($v); ;
+           # since Digest::SHA expects a series of bytes,
+           #  we have to encode the value here to prevent errors when
+           #  using utf8 characters (eg. in comments)
+           $sha->add($k, ':', encode_utf8($v), "\n") if !ref($v); ;
        }
        push @$res, $data;
     }
@@ -1866,6 +1873,18 @@ sub ruleset_add_chain_policy {
     }
 }
 
+sub ruleset_chain_add_ndp {
+    my ($ruleset, $chain, $ipversion, $options, $direction) = @_;
+    return if $ipversion != 6 || (defined($options->{ndp}) && !$options->{ndp});
+
+    ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type router-solicitation -j ACCEPT");
+    if ($direction ne 'OUT' || $options->{radv}) {
+       ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type router-advertisement -j ACCEPT");
+    }
+    ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT");
+    ruleset_addrule($ruleset, $chain, "-p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT");
+}
+
 sub ruleset_chain_add_conn_filters {
     my ($ruleset, $chain, $accept) = @_;
 
@@ -1904,21 +1923,39 @@ sub ruleset_create_vm_chain {
     my $accept = generate_nfqueue($options);
 
     if (!(defined($options->{dhcp}) && $options->{dhcp} == 0)) {
-       if ($direction eq 'OUT') {
-           ruleset_generate_rule($ruleset, $chain, $ipversion, 
-                                 { action => 'PVEFW-SET-ACCEPT-MARK',
-                                   proto => 'udp', sport => 68, dport => 67 });
-       } else {
-           ruleset_generate_rule($ruleset, $chain, $ipversion,
-                                 { action => 'ACCEPT',
-                                   proto => 'udp', sport => 67, dport => 68 });
+       if ($ipversion == 4) {
+           if ($direction eq 'OUT') {
+               ruleset_generate_rule($ruleset, $chain, $ipversion, 
+                                     { action => 'PVEFW-SET-ACCEPT-MARK',
+                                       proto => 'udp', sport => 68, dport => 67 });
+           } else {
+               ruleset_generate_rule($ruleset, $chain, $ipversion,
+                                     { action => 'ACCEPT',
+                                       proto => 'udp', sport => 67, dport => 68 });
+           }
+       } elsif ($ipversion == 6) {
+           if ($direction eq 'OUT') {
+               ruleset_generate_rule($ruleset, $chain, $ipversion,
+                                     { action => 'PVEFW-SET-ACCEPT-MARK',
+                                       proto => 'udp', sport => 546, dport => 547 });
+           } else {
+               ruleset_generate_rule($ruleset, $chain, $ipversion,
+                                     { action => 'ACCEPT',
+                                       proto => 'udp', sport => 547, dport => 546 });
+           }
        }
+
     }
 
+    ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options, $direction);
+
     if ($direction eq 'OUT') {
        if (defined($macaddr) && !(defined($options->{macfilter}) && $options->{macfilter} == 0)) {
            ruleset_addrule($ruleset, $chain, "-m mac ! --mac-source $macaddr -j DROP");
        }
+       if ($ipversion == 6 && !$options->{radv}) {
+           ruleset_addrule($ruleset, $chain, '-p icmpv6 --icmpv6-type router-advertisement -j DROP');
+       }
        if ($ipfilter_ipset) {
            ruleset_addrule($ruleset, $chain, "-m set ! --match-set $ipfilter_ipset src -j DROP");
        }
@@ -2079,6 +2116,7 @@ sub enable_host_firewall {
 
     ruleset_addrule($ruleset, $chain, "-i lo -j ACCEPT");
 
+    ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options);
     ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
     ruleset_chain_add_input_filters($ruleset, $chain, $ipversion, $options, $cluster_conf, $loglevel);
 
@@ -2137,6 +2175,7 @@ sub enable_host_firewall {
 
     ruleset_addrule($ruleset, $chain, "-o lo -j ACCEPT");
 
+    ruleset_chain_add_ndp($ruleset, $chain, $ipversion, $options);
     ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
 
     # we use RETURN because we may want to check other thigs later
@@ -2311,7 +2350,7 @@ sub parse_vmfw_option {
 
     my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
 
-    if ($line =~ m/^(enable|dhcp|macfilter|ips):\s*(0|1)\s*$/i) {
+    if ($line =~ m/^(enable|dhcp|ndp|radv|macfilter|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) {
@@ -2337,7 +2376,7 @@ sub parse_hostfw_option {
 
     my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
 
-    if ($line =~ m/^(enable|nosmurfs|tcpflags):\s*(0|1)\s*$/i) {
+    if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp):\s*(0|1)\s*$/i) {
        $opt = lc($1);
        $value = int($2);
     } elsif ($line =~ m/^(log_level_in|log_level_out|tcp_flags_log_level|smurf_log_level):\s*(($loglevels)\s*)?$/i) {
@@ -2815,10 +2854,13 @@ sub save_vmfw_conf {
        $raw .= "\n";
     }
 
-    mkdir $pvefw_conf_dir;
-
     my $filename = "$pvefw_conf_dir/$vmid.fw";
-    PVE::Tools::file_set_contents($filename, $raw);
+    if ($raw) {
+       mkdir $pvefw_conf_dir;
+       PVE::Tools::file_set_contents($filename, $raw);
+    } else {
+       unlink $filename;
+    }
 }
 
 sub remove_vmfw_conf {
@@ -3040,8 +3082,12 @@ sub save_clusterfw_conf {
        }
     }
 
-    mkdir $pvefw_conf_dir;
-    PVE::Tools::file_set_contents($clusterfw_conf_filename, $raw);
+    if ($raw) {
+       mkdir $pvefw_conf_dir;
+       PVE::Tools::file_set_contents($clusterfw_conf_filename, $raw);
+    } else {
+       unlink $clusterfw_conf_filename;
+    }
 }
 
 sub load_hostfw_conf {
@@ -3071,7 +3117,11 @@ sub save_hostfw_conf {
        $raw .= "\n";
     }
 
-    PVE::Tools::file_set_contents($hostfw_conf_filename, $raw);
+    if ($raw) {
+       PVE::Tools::file_set_contents($hostfw_conf_filename, $raw);
+    } else {
+       unlink $hostfw_conf_filename;
+    }
 }
 
 sub compile {