summary refs log tree commit diff
path: root/src/core/dhcp
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2024-01-25 09:46:18 +0100
committerMichael Biebl <biebl@debian.org>2024-01-25 09:46:18 +0100
commit70e18d99b8e3e77bb37e218d7ac582130156f8ef (patch)
treed40c587e6d3f0e094ff558e415f1bb9803643214 /src/core/dhcp
parentd4d8b2b91f7ba000d97a8b2aab48c85000c11314 (diff)
New upstream version 1.45.90 upstream/1.45.90
Diffstat (limited to 'src/core/dhcp')
-rw-r--r--src/core/dhcp/nm-dhcp-client.c2
-rw-r--r--src/core/dhcp/nm-dhcp-client.h3
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient-utils.c12
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient-utils.h1
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient.c125
-rw-r--r--src/core/dhcp/nm-dhcp-dhcpcd.c2
-rw-r--r--src/core/dhcp/nm-dhcp-helper.c4
-rw-r--r--src/core/dhcp/nm-dhcp-nettools.c40
-rw-r--r--src/core/dhcp/tests/test-dhcp-dhclient.c100
9 files changed, 187 insertions, 102 deletions
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c
index 6978bd3c..4be03f4b 100644
--- a/src/core/dhcp/nm-dhcp-client.c
+++ b/src/core/dhcp/nm-dhcp-client.c
@@ -527,7 +527,7 @@ _acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log)
 
     nm_clear_l3cd(&reglist_data->l3cd);
 
-    nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_UPDATE);
+    nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO);
 
     g_array_remove_index(priv->v4.acd.reglist, idx);
 
diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h
index 903ea6ac..4dd2c4fd 100644
--- a/src/core/dhcp/nm-dhcp-client.h
+++ b/src/core/dhcp/nm-dhcp-client.h
@@ -162,6 +162,9 @@ typedef struct {
              * will always broadcast replies. */
             bool request_broadcast : 1;
 
+            /* Whether to send or not the client identifier */
+            bool send_client_id : 1;
+
         } v4;
         struct {
             /* If set, the DUID from the connection is used; otherwise
diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c
index ea8943fa..286f7aa1 100644
--- a/src/core/dhcp/nm-dhcp-dhclient-utils.c
+++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c
@@ -120,7 +120,10 @@ add_ip4_config(GString            *str,
         }
 
         g_string_append(str, CLIENTID_TAG " ");
-        if (i < l) {
+        if (l == 0) {
+            /* An empty value effectively unsets the client-id to avoid sending it */
+            g_string_append(str, "\"\"");
+        } else if (i < l) {
             /* Unprintable; convert to a hex string */
             for (i = 0; i < l; i++) {
                 if (i > 0)
@@ -293,6 +296,7 @@ char *
 nm_dhcp_dhclient_create_config(const char         *interface,
                                int                 addr_family,
                                GBytes             *client_id,
+                               gboolean            send_client_id,
                                const char         *anycast_address,
                                const char         *hostname,
                                guint32             timeout,
@@ -391,8 +395,8 @@ nm_dhcp_dhclient_create_config(const char         *interface,
                 continue;
 
             if (NM_STR_HAS_PREFIX(p, CLIENTID_TAG)) {
-                /* Override config file "dhcp-client-id" and use one from the connection */
-                if (client_id)
+                /* Skip "dhcp-client-id" if the connection has defined a custom one or "none" */
+                if (client_id || !send_client_id)
                     continue;
 
                 /* Otherwise, capture and return the existing client id */
@@ -477,6 +481,8 @@ nm_dhcp_dhclient_create_config(const char         *interface,
     }
 
     if (addr_family == AF_INET) {
+        nm_auto_unref_bytes GBytes *client_id_none = NULL;
+        client_id = send_client_id ? client_id : (client_id_none = g_bytes_new_static("", 0));
         add_ip4_config(new_contents, client_id, hostname, use_fqdn, hostname_flags);
         add_request(reqs, "rfc3442-classless-static-routes");
         add_request(reqs, "ms-classless-static-routes");
diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.h b/src/core/dhcp/nm-dhcp-dhclient-utils.h
index 6187cce0..34b26175 100644
--- a/src/core/dhcp/nm-dhcp-dhclient-utils.h
+++ b/src/core/dhcp/nm-dhcp-dhclient-utils.h
@@ -12,6 +12,7 @@
 char *nm_dhcp_dhclient_create_config(const char         *interface,
                                      int                 addr_family,
                                      GBytes             *client_id,
+                                     gboolean            send_client_id,
                                      const char         *anycast_addr,
                                      const char         *hostname,
                                      guint32             timeout,
diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c
index 4aab4b1e..2a3af10a 100644
--- a/src/core/dhcp/nm-dhcp-dhclient.c
+++ b/src/core/dhcp/nm-dhcp-dhclient.c
@@ -148,56 +148,6 @@ get_dhclient_leasefile(int         addr_family,
     return NULL;
 }
 
-static gboolean
-merge_dhclient_config(NMDhcpDhclient     *self,
-                      int                 addr_family,
-                      const char         *iface,
-                      const char         *conf_file,
-                      GBytes             *client_id,
-                      const char         *anycast_address,
-                      const char         *hostname,
-                      guint32             timeout,
-                      gboolean            use_fqdn,
-                      NMDhcpHostnameFlags hostname_flags,
-                      const char         *mud_url,
-                      const char *const  *reject_servers,
-                      const char         *orig_path,
-                      GBytes            **out_new_client_id,
-                      GError            **error)
-{
-    gs_free char *orig = NULL;
-    gs_free char *new  = NULL;
-
-    g_return_val_if_fail(iface, FALSE);
-    g_return_val_if_fail(conf_file, FALSE);
-
-    if (orig_path && g_file_test(orig_path, G_FILE_TEST_EXISTS)) {
-        GError *read_error = NULL;
-
-        if (!g_file_get_contents(orig_path, &orig, NULL, &read_error)) {
-            _LOGW("error reading dhclient configuration %s: %s", orig_path, read_error->message);
-            g_error_free(read_error);
-        }
-    }
-
-    new = nm_dhcp_dhclient_create_config(iface,
-                                         addr_family,
-                                         client_id,
-                                         anycast_address,
-                                         hostname,
-                                         timeout,
-                                         use_fqdn,
-                                         hostname_flags,
-                                         mud_url,
-                                         reject_servers,
-                                         orig_path,
-                                         orig,
-                                         out_new_client_id);
-    nm_assert(new);
-
-    return g_file_set_contents(conf_file, new, -1, error);
-}
-
 static char *
 find_existing_config(NMDhcpDhclient *self, int addr_family, const char *iface, const char *uuid)
 {
@@ -283,6 +233,7 @@ create_dhclient_config(NMDhcpDhclient     *self,
                        const char         *iface,
                        const char         *uuid,
                        GBytes             *client_id,
+                       gboolean            send_client_id,
                        const char         *anycast_address,
                        const char         *hostname,
                        guint32             timeout,
@@ -292,44 +243,56 @@ create_dhclient_config(NMDhcpDhclient     *self,
                        const char *const  *reject_servers,
                        GBytes            **out_new_client_id)
 {
-    gs_free char *orig = NULL;
-    char *new          = NULL;
-    GError *error      = NULL;
+    gs_free char *orig_path    = NULL;
+    gs_free char *orig_content = NULL;
+    char         *new_path     = NULL;
+    gs_free char *new_content  = NULL;
+    GError       *error        = NULL;
 
     g_return_val_if_fail(iface != NULL, NULL);
 
-    new = g_strdup_printf(NMSTATEDIR "/dhclient%s-%s.conf",
-                          _addr_family_to_path_part(addr_family),
-                          iface);
-
-    _LOGD("creating composite dhclient config %s", new);
+    new_path = g_strdup_printf(NMSTATEDIR "/dhclient%s-%s.conf",
+                               _addr_family_to_path_part(addr_family),
+                               iface);
+    _LOGD("creating composite dhclient config %s", new_path);
 
-    orig = find_existing_config(self, addr_family, iface, uuid);
-    if (orig)
-        _LOGD("merging existing dhclient config %s", orig);
+    orig_path = find_existing_config(self, addr_family, iface, uuid);
+    if (orig_path)
+        _LOGD("merging existing dhclient config %s", orig_path);
     else
         _LOGD("no existing dhclient configuration to merge");
 
-    if (!merge_dhclient_config(self,
-                               addr_family,
-                               iface,
-                               new,
-                               client_id,
-                               anycast_address,
-                               hostname,
-                               timeout,
-                               use_fqdn,
-                               hostname_flags,
-                               mud_url,
-                               reject_servers,
-                               orig,
-                               out_new_client_id,
-                               &error)) {
+    if (orig_path && g_file_test(orig_path, G_FILE_TEST_EXISTS)) {
+        if (!g_file_get_contents(orig_path, &orig_content, NULL, &error)) {
+            _LOGW("error reading dhclient configuration %s: %s", orig_path, error->message);
+            g_error_free(error);
+        }
+    }
+
+    new_content = nm_dhcp_dhclient_create_config(iface,
+                                                 addr_family,
+                                                 client_id,
+                                                 send_client_id,
+                                                 anycast_address,
+                                                 hostname,
+                                                 timeout,
+                                                 use_fqdn,
+                                                 hostname_flags,
+                                                 mud_url,
+                                                 reject_servers,
+                                                 orig_path,
+                                                 orig_content,
+                                                 out_new_client_id);
+    nm_assert(new_content);
+
+    if (!g_file_set_contents(new_path, new_content, -1, &error)) {
         _LOGW("error creating dhclient configuration: %s", error->message);
-        g_clear_error(&error);
+        g_error_free(error);
+        g_free(new_path);
+        return NULL;
     }
 
-    return new;
+    return new_path;
 }
 
 static gboolean
@@ -547,11 +510,14 @@ ip4_start(NMDhcpClient *client, GError **error)
 
     client_config = nm_dhcp_client_get_config(client);
 
+    nm_assert(client_config->addr_family == AF_INET);
+
     priv->conf_file = create_dhclient_config(self,
                                              AF_INET,
                                              client_config->iface,
                                              client_config->uuid,
                                              client_config->client_id,
+                                             client_config->v4.send_client_id,
                                              client_config->anycast_address,
                                              client_config->hostname,
                                              client_config->timeout,
@@ -584,6 +550,8 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
 
     config = nm_dhcp_client_get_config(client);
 
+    nm_assert(config->addr_family == AF_INET6);
+
     if (config->v6.iaid_explicit)
         _LOGW("dhclient does not support specifying an IAID for DHCPv6, it will be ignored");
 
@@ -592,6 +560,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
                                              config->iface,
                                              config->uuid,
                                              NULL,
+                                             TRUE,
                                              config->anycast_address,
                                              config->hostname,
                                              config->timeout,
diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c
index 8d2f928b..7c95994a 100644
--- a/src/core/dhcp/nm-dhcp-dhcpcd.c
+++ b/src/core/dhcp/nm-dhcp-dhcpcd.c
@@ -174,7 +174,7 @@ stop(NMDhcpClient *client, gboolean release)
          */
         if (kill(pid, sig) == -1) {
             errsv = errno;
-            _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv));
+            _LOGE("failed to kill dhcpcd %d:%s", errsv, nm_strerror_native(errsv));
         }
 
         /* When this function exits NM expects the PID to be -1.
diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c
index ee95abb7..9e4cedf2 100644
--- a/src/core/dhcp/nm-dhcp-helper.c
+++ b/src/core/dhcp/nm-dhcp-helper.c
@@ -159,7 +159,7 @@ do_connect:
                       error->message,
                       try_count,
                       (long long) (time_end - remaining_time - time_start) / 1000);
-                interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 100000);
+                interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31u))), 5000, 100000);
                 g_usleep(NM_MIN(interval, remaining_time));
                 g_clear_error(&error);
                 goto do_connect;
@@ -222,7 +222,7 @@ do_notify:
         gint64 interval;
 
         _LOGi("failure to call notify: %s (retry %u)", error->message, try_count);
-        interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000);
+        interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31u))), 5000, 25000);
         g_usleep(NM_MIN(interval, remaining_time));
         g_clear_error(&error);
         goto do_notify;
diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c
index f36dfb4d..fc468d4c 100644
--- a/src/core/dhcp/nm-dhcp-nettools.c
+++ b/src/core/dhcp/nm-dhcp-nettools.c
@@ -1119,6 +1119,7 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError *
     gs_unref_bytes GBytes                                   *client_id_new = NULL;
     const uint8_t                                           *client_id_arr;
     size_t                                                   client_id_len;
+    bool                                                     send_client_id;
     int                                                      r, fd, arp_type, transport;
     const NMDhcpClientConfig                                *client_config;
 
@@ -1150,20 +1151,37 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError *
         return FALSE;
     }
 
-    /* Note that we always set a client-id. In particular for infiniband that is necessary,
-     * see https://tools.ietf.org/html/rfc4390#section-2.1 . */
-    client_id = client_config->client_id;
-    if (!client_id) {
+    client_id      = client_config->client_id;
+    send_client_id = client_config->v4.send_client_id;
+
+    if (!send_client_id && transport == N_DHCP4_TRANSPORT_INFINIBAND) {
+        /* Client-id is mandatory for infiniband: https://tools.ietf.org/html/rfc4390#section-2.1 */
+        _LOGI("ipv4.client-id is set to \"none\", but it's mandatory for Infiniband. Setting a "
+              "default one.");
+        send_client_id = TRUE;
+    }
+
+    if (send_client_id && !client_id) {
         client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len);
         client_id     = client_id_new;
     }
 
-    if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) {
-        /* invalid client-ids are not expected. */
-        nm_assert_not_reached();
+    g_return_val_if_fail(client_id || !send_client_id, FALSE);
 
-        nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
-        return FALSE;
+    if (send_client_id) {
+        client_id_arr = g_bytes_get_data(client_id, &client_id_len);
+        client_id_len = NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN);
+
+        if (!client_id_arr || client_id_len < 2) {
+            /* invalid client-ids are not expected. */
+            nm_assert_not_reached();
+            nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
+            return FALSE;
+        }
+    } else {
+        client_id_arr = NULL;
+        /* This will unset the client-id and prevent it from being sent */
+        client_id_len = 0;
     }
 
     r = n_dhcp4_client_config_new(&config);
@@ -1177,9 +1195,7 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError *
     n_dhcp4_client_config_set_mac(config, hwaddr_arr, hwaddr_len);
     n_dhcp4_client_config_set_broadcast_mac(config, bcast_hwaddr_arr, bcast_hwaddr_len);
     n_dhcp4_client_config_set_request_broadcast(config, client_config->v4.request_broadcast);
-    r = n_dhcp4_client_config_set_client_id(config,
-                                            client_id_arr,
-                                            NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN));
+    r = n_dhcp4_client_config_set_client_id(config, client_id_arr, client_id_len);
     if (r) {
         set_error_nettools(error, r, "failed to set client-id");
         return FALSE;
diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c
index e95f218e..0edcc296 100644
--- a/src/core/dhcp/tests/test-dhcp-dhclient.c
+++ b/src/core/dhcp/tests/test-dhcp-dhclient.c
@@ -36,11 +36,14 @@ test_config(const char         *orig,
             const char         *anycast_addr,
             const char         *mud_url)
 {
-    gs_free char *new                    = NULL;
-    gs_unref_bytes GBytes *client_id     = NULL;
-    gs_unref_bytes GBytes *new_client_id = NULL;
-
-    if (dhcp_client_id) {
+    gs_free char *new                     = NULL;
+    gs_unref_bytes GBytes *client_id      = NULL;
+    gs_unref_bytes GBytes *new_client_id  = NULL;
+    gboolean               send_client_id = TRUE;
+
+    if (nm_streq0(dhcp_client_id, "none")) {
+        send_client_id = FALSE;
+    } else if (dhcp_client_id) {
         client_id = nm_dhcp_utils_client_id_string_to_bytes(dhcp_client_id);
         g_assert(client_id);
     }
@@ -48,6 +51,7 @@ test_config(const char         *orig,
     new = nm_dhcp_dhclient_create_config(iface,
                                          addr_family,
                                          client_id,
+                                         send_client_id,
                                          anycast_addr,
                                          hostname,
                                          timeout,
@@ -502,6 +506,90 @@ test_existing_ascii_client_id(void)
                 NULL,
                 NULL);
 }
+
+/*****************************************************************************/
+
+static const char *none_client_id_orig = "send dhcp-client-identifier 10:30:04:20:7A:08;\n";
+
+static const char *none_client_id_expected =
+    "# Created by NetworkManager\n"
+    "# Merged from /path/to/dhclient.conf\n"
+    "\n"
+    "send dhcp-client-identifier \"\"; # added by NetworkManager\n"
+    "\n"
+    "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+    "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
+    "option wpad code 252 = string;\n"
+    "\n"
+    "also request rfc3442-classless-static-routes;\n"
+    "also request ms-classless-static-routes;\n"
+    "also request static-routes;\n"
+    "also request wpad;\n"
+    "also request ntp-servers;\n"
+    "also request root-path;\n"
+    "\n";
+
+static void
+test_none_client_id(void)
+{
+    const char            *connection_client_id = "none";
+    gs_unref_bytes GBytes *expected_client_id   = NULL;
+
+    test_config(none_client_id_orig,
+                none_client_id_expected,
+                AF_INET,
+                NULL,
+                0,
+                FALSE,
+                NM_DHCP_HOSTNAME_FLAG_NONE,
+                connection_client_id,
+                expected_client_id,
+                "eth0",
+                NULL,
+                NULL);
+}
+
+/*****************************************************************************/
+
+static const char *missing_client_id_orig = "";
+
+static const char *missing_client_id_expected =
+    "# Created by NetworkManager\n"
+    "# Merged from /path/to/dhclient.conf\n"
+    "\n"
+    "\n"
+    "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+    "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
+    "option wpad code 252 = string;\n"
+    "\n"
+    "also request rfc3442-classless-static-routes;\n"
+    "also request ms-classless-static-routes;\n"
+    "also request static-routes;\n"
+    "also request wpad;\n"
+    "also request ntp-servers;\n"
+    "also request root-path;\n"
+    "\n";
+
+static void
+test_missing_client_id(void)
+{
+    const char            *connection_client_id = NULL;
+    gs_unref_bytes GBytes *expected_client_id   = NULL;
+
+    test_config(missing_client_id_orig,
+                missing_client_id_expected,
+                AF_INET,
+                NULL,
+                0,
+                FALSE,
+                NM_DHCP_HOSTNAME_FLAG_NONE,
+                connection_client_id,
+                expected_client_id,
+                "eth0",
+                NULL,
+                NULL);
+}
+
 /*****************************************************************************/
 
 static const char *fqdn_expected =
@@ -1364,6 +1452,8 @@ main(int argc, char **argv)
     g_test_add_func("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id);
     g_test_add_func("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id);
     g_test_add_func("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id);
+    g_test_add_func("/dhcp/dhclient/none-client-id", test_none_client_id);
+    g_test_add_func("/dhcp/dhclient/missing-client-id", test_missing_client_id);
     g_test_add_func("/dhcp/dhclient/fqdn", test_fqdn);
     g_test_add_func("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override);
     g_test_add_func("/dhcp/dhclient/override_hostname", test_override_hostname);