Commit bf0b48df authored by Brian Haley's avatar Brian Haley Committed by David S. Miller

[IPv6]: Fix ICMPv6 redirect handling with target multicast address

When the ICMPv6 Target address is multicast, Linux processes the 
redirect instead of dropping it.  The problem is in this code in 
ndisc_redirect_rcv():

         if (ipv6_addr_equal(dest, target)) {
                 on_link = 1;
         } else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
                 ND_PRINTK2(KERN_WARNING
                            "ICMPv6 Redirect: target address is not 
link-local.\n");
                 return;
         }

This second check will succeed if the Target address is, for example, 
FF02::1 because it has link-local scope.  Instead, it should be checking 
if it's a unicast link-local address, as stated in RFC 2461/4861 Section 
8.1:

       - The ICMP Target Address is either a link-local address (when
         redirected to a router) or the same as the ICMP Destination
         Address (when redirected to the on-link destination).

I know this doesn't explicitly say unicast link-local address, but it's 
implied.

This bug is preventing Linux kernels from achieving IPv6 Logo Phase II 
certification because of a recent error that was found in the TAHI test 
suite - Neighbor Disovery suite test 206 (v6LC.2.3.6_G) had the 
multicast address in the Destination field instead of Target field, so 
we were passing the test.  This won't be the case anymore.

The patch below fixes this problem, and also fixes ndisc_send_redirect() 
to not send an invalid redirect with a multicast address in the Target 
field.  I re-ran the TAHI Neighbor Discovery section to make sure Linux 
passes all 245 tests now.
Signed-off-by: default avatarBrian Haley <brian.haley@hp.com>
Acked-by: default avatarDavid L Stevens <dlstevens@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bf1b803b
...@@ -1268,9 +1268,10 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) ...@@ -1268,9 +1268,10 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
if (ipv6_addr_equal(dest, target)) { if (ipv6_addr_equal(dest, target)) {
on_link = 1; on_link = 1;
} else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) { } else if (ipv6_addr_type(target) !=
(IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
ND_PRINTK2(KERN_WARNING ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: target address is not link-local.\n"); "ICMPv6 Redirect: target address is not link-local unicast.\n");
return; return;
} }
...@@ -1344,9 +1345,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1344,9 +1345,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
} }
if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) && if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) { ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
ND_PRINTK2(KERN_WARNING ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: target address is not link-local.\n"); "ICMPv6 Redirect: target address is not link-local unicast.\n");
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment