aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2012-10-08 07:41:15 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-08 17:42:35 -0400
commite81da0e113a1b7fc7449ae6213f65f89ccac6d06 (patch)
tree3d5bb2401d12017decf57263936784aa809e524a /net
parent863472454ce50d4ef0929c6aa738cc5d64b84679 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_frontend.c3
-rw-r--r--net/ipv4/route.c30
2 files changed, 18 insertions, 15 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 68c93d1bb03a..825c608826de 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -322,7 +322,8 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
322{ 322{
323 int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); 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 *itag = 0; 327 *itag = 0;
327 return 0; 328 return 0;
328 } 329 }
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 132e0dfee53a..b90da1bc2704 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -802,7 +802,8 @@ void ip_rt_send_redirect(struct sk_buff *skb)
802 net = dev_net(rt->dst.dev); 802 net = dev_net(rt->dst.dev);
803 peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1); 803 peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
804 if (!peer) { 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 return; 807 return;
807 } 808 }
808 809
@@ -827,7 +828,9 @@ void ip_rt_send_redirect(struct sk_buff *skb)
827 time_after(jiffies, 828 time_after(jiffies,
828 (peer->rate_last + 829 (peer->rate_last +
829 (ip_rt_redirect_load << peer->rate_tokens)))) { 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 peer->rate_last = jiffies; 834 peer->rate_last = jiffies;
832 ++peer->rate_tokens; 835 ++peer->rate_tokens;
833#ifdef CONFIG_IP_ROUTE_VERBOSE 836#ifdef CONFIG_IP_ROUTE_VERBOSE
@@ -835,7 +838,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
835 peer->rate_tokens == ip_rt_redirect_number) 838 peer->rate_tokens == ip_rt_redirect_number)
836 net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n", 839 net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n",
837 &ip_hdr(skb)->saddr, inet_iif(skb), 840 &ip_hdr(skb)->saddr, inet_iif(skb),
838 &ip_hdr(skb)->daddr, &rt->rt_gateway); 841 &ip_hdr(skb)->daddr, &gw);
839#endif 842#endif
840 } 843 }
841out_put_peer: 844out_put_peer:
@@ -1442,10 +1445,13 @@ static int __mkroute_input(struct sk_buff *skb,
1442 goto cleanup; 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 (IN_DEV_SHARED_MEDIA(out_dev) || 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 flags |= RTCF_DOREDIRECT; 1452 flags |= RTCF_DOREDIRECT;
1453 do_cache = false;
1454 }
1449 1455
1450 if (skb->protocol != htons(ETH_P_IP)) { 1456 if (skb->protocol != htons(ETH_P_IP)) {
1451 /* Not IP (i.e. ARP). Do not create route, if it is 1457 /* Not IP (i.e. ARP). Do not create route, if it is
@@ -1462,15 +1468,11 @@ static int __mkroute_input(struct sk_buff *skb,
1462 } 1468 }
1463 } 1469 }
1464 1470
1465 do_cache = false; 1471 if (do_cache) {
1466 if (res->fi) { 1472 rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
1467 if (!itag) { 1473 if (rt_cache_valid(rth)) {
1468 rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input); 1474 skb_dst_set_noref(skb, &rth->dst);
1469 if (rt_cache_valid(rth)) { 1475 goto out;
1470 skb_dst_set_noref(skb, &rth->dst);
1471 goto out;
1472 }
1473 do_cache = true;
1474 } 1476 }
1475 } 1477 }
1476 1478