mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
ipv4: fix sending of redirects
After "Cache input routes in fib_info nexthops" (commitd2d68ba9fe
) and "Elide fib_validate_source() completely when possible" (commit7a9bc9b81a
) we can not send ICMP redirects. It seems we should not cache the RTCF_DOREDIRECT flag in nh_rth_input because the same fib_info can be used for traffic that is not redirected, eg. from other input devices or from sources that are not in same subnet. As result, we have to disable the caching of RTCF_DOREDIRECT flag and to force source validation for the case when forwarding traffic to the input device. If traffic comes from directly connected source we allow redirection as it was done before both changes. Avoid setting RTCF_DOREDIRECT if IN_DEV_TX_REDIRECTS is disabled, this can avoid source address validation and to help caching the routes. After the change "Adjust semantics of rt->rt_gateway" (commitf8126f1d51
) we should make sure our ICMP_REDIR_HOST messages contain daddr instead of 0.0.0.0 when target is directly connected. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
863472454c
commit
e81da0e113
@ -322,7 +322,8 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
|
||||
{
|
||||
int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
|
||||
|
||||
if (!r && !fib_num_tclassid_users(dev_net(dev))) {
|
||||
if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
|
||||
(dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
|
||||
*itag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -802,7 +802,8 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
net = dev_net(rt->dst.dev);
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
|
||||
if (!peer) {
|
||||
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
|
||||
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
|
||||
rt_nexthop(rt, ip_hdr(skb)->daddr));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -827,7 +828,9 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
time_after(jiffies,
|
||||
(peer->rate_last +
|
||||
(ip_rt_redirect_load << peer->rate_tokens)))) {
|
||||
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
|
||||
__be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr);
|
||||
|
||||
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw);
|
||||
peer->rate_last = jiffies;
|
||||
++peer->rate_tokens;
|
||||
#ifdef CONFIG_IP_ROUTE_VERBOSE
|
||||
@ -835,7 +838,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
peer->rate_tokens == ip_rt_redirect_number)
|
||||
net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n",
|
||||
&ip_hdr(skb)->saddr, inet_iif(skb),
|
||||
&ip_hdr(skb)->daddr, &rt->rt_gateway);
|
||||
&ip_hdr(skb)->daddr, &gw);
|
||||
#endif
|
||||
}
|
||||
out_put_peer:
|
||||
@ -1442,10 +1445,13 @@ static int __mkroute_input(struct sk_buff *skb,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (out_dev == in_dev && err &&
|
||||
do_cache = res->fi && !itag;
|
||||
if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
|
||||
(IN_DEV_SHARED_MEDIA(out_dev) ||
|
||||
inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
|
||||
inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) {
|
||||
flags |= RTCF_DOREDIRECT;
|
||||
do_cache = false;
|
||||
}
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IP)) {
|
||||
/* Not IP (i.e. ARP). Do not create route, if it is
|
||||
@ -1462,16 +1468,12 @@ static int __mkroute_input(struct sk_buff *skb,
|
||||
}
|
||||
}
|
||||
|
||||
do_cache = false;
|
||||
if (res->fi) {
|
||||
if (!itag) {
|
||||
if (do_cache) {
|
||||
rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
|
||||
if (rt_cache_valid(rth)) {
|
||||
skb_dst_set_noref(skb, &rth->dst);
|
||||
goto out;
|
||||
}
|
||||
do_cache = true;
|
||||
}
|
||||
}
|
||||
|
||||
rth = rt_dst_alloc(out_dev->dev,
|
||||
|
Loading…
Reference in New Issue
Block a user