Skip to content

Commit 14ef37b

Browse files
andihofmeisterdavem330
authored andcommitted
ipv6: fix route lookup in addrconf_prefix_rcv()
The route lookup to find a previously auto-configured route for a prefixes used to use rt6_lookup(), with the prefix from the RA used as an address. However, that kind of lookup ignores routing tables, the prefix length and route flags, so when there were other matching routes, even in different tables and/or with a different prefix length, the wrong route would be manipulated. Now, a new function "addrconf_get_prefix_route()" is used for the route lookup, which searches in RT6_TABLE_PREFIX and takes the prefix-length and route flags into account. Signed-off-by: Andreas Hofmeister <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e6d265e commit 14ef37b

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

net/ipv6/addrconf.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,40 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
17131713
ip6_route_add(&cfg);
17141714
}
17151715

1716+
1717+
static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
1718+
int plen,
1719+
const struct net_device *dev,
1720+
u32 flags, u32 noflags)
1721+
{
1722+
struct fib6_node *fn;
1723+
struct rt6_info *rt = NULL;
1724+
struct fib6_table *table;
1725+
1726+
table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
1727+
if (table == NULL)
1728+
return NULL;
1729+
1730+
write_lock_bh(&table->tb6_lock);
1731+
fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0);
1732+
if (!fn)
1733+
goto out;
1734+
for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1735+
if (rt->rt6i_dev->ifindex != dev->ifindex)
1736+
continue;
1737+
if ((rt->rt6i_flags & flags) != flags)
1738+
continue;
1739+
if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0))
1740+
continue;
1741+
dst_hold(&rt->dst);
1742+
break;
1743+
}
1744+
out:
1745+
write_unlock_bh(&table->tb6_lock);
1746+
return rt;
1747+
}
1748+
1749+
17161750
/* Create "default" multicast route to the interface */
17171751

17181752
static void addrconf_add_mroute(struct net_device *dev)
@@ -1842,10 +1876,13 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
18421876
if (addrconf_finite_timeout(rt_expires))
18431877
rt_expires *= HZ;
18441878

1845-
rt = rt6_lookup(net, &pinfo->prefix, NULL,
1846-
dev->ifindex, 1);
1879+
rt = addrconf_get_prefix_route(&pinfo->prefix,
1880+
pinfo->prefix_len,
1881+
dev,
1882+
RTF_ADDRCONF | RTF_PREFIX_RT,
1883+
RTF_GATEWAY | RTF_DEFAULT);
18471884

1848-
if (rt && addrconf_is_prefix_route(rt)) {
1885+
if (rt) {
18491886
/* Autoconf prefix route */
18501887
if (valid_lft == 0) {
18511888
ip6_del_rt(rt);

0 commit comments

Comments
 (0)