]> git.hungrycats.org Git - linux/commitdiff
[IPV6]: Add and use new 'strict' parameter to ip6_chk_addr().
authorVille Nuorvala <vnourval@tcs.hut.fi>
Wed, 21 Jan 2004 14:38:52 +0000 (06:38 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 21 Jan 2004 14:38:52 +0000 (06:38 -0800)
RFC 2461 requires that the source address of Neighbor Discovery messages
is an address assigned to the sending interface.

Duplicate Address Detection should also be interface specific. We don't,
for example, want a node to DoS itself just because it has two interfaces
on the same link and both happen to listen to the same multicast group. If
there is a true duplicate on the link, the interface doing DAD will notice
it anyway.

The attached patch adds a 'strict' parameter to ip6_chk_addr() and
ip6_get_ifaddr() to allow link-local protocols like ND and DAD to do
strict address checks even on addresses with greater scope than
link-local.

include/net/addrconf.h
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/anycast.c
net/ipv6/datagram.c
net/ipv6/icmp.c
net/ipv6/ip6_tunnel.c
net/ipv6/ndisc.c
net/ipv6/raw.c
net/sctp/ipv6.c

index 92cbb7794cac926ad2dd47e3d8810392f3a55a21..bdc0973b0070b7a6c20cb64da92be7a010148629 100644 (file)
@@ -57,9 +57,11 @@ extern int                   addrconf_del_ifaddr(void *arg);
 extern int                     addrconf_set_dstaddr(void *arg);
 
 extern int                     ipv6_chk_addr(struct in6_addr *addr,
-                                             struct net_device *dev);
+                                             struct net_device *dev,
+                                             int strict);
 extern struct inet6_ifaddr *   ipv6_get_ifaddr(struct in6_addr *addr,
-                                               struct net_device *dev);
+                                               struct net_device *dev,
+                                               int strict);
 extern int                     ipv6_get_saddr(struct dst_entry *dst, 
                                               struct in6_addr *daddr,
                                               struct in6_addr *saddr);
index 4b9135da6e3354934f5969ff292625aa278ffd65..de4a1da22ae7fb57522c786d24fec0952b0007e6 100644 (file)
@@ -910,7 +910,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
        return cnt;
 }
 
-int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev)
+int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict)
 {
        struct inet6_ifaddr * ifp;
        u8 hash = ipv6_addr_hash(addr);
@@ -920,7 +920,7 @@ int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev)
                if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
                    !(ifp->flags&IFA_F_TENTATIVE)) {
                        if (dev == NULL || ifp->idev->dev == dev ||
-                           !(ifp->scope&(IFA_LINK|IFA_HOST)))
+                           !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))
                                break;
                }
        }
@@ -945,7 +945,7 @@ int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
        return ifp != NULL;
 }
 
-struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev)
+struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev, int strict)
 {
        struct inet6_ifaddr * ifp;
        u8 hash = ipv6_addr_hash(addr);
@@ -954,7 +954,7 @@ struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *
        for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
                if (ipv6_addr_cmp(&ifp->addr, addr) == 0) {
                        if (dev == NULL || ifp->idev->dev == dev ||
-                           !(ifp->scope&(IFA_LINK|IFA_HOST))) {
+                           !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) {
                                in6_ifa_hold(ifp);
                                break;
                        }
@@ -1393,7 +1393,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 
 ok:
 
-               ifp = ipv6_get_ifaddr(&addr, dev);
+               ifp = ipv6_get_ifaddr(&addr, dev, 1);
 
                if (ifp == NULL && valid_lft) {
                        int max_addresses = in6_dev->cnf.max_addresses;
@@ -2952,7 +2952,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                        if (!ipv6_addr_any(&addr))
                                ipv6_dev_ac_dec(ifp->idev->dev, &addr);
                }
-               if (!ipv6_chk_addr(&ifp->addr, NULL))
+               if (!ipv6_chk_addr(&ifp->addr, ifp->idev->dev, 1))
                        ip6_rt_addr_del(&ifp->addr, ifp->idev->dev);
                break;
        }
index 4bde99b2257e1cd22c541046e11bcb9160467a83..54e85a0ab2dba2eb77a2a43a7e13074534de31a4 100644 (file)
@@ -355,7 +355,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                         */
                        v4addr = LOOPBACK4_IPV6;
                        if (!(addr_type & IPV6_ADDR_MULTICAST)) {
-                               if (!ipv6_chk_addr(&addr->sin6_addr, dev)) {
+                               if (!ipv6_chk_addr(&addr->sin6_addr, dev, 0)) {
                                        if (dev)
                                                dev_put(dev);
                                        err = -EADDRNOTAVAIL;
index fc10df7d327d09eaa41db6276c5d9561ee535afe..291be6d3ac164e21078918f876ab486a71be9c4a 100644 (file)
@@ -113,7 +113,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
                return -EPERM;
        if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)
                return -EINVAL;
-       if (ipv6_chk_addr(addr, NULL))
+       if (ipv6_chk_addr(addr, NULL, 0))
                return -EINVAL;
 
        pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
index 57192b5abf566bd398ff3bccfeeb89bc3ec75d4e..a32e0b5d9c82ff779a830e042d867f60ec68ee3e 100644 (file)
@@ -307,7 +307,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                                                return -ENODEV;
                                }
                        }
-                       if (!ipv6_chk_addr(&src_info->ipi6_addr, dev)) {
+                       if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
                                if (dev)
                                        dev_put(dev);
                                err = -EINVAL;
index 933917fa10ff3e60e6a4d86070dc11fb0b73e6a3..09e101c8e46d7dc34d59e2b10b730d089773056c 100644 (file)
@@ -298,7 +298,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         */
        addr_type = ipv6_addr_type(&hdr->daddr);
 
-       if (ipv6_chk_addr(&hdr->daddr, skb->dev))
+       if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0))
                saddr = &hdr->daddr;
 
        /*
index 7f02c1901e9dcf213bee27bb0e29d3eb579602ff..4568118d688182ac48a30bbc4bf0c0e46d37326d 100644 (file)
@@ -777,10 +777,10 @@ static void ip6_tnl_set_cap(struct ip6_tnl *t)
                if (p->link)
                        ldev = dev_get_by_index(p->link);
                
-               if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
+               if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(laddr, ldev, 0))
                        l_ok = 0;
                
-               if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
+               if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(raddr, NULL, 0))
                        r_ok = 0;
                
                if (l_ok && r_ok) {
index f725744e6d485f575b715dfb062edb042a77d643..28f0d59645fbc0285bd9d217c66d4cfb56ae5cd1 100644 (file)
@@ -434,7 +434,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
        len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
        /* for anycast or proxy, solicited_addr != src_addr */
-       ifp = ipv6_get_ifaddr(solicited_addr, dev);
+       ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
        if (ifp) {
                src_addr = solicited_addr;
                in6_ifa_put(ifp);
@@ -680,7 +680,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
        struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
        int probes = atomic_read(&neigh->probes);
 
-       if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev))
+       if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1))
                saddr = &skb->nh.ipv6h->saddr;
 
        if ((probes -= neigh->parms->ucast_probes) < 0) {
@@ -758,7 +758,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                }
        }
 
-       if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
+       if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
                if (ifp->flags & IFA_F_TENTATIVE) {
                        /* Address is tentative. If the source
                           is unspecified address, it is someone
@@ -955,7 +955,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
                        return;
                }
        }
-       if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
+       if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1))) {
                if (ifp->flags & IFA_F_TENTATIVE) {
                        addrconf_dad_failure(ifp);
                        return;
index 4f61e8da6bd0c5e447d33efc916771b6bd8a70c3..78b599a352405e81257ff7ca11a73791c49bebbd 100644 (file)
@@ -227,7 +227,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                v4addr = LOOPBACK4_IPV6;
                if (!(addr_type & IPV6_ADDR_MULTICAST)) {
                        err = -EADDRNOTAVAIL;
-                       if (!ipv6_chk_addr(&addr->sin6_addr, dev)) {
+                       if (!ipv6_chk_addr(&addr->sin6_addr, dev, 0)) {
                                if (dev)
                                        dev_put(dev);
                                goto out;
index 32ec1d5176ff9d44417bd4c21bebf43376299db2..ae2be090ad1168dd9c4700d3f32ad5c5f95224be 100644 (file)
@@ -510,7 +510,7 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp)
        if (!(type & IPV6_ADDR_UNICAST))
                return 0;
 
-       return ipv6_chk_addr(in6, NULL);
+       return ipv6_chk_addr(in6, NULL, 0);
 }
 
 /* This function checks if the address is a valid address to be used for