aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/route.c90
1 files changed, 47 insertions, 43 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f587a0e6cf34..e16c9825c4dc 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1144,59 +1144,63 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r
1144void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, 1144void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
1145 struct neighbour *neigh, u8 *lladdr, int on_link) 1145 struct neighbour *neigh, u8 *lladdr, int on_link)
1146{ 1146{
1147 struct rt6_info *rt, *nrt; 1147 struct rt6_info *rt, *nrt = NULL;
1148 1148 int strict;
1149 /* Locate old route to this destination. */ 1149 struct fib6_node *fn;
1150 rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
1151
1152 if (rt == NULL)
1153 return;
1154
1155 if (neigh->dev != rt->rt6i_dev)
1156 goto out;
1157 1150
1158 /* 1151 /*
1159 * Current route is on-link; redirect is always invalid. 1152 * Get the "current" route for this destination and
1160 * 1153 * check if the redirect has come from approriate router.
1161 * Seems, previous statement is not true. It could 1154 *
1162 * be node, which looks for us as on-link (f.e. proxy ndisc) 1155 * RFC 2461 specifies that redirects should only be
1163 * But then router serving it might decide, that we should 1156 * accepted if they come from the nexthop to the target.
1164 * know truth 8)8) --ANK (980726). 1157 * Due to the way the routes are chosen, this notion
1158 * is a bit fuzzy and one might need to check all possible
1159 * routes.
1165 */ 1160 */
1166 if (!(rt->rt6i_flags&RTF_GATEWAY)) 1161 strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
1167 goto out;
1168 1162
1169 /* 1163 read_lock_bh(&rt6_lock);
1170 * RFC 2461 specifies that redirects should only be 1164 fn = fib6_lookup(&ip6_routing_table, dest, NULL);
1171 * accepted if they come from the nexthop to the target. 1165restart:
1172 * Due to the way default routers are chosen, this notion 1166 for (rt = fn->leaf; rt; rt = rt->u.next) {
1173 * is a bit fuzzy and one might need to check all default 1167 /*
1174 * routers. 1168 * Current route is on-link; redirect is always invalid.
1175 */ 1169 *
1176 if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) { 1170 * Seems, previous statement is not true. It could
1177 if (rt->rt6i_flags & RTF_DEFAULT) { 1171 * be node, which looks for us as on-link (f.e. proxy ndisc)
1178 struct rt6_info *rt1; 1172 * But then router serving it might decide, that we should
1179 1173 * know truth 8)8) --ANK (980726).
1180 read_lock(&rt6_lock); 1174 */
1181 for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { 1175 if (rt6_check_expired(rt))
1182 if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) { 1176 continue;
1183 dst_hold(&rt1->u.dst); 1177 if (!(rt->rt6i_flags & RTF_GATEWAY))
1184 dst_release(&rt->u.dst); 1178 continue;
1185 read_unlock(&rt6_lock); 1179 if (neigh->dev != rt->rt6i_dev)
1186 rt = rt1; 1180 continue;
1187 goto source_ok; 1181 if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway))
1188 } 1182 continue;
1189 } 1183 break;
1190 read_unlock(&rt6_lock); 1184 }
1185 if (rt)
1186 dst_hold(&rt->u.dst);
1187 else if (strict) {
1188 while ((fn = fn->parent) != NULL) {
1189 if (fn->fn_flags & RTN_ROOT)
1190 break;
1191 if (fn->fn_flags & RTN_RTINFO)
1192 goto restart;
1191 } 1193 }
1194 }
1195 read_unlock_bh(&rt6_lock);
1196
1197 if (!rt) {
1192 if (net_ratelimit()) 1198 if (net_ratelimit())
1193 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " 1199 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
1194 "for redirect target\n"); 1200 "for redirect target\n");
1195 goto out; 1201 return;
1196 } 1202 }
1197 1203
1198source_ok:
1199
1200 /* 1204 /*
1201 * We have finally decided to accept it. 1205 * We have finally decided to accept it.
1202 */ 1206 */