summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2017-12-14 14:13:34 +0100
committerHans Dedecker <dedeckeh@gmail.com>2017-12-15 17:20:54 +0100
commit81ff6d120e8c247b7c714daefd45ae7b90e3b643 (patch)
tree47df830859b691ecce7dcf69ca640f52e7de7c64
parentd3a5df04bdcc039d900df49c8c608c1a91a976c7 (diff)
downloadnetifd-81ff6d120e8c247b7c714daefd45ae7b90e3b643.tar.gz
interface-ip: fix race condition in IPv6 prefix address generation
Don't generate an IPv6 prefix address without taking into account the interface state. In case eui64 is configured to generate the ifaceid this could fail as the layer3 device mac address could not yet be available if the interface is not yet in setup or up state. While at it remove the interface metric assignment as this is already done by the function interface_set_route_info. Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
-rw-r--r--interface-ip.c33
1 files changed, 19 insertions, 14 deletions
diff --git a/interface-ip.c b/interface-ip.c
index 1490ca4..716a093 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -761,15 +761,7 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
memset(&addr, 0, sizeof(addr));
memset(&route, 0, sizeof(route));
- if (IN6_IS_ADDR_UNSPECIFIED(&assignment->addr)) {
- addr.addr.in6 = prefix->addr;
- addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned);
- generate_ifaceid(iface, &addr.addr.in6);
- assignment->addr = addr.addr.in6;
- }
- else
- addr.addr.in6 = assignment->addr;
-
+ addr.addr.in6 = assignment->addr;
addr.mask = assignment->length;
addr.flags = DEVADDR_INET6 | DEVADDR_OFFLINK;
addr.preferred_until = prefix->preferred_until;
@@ -778,11 +770,10 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
route.flags = DEVADDR_INET6;
route.mask = addr.mask < 64 ? 64 : addr.mask;
route.addr = addr.addr;
- clear_if_addr(&route.addr, route.mask);
- interface_set_route_info(iface, &route);
if (!add && assignment->enabled) {
time_t now = system_get_rtime();
+
addr.preferred_until = now;
if (!addr.valid_until || addr.valid_until - now > 7200)
addr.valid_until = now + 7200;
@@ -800,12 +791,24 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
addr.mask, 0, iface, "unreachable", true);
}
+ clear_if_addr(&route.addr, route.mask);
+ interface_set_route_info(iface, &route);
+
system_del_route(l3_downlink, &route);
system_add_address(l3_downlink, &addr);
assignment->enabled = false;
- } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP) &&
- !system_add_address(l3_downlink, &addr)) {
+ } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP)) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&addr.addr.in6)) {
+ addr.addr.in6 = prefix->addr;
+ addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned);
+ generate_ifaceid(iface, &addr.addr.in6);
+ assignment->addr = addr.addr.in6;
+ route.addr = addr.addr;
+ }
+
+ if (system_add_address(l3_downlink, &addr))
+ return;
if (!assignment->enabled) {
if (iface->ip6table)
@@ -822,7 +825,9 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
}
}
- route.metric = iface->metric;
+ clear_if_addr(&route.addr, route.mask);
+ interface_set_route_info(iface, &route);
+
system_add_route(l3_downlink, &route);
if (uplink && uplink->l3_dev.dev && !(l3_downlink->settings.flags & DEV_OPT_MTU6)) {