221 lines
10 KiB
Diff
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
|
|
|