diff options
author | Stephen Suryaputra <ssuryaextr@gmail.com> | 2019-06-26 02:21:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-26 15:40:10 -0400 |
commit | 5b18f1289808fee5d04a7e6ecf200189f41a4db6 (patch) | |
tree | c4f8ffda52e1fa30489d1eae8c7f4066c0fc2df6 | |
parent | ee4297420d56a0033a8593e80b33fcc93fda8509 (diff) |
ipv4: reset rt_iif for recirculated mcast/bcast out pkts
Multicast or broadcast egress packets have rt_iif set to the oif. These
packets might be recirculated back as input and lookup to the raw
sockets may fail because they are bound to the incoming interface
(skb_iif). If rt_iif is not zero, during the lookup, inet_iif() function
returns rt_iif instead of skb_iif. Hence, the lookup fails.
v2: Make it non vrf specific (David Ahern). Reword the changelog to
reflect it.
Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/route.h | 1 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 12 | ||||
-rw-r--r-- | net/ipv4/route.c | 33 |
3 files changed, 46 insertions, 0 deletions
diff --git a/include/net/route.h b/include/net/route.h index 065b47754f05..55ff71ffb796 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -221,6 +221,7 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); | |||
221 | struct rtable *rt_dst_alloc(struct net_device *dev, | 221 | struct rtable *rt_dst_alloc(struct net_device *dev, |
222 | unsigned int flags, u16 type, | 222 | unsigned int flags, u16 type, |
223 | bool nopolicy, bool noxfrm, bool will_cache); | 223 | bool nopolicy, bool noxfrm, bool will_cache); |
224 | struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); | ||
224 | 225 | ||
225 | struct in_ifaddr; | 226 | struct in_ifaddr; |
226 | void fib_add_ifaddr(struct in_ifaddr *); | 227 | void fib_add_ifaddr(struct in_ifaddr *); |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 16f9159234a2..8c2ec35b6512 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -318,6 +318,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk | |||
318 | static int ip_mc_finish_output(struct net *net, struct sock *sk, | 318 | static int ip_mc_finish_output(struct net *net, struct sock *sk, |
319 | struct sk_buff *skb) | 319 | struct sk_buff *skb) |
320 | { | 320 | { |
321 | struct rtable *new_rt; | ||
321 | int ret; | 322 | int ret; |
322 | 323 | ||
323 | ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); | 324 | ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); |
@@ -326,6 +327,17 @@ static int ip_mc_finish_output(struct net *net, struct sock *sk, | |||
326 | return ret; | 327 | return ret; |
327 | } | 328 | } |
328 | 329 | ||
330 | /* Reset rt_iif so that inet_iif() will return skb->skb_iif. Setting | ||
331 | * this to non-zero causes ipi_ifindex in in_pktinfo to be overwritten, | ||
332 | * see ipv4_pktinfo_prepare(). | ||
333 | */ | ||
334 | new_rt = rt_dst_clone(net->loopback_dev, skb_rtable(skb)); | ||
335 | if (new_rt) { | ||
336 | new_rt->rt_iif = 0; | ||
337 | skb_dst_drop(skb); | ||
338 | skb_dst_set(skb, &new_rt->dst); | ||
339 | } | ||
340 | |||
329 | return dev_loopback_xmit(net, sk, skb); | 341 | return dev_loopback_xmit(net, sk, skb); |
330 | } | 342 | } |
331 | 343 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6cb7cff22db9..8ea0735a6754 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1647,6 +1647,39 @@ struct rtable *rt_dst_alloc(struct net_device *dev, | |||
1647 | } | 1647 | } |
1648 | EXPORT_SYMBOL(rt_dst_alloc); | 1648 | EXPORT_SYMBOL(rt_dst_alloc); |
1649 | 1649 | ||
1650 | struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt) | ||
1651 | { | ||
1652 | struct rtable *new_rt; | ||
1653 | |||
1654 | new_rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK, | ||
1655 | rt->dst.flags); | ||
1656 | |||
1657 | if (new_rt) { | ||
1658 | new_rt->rt_genid = rt_genid_ipv4(dev_net(dev)); | ||
1659 | new_rt->rt_flags = rt->rt_flags; | ||
1660 | new_rt->rt_type = rt->rt_type; | ||
1661 | new_rt->rt_is_input = rt->rt_is_input; | ||
1662 | new_rt->rt_iif = rt->rt_iif; | ||
1663 | new_rt->rt_pmtu = rt->rt_pmtu; | ||
1664 | new_rt->rt_mtu_locked = rt->rt_mtu_locked; | ||
1665 | new_rt->rt_gw_family = rt->rt_gw_family; | ||
1666 | if (rt->rt_gw_family == AF_INET) | ||
1667 | new_rt->rt_gw4 = rt->rt_gw4; | ||
1668 | else if (rt->rt_gw_family == AF_INET6) | ||
1669 | new_rt->rt_gw6 = rt->rt_gw6; | ||
1670 | INIT_LIST_HEAD(&new_rt->rt_uncached); | ||
1671 | |||
1672 | new_rt->dst.flags |= DST_HOST; | ||
1673 | new_rt->dst.input = rt->dst.input; | ||
1674 | new_rt->dst.output = rt->dst.output; | ||
1675 | new_rt->dst.error = rt->dst.error; | ||
1676 | new_rt->dst.lastuse = jiffies; | ||
1677 | new_rt->dst.lwtstate = lwtstate_get(rt->dst.lwtstate); | ||
1678 | } | ||
1679 | return new_rt; | ||
1680 | } | ||
1681 | EXPORT_SYMBOL(rt_dst_clone); | ||
1682 | |||
1650 | /* called in rcu_read_lock() section */ | 1683 | /* called in rcu_read_lock() section */ |
1651 | int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, | 1684 | int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, |
1652 | u8 tos, struct net_device *dev, | 1685 | u8 tos, struct net_device *dev, |