summaryrefslogtreecommitdiff
path: root/interface-ip.c
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 /interface-ip.c
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>
Diffstat (limited to 'interface-ip.c')
-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);