Commit e81da0e113a1b7fc7449ae6213f65f89ccac6d06

Authored by Julian Anastasov
Committed by David S. Miller
1 parent 863472454c

ipv4: fix sending of redirects

After "Cache input routes in fib_info nexthops" (commit
d2d68ba9fe) and "Elide fib_validate_source() completely when possible"
(commit 7a9bc9b81a) 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"
(commit f8126f1d51) 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>

Showing 2 changed files with 18 additions and 15 deletions Side-by-side Diff

net/ipv4/fib_frontend.c
... ... @@ -322,7 +322,8 @@
322 322 {
323 323 int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
324 324  
325   - if (!r && !fib_num_tclassid_users(dev_net(dev))) {
  325 + if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
  326 + (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
326 327 *itag = 0;
327 328 return 0;
328 329 }
... ... @@ -802,7 +802,8 @@
802 802 net = dev_net(rt->dst.dev);
803 803 peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
804 804 if (!peer) {
805   - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
  805 + icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
  806 + rt_nexthop(rt, ip_hdr(skb)->daddr));
806 807 return;
807 808 }
808 809  
... ... @@ -827,7 +828,9 @@
827 828 time_after(jiffies,
828 829 (peer->rate_last +
829 830 (ip_rt_redirect_load << peer->rate_tokens)))) {
830   - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
  831 + __be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr);
  832 +
  833 + icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw);
831 834 peer->rate_last = jiffies;
832 835 ++peer->rate_tokens;
833 836 #ifdef CONFIG_IP_ROUTE_VERBOSE
... ... @@ -835,7 +838,7 @@
835 838 peer->rate_tokens == ip_rt_redirect_number)
836 839 net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n",
837 840 &ip_hdr(skb)->saddr, inet_iif(skb),
838   - &ip_hdr(skb)->daddr, &rt->rt_gateway);
  841 + &ip_hdr(skb)->daddr, &gw);
839 842 #endif
840 843 }
841 844 out_put_peer:
842 845  
843 846  
... ... @@ -1442,10 +1445,13 @@
1442 1445 goto cleanup;
1443 1446 }
1444 1447  
1445   - if (out_dev == in_dev && err &&
  1448 + do_cache = res->fi && !itag;
  1449 + if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
1446 1450 (IN_DEV_SHARED_MEDIA(out_dev) ||
1447   - inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
  1451 + inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) {
1448 1452 flags |= RTCF_DOREDIRECT;
  1453 + do_cache = false;
  1454 + }
1449 1455  
1450 1456 if (skb->protocol != htons(ETH_P_IP)) {
1451 1457 /* Not IP (i.e. ARP). Do not create route, if it is
... ... @@ -1462,15 +1468,11 @@
1462 1468 }
1463 1469 }
1464 1470  
1465   - do_cache = false;
1466   - if (res->fi) {
1467   - if (!itag) {
1468   - rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
1469   - if (rt_cache_valid(rth)) {
1470   - skb_dst_set_noref(skb, &rth->dst);
1471   - goto out;
1472   - }
1473   - do_cache = true;
  1471 + if (do_cache) {
  1472 + rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
  1473 + if (rt_cache_valid(rth)) {
  1474 + skb_dst_set_noref(skb, &rth->dst);
  1475 + goto out;
1474 1476 }
1475 1477 }
1476 1478