aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-11 23:55:47 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-11 23:55:47 -0400
commite47a185b31dd2acd424fac7dc0efb96fc5b31a33 (patch)
tree31947f03e2600b8fd73a9afd391a69c218234f03
parent94206125c4aac32e43c25bfe1b827e7ab993b7dc (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>
-rw-r--r--include/net/dst_ops.h1
-rw-r--r--net/ipv4/route.c94
2 files changed, 55 insertions, 40 deletions
diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h
index 4badc86e45d1..085931fa7ce0 100644
--- a/include/net/dst_ops.h
+++ b/include/net/dst_ops.h
@@ -25,6 +25,7 @@ struct dst_ops {
25 struct dst_entry * (*negative_advice)(struct dst_entry *); 25 struct dst_entry * (*negative_advice)(struct dst_entry *);
26 void (*link_failure)(struct sk_buff *); 26 void (*link_failure)(struct sk_buff *);
27 void (*update_pmtu)(struct dst_entry *dst, u32 mtu); 27 void (*update_pmtu)(struct dst_entry *dst, u32 mtu);
28 void (*redirect)(struct dst_entry *dst, struct sk_buff *skb);
28 int (*local_out)(struct sk_buff *skb); 29 int (*local_out)(struct sk_buff *skb);
29 struct neighbour * (*neigh_lookup)(const struct dst_entry *dst, 30 struct neighbour * (*neigh_lookup)(const struct dst_entry *dst,
30 struct sk_buff *skb, 31 struct sk_buff *skb,
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);
149static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); 149static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
150static void ipv4_link_failure(struct sk_buff *skb); 150static void ipv4_link_failure(struct sk_buff *skb);
151static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); 151static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
152static void ip_do_redirect(struct dst_entry *dst, struct sk_buff *skb);
152static int rt_garbage_collect(struct dst_ops *ops); 153static int rt_garbage_collect(struct dst_ops *ops);
153 154
154static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 155static 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
1274static void ip_do_redirect(struct rtable *rt, __be32 old_gw, __be32 new_gw) 1276static 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 */
1295void 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
1337reject_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 */
1349void 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
1367reject_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
1378static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) 1392static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)