Commit 30bbaa19 authored by David Ahern's avatar David Ahern Committed by David S. Miller

net: Fix up inet_addr_type checks

Currently inet_addr_type and inet_dev_addr_type expect local addresses
to be in the local table. With the VRF device local routes for devices
associated with a VRF will be in the table associated with the VRF.
Provide an alternate inet_addr lookup to use a specific table rather
than defaulting to the local table.

inet_addr_type_dev_table keeps the same semantics as inet_addr_type but
if the passed in device is enslaved to a VRF then the table for that VRF
is used for the lookup.
Signed-off-by: default avatarDavid Ahern <dsa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15be405e
...@@ -192,6 +192,9 @@ unsigned int inet_addr_type(struct net *net, __be32 addr); ...@@ -192,6 +192,9 @@ unsigned int inet_addr_type(struct net *net, __be32 addr);
unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id); unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id);
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
__be32 addr); __be32 addr);
unsigned int inet_addr_type_dev_table(struct net *net,
const struct net_device *dev,
__be32 addr);
void ip_rt_multicast_event(struct in_device *); void ip_rt_multicast_event(struct in_device *);
int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg); int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
......
...@@ -119,6 +119,7 @@ ...@@ -119,6 +119,7 @@
#ifdef CONFIG_IP_MROUTE #ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h> #include <linux/mroute.h>
#endif #endif
#include <net/vrf.h>
/* The inetsw table contains everything that inet_create needs to /* The inetsw table contains everything that inet_create needs to
...@@ -427,6 +428,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -427,6 +428,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
unsigned short snum; unsigned short snum;
int chk_addr_ret; int chk_addr_ret;
int tb_id = RT_TABLE_LOCAL;
int err; int err;
/* If the socket has its own bind function then use it. (RAW) */ /* If the socket has its own bind function then use it. (RAW) */
...@@ -448,7 +450,16 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -448,7 +450,16 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out; goto out;
} }
chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr); if (sk->sk_bound_dev_if) {
struct net_device *dev;
rcu_read_lock();
dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
if (dev)
tb_id = vrf_dev_table_rcu(dev) ? : tb_id;
rcu_read_unlock();
}
chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
/* Not specified by any standard per-se, however it breaks too /* Not specified by any standard per-se, however it breaks too
* many applications when removed. It is unfortunate since * many applications when removed. It is unfortunate since
......
...@@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh) ...@@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)
return -EINVAL; return -EINVAL;
} }
neigh->type = inet_addr_type(dev_net(dev), addr); neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);
parms = in_dev->arp_parms; parms = in_dev->arp_parms;
__neigh_parms_put(neigh->parms); __neigh_parms_put(neigh->parms);
...@@ -343,7 +343,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) ...@@ -343,7 +343,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
default: default:
case 0: /* By default announce any local IP */ case 0: /* By default announce any local IP */
if (skb && inet_addr_type(dev_net(dev), if (skb && inet_addr_type_dev_table(dev_net(dev), dev,
ip_hdr(skb)->saddr) == RTN_LOCAL) ip_hdr(skb)->saddr) == RTN_LOCAL)
saddr = ip_hdr(skb)->saddr; saddr = ip_hdr(skb)->saddr;
break; break;
...@@ -351,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) ...@@ -351,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
if (!skb) if (!skb)
break; break;
saddr = ip_hdr(skb)->saddr; saddr = ip_hdr(skb)->saddr;
if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) { if (inet_addr_type_dev_table(dev_net(dev), dev,
saddr) == RTN_LOCAL) {
/* saddr should be known to target */ /* saddr should be known to target */
if (inet_addr_onlink(in_dev, target, saddr)) if (inet_addr_onlink(in_dev, target, saddr))
break; break;
...@@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) ...@@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
/* Special case: IPv4 duplicate address detection packet (RFC2131) */ /* Special case: IPv4 duplicate address detection packet (RFC2131) */
if (sip == 0) { if (sip == 0) {
if (arp->ar_op == htons(ARPOP_REQUEST) && if (arp->ar_op == htons(ARPOP_REQUEST) &&
inet_addr_type(net, tip) == RTN_LOCAL && inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
!arp_ignore(in_dev, sip, tip)) !arp_ignore(in_dev, sip, tip))
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
dev->dev_addr, sha); dev->dev_addr, sha);
...@@ -811,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb) ...@@ -811,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
n = __neigh_lookup(&arp_tbl, &sip, dev, 0); n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
if (IN_DEV_ARP_ACCEPT(in_dev)) { if (IN_DEV_ARP_ACCEPT(in_dev)) {
unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);
/* Unsolicited ARP is not accepted by default. /* Unsolicited ARP is not accepted by default.
It is possible, that this option should be enabled for some It is possible, that this option should be enabled for some
devices (strip is candidate) devices (strip is candidate)
*/ */
is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
inet_addr_type(net, sip) == RTN_UNICAST; addr_type == RTN_UNICAST;
if (!n && if (!n &&
((arp->ar_op == htons(ARPOP_REPLY) && ((arp->ar_op == htons(ARPOP_REPLY) &&
inet_addr_type(net, sip) == RTN_UNICAST) || is_garp)) addr_type == RTN_UNICAST) || is_garp))
n = __neigh_lookup(&arp_tbl, &sip, dev, 1); n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
} }
......
...@@ -260,6 +260,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, ...@@ -260,6 +260,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
} }
EXPORT_SYMBOL(inet_dev_addr_type); EXPORT_SYMBOL(inet_dev_addr_type);
/* inet_addr_type with dev == NULL but using the table from a dev
* if one is associated
*/
unsigned int inet_addr_type_dev_table(struct net *net,
const struct net_device *dev,
__be32 addr)
{
int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;
return __inet_dev_addr_type(net, NULL, addr, rt_table);
}
EXPORT_SYMBOL(inet_addr_type_dev_table);
__be32 fib_compute_spec_dst(struct sk_buff *skb) __be32 fib_compute_spec_dst(struct sk_buff *skb)
{ {
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
...@@ -510,9 +523,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt, ...@@ -510,9 +523,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
addr = sk_extract_addr(&rt->rt_gateway); addr = sk_extract_addr(&rt->rt_gateway);
if (rt->rt_gateway.sa_family == AF_INET && addr) { if (rt->rt_gateway.sa_family == AF_INET && addr) {
unsigned int addr_type;
cfg->fc_gw = addr; cfg->fc_gw = addr;
addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
if (rt->rt_flags & RTF_GATEWAY && if (rt->rt_flags & RTF_GATEWAY &&
inet_addr_type(net, addr) == RTN_UNICAST) addr_type == RTN_UNICAST)
cfg->fc_scope = RT_SCOPE_UNIVERSE; cfg->fc_scope = RT_SCOPE_UNIVERSE;
} }
...@@ -984,11 +1000,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) ...@@ -984,11 +1000,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
} }
if (!(ok & LOCAL_OK)) { if (!(ok & LOCAL_OK)) {
unsigned int addr_type;
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
/* Check, that this local address finally disappeared. */ /* Check, that this local address finally disappeared. */
if (gone && addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { ifa->ifa_local);
if (gone && addr_type != RTN_LOCAL) {
/* And the last, but not the least thing. /* And the last, but not the least thing.
* We must flush stray FIB entries. * We must flush stray FIB entries.
* *
......
...@@ -670,16 +670,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, ...@@ -670,16 +670,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
struct fib_result res; struct fib_result res;
if (nh->nh_flags & RTNH_F_ONLINK) { if (nh->nh_flags & RTNH_F_ONLINK) {
unsigned int addr_type;
if (cfg->fc_scope >= RT_SCOPE_LINK) if (cfg->fc_scope >= RT_SCOPE_LINK)
return -EINVAL; return -EINVAL;
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
return -EINVAL;
dev = __dev_get_by_index(net, nh->nh_oif); dev = __dev_get_by_index(net, nh->nh_oif);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
if (!(dev->flags & IFF_UP)) if (!(dev->flags & IFF_UP))
return -ENETDOWN; return -ENETDOWN;
addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw);
if (addr_type != RTN_UNICAST)
return -EINVAL;
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
nh->nh_flags |= RTNH_F_LINKDOWN; nh->nh_flags |= RTNH_F_LINKDOWN;
nh->nh_dev = dev; nh->nh_dev = dev;
......
...@@ -484,7 +484,8 @@ static struct rtable *icmp_route_lookup(struct net *net, ...@@ -484,7 +484,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
if (err) if (err)
goto relookup_failed; goto relookup_failed;
if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) { if (inet_addr_type_dev_table(net, skb_in->dev,
fl4_dec.saddr) == RTN_LOCAL) {
rt2 = __ip_route_output_key(net, &fl4_dec); rt2 = __ip_route_output_key(net, &fl4_dec);
if (IS_ERR(rt2)) if (IS_ERR(rt2))
err = PTR_ERR(rt2); err = PTR_ERR(rt2);
...@@ -833,7 +834,7 @@ static bool icmp_unreach(struct sk_buff *skb) ...@@ -833,7 +834,7 @@ static bool icmp_unreach(struct sk_buff *skb)
*/ */
if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n", net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
&ip_hdr(skb)->saddr, &ip_hdr(skb)->saddr,
icmph->type, icmph->code, icmph->type, icmph->code,
......
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