Merge pull request #32215 from yuwata/network-ndisc-address-lifetime

network/ndisc: fix assignment of valid lifetime
This commit is contained in:
Luca Boccassi 2024-04-11 12:16:31 +01:00 committed by GitHub
commit 947143e897
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -327,20 +327,14 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
return 1;
}
static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *rt) {
static int ndisc_request_address(Address *address, Link *link) {
bool is_new;
int r;
assert(address);
assert(link);
if (rt) {
r = sd_ndisc_router_get_sender_address(rt, &address->provider.in6);
if (r < 0)
return r;
address->source = NETWORK_CONFIG_SOURCE_NDISC;
}
address->source = NETWORK_CONFIG_SOURCE_NDISC;
r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
if (r < 0)
@ -388,7 +382,7 @@ int ndisc_reconfigure_address(Address *address, Link *link) {
if (r <= 0)
return r;
r = ndisc_request_address(address, link, NULL);
r = ndisc_request_address(address, link);
if (r < 0)
return r;
@ -1079,9 +1073,67 @@ static int ndisc_router_process_mtu(Link *link, sd_ndisc_router *rt) {
return 0;
}
static int ndisc_address_set_lifetime(Address *address, Link *link, sd_ndisc_router *rt) {
Address *existing;
usec_t t;
int r;
assert(address);
assert(link);
assert(rt);
/* This is mostly based on RFC 4862 section 5.5.3 (e). However, the definition of 'RemainingLifetime'
* is ambigous, and there is no clear explanation when the address is not assigned yet. If we assume
* that 'RemainingLifetime' is zero in that case, then IPv6 Core Conformance test [v6LC.3.2.5 Part C]
* fails. So, in such case, we skip the conditions about 'RemainingLifetime'. */
r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &address->lifetime_valid_usec);
if (r < 0)
return r;
r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &address->lifetime_preferred_usec);
if (r < 0)
return r;
/* RFC 4862 section 5.5.3 (e)
* 1. If the received Valid Lifetime is greater than 2 hours or greater than RemainingLifetime,
* set the valid lifetime of the corresponding address to the advertised Valid Lifetime. */
r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &t);
if (r < 0)
return r;
if (t > 2 * USEC_PER_HOUR)
return 0;
r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &t);
if (r < 0)
return r;
if (address_get(link, address, &existing) >= 0 && existing->source == NETWORK_CONFIG_SOURCE_NDISC) {
if (address->lifetime_valid_usec > existing->lifetime_valid_usec)
return 0;
/* 2. If RemainingLifetime is less than or equal to 2 hours, ignore the Prefix Information
* option with regards to the valid lifetime, unless the Router Advertisement from which
* this option was obtained has been authenticated (e.g., via Secure Neighbor Discovery
* [RFC3971]). If the Router Advertisement was authenticated, the valid lifetime of the
* corresponding address should be set to the Valid Lifetime in the received option.
*
* Currently, authentication is not supported. So check the lifetime of the existing address. */
if (existing->lifetime_valid_usec <= usec_add(t, 2 * USEC_PER_HOUR)) {
address->lifetime_valid_usec = existing->lifetime_valid_usec;
return 0;
}
}
/* 3. Otherwise, reset the valid lifetime of the corresponding address to 2 hours. */
address->lifetime_valid_usec = usec_add(t, 2 * USEC_PER_HOUR);
return 0;
}
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
usec_t lifetime_valid_usec, lifetime_preferred_usec;
struct in6_addr prefix;
struct in6_addr prefix, router;
uint8_t prefixlen;
int r;
@ -1092,6 +1144,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (!link->network->ndisc_use_autonomous_prefix)
return 0;
r = sd_ndisc_router_get_sender_address(rt, &router);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get router address: %m");
r = sd_ndisc_router_prefix_get_address(rt, &prefix);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
@ -1107,15 +1163,17 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
return 0;
}
r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_valid_usec);
r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid_usec);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix valid lifetime: %m");
r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_preferred_usec);
r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred_usec);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix preferred lifetime: %m");
/* The preferred lifetime is never greater than the valid lifetime */
/* RFC 4862 section 5.5.3 (c)
* If the preferred lifetime is greater than the valid lifetime, silently ignore the Prefix
* Information option. */
if (lifetime_preferred_usec > lifetime_valid_usec)
return 0;
@ -1133,30 +1191,22 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (r < 0)
return log_oom();
address->provider.in6 = router;
address->family = AF_INET6;
address->in_addr.in6 = *a;
address->prefixlen = prefixlen;
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
address->lifetime_valid_usec = lifetime_valid_usec;
address->lifetime_preferred_usec = lifetime_preferred_usec;
address->token = ipv6_token_ref(token);
/* draft-ietf-6man-slaac-renum-07 section 4.2
* https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
*
* If the advertised prefix is equal to the prefix of an address configured by stateless
* autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
* address should be updated by processing the Valid Lifetime and the Preferred Lifetime
* (respectively) in the received advertisement. */
if (lifetime_valid_usec == 0) {
r = address_remove_and_cancel(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
} else {
r = ndisc_request_address(address, link, rt);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
}
r = ndisc_address_set_lifetime(address, link, rt);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to set lifetime of SLAAC address: %m");
assert(address->lifetime_preferred_usec <= address->lifetime_valid_usec);
r = ndisc_request_address(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
}
return 0;