summaryrefslogtreecommitdiff
path: root/src/network/networkd-ndisc.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-10-03 12:18:49 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-10-04 00:25:14 +0900
commit94e6d37c2be87f8a9e7d563aa0c487946a6e5cc8 (patch)
treef8a2b8385160f6053d6a5d6e12605200741c31f8 /src/network/networkd-ndisc.c
parent8d1babc51d9f40da28bc08c9d0ff401bd00b8e1f (diff)
downloadsystemd-94e6d37c2be87f8a9e7d563aa0c487946a6e5cc8.tar.gz
network: ndisc: drop outdated settings before processing RA message
Otherwise, e.g. if a router is replaced, then the previously received settings may never dropped. Follow-up for 2ccada8dc4a3571468a335808fd6fe49b8c6c6dd.
Diffstat (limited to 'src/network/networkd-ndisc.c')
-rw-r--r--src/network/networkd-ndisc.c83
1 files changed, 71 insertions, 12 deletions
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 5b772adc03..6452010d2d 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -372,7 +372,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
SET_FOREACH(a, addresses) {
_cleanup_(address_freep) Address *address = NULL;
- Address *e;
r = address_new(&address);
if (r < 0)
@@ -385,17 +384,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->lifetime_valid_usec = lifetime_valid_usec;
address->lifetime_preferred_usec = lifetime_preferred_usec;
- /* See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by
- * honoring all valid lifetimes to improve the reaction of SLAAC to renumbering events.
- * See draft-ietf-6man-slaac-renum-02, section 4.2. */
- r = address_get(link, address, &e);
- if (r >= 0) {
- /* If the address is already assigned, but not valid anymore, then refuse to
- * update the address, and it will be removed. */
- if (e->lifetime_valid_usec < timestamp_usec)
- continue;
- }
-
r = ndisc_request_address(TAKE_PTR(address), link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not request SLAAC address: %m");
@@ -824,6 +812,68 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
}
}
+static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
+ bool updated = false;
+ NDiscDNSSL *dnssl;
+ NDiscRDNSS *rdnss;
+ Address *address;
+ Route *route;
+ int r = 0, k;
+
+ assert(link);
+
+ /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
+ * and let's immediately remove it.
+ * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
+ * valid lifetimes to improve the reaction of SLAAC to renumbering events.
+ * See draft-ietf-6man-slaac-renum-02, section 4.2. */
+
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
+ continue;
+
+ if (route->lifetime_usec >= timestamp_usec)
+ continue; /* the route is still valid */
+
+ k = route_remove_and_drop(route);
+ if (k < 0)
+ r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC route, ignoring: %m");
+ }
+
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
+ continue;
+
+ if (address->lifetime_valid_usec >= timestamp_usec)
+ continue; /* the address is still valid */
+
+ k = address_remove_and_drop(address);
+ if (k < 0)
+ r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC address, ignoring: %m");
+ }
+
+ SET_FOREACH(rdnss, link->ndisc_rdnss) {
+ if (rdnss->lifetime_usec >= timestamp_usec)
+ continue; /* the DNS server is still valid */
+
+ free(set_remove(link->ndisc_rdnss, rdnss));
+ updated = true;
+ }
+
+ SET_FOREACH(dnssl, link->ndisc_dnssl) {
+ if (dnssl->lifetime_usec >= timestamp_usec)
+ continue; /* the DNS domain is still valid */
+
+ free(set_remove(link->ndisc_dnssl, dnssl));
+ updated = true;
+ }
+
+ if (updated)
+ link_dirty(link);
+
+ return r;
+}
+
static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
int r;
@@ -869,6 +919,7 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
struct in6_addr router;
+ usec_t timestamp_usec;
int r;
assert(link);
@@ -890,6 +941,14 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
return 0;
}
+ r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
+ if (r < 0)
+ return r;
+
+ r = ndisc_drop_outdated(link, timestamp_usec);
+ if (r < 0)
+ return r;
+
r = ndisc_start_dhcp6_client(link, rt);
if (r < 0)
return r;