Skip to content

Commit 30bbaa1

Browse files
David Aherndavem330
authored andcommitted
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: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 15be405 commit 30bbaa1

File tree

6 files changed

+53
-14
lines changed

6 files changed

+53
-14
lines changed

include/net/route.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ unsigned int inet_addr_type(struct net *net, __be32 addr);
192192
unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id);
193193
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
194194
__be32 addr);
195+
unsigned int inet_addr_type_dev_table(struct net *net,
196+
const struct net_device *dev,
197+
__be32 addr);
195198
void ip_rt_multicast_event(struct in_device *);
196199
int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
197200
void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);

net/ipv4/af_inet.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
#ifdef CONFIG_IP_MROUTE
120120
#include <linux/mroute.h>
121121
#endif
122+
#include <net/vrf.h>
122123

123124

124125
/* 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)
427428
struct net *net = sock_net(sk);
428429
unsigned short snum;
429430
int chk_addr_ret;
431+
int tb_id = RT_TABLE_LOCAL;
430432
int err;
431433

432434
/* 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)
448450
goto out;
449451
}
450452

451-
chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
453+
if (sk->sk_bound_dev_if) {
454+
struct net_device *dev;
455+
456+
rcu_read_lock();
457+
dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
458+
if (dev)
459+
tb_id = vrf_dev_table_rcu(dev) ? : tb_id;
460+
rcu_read_unlock();
461+
}
462+
chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
452463

453464
/* Not specified by any standard per-se, however it breaks too
454465
* many applications when removed. It is unfortunate since

net/ipv4/arp.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)
233233
return -EINVAL;
234234
}
235235

236-
neigh->type = inet_addr_type(dev_net(dev), addr);
236+
neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);
237237

238238
parms = in_dev->arp_parms;
239239
__neigh_parms_put(neigh->parms);
@@ -343,15 +343,16 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
343343
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
344344
default:
345345
case 0: /* By default announce any local IP */
346-
if (skb && inet_addr_type(dev_net(dev),
346+
if (skb && inet_addr_type_dev_table(dev_net(dev), dev,
347347
ip_hdr(skb)->saddr) == RTN_LOCAL)
348348
saddr = ip_hdr(skb)->saddr;
349349
break;
350350
case 1: /* Restrict announcements of saddr in same subnet */
351351
if (!skb)
352352
break;
353353
saddr = ip_hdr(skb)->saddr;
354-
if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) {
354+
if (inet_addr_type_dev_table(dev_net(dev), dev,
355+
saddr) == RTN_LOCAL) {
355356
/* saddr should be known to target */
356357
if (inet_addr_onlink(in_dev, target, saddr))
357358
break;
@@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
751752
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
752753
if (sip == 0) {
753754
if (arp->ar_op == htons(ARPOP_REQUEST) &&
754-
inet_addr_type(net, tip) == RTN_LOCAL &&
755+
inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
755756
!arp_ignore(in_dev, sip, tip))
756757
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
757758
dev->dev_addr, sha);
@@ -811,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
811812
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
812813

813814
if (IN_DEV_ARP_ACCEPT(in_dev)) {
815+
unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);
816+
814817
/* Unsolicited ARP is not accepted by default.
815818
It is possible, that this option should be enabled for some
816819
devices (strip is candidate)
817820
*/
818821
is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
819-
inet_addr_type(net, sip) == RTN_UNICAST;
822+
addr_type == RTN_UNICAST;
820823

821824
if (!n &&
822825
((arp->ar_op == htons(ARPOP_REPLY) &&
823-
inet_addr_type(net, sip) == RTN_UNICAST) || is_garp))
826+
addr_type == RTN_UNICAST) || is_garp))
824827
n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
825828
}
826829

net/ipv4/fib_frontend.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
260260
}
261261
EXPORT_SYMBOL(inet_dev_addr_type);
262262

263+
/* inet_addr_type with dev == NULL but using the table from a dev
264+
* if one is associated
265+
*/
266+
unsigned int inet_addr_type_dev_table(struct net *net,
267+
const struct net_device *dev,
268+
__be32 addr)
269+
{
270+
int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;
271+
272+
return __inet_dev_addr_type(net, NULL, addr, rt_table);
273+
}
274+
EXPORT_SYMBOL(inet_addr_type_dev_table);
275+
263276
__be32 fib_compute_spec_dst(struct sk_buff *skb)
264277
{
265278
struct net_device *dev = skb->dev;
@@ -510,9 +523,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
510523

511524
addr = sk_extract_addr(&rt->rt_gateway);
512525
if (rt->rt_gateway.sa_family == AF_INET && addr) {
526+
unsigned int addr_type;
527+
513528
cfg->fc_gw = addr;
529+
addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
514530
if (rt->rt_flags & RTF_GATEWAY &&
515-
inet_addr_type(net, addr) == RTN_UNICAST)
531+
addr_type == RTN_UNICAST)
516532
cfg->fc_scope = RT_SCOPE_UNIVERSE;
517533
}
518534

@@ -984,11 +1000,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
9841000
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
9851001
}
9861002
if (!(ok & LOCAL_OK)) {
1003+
unsigned int addr_type;
1004+
9871005
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
9881006

9891007
/* Check, that this local address finally disappeared. */
990-
if (gone &&
991-
inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
1008+
addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
1009+
ifa->ifa_local);
1010+
if (gone && addr_type != RTN_LOCAL) {
9921011
/* And the last, but not the least thing.
9931012
* We must flush stray FIB entries.
9941013
*

net/ipv4/fib_semantics.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,16 +670,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
670670
struct fib_result res;
671671

672672
if (nh->nh_flags & RTNH_F_ONLINK) {
673+
unsigned int addr_type;
673674

674675
if (cfg->fc_scope >= RT_SCOPE_LINK)
675676
return -EINVAL;
676-
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
677-
return -EINVAL;
678677
dev = __dev_get_by_index(net, nh->nh_oif);
679678
if (!dev)
680679
return -ENODEV;
681680
if (!(dev->flags & IFF_UP))
682681
return -ENETDOWN;
682+
addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw);
683+
if (addr_type != RTN_UNICAST)
684+
return -EINVAL;
683685
if (!netif_carrier_ok(dev))
684686
nh->nh_flags |= RTNH_F_LINKDOWN;
685687
nh->nh_dev = dev;

net/ipv4/icmp.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
484484
if (err)
485485
goto relookup_failed;
486486

487-
if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) {
487+
if (inet_addr_type_dev_table(net, skb_in->dev,
488+
fl4_dec.saddr) == RTN_LOCAL) {
488489
rt2 = __ip_route_output_key(net, &fl4_dec);
489490
if (IS_ERR(rt2))
490491
err = PTR_ERR(rt2);
@@ -833,7 +834,7 @@ static bool icmp_unreach(struct sk_buff *skb)
833834
*/
834835

835836
if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
836-
inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
837+
inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
837838
net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
838839
&ip_hdr(skb)->saddr,
839840
icmph->type, icmph->code,

0 commit comments

Comments
 (0)