]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
firewall ipversion comparison fix
[pve-firewall.git] / src / PVE / Firewall.pm
index a69583bbbd95cbedac25189a92c23aec4f242ee2..83915df8728720eb9ce3177461699510a29efb71 100644 (file)
@@ -135,6 +135,12 @@ my $pve_ipv6fw_macros = {
     'Ping' => [
        { action => 'PARAM', proto => 'icmpv6', dport => 'echo-request' },
     ],
+    'NeighborDiscovery' => [
+       "IPv6 neighbor solicitation, neighbor and router advertisement",
+       { action => 'PARAM', proto => 'icmpv6', dport => 'router-advertisement' },
+       { action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-solicitation' },
+       { action => 'PARAM', proto => 'icmpv6', dport => 'neighbor-advertisement' },
+    ],
     'Trcrt' => [
        { action => 'PARAM', proto => 'udp', dport => '33434:33524' },
        { action => 'PARAM', proto => 'icmpv6', dport => 'echo-request' },
@@ -500,6 +506,7 @@ my $pve_fw_macros = {
 
 my $pve_fw_parsed_macros;
 my $pve_fw_macro_descr;
+my $pve_fw_macro_ipversion = {};
 my $pve_fw_preferred_macro_names = {};
 
 my $pve_std_chains = {};
@@ -749,14 +756,32 @@ sub init_firewall_macros {
 
     $pve_fw_parsed_macros = {};
 
-    foreach my $k (keys %$pve_fw_macros) {
+    my $parse = sub {
+       my ($k, $macro) = @_;
        my $lc_name = lc($k);
-       my $macro = $pve_fw_macros->{$k};
-       if (!ref($macro->[0])) {
-           $pve_fw_macro_descr->{$k} = shift @$macro;
+       $pve_fw_macro_ipversion->{$k} = 0;
+       while (!ref($macro->[0])) {
+           my $desc = shift @$macro;
+           if ($desc eq 'ipv4only') {
+               $pve_fw_macro_ipversion->{$k} = 4;
+           } elsif ($desc eq 'ipv6only') {
+               $pve_fw_macro_ipversion->{$k} = 6;
+           } else {
+               $pve_fw_macro_descr->{$k} = $desc;
+           }
        }
        $pve_fw_preferred_macro_names->{$lc_name} = $k;
        $pve_fw_parsed_macros->{$k} = $macro;
+    };
+
+    foreach my $k (keys %$pve_fw_macros) {
+       &$parse($k, $pve_fw_macros->{$k});
+    }
+
+    foreach my $k (keys %$pve_ipv6fw_macros) {
+       next if $pve_fw_parsed_macros->{$k};
+       &$parse($k, $pve_ipv6fw_macros->{$k});
+       $pve_fw_macro_ipversion->{$k} = 6;
     }
 }
 
@@ -874,14 +899,20 @@ sub local_network {
 
        my $testip = Net::IP->new($ip);
 
-       my $routes = PVE::ProcFSTools::read_proc_net_route();
+       my $isv6 = $testip->version == 6;
+       my $routes = $isv6 ? PVE::ProcFSTools::read_proc_net_ipv6_route()
+                          : PVE::ProcFSTools::read_proc_net_route();
        foreach my $entry (@$routes) {
-           my $mask = $ipv4_mask_hash_localnet->{$entry->{mask}};
-           next if !defined($mask);
-           return if $mask eq '0.0.0.0';
+           my $mask;
+           if ($isv6) {
+               $mask = $entry->{prefix};
+           } else {
+               $mask = $ipv4_mask_hash_localnet->{$entry->{mask}};
+               next if !defined($mask);
+           }
            my $cidr = "$entry->{dest}/$mask";
            my $testnet = Net::IP->new($cidr);
-           if ($testnet->overlaps($testip)) {
+           if ($testnet->overlaps($testip) == $Net::IP::IP_B_IN_A_OVERLAP) {
                $__local_network = $cidr;
                return;
            }
@@ -1165,6 +1196,11 @@ my $apply_macro = sub {
        $macro_rules = $pve_ipv6fw_macros->{$macro_name};
     }
 
+    # skip macros which are specific to another ipversion
+    if ($ipversion && (my $required = $pve_fw_macro_ipversion->{$macro_name})) {
+       return if $ipversion != $required;
+    }
+
     my $rules = [];
 
     foreach my $templ (@$macro_rules) {
@@ -2924,8 +2960,7 @@ sub generate_ipset_chains {
                }
                #http://backreference.org/2013/03/01/ipv6-address-normalization/
                if ($ver == 6) {
-                   my $ipv6 = inet_pton(AF_INET6, lc($cidr));
-                   $cidr = inet_ntop(AF_INET6, $ipv6);
+                   $cidr = lc(Net::IP::ip_compress_address($cidr, 6));
                    $cidr =~ s|/128$||;
                } else {
                    $cidr =~ s|/32$||;