From 56865366471c52480c9077b663ed193d70e4a7ad Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 16 Apr 2018 15:42:02 +0200 Subject: [PATCH 01/10] dhclient: fix updating the DUID in multiline lease files The nm_dhcp_dhclient_save_duid() function will save a newly generated DUID to a previously existing lease file. The function will only save the DUID if not present in the lease file: in this case, should preserve the other contents of the lease file. A dhclient lease file for IPv6 generated by NetworkManager will always add the DUID as a first item: so in practice finding a lease file without DUID will never happen. This has hidden a bug in the function: the loop that is meant to append the non-duid lines in the lease file would strip all the newlines, mangling the lease file. Fix the function allowing to keep the original lines and add a test to check this functionality is kept well functioning. FIXME: the new test and the other duid ones already there store the file in the current working-directory. Tests should not do that. --- src/dhcp/nm-dhcp-dhclient-utils.c | 9 +++++-- src/dhcp/tests/test-dhcp-dhclient.c | 38 +++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 16a76d23eb..a38411ba95 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -630,8 +630,13 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, /* Preserve existing leasefile contents */ if (lines) { - for (iter = lines; iter && *iter; iter++) - g_string_append (s, *iter[0] ? *iter : "\n"); + for (iter = lines; iter && *iter; iter++) { + if (*iter[0]) + g_string_append (s, *iter); + /* avoid to add an extra '\n' at the end of file */ + if ((iter[1]) != NULL) + g_string_append_c (s, '\n'); + } g_strfreev (lines); } diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index a8284b23de..348c625afb 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -811,14 +811,14 @@ test_write_existing_duid (void) g_free (contents); } +#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" static void test_write_existing_commented_duid (void) { - #define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" - #define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" - const char *expected_contents = \ - "default-duid \"" DUID "\";\n" - ORIG_CONTENTS; +#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" + const char *expected_contents = + "default-duid \"" DUID "\";\n" + ORIG_CONTENTS; GError *error = NULL; char *contents = NULL; gboolean success; @@ -842,6 +842,33 @@ test_write_existing_commented_duid (void) g_assert_cmpstr (expected_contents, ==, contents); g_free (contents); +#undef ORIG_CONTENTS +} + +static void +test_write_existing_multiline_duid (void) +{ +#define ORIG_CONTENTS "### Commented old DUID ###\n" \ + "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" + const char *expected_contents = \ + "default-duid \"" DUID "\";\n" + ORIG_CONTENTS; + GError *error = NULL; + gs_free char *contents = NULL; + gboolean success; + nmtst_auto_unlinkfile char *path = g_strdup ("test-dhclient-write-existing-multiline-duid.leases"); + + success = g_file_set_contents (path, ORIG_CONTENTS, -1, &error); + nmtst_assert_success (success, error); + + success = nm_dhcp_dhclient_save_duid (path, DUID, &error); + nmtst_assert_success (success, error); + + success = g_file_get_contents (path, &contents, NULL, &error); + nmtst_assert_success (success, error); + + g_assert_cmpstr (expected_contents, ==, contents); +#undef ORIG_CONTENTS } /*****************************************************************************/ @@ -1025,6 +1052,7 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/write_duid", test_write_duid); g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid); + g_test_add_func ("/dhcp/dhclient/write_existing_multiline_duid", test_write_existing_multiline_duid); return g_test_run (); } From 84c9ce0d79dacf271e976158420305e808d01479 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 10 Apr 2018 11:40:29 +0200 Subject: [PATCH 02/10] dhclient: always update the DUID in the lease file We will soon introduce a property to set a custom DUID and we want to enforce that the provided value is used. Note that this commit does not cause any change in behavior in current code. --- src/dhcp/nm-dhcp-client.c | 8 ++++---- src/dhcp/nm-dhcp-dhclient-utils.c | 32 ++++++++++++++++++----------- src/dhcp/tests/test-dhcp-dhclient.c | 9 ++++---- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index ba517606ed..9ac9af4484 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -592,11 +592,11 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_return_val_if_fail (priv->addr_family == AF_INET6, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); - /* If we don't have one yet, read the default DUID for this DHCPv6 client - * from the client-specific persistent configuration. + nm_assert (!priv->duid); + /* Read the default DUID for this DHCPv6 client from the + * client-specific persistent configuration. */ - if (!priv->duid) - priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); _LOGD ("DUID is '%s'", (str = nm_dhcp_utils_duid_to_string (priv->duid))); diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index a38411ba95..3290dd65cc 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -594,7 +594,8 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error) { - char **lines = NULL, **iter, *l; + gs_strfreev char **lines = NULL; + char **iter, *l; GString *s; gboolean success; gsize len = 0; @@ -610,19 +611,9 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, return FALSE; } - /* If the file already contains an uncommented DUID, leave it */ g_assert (contents); lines = g_strsplit_set (contents, "\n\r", -1); g_free (contents); - for (iter = lines; iter && *iter; iter++) { - l = *iter; - while (g_ascii_isspace (*l)) - l++; - if (g_str_has_prefix (l, DUID_PREFIX)) { - g_strfreev (lines); - return TRUE; - } - } } s = g_string_sized_new (len + 50); @@ -631,13 +622,30 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, /* Preserve existing leasefile contents */ if (lines) { for (iter = lines; iter && *iter; iter++) { + l = *iter; + while (g_ascii_isspace (*l)) + l++; + /* If we find an uncommented DUID in the file, check if + * equal to the one we are going to write: if so, no need + * to update the lease file, otherwise skip the old DUID. + */ + if (g_str_has_prefix (l, DUID_PREFIX)) { + gs_strfreev char **split = NULL; + + split = g_strsplit (l, "\"", -1); + if (nm_streq0 (split[1], escaped_duid)) { + g_string_free (s, TRUE); + return TRUE; + } + continue; + } + if (*iter[0]) g_string_append (s, *iter); /* avoid to add an extra '\n' at the end of file */ if ((iter[1]) != NULL) g_string_append_c (s, '\n'); } - g_strfreev (lines); } success = g_file_set_contents (leasefile, s->str, -1, error); diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index 348c625afb..2f369aacc0 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -785,17 +785,18 @@ static void test_write_existing_duid (void) { const char *duid = "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"; - const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; + const char *original_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; + const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n"; GError *error = NULL; char *contents = NULL; gboolean success; const char *path = "test-dhclient-write-existing-duid.leases"; - success = g_file_set_contents (path, expected_contents, -1, &error); + success = g_file_set_contents (path, original_contents, -1, &error); g_assert_no_error (error); g_assert (success); - /* Save other DUID; should be a no-op */ + /* Save other DUID; should be overwritten */ success = nm_dhcp_dhclient_save_duid (path, duid, &error); g_assert_no_error (error); g_assert (success); @@ -828,7 +829,7 @@ test_write_existing_commented_duid (void) g_assert_no_error (error); g_assert (success); - /* Save other DUID; should be a no-op */ + /* Save other DUID; should be saved on top */ success = nm_dhcp_dhclient_save_duid (path, DUID, &error); g_assert_no_error (error); g_assert (success); From fcc6bf7198779f69c5048fb477a1e23c5c567967 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 25 May 2018 10:33:02 +0200 Subject: [PATCH 03/10] core: add function to retrieve secret_key generation time This will be soon used to derive the timestamp to generate DHCPv6 DUIDs of type DUID-LLT. --- src/nm-core-utils.c | 16 ++++++++++++++++ src/nm-core-utils.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index b1a4cc25a2..40b2b40ad9 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2896,6 +2896,22 @@ nm_utils_secret_key_get (const guint8 **out_secret_key, return secret_key->is_good; } +guint64 +nm_utils_secret_key_get_timestamp (void) +{ + struct stat stat_buf; + const guint8 *key; + gsize key_len; + + if (!nm_utils_secret_key_get (&key, &key_len)) + return 0; + + if (stat (NMSTATEDIR "/secret_key", &stat_buf) != 0) + return 0; + + return stat_buf.st_mtim.tv_sec; +} + /*****************************************************************************/ const char * diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 7f406d214c..69532d3418 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -285,6 +285,7 @@ gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_u gboolean nm_utils_secret_key_get (const guint8 **out_secret_key, gsize *out_key_len); +guint64 nm_utils_secret_key_get_timestamp (void); const char *nm_utils_get_boot_id (void); From 7a0b6b17bb99118ab5a9542c03c3006907538ed0 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 6 Mar 2018 16:10:01 +0100 Subject: [PATCH 04/10] libnm-core: add ipv6.dhcp-duid property allow to specify the DUID to be used int the DHCPv6 client identifier option: the dhcp-duid property accepts either a hex string or the special values "lease", "llt", "ll", "stable-llt", "stable-ll" and "stable-uuid". "lease": give priority to the DUID available in the lease file if any, otherwise fallback to a global default dependant on the dhcp client used. This is the default and reflects how the DUID was managed previously. "ll": enforce generation and use of LL type DUID based on the current hardware address. "llt": enforce generation and use of LLT type DUID based on the current hardware address and a stable time field. "stable-ll": enforce generation and use of LL type DUID based on a link layer address derived from the stable id. "stable-llt": enforce generation and use of LLT type DUID based on a link layer address and a timestamp both derived from the stable id. "stable-uuid": enforce generation and use of a UUID type DUID based on a uuid generated from the stable id. --- clients/common/settings-docs.h.in | 3 +- libnm-core/nm-core-internal.h | 3 + libnm-core/nm-setting-connection.c | 3 +- libnm-core/nm-setting-ip6-config.c | 83 ++++++++++++ libnm-core/nm-setting-ip6-config.h | 4 + libnm-core/nm-utils.c | 46 +++++++ libnm/libnm.ver | 1 + man/NetworkManager.conf.xml | 4 + src/devices/nm-device.c | 197 +++++++++++++++++++++++++++++ src/dhcp/nm-dhcp-client.c | 23 +++- src/dhcp/nm-dhcp-client.h | 3 + src/dhcp/nm-dhcp-manager.c | 11 +- src/dhcp/nm-dhcp-manager.h | 2 + src/dhcp/nm-dhcp-utils.h | 6 + src/nm-core-utils.c | 2 +- src/nm-core-utils.h | 2 +- 16 files changed, 381 insertions(+), 12 deletions(-) diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 06f96a4e1f..c4b15b4cc2 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -152,7 +152,7 @@ #define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").") @@ -233,6 +233,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.") diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index cace423a7d..2a2045e6ba 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -508,4 +508,7 @@ _nm_connection_type_is_master (const char *type) /*****************************************************************************/ +gboolean _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin); + +/*****************************************************************************/ #endif diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index f8f1b017e6..2649838c43 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -1544,7 +1544,8 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) * with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the * generated cloned MAC address for ethernet.cloned-mac-address=stable * and wifi.cloned-mac-address=stable. It is also used as DHCP client - * identifier with ipv4.dhcp-client-id=stable. + * identifier with ipv4.dhcp-client-id=stable and to derive the DHCP + * DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. * * Note that depending on the context where it is used, other parameters are * also seeded into the generation algorithm. For example, a per-host key diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 7c2b45f29f..703afb9e08 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -28,6 +28,7 @@ #include "nm-setting-private.h" #include "nm-core-enum-types.h" +#include "nm-core-internal.h" /** * SECTION:nm-setting-ip6-config @@ -61,6 +62,7 @@ typedef struct { NMSettingIP6ConfigPrivacy ip6_privacy; NMSettingIP6ConfigAddrGenMode addr_gen_mode; char *token; + char *dhcp_duid; } NMSettingIP6ConfigPrivate; enum { @@ -68,6 +70,7 @@ enum { PROP_IP6_PRIVACY, PROP_ADDR_GEN_MODE, PROP_TOKEN, + PROP_DHCP_DUID, LAST_PROP }; @@ -141,6 +144,26 @@ nm_setting_ip6_config_get_token (NMSettingIP6Config *setting) return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->token; } +/** + * nm_setting_ip6_config_get_dhcp_duid: + * @setting: the #NMSettingIP6Config + * + * Returns the value contained in the #NMSettingIP6Config:dhcp-duid + * property. + * + * Returns: The configured DUID value to be included in the DHCPv6 requests + * sent to the DHCPv6 servers. + * + * Since: 1.12 + **/ +const char * +nm_setting_ip6_config_get_dhcp_duid (NMSettingIP6Config *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), NULL); + + return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->dhcp_duid; +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -254,6 +277,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } + if (priv->dhcp_duid) { + if (!_nm_utils_dhcp_duid_valid (priv->dhcp_duid, NULL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid DUID")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_DHCP_DUID); + return FALSE; + } + } + /* Failures from here on, are NORMALIZABLE_ERROR... */ if (token_needs_normalization) { @@ -467,6 +501,10 @@ set_property (GObject *object, guint prop_id, g_free (priv->token); priv->token = g_value_dup_string (value); break; + case PROP_DHCP_DUID: + g_free (priv->dhcp_duid); + priv->dhcp_duid = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -489,6 +527,9 @@ get_property (GObject *object, guint prop_id, case PROP_TOKEN: g_value_set_string (value, priv->token); break; + case PROP_DHCP_DUID: + g_value_set_string (value, priv->dhcp_duid); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -502,6 +543,7 @@ finalize (GObject *object) NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE (self); g_free (priv->token); + g_free (priv->dhcp_duid); G_OBJECT_CLASS (nm_setting_ip6_config_parent_class)->finalize (object); } @@ -790,6 +832,47 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS)); + /** + * NMSettingIP6Config:dhcp-duid: + * + * A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp + * client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried + * in the Client Identifier option. + * If the property is a hex string ('aa:bb:cc') it is interpreted as a binary + * DUID and filled as an opaque value in the Client Identifier option. + * + * The special value "lease" will retrieve the DUID previously used from the + * lease file belonging to the connection. If no DUID is found and "dhclient" + * is the configured dhcp client, the DUID is searched in the system-wide + * dhclient lease file. If still no DUID is found, or another dhcp client is + * used, a global and permanent DUID-UUID (RFC 6355) will be generated based + * on the machine-id. + * + * The special values "llt" and "ll" will generate a DUID of type LLT or LL + * (see RFC 3315) based on the current MAC address of the device. In order to + * try providing a stable DUID-LLT, the time field will contain a constant + * timestamp that is used globally (for all profiles) and persisted to disk. + * + * The special values "stable-llt", "stable-ll" and "stable-uuid" will generate + * a DUID of the corresponding type, derived from the connection's stable-id and + * a per-host unique key. + * So, the link-layer address of "stable-ll" and "stable-llt" will be a generated + * address derived from the stable id. The DUID-LLT time value in the "stable-llt" + * option will be picked among a static timespan of three years (the upper bound + * of the interval is the same constant timestamp used in "llt"). + * + * When the property is unset, the global value provided for "ipv6.dhcp-duid" is + * used. If no global value is provided, the default "lease" value is assumed. + * + * Since: 1.12 + **/ + g_object_class_install_property + (object_class, PROP_DHCP_DUID, + g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_DUID, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /* IP6-specific property overrides */ /* ---dbus--- diff --git a/libnm-core/nm-setting-ip6-config.h b/libnm-core/nm-setting-ip6-config.h index e01a36b756..ae8ab1a23a 100644 --- a/libnm-core/nm-setting-ip6-config.h +++ b/libnm-core/nm-setting-ip6-config.h @@ -45,6 +45,8 @@ G_BEGIN_DECLS #define NM_SETTING_IP6_CONFIG_TOKEN "token" +#define NM_SETTING_IP6_CONFIG_DHCP_DUID "dhcp-duid" + /** * NM_SETTING_IP6_CONFIG_METHOD_IGNORE: * @@ -162,6 +164,8 @@ NM_AVAILABLE_IN_1_2 NMSettingIP6ConfigAddrGenMode nm_setting_ip6_config_get_addr_gen_mode (NMSettingIP6Config *setting); NM_AVAILABLE_IN_1_4 const char *nm_setting_ip6_config_get_token (NMSettingIP6Config *setting); +NM_AVAILABLE_IN_1_12 +const char *nm_setting_ip6_config_get_dhcp_duid (NMSettingIP6Config *setting); G_END_DECLS diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index eb65f8db7d..861b283e45 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4436,6 +4436,52 @@ _nm_utils_inet6_is_token (const struct in6_addr *in6addr) return FALSE; } +/** + * _nm_utils_dhcp_duid_valid: + * @duid: the candidate DUID + * + * Checks if @duid string contains either a special duid value ("ll", + * "llt", "lease" or the "stable" variants) or a valid hex DUID. + * + * Return value: %TRUE or %FALSE + */ +gboolean +_nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin) +{ + gsize duid_len; + gs_unref_bytes GBytes *duid_bin = NULL; + + if (out_duid_bin) + *out_duid_bin = NULL; + + if (!duid) + return FALSE; + + if (NM_IN_STRSET (duid, "lease", + "llt", + "ll", + "stable-llt", + "stable-ll", + "stable-uuid")) { + return TRUE; + } + + duid_bin = nm_utils_hexstr2bin (duid); + if (!duid_bin) + return FALSE; + + duid_len = g_bytes_get_size (duid_bin); + /* MAX DUID lenght is 128 octects + the type code (2 octects). */ + if ( duid_len <= 2 + || duid_len > (128 + 2)) + return FALSE; + + if (out_duid_bin) + *out_duid_bin = g_steal_pointer (&duid_bin); + + return TRUE; +} + /** * nm_utils_check_virtual_device_compatibility: * @virtual_type: a virtual connection type diff --git a/libnm/libnm.ver b/libnm/libnm.ver index ec1b91dad0..8afd01b070 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1355,6 +1355,7 @@ global: nm_setting_connection_get_mdns; nm_setting_connection_mdns_get_type; nm_setting_ip_tunnel_get_flags; + nm_setting_ip6_config_get_dhcp_duid; nm_setting_vpn_get_data_keys; nm_setting_vpn_get_secret_keys; nm_setting_wireless_security_get_fils; diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 8fd62c4782..e2c6562bc6 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -704,6 +704,10 @@ ipv6.ip6-privacy=0 removes extraneous routes from the tables. + + ipv6.dhcp-duid + If left unspecified, it defaults to "lease". + ipv6.dhcp-timeout If left unspecified, the default value for diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7c46f1d608..0edc1f440e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -37,8 +37,11 @@ #include #include #include +#include #include "nm-utils/nm-dedup-multi.h" +#include "nm-utils/nm-random-utils.h" +#include "nm-utils/unaligned.h" #include "nm-common-macros.h" #include "nm-device-private.h" @@ -7679,12 +7682,203 @@ dhcp6_prefix_delegated (NMDhcpClient *client, g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix); } +/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */ +#define EPOCH_DATETIME_200001010000 946684800 + +static GBytes * +generate_duid_llt (const guint8 *hwaddr /* ETH_ALEN bytes */, + gint64 time) +{ + GByteArray *duid_arr; + const guint16 duid_type = htons (1); + const guint16 hw_type = htons (ARPHRD_ETHER); + const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000)); + + duid_arr = g_byte_array_sized_new (2 + 4 + 2 + ETH_ALEN); + + g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &duid_time, 4); + g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + + return g_byte_array_free_to_bytes (duid_arr); +} + +static GBytes * +generate_duid_ll (const guint8 *hwaddr /* ETH_ALEN bytes */) +{ + GByteArray *duid_arr; + const guint16 duid_type = htons (3); + const guint16 hw_type = htons (ARPHRD_ETHER); + gs_unref_bytes GBytes *stable_hwaddr = NULL; + + duid_arr = g_byte_array_sized_new (2 + 2 + ETH_ALEN); + + g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); + g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + + return g_byte_array_free_to_bytes (duid_arr); +} + +static GBytes * +generate_duid_uuid (guint8 *data, gsize data_len) +{ + const guint16 duid_type = g_htons (4); + const int DUID_SIZE = 18; + guint8 *duid_buffer; + + nm_assert (data); + nm_assert (data_len >= 16); + + /* Generate a DHCP Unique Identifier for DHCPv6 using the + * DUID-UUID method (see RFC 6355 section 4). Format is: + * + * u16: type (DUID-UUID = 4) + * u8[16]: UUID bytes + */ + duid_buffer = g_malloc (DUID_SIZE); + + G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); + memcpy (&duid_buffer[0], &duid_type, 2); + + /* UUID is 128 bits, we just take the first 128 bits + * (regardless of data size) as the DUID-UUID. + */ + memcpy (&duid_buffer[2], data, 16); + + return g_bytes_new_take (duid_buffer, DUID_SIZE); +} + +static GBytes * +dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce) +{ + NMSettingIPConfig *s_ip6; + const char *duid; + gs_free char *duid_default = NULL; + const char *duid_error = NULL; + GBytes *duid_out = NULL; + guint8 sha256_digest[32]; + gsize len = sizeof (sha256_digest); + + NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_NEVER); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); + + if (!duid) { + duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ipv6.dhcp-duid", self); + duid = duid_default; + } + + if (!duid || nm_streq (duid, "lease")) + return NULL; + + if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) + return NULL; + + if (duid_out) + return duid_out; + + if (NM_IN_STRSET (duid, "ll", "llt")) { + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto end; + } + if (g_bytes_get_size (hwaddr) != ETH_ALEN) { + duid_error = "unsupported link-layer address"; + goto end; + } + } else if (NM_IN_STRSET (duid, "stable-llt", "stable-ll", "stable-uuid")) { + NMUtilsStableType stable_type; + const char *stable_id = NULL; + guint32 salted_header; + GChecksum *sum; + const guint8 *secret_key; + gsize secret_key_len; + + stable_id = _get_stable_id (self, connection, &stable_type); + if (!stable_id) { + nm_assert_not_reached (); + duid_error = "cannot retrieve the stable id"; + goto end; + } + + salted_header = htonl (670531087 + stable_type); + + nm_utils_secret_key_get (&secret_key, &secret_key_len); + + sum = g_checksum_new (G_CHECKSUM_SHA256); + + g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); + g_checksum_update (sum, (const guchar *) stable_id, -1); + g_checksum_update (sum, (const guchar *) secret_key, secret_key_len); + + g_checksum_get_digest (sum, sha256_digest, &len); + g_checksum_free (sum); + } + + NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_ALWAYS); + +#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) + if (nm_streq0 (duid, "ll")) { + duid_out = generate_duid_ll (g_bytes_get_data (hwaddr, NULL)); + + } else if (nm_streq0 (duid, "llt")) { + gint64 time; + + time = nm_utils_secret_key_get_timestamp (); + if (!time) { + duid_error = "cannot retrieve the secret key timestamp"; + goto end; + } + + duid_out = generate_duid_llt (g_bytes_get_data (hwaddr, NULL), time); + } else if (nm_streq0 (duid, "stable-ll")) { + duid_out = generate_duid_ll (sha256_digest); + + } else if (nm_streq0 (duid, "stable-llt")) { + gint64 time; + + /* We want a variable time between the secret_key timestamp and three years + * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll + * subtract it from the secret_key timestamp. + */ + time = nm_utils_secret_key_get_timestamp (); + if (!time) { + duid_error = "cannot retrieve the secret key timestamp"; + goto end; + } + /* don't use too old timestamps. They cannot be expressed in DUID-LLT and + * would all be truncated to zero. */ + time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); + time -= (unaligned_read_be32 (&sha256_digest[ETH_ALEN]) % EPOCH_DATETIME_THREE_YEARS); + + duid_out = generate_duid_llt (sha256_digest, time); + + } else if (nm_streq0 (duid, "stable-uuid")) { + duid_out = generate_duid_uuid (sha256_digest, len); + } + +end: + if (!duid_out) { + if (!duid_error) + duid_error = "generation failed"; + _LOGD (LOGD_IP6, "duid-gen (%s): %s. Fallback to 'lease'.", duid, duid_error); + } + return duid_out; +} + static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip6; gs_unref_bytes GBytes *hwaddr = NULL; + gs_unref_bytes GBytes *duid = NULL; + NMDhcpDuidEnforce enforce_duid; + const NMPlatformIP6Address *ll_addr = NULL; g_assert (connection); @@ -7705,6 +7899,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); + duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_multi_index (self), nm_device_get_ip_iface (self), @@ -7716,6 +7911,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_device_get_route_metric (self, AF_INET6), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), nm_setting_ip_config_get_dhcp_hostname (s_ip6), + duid, + enforce_duid, get_dhcp_timeout (self, AF_INET6), priv->dhcp_anycast_address, (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 9ac9af4484..03d5dedbdf 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -576,6 +576,8 @@ get_duid (NMDhcpClient *self) gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, + GBytes *client_id, + NMDhcpDuidEnforce enforce_duid, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, @@ -593,10 +595,23 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_return_val_if_fail (priv->uuid != NULL, FALSE); nm_assert (!priv->duid); - /* Read the default DUID for this DHCPv6 client from the - * client-specific persistent configuration. - */ - priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); + + switch (enforce_duid) { + case NM_DHCP_DUID_ENFORCE_NEVER: + case NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK: + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); + if (priv->duid) + break; + /* fall through */ + case NM_DHCP_DUID_ENFORCE_ALWAYS: + if (client_id) { + priv->duid = g_bytes_ref (client_id); + break; + } + /* fall through */ + default: + nm_assert_not_reached (); + } _LOGD ("DUID is '%s'", (str = nm_dhcp_utils_duid_to_string (priv->duid))); diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 111b063bd5..fc8c1a5693 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -23,6 +23,7 @@ #include "nm-setting-ip6-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" +#include "nm-dhcp-utils.h" #define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ #define NM_DHCP_TIMEOUT_INFINITY G_MAXINT32 @@ -149,6 +150,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, + GBytes *client_id, + NMDhcpDuidEnforce enforce_duid, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index aa40e8037d..2d85c73ac7 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -164,6 +164,7 @@ client_start (NMDhcpManager *self, guint32 route_metric, const struct in6_addr *ipv6_ll_addr, GBytes *dhcp_client_id, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, @@ -218,7 +219,7 @@ client_start (NMDhcpManager *self, if (addr_family == AF_INET) success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); else - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); + success = nm_dhcp_client_start_ip6 (client, dhcp_client_id, enforce_duid, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); if (!success) { remove_client_unref (self, client); @@ -280,7 +281,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, return client_start (self, AF_INET, multi_idx, iface, ifindex, hwaddr, uuid, route_table, route_metric, NULL, - dhcp_client_id, timeout, dhcp_anycast_addr, hostname, + dhcp_client_id, 0, timeout, dhcp_anycast_addr, hostname, use_fqdn, FALSE, 0, last_ip_address, 0); } @@ -297,6 +298,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, + GBytes *duid, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, @@ -314,8 +317,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, hostname = dhcp_hostname ?: priv->default_hostname; } return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid, - route_table, route_metric, ll_addr, - NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only, + route_table, route_metric, ll_addr, duid, enforce_duid, + timeout, dhcp_anycast_addr, hostname, TRUE, info_only, privacy, NULL, needed_prefixes); } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index f8a7e31d2d..ed8ee742a9 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -72,6 +72,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, + GBytes *duid, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 5c127bd194..afb87c1a14 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -24,6 +24,12 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" +typedef enum { + NM_DHCP_DUID_ENFORCE_NEVER = 0, + NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK, + NM_DHCP_DUID_ENFORCE_ALWAYS, +} NMDhcpDuidEnforce; + NMIP4Config *nm_dhcp_utils_ip4_config_from_options (struct _NMDedupMultiIndex *multi_idx, int ifindex, const char *iface, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 40b2b40ad9..09b465a07e 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2896,7 +2896,7 @@ nm_utils_secret_key_get (const guint8 **out_secret_key, return secret_key->is_good; } -guint64 +gint64 nm_utils_secret_key_get_timestamp (void) { struct stat stat_buf; diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 69532d3418..085304008c 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -285,7 +285,7 @@ gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_u gboolean nm_utils_secret_key_get (const guint8 **out_secret_key, gsize *out_key_len); -guint64 nm_utils_secret_key_get_timestamp (void); +gint64 nm_utils_secret_key_get_timestamp (void); const char *nm_utils_get_boot_id (void); From 0d841e7471325b4bda484ae1838675debf08d2a5 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 3 May 2018 18:20:29 +0200 Subject: [PATCH 05/10] dhcp: remove fallback DUID-UUID generation from dhcp code This commit centralizes the DUID generation in nm-device.c. As a consequence, a DUID is always provided when starting a DHCPv6 client. The DHCP client can override the passed DUID with the value contained in the client-specific lease file. --- src/devices/nm-device.c | 67 +++++++++++++++++++++++++++++++------ src/dhcp/nm-dhcp-client.c | 66 +++--------------------------------- src/dhcp/nm-dhcp-dhclient.c | 3 +- 3 files changed, 62 insertions(+), 74 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0edc1f440e..66bd419447 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7750,6 +7750,37 @@ generate_duid_uuid (guint8 *data, gsize data_len) return g_bytes_new_take (duid_buffer, DUID_SIZE); } +static GBytes * +generate_duid_from_machine_id (void) +{ + gs_free const char *machine_id_s = NULL; + uuid_t uuid; + GChecksum *sum; + guint8 sha256_digest[32]; + gsize len = sizeof (sha256_digest); + static GBytes *global_duid = NULL; + + if (global_duid) + return g_bytes_ref (global_duid); + + machine_id_s = nm_utils_machine_id_read (); + if (nm_utils_machine_id_parse (machine_id_s, uuid)) { + /* Hash the machine ID so it's not leaked to the network */ + sum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid)); + g_checksum_get_digest (sum, sha256_digest, &len); + g_checksum_free (sum); + } else { + nm_log_warn (LOGD_IP6, "global duid: failed to read " SYSCONFDIR "/machine-id " + "or " LOCALSTATEDIR "/lib/dbus/machine-id to generate " + "DHCPv6 DUID; creating non-persistent random DUID."); + nm_utils_random_bytes (sha256_digest, len); + } + + global_duid = generate_duid_uuid (sha256_digest, len); + return g_bytes_ref (global_duid); +} + static GBytes * dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce) { @@ -7760,8 +7791,8 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp GBytes *duid_out = NULL; guint8 sha256_digest[32]; gsize len = sizeof (sha256_digest); + NMDhcpDuidEnforce duid_enforce = NM_DHCP_DUID_ENFORCE_NEVER; - NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_NEVER); s_ip6 = nm_connection_get_setting_ip6_config (connection); duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); @@ -7772,14 +7803,18 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp duid = duid_default; } - if (!duid || nm_streq (duid, "lease")) - return NULL; + if (!duid || nm_streq (duid, "lease")) { + duid_out = generate_duid_from_machine_id (); + goto end; + } - if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) - return NULL; + if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) { + duid_error = "invalid duid"; + goto end; + } if (duid_out) - return duid_out; + goto end; if (NM_IN_STRSET (duid, "ll", "llt")) { if (!hwaddr) { @@ -7819,7 +7854,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp g_checksum_free (sum); } - NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_ALWAYS); + duid_enforce = NM_DHCP_DUID_ENFORCE_ALWAYS; #define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) if (nm_streq0 (duid, "ll")) { @@ -7861,12 +7896,24 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp duid_out = generate_duid_uuid (sha256_digest, len); } + duid_error = "generation failed"; end: if (!duid_out) { - if (!duid_error) - duid_error = "generation failed"; - _LOGD (LOGD_IP6, "duid-gen (%s): %s. Fallback to 'lease'.", duid, duid_error); + guint8 uuid[16]; + + if (duid_error) + _LOGW (LOGD_IP6, "duid-gen (%s): %s. Fallback to random DUID-UUID.", duid, duid_error); + + nm_utils_random_bytes (uuid, sizeof (uuid)); + duid_out = generate_duid_uuid (uuid, sizeof (uuid)); } + + _LOGD (LOGD_IP6, "DUID gen: '%s' (%s)", + nm_dhcp_utils_duid_to_string (duid_out), + (duid_enforce == NM_DHCP_DUID_ENFORCE_ALWAYS) ? "enforcing" : "fallback"); + + NM_SET_OUT (out_enforce, duid_enforce); + return duid_out; } diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 03d5dedbdf..be2b538db6 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -512,66 +512,10 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } -static GBytes * -generate_duid_from_machine_id (void) -{ - const int DUID_SIZE = 18; - guint8 *duid_buffer; - GChecksum *sum; - guint8 buffer[32]; /* SHA256 digest size */ - gsize sumlen = sizeof (buffer); - const guint16 duid_type = g_htons (4); - uuid_t uuid; - gs_free char *machine_id_s = NULL; - gs_free char *str = NULL; - GBytes *duid; - - machine_id_s = nm_utils_machine_id_read (); - if (nm_utils_machine_id_parse (machine_id_s, uuid)) { - /* Hash the machine ID so it's not leaked to the network */ - sum = g_checksum_new (G_CHECKSUM_SHA256); - g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid)); - g_checksum_get_digest (sum, buffer, &sumlen); - g_checksum_free (sum); - } else { - nm_log_warn (LOGD_DHCP, "dhcp: failed to read " SYSCONFDIR "/machine-id " - "or " LOCALSTATEDIR "/lib/dbus/machine-id to generate " - "DHCPv6 DUID; creating non-persistent random DUID."); - - nm_utils_random_bytes (buffer, sizeof (buffer)); - } - - /* Generate a DHCP Unique Identifier for DHCPv6 using the - * DUID-UUID method (see RFC 6355 section 4). Format is: - * - * u16: type (DUID-UUID = 4) - * u8[16]: UUID bytes - */ - duid_buffer = g_malloc (DUID_SIZE); - - G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); - memcpy (&duid_buffer[0], &duid_type, 2); - - /* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first - * 128 bits of the SHA256 as the DUID-UUID. - */ - memcpy (&duid_buffer[2], buffer, 16); - - duid = g_bytes_new_take (duid_buffer, DUID_SIZE); - nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s", - (str = nm_dhcp_utils_duid_to_string (duid))); - return duid; -} - static GBytes * get_duid (NMDhcpClient *self) { - static GBytes *duid = NULL; - - if (G_UNLIKELY (!duid)) - duid = generate_duid_from_machine_id (); - - return g_bytes_ref (duid); + return NULL; } gboolean @@ -595,6 +539,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_return_val_if_fail (priv->uuid != NULL, FALSE); nm_assert (!priv->duid); + nm_assert (client_id); switch (enforce_duid) { case NM_DHCP_DUID_ENFORCE_NEVER: @@ -604,11 +549,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, break; /* fall through */ case NM_DHCP_DUID_ENFORCE_ALWAYS: - if (client_id) { - priv->duid = g_bytes_ref (client_id); - break; - } - /* fall through */ + priv->duid = g_bytes_ref (client_id); + break; default: nm_assert_not_reached (); } diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 93306ddd5f..3bd14ebe89 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -619,8 +619,7 @@ get_duid (NMDhcpClient *client) } } - /* return our DUID, otherwise let the parent class make a default DUID */ - return duid ?: NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); + return duid; } /*****************************************************************************/ From f054c3fcaadb39c6597d9d9e4ed94b5d4fc29508 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 3 May 2018 18:52:43 +0200 Subject: [PATCH 06/10] dhcp: allow to skip DUID search from DHCP client global configuration When the used client is dhclient we were used to search for DUID not only in the specific lease files generated by NetworkManager, but also in the global lease file generated outside NetworkManager. Keep this capability but allow to just search in the NM lease files if a value different from the default one is specified in dhcp-duid. --- src/dhcp/nm-dhcp-client.c | 21 ++++++++------------- src/dhcp/nm-dhcp-client.h | 4 +++- src/dhcp/nm-dhcp-dhclient.c | 4 ++-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index be2b538db6..390b7054ec 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -513,7 +513,7 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, } static GBytes * -get_duid (NMDhcpClient *self) +get_duid (NMDhcpClient *self, gboolean global) { return NULL; } @@ -541,19 +541,14 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, nm_assert (!priv->duid); nm_assert (client_id); - switch (enforce_duid) { - case NM_DHCP_DUID_ENFORCE_NEVER: - case NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK: - priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); - if (priv->duid) - break; - /* fall through */ - case NM_DHCP_DUID_ENFORCE_ALWAYS: + if (enforce_duid == NM_DHCP_DUID_ENFORCE_NEVER) + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self, TRUE); + else if (enforce_duid == NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK) + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self, FALSE); + + /* NM_DHCP_DUID_ENFORCE_ALWAYS and fallback */ + if (!priv->duid) priv->duid = g_bytes_ref (client_id); - break; - default: - nm_assert_not_reached (); - } _LOGD ("DUID is '%s'", (str = nm_dhcp_utils_duid_to_string (priv->duid))); diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index fc8c1a5693..98c3ed262e 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -96,13 +96,15 @@ typedef struct { /** * get_duid: * @self: the #NMDhcpClient + * @global: if set to #true, the duid should be searched also in the + * DHCP client's system-wide persistent configuration. * * Attempts to find an existing DHCPv6 DUID for this client in the DHCP * client's persistent configuration. Returned DUID should be the binary * representation of the DUID. If no DUID is found, %NULL should be * returned. */ - GBytes *(*get_duid) (NMDhcpClient *self); + GBytes *(*get_duid) (NMDhcpClient *self, gboolean global); /* Signals */ void (*state_changed) (NMDhcpClient *self, diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 3bd14ebe89..43746dd394 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -582,7 +582,7 @@ state_changed (NMDhcpClient *client, } static GBytes * -get_duid (NMDhcpClient *client) +get_duid (NMDhcpClient *client, gboolean global) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -607,7 +607,7 @@ get_duid (NMDhcpClient *client) g_free (leasefile); } - if (!duid) { + if (!duid && global) { /* Otherwise read the default machine-wide DUID */ _LOGD ("looking for default DUID in '%s'", priv->def_leasefile); duid = nm_dhcp_dhclient_read_duid (priv->def_leasefile, &error); From fa478d8f22873be0d1c85fdab781afde3a58176f Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 16 Apr 2018 16:41:23 +0200 Subject: [PATCH 07/10] ifcfg: make_ip6_setting cleanup & optimization 1/2 get rid of the useless "str_value" variable. --- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 722d4e366d..d20c3f303d 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1686,7 +1686,6 @@ make_ip6_setting (shvarFile *ifcfg, NMSettingIPConfig *s_ip6 = NULL; const char *v; char *value = NULL; - char *str_value; char *route6_path = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; @@ -1745,56 +1744,56 @@ make_ip6_setting (shvarFile *ifcfg, /* Find out method property */ /* Is IPV6 enabled? Set method to "ignored", when not enabled */ - str_value = svGetValueStr_cp (ifcfg, "IPV6INIT"); + value = svGetValueStr_cp (ifcfg, "IPV6INIT"); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); - if (!str_value) { + if (!value) { if (network_ifcfg) ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); } - g_free (str_value); + g_free (value); if (!ipv6init) method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); - str_value = svGetValueStr_cp (ifcfg, "IPV6_AUTOCONF"); + value = svGetValueStr_cp (ifcfg, "IPV6_AUTOCONF"); dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); - if (!g_strcmp0 (str_value, "shared")) + if (!g_strcmp0 (value, "shared")) method = NM_SETTING_IP6_CONFIG_METHOD_SHARED; - else if (svParseBoolean (str_value, !ipv6forwarding)) + else if (svParseBoolean (value, !ipv6forwarding)) method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; else if (dhcp6) method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; else { /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ - g_free (str_value); - str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR"); - if (!str_value) - str_value = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); + g_free (value); + value = svGetValueStr_cp (ifcfg, "IPV6ADDR"); + if (!value) + value = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); - if (!str_value) + if (!value) method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; } - g_free (str_value); + g_free (value); } /* TODO - handle other methods */ /* Read IPv6 Privacy Extensions configuration */ - str_value = svGetValueStr_cp (ifcfg, "IPV6_PRIVACY"); - if (str_value) { - ip6_privacy = svParseBoolean (str_value, FALSE); + value = svGetValueStr_cp (ifcfg, "IPV6_PRIVACY"); + if (value) { + ip6_privacy = svParseBoolean (value, FALSE); if (!ip6_privacy) - ip6_privacy = (g_strcmp0 (str_value, "rfc4941") == 0) || - (g_strcmp0 (str_value, "rfc3041") == 0); + ip6_privacy = (g_strcmp0 (value, "rfc4941") == 0) || + (g_strcmp0 (value, "rfc3041") == 0); } ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); - ip6_privacy_val = str_value ? + ip6_privacy_val = value ? (ip6_privacy ? (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) : NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - g_free (str_value); + g_free (value); /* the route table (policy routing) is ignored if we don't handle routes. */ route_table = svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10, @@ -1900,10 +1899,10 @@ make_ip6_setting (shvarFile *ifcfg, g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, i_val, NULL); /* IPv6 tokenized interface identifier */ - str_value = svGetValueStr_cp (ifcfg, "IPV6_TOKEN"); - if (str_value) { - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, str_value, NULL); - g_free (str_value); + value = svGetValueStr_cp (ifcfg, "IPV6_TOKEN"); + if (value) { + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, value, NULL); + g_free (value); } /* DNS servers From e9321713a90a2f1098afbdbbfbb462638c54a368 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 16 Apr 2018 17:16:28 +0200 Subject: [PATCH 08/10] ifcfg: make_ip6_setting cleanup & optimization 2/2 get rid of svGetValueStr_cp() in favor of svGetValueStr() in the make_ip6_setting() function --- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 141 +++++++++--------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index d20c3f303d..4d9e7f6595 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1685,11 +1685,13 @@ make_ip6_setting (shvarFile *ifcfg, { NMSettingIPConfig *s_ip6 = NULL; const char *v; - char *value = NULL; + gs_free char *value = NULL; char *route6_path = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - char *ipv6addr, *ipv6addr_secondaries; + const char *ipv6addr, *ipv6addr_secondaries; + gs_free char *ipv6addr_to_free = NULL; + gs_free char *ipv6addr_secondaries_to_free = NULL; gs_free const char **list = NULL; const char *const *iter; guint32 i; @@ -1715,13 +1717,16 @@ make_ip6_setting (shvarFile *ifcfg, * When both are set, the device specified in IPV6_DEFAULTGW takes preference. */ if (network_ifcfg) { - char *ipv6_defaultgw, *ipv6_defaultdev; - char *default_dev = NULL; + const char *ipv6_defaultgw, *ipv6_defaultdev; + gs_free char *ipv6_defaultgw_to_free = NULL; + gs_free char *ipv6_defaultdev_to_free = NULL; + const char *default_dev = NULL; /* Get the connection ifcfg device name and the global default route device */ - value = svGetValueStr_cp (ifcfg, "DEVICE"); - ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); - ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV"); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DEVICE", &value); + ipv6_defaultgw = svGetValueStr (network_ifcfg, "IPV6_DEFAULTGW", &ipv6_defaultgw_to_free); + ipv6_defaultdev = svGetValueStr (network_ifcfg, "IPV6_DEFAULTDEV", &ipv6_defaultdev_to_free); if (ipv6_defaultgw) { default_dev = strchr (ipv6_defaultgw, '%'); @@ -1734,66 +1739,64 @@ make_ip6_setting (shvarFile *ifcfg, /* If there was a global default route device specified, then only connections * for that device can be the default connection. */ - if (default_dev && value) - never_default = !!strcmp (value, default_dev); - - g_free (ipv6_defaultgw); - g_free (ipv6_defaultdev); - g_free (value); + if (default_dev && v) + never_default = !!strcmp (v, default_dev); } /* Find out method property */ /* Is IPV6 enabled? Set method to "ignored", when not enabled */ - value = svGetValueStr_cp (ifcfg, "IPV6INIT"); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6INIT", &value); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); - if (!value) { + if (!v) { if (network_ifcfg) ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); } - g_free (value); if (!ipv6init) method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); - value = svGetValueStr_cp (ifcfg, "IPV6_AUTOCONF"); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_AUTOCONF", &value); dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); - if (!g_strcmp0 (value, "shared")) + if (!g_strcmp0 (v, "shared")) method = NM_SETTING_IP6_CONFIG_METHOD_SHARED; - else if (svParseBoolean (value, !ipv6forwarding)) + else if (svParseBoolean (v, !ipv6forwarding)) method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; else if (dhcp6) method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; else { /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ - g_free (value); - value = svGetValueStr_cp (ifcfg, "IPV6ADDR"); - if (!value) - value = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6ADDR", &value); + if (!v) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6ADDR_SECONDARIES", &value); + } - if (!value) + if (!v) method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; } - g_free (value); } /* TODO - handle other methods */ /* Read IPv6 Privacy Extensions configuration */ - value = svGetValueStr_cp (ifcfg, "IPV6_PRIVACY"); - if (value) { - ip6_privacy = svParseBoolean (value, FALSE); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_PRIVACY", &value); + if (v) { + ip6_privacy = svParseBoolean (v, FALSE); if (!ip6_privacy) - ip6_privacy = (g_strcmp0 (value, "rfc4941") == 0) || - (g_strcmp0 (value, "rfc3041") == 0); + ip6_privacy = (g_strcmp0 (v, "rfc4941") == 0) || + (g_strcmp0 (v, "rfc3041") == 0); } ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); - ip6_privacy_val = value ? + ip6_privacy_val = v ? (ip6_privacy ? (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) : NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - g_free (value); /* the route table (policy routing) is ignored if we don't handle routes. */ route_table = svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10, @@ -1820,19 +1823,20 @@ make_ip6_setting (shvarFile *ifcfg, if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) return NM_SETTING (s_ip6); - value = svGetValueStr_cp (ifcfg, "DHCPV6_HOSTNAME"); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCPV6_HOSTNAME", &value); /* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is * auto or dhcp: this is required to support old ifcfg files */ - if (!value && ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + if (!v && ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP))) { - value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME"); - if (value && !strchr (value, '.')) - g_clear_pointer (&value, g_free); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCP_HOSTNAME", &value); + if (v && !strchr (v, '.')) + v = NULL; } - if (value) - g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL); - g_free (value); + if (v) + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, v, NULL); g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCPV6_SEND_HOSTNAME", TRUE), NULL); @@ -1842,18 +1846,16 @@ make_ip6_setting (shvarFile *ifcfg, * added to the automatic ones. Note that this is not currently supported by * the legacy 'network' service (ifup-eth). */ - ipv6addr = svGetValueStr_cp (ifcfg, "IPV6ADDR"); - ipv6addr_secondaries = svGetValueStr_cp (ifcfg, "IPV6ADDR_SECONDARIES"); + ipv6addr = svGetValueStr (ifcfg, "IPV6ADDR", &ipv6addr_to_free); + ipv6addr_secondaries = svGetValueStr (ifcfg, "IPV6ADDR_SECONDARIES", &ipv6addr_secondaries_to_free); + nm_clear_g_free (&value); value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL, ipv6addr ?: "", ipv6addr_secondaries ?: "", NULL); - g_free (ipv6addr); - g_free (ipv6addr_secondaries); list = nm_utils_strsplit_set (value, " "); - g_free (value); for (iter = list, i = 0; iter && *iter; iter++, i++) { NMIPAddress *addr = NULL; @@ -1867,25 +1869,26 @@ make_ip6_setting (shvarFile *ifcfg, /* Gateway */ if (nm_setting_ip_config_get_num_addresses (s_ip6)) { - value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); - if (!value) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_DEFAULTGW", &value); + if (!v) { /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ - if (network_ifcfg) - value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); + if (network_ifcfg) { + nm_clear_g_free (&value); + v = svGetValueStr (network_ifcfg, "IPV6_DEFAULTGW", &value); + } } - if (value) { + if (v) { char *ptr; - if ((ptr = strchr (value, '%')) != NULL) + if ((ptr = strchr (v, '%')) != NULL) *ptr = '\0'; /* remove %interface prefix if present */ - if (!nm_utils_ipaddr_valid (AF_INET6, value)) { + if (!nm_utils_ipaddr_valid (AF_INET6, v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP6 address '%s'", value); - g_free (value); + "Invalid IP6 address '%s'", v); goto error; } - g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, value, NULL); - g_free (value); + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, v, NULL); } } @@ -1899,11 +1902,10 @@ make_ip6_setting (shvarFile *ifcfg, g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, i_val, NULL); /* IPv6 tokenized interface identifier */ - value = svGetValueStr_cp (ifcfg, "IPV6_TOKEN"); - if (value) { - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, value, NULL); - g_free (value); - } + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_TOKEN", &value); + if (v) + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, v, NULL); /* DNS servers * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) @@ -1912,24 +1914,22 @@ make_ip6_setting (shvarFile *ifcfg, char tag[256]; numbered_tag (tag, "DNS", i); - value = svGetValueStr_cp (ifcfg, tag); - if (!value) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, tag, &value); + if (!v) { /* all done */ break; } - if (nm_utils_ipaddr_valid (AF_INET6, value)) { - if (!nm_setting_ip_config_add_dns (s_ip6, value)) + if (nm_utils_ipaddr_valid (AF_INET6, v)) { + if (!nm_setting_ip_config_add_dns (s_ip6, v)) PARSE_WARNING ("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_valid (AF_INET, value)) { + } else if (nm_utils_ipaddr_valid (AF_INET, v)) { /* Ignore IPv4 addresses */ } else { - PARSE_WARNING ("invalid DNS server address %s", value); - g_free (value); + PARSE_WARNING ("invalid DNS server address %s", v); goto error; } - - g_free (value); } if (!routes_read) { @@ -1960,7 +1960,6 @@ make_ip6_setting (shvarFile *ifcfg, /* DNS options */ nm_clear_g_free (&value); parse_dns_options (s_ip6, svGetValue (ifcfg, "IPV6_RES_OPTIONS", &value)); - g_free (value); /* DNS priority */ priority = svGetValueInt64 (ifcfg, "IPV6_DNS_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); From f913ed4d0c4052658fc08b14e81aea4285d8fe42 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 6 Apr 2018 18:25:06 +0200 Subject: [PATCH 09/10] ifcfg: introduce DHCPV6_DUID to map ipv6.dhcp-duid property --- libnm-core/nm-setting-ip6-config.c | 10 ++++++++++ src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 5 +++++ src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 703afb9e08..808c88a763 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -866,6 +866,16 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) * * Since: 1.12 **/ + /* ---ifcfg-rh--- + * property: dhcp-duid + * variable: DHCPV6_DUID(+) + * description: A string sent to the DHCPv6 server to identify the local machine. + * Apart from the special values "lease", "stable-llt", "stable-ll", "stable-uuid", + * "llt" and "ll" a binary value in hex format is expected. An hex string where + * each octet is separated by a colon is also accepted. + * example: DHCPV6_DUID=LL; DHCPV6_DUID=0301deadbeef0001; DHCPV6_DUID=03:01:de:ad:be:ef:00:01 + * ---end--- + */ g_object_class_install_property (object_class, PROP_DHCP_DUID, g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_DUID, "", "", diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 4d9e7f6595..b16cc28122 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1823,6 +1823,11 @@ make_ip6_setting (shvarFile *ifcfg, if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) return NM_SETTING (s_ip6); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCPV6_DUID", &value); + if (v) + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_DHCP_DUID, v, NULL); + nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "DHCPV6_HOSTNAME", &value); /* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index bdad738966..1656530911 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2568,6 +2568,7 @@ write_ip6_setting (NMConnection *connection, svUnsetValue (ifcfg, "IPV6INIT"); svUnsetValue (ifcfg, "IPV6_AUTOCONF"); svUnsetValue (ifcfg, "DHCPV6C"); + svUnsetValue (ifcfg, "DHCPv6_DUID"); svUnsetValue (ifcfg, "DHCPV6_HOSTNAME"); svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME"); svUnsetValue (ifcfg, "IPV6_DEFROUTE"); @@ -2608,6 +2609,9 @@ write_ip6_setting (NMConnection *connection, svUnsetValue (ifcfg, "DHCPV6C"); } + svSetValueStr (ifcfg, "DHCPV6_DUID", + nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6))); + write_ip6_setting_dhcp_hostname (s_ip6, ifcfg); /* Write out IP addresses */ From 02c4b2c9a8f570f668bc9391117fc96dcc57307e Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 30 May 2018 11:53:52 +0200 Subject: [PATCH 10/10] cli: add dhcp-duid support --- clients/common/nm-meta-setting-desc.c | 3 +++ clients/tests/test-client.check-on-disk/test_003-022.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-023.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-026.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-027.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-043.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-044.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-047.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-048.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-069.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-070.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-071.expected | 3 ++- clients/tests/test-client.check-on-disk/test_003-072.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-008.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-009.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-013.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-014.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-021.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-022.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-023.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-024.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-025.expected | 3 ++- clients/tests/test-client.check-on-disk/test_004-026.expected | 3 ++- 23 files changed, 47 insertions(+), 22 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 2988b084b7..1154fabfb6 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -6073,6 +6073,9 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { | NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT, ), ), + PROPERTY_INFO (NM_SETTING_IP6_CONFIG_DHCP_DUID, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID, + .property_type = &_pt_gobject_string, + ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME, .property_type = &_pt_gobject_bool, ), diff --git a/clients/tests/test-client.check-on-disk/test_003-022.expected b/clients/tests/test-client.check-on-disk/test_003-022.expected index fb27dfc02a..b29a2ea543 100644 --- a/clients/tests/test-client.check-on-disk/test_003-022.expected +++ b/clients/tests/test-client.check-on-disk/test_003-022.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:751:test_003()/22 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 3516 bytes +stdout: 3559 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-023.expected b/clients/tests/test-client.check-on-disk/test_003-023.expected index 577bd49818..0c0b7e4e16 100644 --- a/clients/tests/test-client.check-on-disk/test_003-023.expected +++ b/clients/tests/test-client.check-on-disk/test_003-023.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:751:test_003()/23 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3534 bytes +stdout: 3577 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-026.expected b/clients/tests/test-client.check-on-disk/test_003-026.expected index 836780edd9..6a9803af4b 100644 --- a/clients/tests/test-client.check-on-disk/test_003-026.expected +++ b/clients/tests/test-client.check-on-disk/test_003-026.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:757:test_003()/26 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 4180 bytes +stdout: 4223 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-027.expected b/clients/tests/test-client.check-on-disk/test_003-027.expected index d7122ebfb2..c4650c059e 100644 --- a/clients/tests/test-client.check-on-disk/test_003-027.expected +++ b/clients/tests/test-client.check-on-disk/test_003-027.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:757:test_003()/27 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4202 bytes +stdout: 4245 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-043.expected b/clients/tests/test-client.check-on-disk/test_003-043.expected index ee879f85a6..ed2e00d73e 100644 --- a/clients/tests/test-client.check-on-disk/test_003-043.expected +++ b/clients/tests/test-client.check-on-disk/test_003-043.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:751:test_003()/43 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 3516 bytes +stdout: 3559 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-044.expected b/clients/tests/test-client.check-on-disk/test_003-044.expected index b891b3d940..97a1a3d470 100644 --- a/clients/tests/test-client.check-on-disk/test_003-044.expected +++ b/clients/tests/test-client.check-on-disk/test_003-044.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:751:test_003()/44 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3534 bytes +stdout: 3577 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-047.expected b/clients/tests/test-client.check-on-disk/test_003-047.expected index 9ab2a4ca49..bc4f457889 100644 --- a/clients/tests/test-client.check-on-disk/test_003-047.expected +++ b/clients/tests/test-client.check-on-disk/test_003-047.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:757:test_003()/47 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 4845 bytes +stdout: 4888 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-048.expected b/clients/tests/test-client.check-on-disk/test_003-048.expected index a6171ff9c2..9742869cb8 100644 --- a/clients/tests/test-client.check-on-disk/test_003-048.expected +++ b/clients/tests/test-client.check-on-disk/test_003-048.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:757:test_003()/48 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4871 bytes +stdout: 4914 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-069.expected b/clients/tests/test-client.check-on-disk/test_003-069.expected index 92f207a075..81d1edaa2f 100644 --- a/clients/tests/test-client.check-on-disk/test_003-069.expected +++ b/clients/tests/test-client.check-on-disk/test_003-069.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:801:test_003()/69 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 4848 bytes +stdout: 4891 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-070.expected b/clients/tests/test-client.check-on-disk/test_003-070.expected index 454f96d7d1..50cf870741 100644 --- a/clients/tests/test-client.check-on-disk/test_003-070.expected +++ b/clients/tests/test-client.check-on-disk/test_003-070.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:801:test_003()/70 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4875 bytes +stdout: 4918 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-071.expected b/clients/tests/test-client.check-on-disk/test_003-071.expected index 6ce3b3a698..14a0b2a06b 100644 --- a/clients/tests/test-client.check-on-disk/test_003-071.expected +++ b/clients/tests/test-client.check-on-disk/test_003-071.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:804:test_003()/71 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 4183 bytes +stdout: 4226 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_003-072.expected b/clients/tests/test-client.check-on-disk/test_003-072.expected index 52d30d16b2..d7912b81b8 100644 --- a/clients/tests/test-client.check-on-disk/test_003-072.expected +++ b/clients/tests/test-client.check-on-disk/test_003-072.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:804:test_003()/72 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4206 bytes +stdout: 4249 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -75,6 +75,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-008.expected b/clients/tests/test-client.check-on-disk/test_004-008.expected index eb0d66afdf..51ce2a39e8 100644 --- a/clients/tests/test-client.check-on-disk/test_004-008.expected +++ b/clients/tests/test-client.check-on-disk/test_004-008.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:823:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 3713 bytes +stdout: 3756 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -77,6 +77,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-009.expected b/clients/tests/test-client.check-on-disk/test_004-009.expected index 3248f83504..c5155cf832 100644 --- a/clients/tests/test-client.check-on-disk/test_004-009.expected +++ b/clients/tests/test-client.check-on-disk/test_004-009.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:823:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3731 bytes +stdout: 3774 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -77,6 +77,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-013.expected b/clients/tests/test-client.check-on-disk/test_004-013.expected index b2fad08bd4..74164e5544 100644 --- a/clients/tests/test-client.check-on-disk/test_004-013.expected +++ b/clients/tests/test-client.check-on-disk/test_004-013.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:835:test_004()/13 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 3231 bytes +stdout: 3274 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-014.expected b/clients/tests/test-client.check-on-disk/test_004-014.expected index 8ad3eb0350..ede05f47ad 100644 --- a/clients/tests/test-client.check-on-disk/test_004-014.expected +++ b/clients/tests/test-client.check-on-disk/test_004-014.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:835:test_004()/14 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3241 bytes +stdout: 3284 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-021.expected b/clients/tests/test-client.check-on-disk/test_004-021.expected index 5ae414a111..7f876ded47 100644 --- a/clients/tests/test-client.check-on-disk/test_004-021.expected +++ b/clients/tests/test-client.check-on-disk/test_004-021.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:845:test_004()/21 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 4283 bytes +stdout: 4326 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-022.expected b/clients/tests/test-client.check-on-disk/test_004-022.expected index 6921761f5f..75582122f4 100644 --- a/clients/tests/test-client.check-on-disk/test_004-022.expected +++ b/clients/tests/test-client.check-on-disk/test_004-022.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:845:test_004()/22 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4297 bytes +stdout: 4340 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-023.expected b/clients/tests/test-client.check-on-disk/test_004-023.expected index cf49305a88..4043e845b9 100644 --- a/clients/tests/test-client.check-on-disk/test_004-023.expected +++ b/clients/tests/test-client.check-on-disk/test_004-023.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:854:test_004()/23 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 4319 bytes +stdout: 4362 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-024.expected b/clients/tests/test-client.check-on-disk/test_004-024.expected index b901fe23d1..1f5d993662 100644 --- a/clients/tests/test-client.check-on-disk/test_004-024.expected +++ b/clients/tests/test-client.check-on-disk/test_004-024.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:854:test_004()/24 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4337 bytes +stdout: 4380 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-025.expected b/clients/tests/test-client.check-on-disk/test_004-025.expected index 3ec1c5a44d..bf7758b000 100644 --- a/clients/tests/test-client.check-on-disk/test_004-025.expected +++ b/clients/tests/test-client.check-on-disk/test_004-025.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:857:test_004()/25 cmd: $NMCLI -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 3231 bytes +stdout: 3274 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-026.expected b/clients/tests/test-client.check-on-disk/test_004-026.expected index 8409fb7a5f..26e2788827 100644 --- a/clients/tests/test-client.check-on-disk/test_004-026.expected +++ b/clients/tests/test-client.check-on-disk/test_004-026.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:857:test_004()/26 cmd: $NMCLI -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3241 bytes +stdout: 3284 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -61,6 +61,7 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- ipv6.dhcp-send-hostname: tak ipv6.dhcp-hostname: -- ipv6.token: --