diff options
author | Flavio Leitner <fbl@redhat.com> | 2011-10-24 02:56:38 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-29 19:34:17 -0500 |
commit | bebee22bcbf0026f92141990972bd5863ef9b69c (patch) | |
tree | 4ab20deea706db3440687055dc7a3807dc686c93 /net | |
parent | 623f1904ef55789082259573bb6248df5fea3d92 (diff) |
route: fix ICMP redirect validation
[ Upstream commit 7cc9150ebe8ec06cafea9f1c10d92ddacf88d8ae ]
The commit f39925dbde7788cfb96419c0f092b086aa325c0f
(ipv4: Cache learned redirect information in inetpeer.)
removed some ICMP packet validations which are required by
RFC 1122, section 3.2.2.2:
...
A Redirect message SHOULD be silently discarded if the new
gateway address it specifies is not on the same connected
(sub-) net through which the Redirect arrived [INTRO:2,
Appendix A], or if the source of the Redirect is not the
current first-hop gateway for the specified destination (see
Section 3.3.1).
Signed-off-by: Flavio Leitner <fbl@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/route.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 65ff2e52a14..f881be2983c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1373,7 +1373,12 @@ static void rt_del(unsigned hash, struct rtable *rt) | |||
1373 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | 1373 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, |
1374 | __be32 saddr, struct net_device *dev) | 1374 | __be32 saddr, struct net_device *dev) |
1375 | { | 1375 | { |
1376 | int s, i; | ||
1376 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 1377 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1378 | struct rtable *rt; | ||
1379 | __be32 skeys[2] = { saddr, 0 }; | ||
1380 | int ikeys[2] = { dev->ifindex, 0 }; | ||
1381 | struct flowi4 fl4; | ||
1377 | struct inet_peer *peer; | 1382 | struct inet_peer *peer; |
1378 | struct net *net; | 1383 | struct net *net; |
1379 | 1384 | ||
@@ -1396,13 +1401,34 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1396 | goto reject_redirect; | 1401 | goto reject_redirect; |
1397 | } | 1402 | } |
1398 | 1403 | ||
1399 | peer = inet_getpeer_v4(daddr, 1); | 1404 | memset(&fl4, 0, sizeof(fl4)); |
1400 | if (peer) { | 1405 | fl4.daddr = daddr; |
1401 | peer->redirect_learned.a4 = new_gw; | 1406 | for (s = 0; s < 2; s++) { |
1407 | for (i = 0; i < 2; i++) { | ||
1408 | fl4.flowi4_oif = ikeys[i]; | ||
1409 | fl4.saddr = skeys[s]; | ||
1410 | rt = __ip_route_output_key(net, &fl4); | ||
1411 | if (IS_ERR(rt)) | ||
1412 | continue; | ||
1402 | 1413 | ||
1403 | inet_putpeer(peer); | 1414 | if (rt->dst.error || rt->dst.dev != dev || |
1415 | rt->rt_gateway != old_gw) { | ||
1416 | ip_rt_put(rt); | ||
1417 | continue; | ||
1418 | } | ||
1404 | 1419 | ||
1405 | atomic_inc(&__rt_peer_genid); | 1420 | if (!rt->peer) |
1421 | rt_bind_peer(rt, rt->rt_dst, 1); | ||
1422 | |||
1423 | peer = rt->peer; | ||
1424 | if (peer) { | ||
1425 | peer->redirect_learned.a4 = new_gw; | ||
1426 | atomic_inc(&__rt_peer_genid); | ||
1427 | } | ||
1428 | |||
1429 | ip_rt_put(rt); | ||
1430 | return; | ||
1431 | } | ||
1406 | } | 1432 | } |
1407 | return; | 1433 | return; |
1408 | 1434 | ||