diff options
author | Flavio Leitner <fbl@redhat.com> | 2011-10-24 02:56:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-24 02:56:38 -0400 |
commit | 7cc9150ebe8ec06cafea9f1c10d92ddacf88d8ae (patch) | |
tree | 0820f1a9de3a2b1a81913550056518c21950e7f8 /net/ipv4/route.c | |
parent | da92b194cc36b5dc1fbd85206aeeffd80bee0c39 (diff) |
route: fix ICMP redirect validation
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>
Diffstat (limited to 'net/ipv4/route.c')
-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 075212e41b83..41557e2bb56e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1309,7 +1309,12 @@ static void rt_del(unsigned hash, struct rtable *rt) | |||
1309 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | 1309 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, |
1310 | __be32 saddr, struct net_device *dev) | 1310 | __be32 saddr, struct net_device *dev) |
1311 | { | 1311 | { |
1312 | int s, i; | ||
1312 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 1313 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1314 | struct rtable *rt; | ||
1315 | __be32 skeys[2] = { saddr, 0 }; | ||
1316 | int ikeys[2] = { dev->ifindex, 0 }; | ||
1317 | struct flowi4 fl4; | ||
1313 | struct inet_peer *peer; | 1318 | struct inet_peer *peer; |
1314 | struct net *net; | 1319 | struct net *net; |
1315 | 1320 | ||
@@ -1332,13 +1337,34 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1332 | goto reject_redirect; | 1337 | goto reject_redirect; |
1333 | } | 1338 | } |
1334 | 1339 | ||
1335 | peer = inet_getpeer_v4(daddr, 1); | 1340 | memset(&fl4, 0, sizeof(fl4)); |
1336 | if (peer) { | 1341 | fl4.daddr = daddr; |
1337 | peer->redirect_learned.a4 = new_gw; | 1342 | for (s = 0; s < 2; s++) { |
1343 | for (i = 0; i < 2; i++) { | ||
1344 | fl4.flowi4_oif = ikeys[i]; | ||
1345 | fl4.saddr = skeys[s]; | ||
1346 | rt = __ip_route_output_key(net, &fl4); | ||
1347 | if (IS_ERR(rt)) | ||
1348 | continue; | ||
1338 | 1349 | ||
1339 | inet_putpeer(peer); | 1350 | if (rt->dst.error || rt->dst.dev != dev || |
1351 | rt->rt_gateway != old_gw) { | ||
1352 | ip_rt_put(rt); | ||
1353 | continue; | ||
1354 | } | ||
1340 | 1355 | ||
1341 | atomic_inc(&__rt_peer_genid); | 1356 | if (!rt->peer) |
1357 | rt_bind_peer(rt, rt->rt_dst, 1); | ||
1358 | |||
1359 | peer = rt->peer; | ||
1360 | if (peer) { | ||
1361 | peer->redirect_learned.a4 = new_gw; | ||
1362 | atomic_inc(&__rt_peer_genid); | ||
1363 | } | ||
1364 | |||
1365 | ip_rt_put(rt); | ||
1366 | return; | ||
1367 | } | ||
1342 | } | 1368 | } |
1343 | return; | 1369 | return; |
1344 | 1370 | ||