diff options
author | David S. Miller <davem@davemloft.net> | 2012-07-11 23:55:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-11 23:55:47 -0400 |
commit | e47a185b31dd2acd424fac7dc0efb96fc5b31a33 (patch) | |
tree | 31947f03e2600b8fd73a9afd391a69c218234f03 /net/ipv4/route.c | |
parent | 94206125c4aac32e43c25bfe1b827e7ab993b7dc (diff) |
ipv4: Generalize ip_do_redirect() and hook into new dst_ops->redirect.
All of the redirect acceptance policy is now contained within.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 94 |
1 files changed, 54 insertions, 40 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f8921b448c39..f3d25656ddb0 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -149,6 +149,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst); | |||
149 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); | 149 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); |
150 | static void ipv4_link_failure(struct sk_buff *skb); | 150 | static void ipv4_link_failure(struct sk_buff *skb); |
151 | static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | 151 | static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); |
152 | static void ip_do_redirect(struct dst_entry *dst, struct sk_buff *skb); | ||
152 | static int rt_garbage_collect(struct dst_ops *ops); | 153 | static int rt_garbage_collect(struct dst_ops *ops); |
153 | 154 | ||
154 | static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 155 | static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -179,6 +180,7 @@ static struct dst_ops ipv4_dst_ops = { | |||
179 | .negative_advice = ipv4_negative_advice, | 180 | .negative_advice = ipv4_negative_advice, |
180 | .link_failure = ipv4_link_failure, | 181 | .link_failure = ipv4_link_failure, |
181 | .update_pmtu = ip_rt_update_pmtu, | 182 | .update_pmtu = ip_rt_update_pmtu, |
183 | .redirect = ip_do_redirect, | ||
182 | .local_out = __ip_local_out, | 184 | .local_out = __ip_local_out, |
183 | .neigh_lookup = ipv4_neigh_lookup, | 185 | .neigh_lookup = ipv4_neigh_lookup, |
184 | }; | 186 | }; |
@@ -1271,42 +1273,18 @@ static void rt_del(unsigned int hash, struct rtable *rt) | |||
1271 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1273 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1272 | } | 1274 | } |
1273 | 1275 | ||
1274 | static void ip_do_redirect(struct rtable *rt, __be32 old_gw, __be32 new_gw) | 1276 | static void ip_do_redirect(struct dst_entry *dst, struct sk_buff *skb) |
1275 | { | ||
1276 | struct neighbour *n; | ||
1277 | |||
1278 | if (rt->rt_gateway != old_gw) | ||
1279 | return; | ||
1280 | |||
1281 | n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw); | ||
1282 | if (n) { | ||
1283 | if (!(n->nud_state & NUD_VALID)) { | ||
1284 | neigh_event_send(n, NULL); | ||
1285 | } else { | ||
1286 | rt->rt_gateway = new_gw; | ||
1287 | rt->rt_flags |= RTCF_REDIRECTED; | ||
1288 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | ||
1289 | } | ||
1290 | neigh_release(n); | ||
1291 | } | ||
1292 | } | ||
1293 | |||
1294 | /* called in rcu_read_lock() section */ | ||
1295 | void ip_rt_redirect(struct sk_buff *skb, __be32 new_gw) | ||
1296 | { | 1277 | { |
1297 | const struct iphdr *iph = (const struct iphdr *) skb->data; | 1278 | const struct iphdr *iph = (const struct iphdr *) skb->data; |
1279 | __be32 new_gw = icmp_hdr(skb)->un.gateway; | ||
1298 | __be32 old_gw = ip_hdr(skb)->saddr; | 1280 | __be32 old_gw = ip_hdr(skb)->saddr; |
1281 | struct net_device *dev = skb->dev; | ||
1299 | __be32 daddr = iph->daddr; | 1282 | __be32 daddr = iph->daddr; |
1300 | __be32 saddr = iph->saddr; | 1283 | __be32 saddr = iph->saddr; |
1301 | struct net_device *dev = skb->dev; | 1284 | struct in_device *in_dev; |
1302 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 1285 | struct neighbour *n; |
1303 | int ikeys[2] = { dev->ifindex, 0 }; | 1286 | struct rtable *rt; |
1304 | __be32 skeys[2] = { saddr, 0 }; | ||
1305 | struct net *net; | 1287 | struct net *net; |
1306 | int s, i; | ||
1307 | |||
1308 | if (!in_dev) | ||
1309 | return; | ||
1310 | 1288 | ||
1311 | switch (icmp_hdr(skb)->code & 7) { | 1289 | switch (icmp_hdr(skb)->code & 7) { |
1312 | case ICMP_REDIR_NET: | 1290 | case ICMP_REDIR_NET: |
@@ -1319,6 +1297,14 @@ void ip_rt_redirect(struct sk_buff *skb, __be32 new_gw) | |||
1319 | return; | 1297 | return; |
1320 | } | 1298 | } |
1321 | 1299 | ||
1300 | rt = (struct rtable *) dst; | ||
1301 | if (rt->rt_gateway != old_gw) | ||
1302 | return; | ||
1303 | |||
1304 | in_dev = __in_dev_get_rcu(dev); | ||
1305 | if (!in_dev) | ||
1306 | return; | ||
1307 | |||
1322 | net = dev_net(dev); | 1308 | net = dev_net(dev); |
1323 | if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || | 1309 | if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || |
1324 | ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || | 1310 | ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || |
@@ -1335,6 +1321,43 @@ void ip_rt_redirect(struct sk_buff *skb, __be32 new_gw) | |||
1335 | goto reject_redirect; | 1321 | goto reject_redirect; |
1336 | } | 1322 | } |
1337 | 1323 | ||
1324 | n = ipv4_neigh_lookup(dst, NULL, &new_gw); | ||
1325 | if (n) { | ||
1326 | if (!(n->nud_state & NUD_VALID)) { | ||
1327 | neigh_event_send(n, NULL); | ||
1328 | } else { | ||
1329 | rt->rt_gateway = new_gw; | ||
1330 | rt->rt_flags |= RTCF_REDIRECTED; | ||
1331 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | ||
1332 | } | ||
1333 | neigh_release(n); | ||
1334 | } | ||
1335 | return; | ||
1336 | |||
1337 | reject_redirect: | ||
1338 | #ifdef CONFIG_IP_ROUTE_VERBOSE | ||
1339 | if (IN_DEV_LOG_MARTIANS(in_dev)) | ||
1340 | net_info_ratelimited("Redirect from %pI4 on %s about %pI4 ignored\n" | ||
1341 | " Advised path = %pI4 -> %pI4\n", | ||
1342 | &old_gw, dev->name, &new_gw, | ||
1343 | &saddr, &daddr); | ||
1344 | #endif | ||
1345 | ; | ||
1346 | } | ||
1347 | |||
1348 | /* called in rcu_read_lock() section */ | ||
1349 | void ip_rt_redirect(struct sk_buff *skb, __be32 new_gw) | ||
1350 | { | ||
1351 | const struct iphdr *iph = (const struct iphdr *) skb->data; | ||
1352 | __be32 daddr = iph->daddr; | ||
1353 | __be32 saddr = iph->saddr; | ||
1354 | struct net_device *dev = skb->dev; | ||
1355 | int ikeys[2] = { dev->ifindex, 0 }; | ||
1356 | __be32 skeys[2] = { saddr, 0 }; | ||
1357 | struct net *net; | ||
1358 | int s, i; | ||
1359 | |||
1360 | net = dev_net(dev); | ||
1338 | for (s = 0; s < 2; s++) { | 1361 | for (s = 0; s < 2; s++) { |
1339 | for (i = 0; i < 2; i++) { | 1362 | for (i = 0; i < 2; i++) { |
1340 | unsigned int hash; | 1363 | unsigned int hash; |
@@ -1358,21 +1381,12 @@ void ip_rt_redirect(struct sk_buff *skb, __be32 new_gw) | |||
1358 | rt->dst.dev != dev) | 1381 | rt->dst.dev != dev) |
1359 | continue; | 1382 | continue; |
1360 | 1383 | ||
1361 | ip_do_redirect(rt, old_gw, new_gw); | 1384 | ip_do_redirect(&rt->dst, skb); |
1362 | } | 1385 | } |
1363 | } | 1386 | } |
1364 | } | 1387 | } |
1365 | return; | 1388 | return; |
1366 | 1389 | ||
1367 | reject_redirect: | ||
1368 | #ifdef CONFIG_IP_ROUTE_VERBOSE | ||
1369 | if (IN_DEV_LOG_MARTIANS(in_dev)) | ||
1370 | net_info_ratelimited("Redirect from %pI4 on %s about %pI4 ignored\n" | ||
1371 | " Advised path = %pI4 -> %pI4\n", | ||
1372 | &old_gw, dev->name, &new_gw, | ||
1373 | &saddr, &daddr); | ||
1374 | #endif | ||
1375 | ; | ||
1376 | } | 1390 | } |
1377 | 1391 | ||
1378 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) | 1392 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) |