diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-03-20 20:07:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-20 20:07:49 -0500 |
commit | e843b9e1bec4a953d848a319da6a18ca5c667f55 (patch) | |
tree | d16508cfd5cafa68eef4b635d2238db37c810201 /net/ipv6/route.c | |
parent | 09c884d4c3b45cda904c2291d4723074ff523611 (diff) |
[IPV6]: ROUTE: Ensure to accept redirects from nexthop for the target.
It is possible to get redirects from nexthop of "more-specific"
routes.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 90 |
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 | |||
1144 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1144 | void 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. | 1165 | restart: |
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 | ||
1198 | source_ok: | ||
1199 | |||
1200 | /* | 1204 | /* |
1201 | * We have finally decided to accept it. | 1205 | * We have finally decided to accept it. |
1202 | */ | 1206 | */ |