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