Commit 0cc526e0 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by David S. Miller

[IPV6]: Fix anycast usage.

- Recognition of reserved anycasts is removed from ipv6_addr_type()
  Flag IPV6_ADDR_ANYCAST is removed as well.
- Some meaningless noop code checking for anycast which are not
  going to happen is removed from ndisc.c
- ipv6_unicast_destination() replaces suboptimal ipv6_chk_acast_addr()
  in data paths
parent 2135f3fb
...@@ -45,7 +45,8 @@ extern int ip6_del_rt(struct rt6_info *, ...@@ -45,7 +45,8 @@ extern int ip6_del_rt(struct rt6_info *,
void *rtattr); void *rtattr);
extern int ip6_rt_addr_add(struct in6_addr *addr, extern int ip6_rt_addr_add(struct in6_addr *addr,
struct net_device *dev); struct net_device *dev,
int anycast);
extern int ip6_rt_addr_del(struct in6_addr *addr, extern int ip6_rt_addr_del(struct in6_addr *addr,
struct net_device *dev); struct net_device *dev);
...@@ -118,5 +119,12 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, ...@@ -118,5 +119,12 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
write_unlock(&sk->sk_dst_lock); write_unlock(&sk->sk_dst_lock);
} }
static inline int ipv6_unicast_destination(struct sk_buff *skb)
{
struct rt6_info *rt = (struct rt6_info *) skb->dst;
return rt->rt6i_flags & RTF_LOCAL;
}
#endif #endif
#endif #endif
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
/* /*
* Addr type * Addr type
* *
* type - unicast | multicast | anycast * type - unicast | multicast
* scope - local | site | global * scope - local | site | global
* v4 - compat * v4 - compat
* v4mapped * v4mapped
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
#define IPV6_ADDR_UNICAST 0x0001U #define IPV6_ADDR_UNICAST 0x0001U
#define IPV6_ADDR_MULTICAST 0x0002U #define IPV6_ADDR_MULTICAST 0x0002U
#define IPV6_ADDR_ANYCAST 0x0004U
#define IPV6_ADDR_LOOPBACK 0x0010U #define IPV6_ADDR_LOOPBACK 0x0010U
#define IPV6_ADDR_LINKLOCAL 0x0020U #define IPV6_ADDR_LINKLOCAL 0x0020U
......
...@@ -209,14 +209,7 @@ int ipv6_addr_type(const struct in6_addr *addr) ...@@ -209,14 +209,7 @@ int ipv6_addr_type(const struct in6_addr *addr)
}; };
return type; return type;
} }
/* check for reserved anycast addresses */
if ((st & htonl(0xE0000000)) &&
((addr->s6_addr32[2] == htonl(0xFDFFFFFF) &&
(addr->s6_addr32[3] | htonl(0x7F)) == (u32)~0) ||
(addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)))
type = IPV6_ADDR_ANYCAST;
else
type = IPV6_ADDR_UNICAST; type = IPV6_ADDR_UNICAST;
/* Consider all addresses with the first three bits different of /* Consider all addresses with the first three bits different of
...@@ -2552,7 +2545,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) ...@@ -2552,7 +2545,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) { switch (event) {
case RTM_NEWADDR: case RTM_NEWADDR:
ip6_rt_addr_add(&ifp->addr, ifp->idev->dev); ip6_rt_addr_add(&ifp->addr, ifp->idev->dev, 0);
break; break;
case RTM_DELADDR: case RTM_DELADDR:
addrconf_leave_solict(ifp->idev->dev, &ifp->addr); addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
......
...@@ -96,7 +96,6 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) ...@@ -96,7 +96,6 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev)
return onlink; return onlink;
} }
/* /*
* socket join an anycast group * socket join an anycast group
*/ */
...@@ -110,8 +109,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -110,8 +109,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
int ishost = !ipv6_devconf.forwarding; int ishost = !ipv6_devconf.forwarding;
int err = 0; int err = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST) if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)
return -EINVAL; return -EINVAL;
if (ipv6_chk_addr(addr, NULL))
return -EINVAL;
pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
if (pac == NULL) if (pac == NULL)
...@@ -161,21 +164,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -161,21 +164,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
* For hosts, allow link-local or matching prefix anycasts. * For hosts, allow link-local or matching prefix anycasts.
* This obviates the need for propagating anycast routes while * This obviates the need for propagating anycast routes while
* still allowing some non-router anycast participation. * still allowing some non-router anycast participation.
*
* allow anyone to join anycasts that don't require a special route
* and can't be spoofs of unicast addresses (reserved anycast only)
*/ */
if (!ip6_onlink(addr, dev)) { if (!ip6_onlink(addr, dev)) {
if (ishost) if (ishost)
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
else if (!capable(CAP_NET_ADMIN))
err = -EPERM;
if (err) if (err)
goto out_dev_put; goto out_dev_put;
} else if (!(ipv6_addr_type(addr) & IPV6_ADDR_ANYCAST) &&
!capable(CAP_NET_ADMIN)) {
err = -EPERM;
goto out_dev_put;
} }
err = ipv6_dev_ac_inc(dev, addr); err = ipv6_dev_ac_inc(dev, addr);
...@@ -266,6 +260,13 @@ void ipv6_sock_ac_close(struct sock *sk) ...@@ -266,6 +260,13 @@ void ipv6_sock_ac_close(struct sock *sk)
dev_put(dev); dev_put(dev);
} }
#if 0
/* The function is not used, which is funny. Apparently, author
* supposed to use it to filter out datagrams inside udp/raw but forgot.
*
* It is OK, anycasts are not special comparing to delivery to unicasts.
*/
int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex) int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
{ {
struct ipv6_ac_socklist *pac; struct ipv6_ac_socklist *pac;
...@@ -286,6 +287,8 @@ int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex) ...@@ -286,6 +287,8 @@ int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
return found; return found;
} }
#endif
static void aca_put(struct ifacaddr6 *ac) static void aca_put(struct ifacaddr6 *ac)
{ {
if (atomic_dec_and_test(&ac->aca_refcnt)) { if (atomic_dec_and_test(&ac->aca_refcnt)) {
...@@ -347,7 +350,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) ...@@ -347,7 +350,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
idev->ac_list = aca; idev->ac_list = aca;
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
ip6_rt_addr_add(&aca->aca_addr, dev); ip6_rt_addr_add(&aca->aca_addr, dev, 1);
addrconf_join_solict(dev, &aca->aca_addr); addrconf_join_solict(dev, &aca->aca_addr);
......
...@@ -415,8 +415,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) ...@@ -415,8 +415,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
saddr = &skb->nh.ipv6h->daddr; saddr = &skb->nh.ipv6h->daddr;
if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST || if (!ipv6_unicast_destination(skb))
ipv6_chk_acast_addr(0, saddr))
saddr = NULL; saddr = NULL;
memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
......
...@@ -785,8 +785,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -785,8 +785,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
ipv6_addr_all_nodes(&maddr); ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &ifp->addr, ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
ifp->idev->cnf.forwarding, 0, ifp->idev->cnf.forwarding, 0,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 1, 1);
1);
in6_ifa_put(ifp); in6_ifa_put(ifp);
return; return;
} }
...@@ -809,8 +808,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -809,8 +808,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
if (neigh || !dev->hard_header) { if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr, ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1, ifp->idev->cnf.forwarding, 1,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 1, 1);
1);
if (neigh) if (neigh)
neigh_release(neigh); neigh_release(neigh);
} }
......
...@@ -1261,7 +1261,7 @@ int ip6_pkt_discard(struct sk_buff *skb) ...@@ -1261,7 +1261,7 @@ int ip6_pkt_discard(struct sk_buff *skb)
* Add address * Add address
*/ */
int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev, int anycast)
{ {
struct rt6_info *rt = ip6_dst_alloc(); struct rt6_info *rt = ip6_dst_alloc();
...@@ -1280,6 +1280,8 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) ...@@ -1280,6 +1280,8 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
rt->u.dst.obsolete = -1; rt->u.dst.obsolete = -1;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
if (!anycast)
rt->rt6i_flags |= RTF_LOCAL;
rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
if (rt->rt6i_nexthop == NULL) { if (rt->rt6i_nexthop == NULL) {
dst_free((struct dst_entry *) rt); dst_free((struct dst_entry *) rt);
......
...@@ -971,7 +971,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) ...@@ -971,7 +971,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
if (th->rst) if (th->rst)
return; return;
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) if (!ipv6_unicast_destination(skb))
return; return;
/* /*
...@@ -1175,8 +1175,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1175,8 +1175,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
if (skb->protocol == htons(ETH_P_IP)) if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb); return tcp_v4_conn_request(sk, skb);
/* FIXME: do the same check for anycast */ if (!ipv6_unicast_destination(skb))
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
goto drop; goto drop;
/* /*
......
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