summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlin Nastac <alin.nastac@gmail.com>2021-11-15 16:54:43 +0100
committerHans Dedecker <dedeckeh@gmail.com>2021-12-12 21:01:04 +0100
commit8875960938faae70aa861866545dd7c5f8b7eb5b (patch)
tree21365d845620c955619154d883743321babf3e48
parente589c0580dcb9031faec2b8106925874b5d648a1 (diff)
downloadnetifd-8875960938faae70aa861866545dd7c5f8b7eb5b.tar.gz
interface-ip: add support for IPv6 prefix invalidation
On dhcpv6 interfaces, DHCPv6 server might invalidate previous PD by advertising it with valid lifetime set to 0. In this case, netifd must immediately remove PD assignments. Signed-off-by: Alin Nastac <alin.nastac@gmail.com>
-rw-r--r--interface-ip.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/interface-ip.c b/interface-ip.c
index 7b63ef9..8b60963 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -969,9 +969,16 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
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;
+ if (addr.valid_until && addr.valid_until - 1 <= now) {
+ addr.valid_until = 0;
+ addr.preferred_until = 0;
+ } else {
+ /* Address is still valid; pass its ownership to kernel (see L-14 RFC 7084). */
+ addr.preferred_until = now;
+
+ if (!addr.valid_until || addr.valid_until > now + 7200)
+ addr.valid_until = now + 7200;
+ }
if (iface->ip6table)
set_ip_source_policy(false, true, IPRULE_PRIORITY_ADDR_MASK, &addr.addr,
@@ -990,7 +997,10 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
interface_set_route_info(iface, &route);
system_del_route(l3_downlink, &route);
- system_add_address(l3_downlink, &addr);
+ if (addr.valid_until)
+ system_add_address(l3_downlink, &addr);
+ else
+ system_del_address(l3_downlink, &addr);
assignment->addr = in6addr_any;
assignment->enabled = false;
@@ -1229,8 +1239,13 @@ void interface_refresh_assignments(bool hint)
static bool refresh = false;
if (!hint && refresh) {
struct device_prefix *p;
- list_for_each_entry(p, &prefixes, head)
- interface_update_prefix_assignments(p, true);
+ time_t now = system_get_rtime();
+
+ list_for_each_entry(p, &prefixes, head) {
+ bool valid = !(p->valid_until && p->valid_until - 1 <= now);
+
+ interface_update_prefix_assignments(p, valid);
+ }
}
refresh = hint;
}
@@ -1238,9 +1253,12 @@ void interface_refresh_assignments(bool hint)
void interface_update_prefix_delegation(struct interface_ip_settings *ip)
{
struct device_prefix *prefix;
+ time_t now = system_get_rtime();
vlist_for_each_element(&ip->prefix, prefix, node) {
- interface_update_prefix_assignments(prefix, !ip->no_delegation);
+ bool valid = !(prefix->valid_until && prefix->valid_until - 1 <= now);
+
+ interface_update_prefix_assignments(prefix, !ip->no_delegation && valid);
if (ip->no_delegation) {
if (prefix->head.next)
@@ -1270,9 +1288,9 @@ interface_update_prefix(struct vlist_tree *tree,
route.mask = (node_new) ? prefix_new->length : prefix_old->length;
route.addr.in6 = (node_new) ? prefix_new->addr : prefix_old->addr;
-
struct device_prefix_assignment *c;
struct interface *iface;
+ bool new_valid = node_new && !(prefix_new->valid_until && prefix_new->valid_until - 1 <= system_get_rtime());
if (node_old && node_new) {
/* Move assignments and refresh addresses to update valid times */
@@ -1280,7 +1298,7 @@ interface_update_prefix(struct vlist_tree *tree,
list_for_each_entry(c, &prefix_new->assignments, head)
if ((iface = vlist_find(&interfaces, c->name, iface, node)))
- interface_set_prefix_address(c, prefix_new, iface, true);
+ interface_set_prefix_address(c, prefix_new, iface, new_valid);
if (prefix_new->preferred_until != prefix_old->preferred_until ||
prefix_new->valid_until != prefix_old->valid_until)
@@ -1290,7 +1308,7 @@ interface_update_prefix(struct vlist_tree *tree,
system_add_route(NULL, &route);
if (!prefix_new->iface || !prefix_new->iface->proto_ip.no_delegation)
- interface_update_prefix_assignments(prefix_new, true);
+ interface_update_prefix_assignments(prefix_new, new_valid);
} else if (node_old) {
/* Remove null-route */
interface_update_prefix_assignments(prefix_old, false);