NetworkManager/SOURCES/1003-dhcp-decline-IPv6-leas...

221 lines
10 KiB
Diff

From 67f7ee1e7a5c4cfc2d0b67c56a8655b3d9f4781d Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Thu, 1 Sep 2022 10:21:20 +0200
Subject: [PATCH] dhcp: decline IPv6 lease if all adresses fail DAD
Currently we accept the DHCPv6 just after addresses are configured on
kernel, without waiting DAD result. Instead, wait that DAD completes
and decline the lease if all addresses are detected as duplicate.
Note that when an address has non-infinite lifetime and fails DAD,
kernel removes it automatically. With iproute2 we see something like:
602: testX6 inet6 2620::1234:5678/128 scope global tentative dynamic noprefixroute
valid_lft 7500sec preferred_lft 7200sec
Deleted 602: testX6 inet6 2620::1234:5678/128 scope global dadfailed tentative dynamic noprefixroute
valid_lft 7500sec preferred_lft 7200sec
Since the address gets removed from the platform cache, at the moment
we don't have a way to check the flags of the removal
message. Therefore, we assume that any address that goes away in
tentative state was detected as duplicate.
https://bugzilla.redhat.com/show_bug.cgi?id=2096386
(cherry picked from commit a7eb77260ae6cfc56313e99f6178daa0b8283226)
(cherry picked from commit b671c36189bcddef058bcdce6c9bfeaddeb6c340)
---
src/core/dhcp/nm-dhcp-client.c | 128 +++++++++++++++++++++++----------
1 file changed, 92 insertions(+), 36 deletions(-)
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c
index 77cfeecf81..a22fe65b6d 100644
--- a/src/core/dhcp/nm-dhcp-client.c
+++ b/src/core/dhcp/nm-dhcp-client.c
@@ -1043,8 +1043,11 @@ ipv6_lladdr_find(NMDhcpClient *self)
return NULL;
}
-static const NMPlatformIP6Address *
-ipv6_tentative_addr_find(NMDhcpClient *self)
+static void
+ipv6_tentative_addr_check(NMDhcpClient *self,
+ GPtrArray **tentative,
+ GPtrArray **missing,
+ const NMPlatformIP6Address **valid)
{
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
NMDedupMultiIter iter;
@@ -1062,16 +1065,26 @@ ipv6_tentative_addr_find(NMDhcpClient *self)
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
&needle));
if (!pladdr) {
- /* Address was removed from platform */
+ /* address removed: we assume that's because DAD failed */
+ if (missing) {
+ if (!*missing)
+ *missing = g_ptr_array_new();
+ g_ptr_array_add(*missing, (gpointer) addr);
+ }
continue;
}
if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE)
- && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC))
- return pladdr;
- }
+ && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) {
+ if (tentative) {
+ if (!*tentative)
+ *tentative = g_ptr_array_new();
+ g_ptr_array_add(*tentative, (gpointer) addr);
+ }
+ }
- return NULL;
+ NM_SET_OUT(valid, addr);
+ }
}
static void
@@ -1108,21 +1121,61 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE
&& priv->l3cfg_notify.wait_ipv6_dad) {
- const NMPlatformIP6Address *tentative;
+ gs_unref_ptrarray GPtrArray *tentative = NULL;
+ gs_unref_ptrarray GPtrArray *missing = NULL;
+ const NMPlatformIP6Address *valid = NULL;
+ char str[NM_UTILS_TO_STRING_BUFFER_SIZE];
+ guint i;
+ gs_free_error GError *error = NULL;
+
+ ipv6_tentative_addr_check(self, &tentative, &missing, &valid);
+ if (tentative) {
+ for (i = 0; i < tentative->len; i++) {
+ _LOGD("still waiting DAD for address: %s",
+ nm_platform_ip6_address_to_string(tentative->pdata[i], str, sizeof(str)));
+ }
+ } else {
+ /* done */
- tentative = ipv6_tentative_addr_find(self);
- if (!tentative) {
- _LOGD("addresses in the lease completed DAD");
priv->l3cfg_notify.wait_ipv6_dad = FALSE;
nm_clear_g_source_inst(&priv->v6.dad_timeout_source);
l3_cfg_notify_check_connected(self);
- _emit_notify(
- self,
- &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE,
- .lease_update = {
- .l3cd = priv->l3cd_curr,
- .accepted = TRUE,
- }}));
+
+ if (missing) {
+ for (i = 0; i < missing->len; i++) {
+ _LOGE("DAD failed for address: %s",
+ nm_platform_ip6_address_to_string(missing->pdata[i], str, sizeof(str)));
+ }
+ }
+
+ if (valid) {
+ /* at least one non-duplicate address */
+ _LOGD("addresses in the lease completed DAD: accept the lease");
+
+ if (_dhcp_client_accept(self, priv->l3cd_curr, &error)) {
+ _emit_notify(self,
+ &((NMDhcpClientNotifyData){
+ .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE,
+ .lease_update = {
+ .l3cd = priv->l3cd_curr,
+ .accepted = TRUE,
+ }}));
+ } else {
+ gs_free char *reason =
+ g_strdup_printf("error accepting lease: %s", error->message);
+
+ _LOGD("accept failed: %s", error->message);
+ _emit_notify(self,
+ &((NMDhcpClientNotifyData){
+ .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD,
+ .it_looks_bad.reason = reason,
+ }));
+ }
+ } else {
+ _LOGD("decline the lease");
+ if (!_dhcp_client_decline(self, priv->l3cd_curr, "DAD failed", &error))
+ _LOGD("decline failed: %s", error->message);
+ }
}
}
@@ -1155,20 +1208,23 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
address4->peer_address))
goto wait_dhcp_commit_done;
} else {
- const NMPlatformIP6Address *address6 = (const NMPlatformIP6Address *) lease_address;
- const NMPlatformIP6Address *tentative;
- char str[NM_UTILS_TO_STRING_BUFFER_SIZE];
+ const NMPlatformIP6Address *address6 = (const NMPlatformIP6Address *) lease_address;
+ gs_unref_ptrarray GPtrArray *tentative = NULL;
+ char str[NM_UTILS_TO_STRING_BUFFER_SIZE];
+ guint i;
if (!nm_l3_config_data_lookup_address_6(committed_l3cd, &address6->address))
goto wait_dhcp_commit_done;
- tentative = ipv6_tentative_addr_find(self);
+ ipv6_tentative_addr_check(self, &tentative, NULL, NULL);
if (tentative) {
priv->l3cfg_notify.wait_ipv6_dad = TRUE;
priv->v6.dad_timeout_source =
nm_g_timeout_add_seconds_source(30, ipv6_dad_timeout, self);
- _LOGD("wait DAD for address %s",
- nm_platform_ip6_address_to_string(tentative, str, sizeof(str)));
+ for (i = 0; i < tentative->len; i++) {
+ _LOGD("wait DAD for address %s",
+ nm_platform_ip6_address_to_string(tentative->pdata[i], str, sizeof(str)));
+ }
} else {
priv->l3cfg_notify.wait_ipv6_dad = FALSE;
nm_clear_g_source_inst(&priv->v6.dad_timeout_source);
@@ -1179,22 +1235,22 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
l3_cfg_notify_check_connected(self);
- _LOGD("accept lease");
+ if (priv->config.addr_family == AF_INET || !priv->l3cfg_notify.wait_ipv6_dad) {
+ _LOGD("accept lease");
- if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) {
- gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message);
+ if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) {
+ gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message);
- _LOGD("accept failed: %s", error->message);
+ _LOGD("accept failed: %s", error->message);
- _emit_notify(self,
- &((NMDhcpClientNotifyData){
- .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD,
- .it_looks_bad.reason = reason,
- }));
- goto wait_dhcp_commit_done;
- }
+ _emit_notify(self,
+ &((NMDhcpClientNotifyData){
+ .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD,
+ .it_looks_bad.reason = reason,
+ }));
+ goto wait_dhcp_commit_done;
+ }
- if (priv->config.addr_family == AF_INET || !priv->l3cfg_notify.wait_ipv6_dad) {
_emit_notify(
self,
&((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE,
--
2.38.1