[PATCH] IPv6: fixes to proxy Neighbor discovery

From: Ville Nuorvala (vnuorval@morphine.tml.hut.fi)
Date: Fri Jan 24 2003 - 03:38:06 EST


Hello!

This patch contains some fixes to proxy Neighbor Discovery.

1) Source address fixed in neigbor advertisements:

RFC 2461
4.4. Neighbor Advertisement Message Format
" Source Address
                     An address assigned to the interface from which the
                     advertisement is sent."

This also applies to proxy Neighbor Adverisements.

2) Proxy protects against Duplicate Address Detection:

RFC 2461
7.2.3. Receipt of Neighbor Solicitations
" A valid Neighbor Solicitation that does not meet any the following
   requirements MUST be silently discarded:

    - The Target Address is a "valid" unicast or anycast address
      assigned to the receiving interface [ADDRCONF],

    - The Target Address is a unicast address for which the node is
      offering proxy service, or

    - The Target Address is a "tentative" address on which Duplicate
      Address Detection is being performed [ADDRCONF].

   If the Target Address is tentative, the Neighbor Solicitation should
   be processed as described in [ADDRCONF]. Otherwise, the following
   description applies. If the Source Address is not the unspecified
   address and, on link layers that have addresses, the solicitation
   includes a Source Link-Layer Address option, then the recipient
   SHOULD create or update the Neighbor Cache entry for the IP Source
   Address of the solicitation."
   ....
" If the Source Address is the unspecified address the node MUST NOT
   create or update the Neighbor Cache entry.

   After any updates to the Neighbor Cache, the node sends a Neighbor
   Advertisement response as described in the next section."

This clearly means the proxy should protect the address against DAD.

Below are patches against both the 2.4 and 2.5 bk trees.

Thanks,
Ville

===== net/ipv6/ndisc.c 1.16 vs edited =====
--- 1.16/net/ipv6/ndisc.c Sat Dec 21 09:43:20 2002
+++ edited/net/ipv6/ndisc.c Fri Jan 24 10:14:33 2003
@@ -23,6 +23,7 @@
  * and moved to net/core.
  * Pekka Savola : RFC2461 validation
  * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
+ * Ville Nuorvala : RFC2461 fixes to proxy ND
  */

 /* Set to 3 to get tracing... */
@@ -370,8 +371,9 @@
  */

 void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
- struct in6_addr *daddr, struct in6_addr *solicited_addr,
- int router, int solicited, int override, int inc_opt)
+ struct in6_addr *daddr, struct in6_addr *saddr,
+ struct in6_addr *solicited_addr, int router,
+ int solicited, int override, int inc_opt)
 {
         struct sock *sk = ndisc_socket->sk;
         struct nd_msg *msg;
@@ -401,7 +403,7 @@
                 return;
         }

- ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+ ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);

         msg = (struct nd_msg *) skb_put(skb, len);

@@ -421,7 +423,7 @@
                 ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);

         /* checksum */
- msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len,
+ msg->icmph.icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
                                                  IPPROTO_ICMPV6,
                                                  csum_partial((__u8 *) msg,
                                                               len, 0));
@@ -669,8 +671,8 @@
                         struct in6_addr maddr;

                         ipv6_addr_all_nodes(&maddr);
- ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
- ifp->idev->cnf.forwarding, 0,
+ ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
+ &ifp->addr, ifp->idev->cnf.forwarding, 0,
                                       ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
                                       1);
                         in6_ifa_put(ifp);
@@ -693,7 +695,8 @@
                         neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);

                         if (neigh || !dev->hard_header) {
- ndisc_send_na(dev, neigh, saddr, &ifp->addr,
+ ndisc_send_na(dev, neigh, saddr,
+ &ifp->addr, &ifp->addr,
                                               ifp->idev->cnf.forwarding, 1,
                                               ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
                                               1);
@@ -707,7 +710,8 @@
                 int addr_type = ipv6_addr_type(saddr);

                 if (in6_dev && in6_dev->cnf.forwarding &&
- (addr_type & IPV6_ADDR_UNICAST) &&
+ (addr_type & IPV6_ADDR_UNICAST ||
+ addr_type == IPV6_ADDR_ANY) &&
                     pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
                         int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;

@@ -715,17 +719,38 @@
                             skb->pkt_type == PACKET_HOST ||
                             inc == 0 ||
                             in6_dev->nd_parms->proxy_delay == 0) {
+ struct in6_addr na_saddr;
+
                                 if (inc)
                                         nd_tbl.stats.rcv_probes_mcast++;
                                 else
                                         nd_tbl.stats.rcv_probes_ucast++;
-
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);

- if (neigh) {
- ndisc_send_na(dev, neigh, saddr, &msg->target,
- 0, 1, 0, 1);
- neigh_release(neigh);
+ /*
+ * RFC2461 4.4:
+ * The souce address is always an address assigned to the interface,
+ * this also applies to proxies
+ */
+ if (ipv6_get_lladdr(dev, &na_saddr)) {
+ in6_dev_put(in6_dev);
+ return;
+ }
+ if (addr_type & IPV6_ADDR_UNICAST) {
+ neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+
+ if (neigh) {
+ ndisc_send_na(dev, neigh, saddr,
+ &na_saddr, &msg->target,
+ 0, 1, 0, 1);
+ neigh_release(neigh);
+ }
+ } else {
+ /* the proxy should also protect against DAD */
+ struct in6_addr maddr;
+ ipv6_addr_all_nodes(&maddr);
+ ndisc_send_na(dev, NULL, &maddr,
+ &na_saddr, &msg->target,
+ 0, 0, 0, 1);
                                 }
                         } else {
                                 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);

===== net/ipv6/ndisc.c 1.21 vs edited =====
--- 1.21/net/ipv6/ndisc.c Sat Dec 21 09:14:32 2002
+++ edited/net/ipv6/ndisc.c Fri Jan 24 10:17:18 2003
@@ -23,6 +23,7 @@
  * and moved to net/core.
  * Pekka Savola : RFC2461 validation
  * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
+ * Ville Nuorvala : RFC2461 fixes to proxy ND
  */

 /* Set to 3 to get tracing... */
@@ -375,8 +376,9 @@
  */

 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
- struct in6_addr *daddr, struct in6_addr *solicited_addr,
- int router, int solicited, int override, int inc_opt)
+ struct in6_addr *daddr, struct in6_addr *saddr,
+ struct in6_addr *solicited_addr, int router,
+ int solicited, int override, int inc_opt)
 {
         struct sock *sk = ndisc_socket->sk;
         struct nd_msg *msg;
@@ -406,7 +408,7 @@
                 return;
         }

- ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+ ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);

         msg = (struct nd_msg *) skb_put(skb, len);

@@ -426,7 +428,7 @@
                 ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);

         /* checksum */
- msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len,
+ msg->icmph.icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
                                                  IPPROTO_ICMPV6,
                                                  csum_partial((__u8 *) msg,
                                                               len, 0));
@@ -674,8 +676,8 @@
                         struct in6_addr maddr;

                         ipv6_addr_all_nodes(&maddr);
- ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
- ifp->idev->cnf.forwarding, 0,
+ ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
+ &ifp->addr, ifp->idev->cnf.forwarding, 0,
                                       ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
                                       1);
                         in6_ifa_put(ifp);
@@ -698,7 +700,8 @@
                         neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);

                         if (neigh || !dev->hard_header) {
- ndisc_send_na(dev, neigh, saddr, &ifp->addr,
+ ndisc_send_na(dev, neigh, saddr,
+ &ifp->addr, &ifp->addr,
                                               ifp->idev->cnf.forwarding, 1,
                                               ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
                                               1);
@@ -712,7 +715,8 @@
                 int addr_type = ipv6_addr_type(saddr);

                 if (in6_dev && in6_dev->cnf.forwarding &&
- (addr_type & IPV6_ADDR_UNICAST) &&
+ (addr_type & IPV6_ADDR_UNICAST ||
+ addr_type == IPV6_ADDR_ANY) &&
                     pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
                         int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;

@@ -720,17 +724,38 @@
                             skb->pkt_type == PACKET_HOST ||
                             inc == 0 ||
                             in6_dev->nd_parms->proxy_delay == 0) {
+ struct in6_addr na_saddr;
+
                                 if (inc)
                                         nd_tbl.stats.rcv_probes_mcast++;
                                 else
                                         nd_tbl.stats.rcv_probes_ucast++;
-
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);

- if (neigh) {
- ndisc_send_na(dev, neigh, saddr, &msg->target,
- 0, 1, 0, 1);
- neigh_release(neigh);
+ /*
+ * RFC2461 4.4:
+ * The souce address is always an address assigned to the interface,
+ * this also applies to proxies
+ */
+ if (ipv6_get_lladdr(dev, &na_saddr)) {
+ in6_dev_put(in6_dev);
+ return;
+ }
+ if (addr_type & IPV6_ADDR_UNICAST) {
+ neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+
+ if (neigh) {
+ ndisc_send_na(dev, neigh, saddr,
+ &na_saddr, &msg->target,
+ 0, 1, 0, 1);
+ neigh_release(neigh);
+ }
+ } else {
+ /* the proxy should also protect against DAD */
+ struct in6_addr maddr;
+ ipv6_addr_all_nodes(&maddr);
+ ndisc_send_na(dev, NULL, &maddr,
+ &na_saddr, &msg->target,
+ 0, 0, 0, 1);
                                 }
                         } else {
                                 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);

--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tml.hut.fi, phone: +358 (0)9 451 5257

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jan 31 2003 - 22:00:11 EST